mirror of
https://github.com/qurator-spk/eynollah.git
synced 2025-11-16 09:24:19 +01:00
Revert to older deskew slope calculation — pairing between skewed and original contours was incorrect, so the original pairing logic has been restored. Also restored some original functions to ensure correct reading order detection.
This commit is contained in:
parent
19b2c3fa42
commit
e60b0e5911
3 changed files with 941 additions and 1062 deletions
|
|
@ -2482,119 +2482,150 @@ class Eynollah:
|
||||||
self, contours_only_text_parent, contours_only_text_parent_h, boxes, textline_mask_tot):
|
self, contours_only_text_parent, contours_only_text_parent_h, boxes, textline_mask_tot):
|
||||||
|
|
||||||
self.logger.debug("enter do_order_of_regions")
|
self.logger.debug("enter do_order_of_regions")
|
||||||
contours_only_text_parent = np.array(contours_only_text_parent)
|
|
||||||
contours_only_text_parent_h = np.array(contours_only_text_parent_h)
|
|
||||||
boxes = np.array(boxes, dtype=int) # to be on the safe side
|
boxes = np.array(boxes, dtype=int) # to be on the safe side
|
||||||
c_boxes = np.stack((0.5 * boxes[:, 2:4].sum(axis=1),
|
cx_text_only, cy_text_only, x_min_text_only, x_max_text_only, _, _, y_cor_x_min_main = find_new_features_of_contours(
|
||||||
0.5 * boxes[:, 0:2].sum(axis=1)))
|
|
||||||
cx_main, cy_main, mx_main, Mx_main, my_main, My_main, mxy_main = find_new_features_of_contours(
|
|
||||||
contours_only_text_parent)
|
contours_only_text_parent)
|
||||||
cx_head, cy_head, mx_head, Mx_head, my_head, My_head, mxy_head = find_new_features_of_contours(
|
cx_text_only_h, cy_text_only_h, x_min_text_only_h, x_max_text_only_h, _, _, y_cor_x_min_main_h = find_new_features_of_contours(
|
||||||
contours_only_text_parent_h)
|
contours_only_text_parent_h)
|
||||||
|
|
||||||
def match_boxes(only_centers: bool):
|
def match_boxes(only_centers: bool):
|
||||||
arg_text_con_main = np.zeros(len(contours_only_text_parent), dtype=int)
|
arg_text_con = []
|
||||||
for ii in range(len(contours_only_text_parent)):
|
for ii in range(len(cx_text_only)):
|
||||||
check_if_textregion_located_in_a_box = False
|
check_if_textregion_located_in_a_box = False
|
||||||
for jj, box in enumerate(boxes):
|
for jj in range(len(boxes)):
|
||||||
if ((cx_main[ii] >= box[0] and
|
if self.right2left:
|
||||||
cx_main[ii] < box[1] and
|
if ((x_max_text_only[ii] - 80 >= boxes[jj][0] and
|
||||||
cy_main[ii] >= box[2] and
|
x_max_text_only[ii] - 80 < boxes[jj][1] and
|
||||||
cy_main[ii] < box[3]) if only_centers else
|
y_cor_x_min_main[ii] >= boxes[jj][2] and
|
||||||
(mx_main[ii] >= box[0] and
|
y_cor_x_min_main[ii] < boxes[jj][3]) if only_centers else
|
||||||
Mx_main[ii] < box[1] and
|
(cx_text_only[ii] >= boxes[jj][0] and
|
||||||
my_main[ii] >= box[2] and
|
cx_text_only[ii] < boxes[jj][1] and
|
||||||
My_main[ii] < box[3])):
|
cy_text_only[ii] >= boxes[jj][2] and
|
||||||
arg_text_con_main[ii] = jj
|
cy_text_only[ii] < boxes[jj][3])):
|
||||||
|
arg_text_con.append(jj)
|
||||||
|
check_if_textregion_located_in_a_box = True
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if ((x_min_text_only[ii] + 80 >= boxes[jj][0] and
|
||||||
|
x_min_text_only[ii] + 80 < boxes[jj][1] and
|
||||||
|
y_cor_x_min_main[ii] >= boxes[jj][2] and
|
||||||
|
y_cor_x_min_main[ii] < boxes[jj][3]) if only_centers else
|
||||||
|
(cx_text_only[ii] >= boxes[jj][0] and
|
||||||
|
cx_text_only[ii] < boxes[jj][1] and
|
||||||
|
cy_text_only[ii] >= boxes[jj][2] and
|
||||||
|
cy_text_only[ii] < boxes[jj][3])):
|
||||||
|
arg_text_con.append(jj)
|
||||||
check_if_textregion_located_in_a_box = True
|
check_if_textregion_located_in_a_box = True
|
||||||
#print("main/matched", (mx_main[ii], Mx_main[ii], my_main[ii], My_main[ii]), "\tin", box, only_centers)
|
|
||||||
break
|
break
|
||||||
if not check_if_textregion_located_in_a_box:
|
if not check_if_textregion_located_in_a_box:
|
||||||
dists_tr_from_box = np.linalg.norm(c_boxes - np.array([[cy_main[ii]], [cx_main[ii]]]), axis=0)
|
dists_tr_from_box = [math.sqrt((cx_text_only[ii] - boxes[jj][1]) ** 2 +
|
||||||
pcontained_in_box = ((boxes[:, 2] <= cy_main[ii]) & (cy_main[ii] < boxes[:, 3]) &
|
(cy_text_only[ii] - boxes[jj][2]) ** 2)
|
||||||
(boxes[:, 0] <= cx_main[ii]) & (cx_main[ii] < boxes[:, 1]))
|
for jj in range(len(boxes))]
|
||||||
ind_min = np.argmin(np.ma.masked_array(dists_tr_from_box, ~pcontained_in_box))
|
ind_min = np.argmin(dists_tr_from_box)
|
||||||
arg_text_con_main[ii] = ind_min
|
arg_text_con.append(ind_min)
|
||||||
#print("main/fallback", (mx_main[ii], Mx_main[ii], my_main[ii], My_main[ii]), "\tin", boxes[ind_min], only_centers)
|
args_contours = np.array(range(len(arg_text_con)))
|
||||||
args_contours_main = np.arange(len(contours_only_text_parent))
|
arg_text_con_h = []
|
||||||
order_by_con_main = np.zeros_like(arg_text_con_main)
|
for ii in range(len(cx_text_only_h)):
|
||||||
|
check_if_textregion_located_in_a_box = False
|
||||||
|
for jj in range(len(boxes)):
|
||||||
|
if self.right2left:
|
||||||
|
if ((x_max_text_only_h[ii] - 80 >= boxes[jj][0] and
|
||||||
|
x_max_text_only_h[ii] - 80 < boxes[jj][1] and
|
||||||
|
y_cor_x_min_main_h[ii] >= boxes[jj][2] and
|
||||||
|
y_cor_x_min_main_h[ii] < boxes[jj][3]) if only_centers else
|
||||||
|
(cx_text_only_h[ii] >= boxes[jj][0] and
|
||||||
|
cx_text_only_h[ii] < boxes[jj][1] and
|
||||||
|
cy_text_only_h[ii] >= boxes[jj][2] and
|
||||||
|
cy_text_only_h[ii] < boxes[jj][3])):
|
||||||
|
arg_text_con_h.append(jj)
|
||||||
|
check_if_textregion_located_in_a_box = True
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if ((x_min_text_only_h[ii] + 80 >= boxes[jj][0] and
|
||||||
|
x_min_text_only_h[ii] + 80 < boxes[jj][1] and
|
||||||
|
y_cor_x_min_main_h[ii] >= boxes[jj][2] and
|
||||||
|
y_cor_x_min_main_h[ii] < boxes[jj][3]) if only_centers else
|
||||||
|
(cx_text_only_h[ii] >= boxes[jj][0] and
|
||||||
|
cx_text_only_h[ii] < boxes[jj][1] and
|
||||||
|
cy_text_only_h[ii] >= boxes[jj][2] and
|
||||||
|
cy_text_only_h[ii] < boxes[jj][3])):
|
||||||
|
arg_text_con_h.append(jj)
|
||||||
|
check_if_textregion_located_in_a_box = True
|
||||||
|
break
|
||||||
|
if not check_if_textregion_located_in_a_box:
|
||||||
|
dists_tr_from_box = [math.sqrt((cx_text_only_h[ii] - boxes[jj][1]) ** 2 +
|
||||||
|
(cy_text_only_h[ii] - boxes[jj][2]) ** 2)
|
||||||
|
for jj in range(len(boxes))]
|
||||||
|
ind_min = np.argmin(dists_tr_from_box)
|
||||||
|
arg_text_con_h.append(ind_min)
|
||||||
|
args_contours_h = np.array(range(len(arg_text_con_h)))
|
||||||
|
|
||||||
arg_text_con_head = np.zeros(len(contours_only_text_parent_h), dtype=int)
|
order_by_con_head = np.zeros(len(arg_text_con_h))
|
||||||
for ii in range(len(contours_only_text_parent_h)):
|
order_by_con_main = np.zeros(len(arg_text_con))
|
||||||
check_if_textregion_located_in_a_box = False
|
|
||||||
for jj, box in enumerate(boxes):
|
|
||||||
if ((cx_head[ii] >= box[0] and
|
|
||||||
cx_head[ii] < box[1] and
|
|
||||||
cy_head[ii] >= box[2] and
|
|
||||||
cy_head[ii] < box[3]) if only_centers else
|
|
||||||
(mx_head[ii] >= box[0] and
|
|
||||||
Mx_head[ii] < box[1] and
|
|
||||||
my_head[ii] >= box[2] and
|
|
||||||
My_head[ii] < box[3])):
|
|
||||||
arg_text_con_head[ii] = jj
|
|
||||||
check_if_textregion_located_in_a_box = True
|
|
||||||
#print("head/matched", (mx_head[ii], Mx_head[ii], my_head[ii], My_head[ii]), "\tin", box, only_centers)
|
|
||||||
break
|
|
||||||
if not check_if_textregion_located_in_a_box:
|
|
||||||
dists_tr_from_box = np.linalg.norm(c_boxes - np.array([[cy_head[ii]], [cx_head[ii]]]), axis=0)
|
|
||||||
pcontained_in_box = ((boxes[:, 2] <= cy_head[ii]) & (cy_head[ii] < boxes[:, 3]) &
|
|
||||||
(boxes[:, 0] <= cx_head[ii]) & (cx_head[ii] < boxes[:, 1]))
|
|
||||||
ind_min = np.argmin(np.ma.masked_array(dists_tr_from_box, ~pcontained_in_box))
|
|
||||||
arg_text_con_head[ii] = ind_min
|
|
||||||
#print("head/fallback", (mx_head[ii], Mx_head[ii], my_head[ii], My_head[ii]), "\tin", boxes[ind_min], only_centers)
|
|
||||||
args_contours_head = np.arange(len(contours_only_text_parent_h))
|
|
||||||
order_by_con_head = np.zeros_like(arg_text_con_head)
|
|
||||||
|
|
||||||
ref_point = 0
|
ref_point = 0
|
||||||
order_of_texts_tot = []
|
order_of_texts_tot = []
|
||||||
id_of_texts_tot = []
|
id_of_texts_tot = []
|
||||||
for iij, box in enumerate(boxes):
|
for iij in range(len(boxes)):
|
||||||
ys = slice(*box[2:4])
|
ys = slice(*boxes[iij][2:4])
|
||||||
xs = slice(*box[0:2])
|
xs = slice(*boxes[iij][0:2])
|
||||||
args_contours_box_main = args_contours_main[arg_text_con_main == iij]
|
args_contours_box = args_contours[np.array(arg_text_con) == iij]
|
||||||
args_contours_box_head = args_contours_head[arg_text_con_head == iij]
|
args_contours_box_h = args_contours_h[np.array(arg_text_con_h) == iij]
|
||||||
con_inter_box = contours_only_text_parent[args_contours_box_main]
|
con_inter_box = []
|
||||||
con_inter_box_h = contours_only_text_parent_h[args_contours_box_head]
|
con_inter_box_h = []
|
||||||
|
|
||||||
|
for box in args_contours_box:
|
||||||
|
con_inter_box.append(contours_only_text_parent[box])
|
||||||
|
|
||||||
|
for box in args_contours_box_h:
|
||||||
|
con_inter_box_h.append(contours_only_text_parent_h[box])
|
||||||
|
|
||||||
indexes_sorted, kind_of_texts_sorted, index_by_kind_sorted = order_of_regions(
|
indexes_sorted, kind_of_texts_sorted, index_by_kind_sorted = order_of_regions(
|
||||||
textline_mask_tot[ys, xs], con_inter_box, con_inter_box_h, box[2], box[0])
|
textline_mask_tot[ys, xs], con_inter_box, con_inter_box_h, boxes[iij][2])
|
||||||
|
|
||||||
order_of_texts, id_of_texts = order_and_id_of_texts(
|
order_of_texts, id_of_texts = order_and_id_of_texts(
|
||||||
con_inter_box, con_inter_box_h,
|
con_inter_box, con_inter_box_h,
|
||||||
indexes_sorted, index_by_kind_sorted, kind_of_texts_sorted, ref_point)
|
indexes_sorted, index_by_kind_sorted, kind_of_texts_sorted, ref_point)
|
||||||
|
|
||||||
indexes_sorted_main = indexes_sorted[kind_of_texts_sorted == 1]
|
indexes_sorted_main = np.array(indexes_sorted)[np.array(kind_of_texts_sorted) == 1]
|
||||||
indexes_by_type_main = index_by_kind_sorted[kind_of_texts_sorted == 1]
|
indexes_by_type_main = np.array(index_by_kind_sorted)[np.array(kind_of_texts_sorted) == 1]
|
||||||
indexes_sorted_head = indexes_sorted[kind_of_texts_sorted == 2]
|
indexes_sorted_head = np.array(indexes_sorted)[np.array(kind_of_texts_sorted) == 2]
|
||||||
indexes_by_type_head = index_by_kind_sorted[kind_of_texts_sorted == 2]
|
indexes_by_type_head = np.array(index_by_kind_sorted)[np.array(kind_of_texts_sorted) == 2]
|
||||||
|
|
||||||
for zahler, _ in enumerate(args_contours_box_main):
|
for zahler, _ in enumerate(args_contours_box):
|
||||||
arg_order_v = indexes_sorted_main[zahler]
|
arg_order_v = indexes_sorted_main[zahler]
|
||||||
order_by_con_main[args_contours_box_main[indexes_by_type_main[zahler]]] = \
|
order_by_con_main[args_contours_box[indexes_by_type_main[zahler]]] = \
|
||||||
np.flatnonzero(indexes_sorted == arg_order_v) + ref_point
|
np.where(indexes_sorted == arg_order_v)[0][0] + ref_point
|
||||||
|
|
||||||
for zahler, _ in enumerate(args_contours_box_head):
|
for zahler, _ in enumerate(args_contours_box_h):
|
||||||
arg_order_v = indexes_sorted_head[zahler]
|
arg_order_v = indexes_sorted_head[zahler]
|
||||||
order_by_con_head[args_contours_box_head[indexes_by_type_head[zahler]]] = \
|
order_by_con_head[args_contours_box_h[indexes_by_type_head[zahler]]] = \
|
||||||
np.flatnonzero(indexes_sorted == arg_order_v) + ref_point
|
np.where(indexes_sorted == arg_order_v)[0][0] + ref_point
|
||||||
|
|
||||||
for jji in range(len(id_of_texts)):
|
for jji in range(len(id_of_texts)):
|
||||||
order_of_texts_tot.append(order_of_texts[jji] + ref_point)
|
order_of_texts_tot.append(order_of_texts[jji] + ref_point)
|
||||||
id_of_texts_tot.append(id_of_texts[jji])
|
id_of_texts_tot.append(id_of_texts[jji])
|
||||||
ref_point += len(id_of_texts)
|
ref_point += len(id_of_texts)
|
||||||
|
|
||||||
order_of_texts_tot = np.concatenate((order_by_con_main,
|
order_of_texts_tot = []
|
||||||
order_by_con_head))
|
for tj1 in range(len(contours_only_text_parent)):
|
||||||
order_text_new = np.argsort(order_of_texts_tot)
|
order_of_texts_tot.append(int(order_by_con_main[tj1]))
|
||||||
|
|
||||||
|
for tj1 in range(len(contours_only_text_parent_h)):
|
||||||
|
order_of_texts_tot.append(int(order_by_con_head[tj1]))
|
||||||
|
|
||||||
|
order_text_new = []
|
||||||
|
for iii in range(len(order_of_texts_tot)):
|
||||||
|
order_text_new.append(np.where(np.array(order_of_texts_tot) == iii)[0][0])
|
||||||
|
|
||||||
return order_text_new, id_of_texts_tot
|
return order_text_new, id_of_texts_tot
|
||||||
|
|
||||||
try:
|
try:
|
||||||
results = match_boxes(False)
|
results = match_boxes(True)
|
||||||
except Exception as why:
|
except Exception as why:
|
||||||
self.logger.exception(why)
|
self.logger.exception(why)
|
||||||
results = match_boxes(True)
|
results = match_boxes(False)
|
||||||
|
self.logger.debug("exit do_order_of_regions_full_layout")
|
||||||
self.logger.debug("exit do_order_of_regions")
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def check_iou_of_bounding_box_and_contour_for_tables(
|
def check_iou_of_bounding_box_and_contour_for_tables(
|
||||||
|
|
@ -3088,7 +3119,7 @@ class Eynollah:
|
||||||
def run_deskew(self, textline_mask_tot_ea):
|
def run_deskew(self, textline_mask_tot_ea):
|
||||||
#print(textline_mask_tot_ea.shape, 'textline_mask_tot_ea deskew')
|
#print(textline_mask_tot_ea.shape, 'textline_mask_tot_ea deskew')
|
||||||
slope_deskew = return_deskew_slop(cv2.erode(textline_mask_tot_ea, KERNEL, iterations=2), 2, 30, True,
|
slope_deskew = return_deskew_slop(cv2.erode(textline_mask_tot_ea, KERNEL, iterations=2), 2, 30, True,
|
||||||
map=self.executor.map, logger=self.logger, plotter=self.plotter)
|
logger=self.logger, plotter=self.plotter)
|
||||||
if self.plotter:
|
if self.plotter:
|
||||||
self.plotter.save_deskewed_image(slope_deskew)
|
self.plotter.save_deskewed_image(slope_deskew)
|
||||||
self.logger.info("slope_deskew: %.2f°", slope_deskew)
|
self.logger.info("slope_deskew: %.2f°", slope_deskew)
|
||||||
|
|
@ -4419,130 +4450,89 @@ class Eynollah:
|
||||||
###min_con_area = 0.000005
|
###min_con_area = 0.000005
|
||||||
contours_only_text, hir_on_text = return_contours_of_image(text_only)
|
contours_only_text, hir_on_text = return_contours_of_image(text_only)
|
||||||
contours_only_text_parent = return_parent_contours(contours_only_text, hir_on_text)
|
contours_only_text_parent = return_parent_contours(contours_only_text, hir_on_text)
|
||||||
contours_only_text_parent_d_ordered = []
|
|
||||||
contours_only_text_parent_d = []
|
|
||||||
|
|
||||||
if len(contours_only_text_parent) > 0:
|
if len(contours_only_text_parent) > 0:
|
||||||
areas_tot_text = np.prod(text_only.shape)
|
|
||||||
areas_cnt_text = np.array([cv2.contourArea(c) for c in contours_only_text_parent])
|
areas_cnt_text = np.array([cv2.contourArea(c) for c in contours_only_text_parent])
|
||||||
areas_cnt_text = areas_cnt_text / float(areas_tot_text)
|
areas_cnt_text = areas_cnt_text / float(text_only.shape[0] * text_only.shape[1])
|
||||||
#self.logger.info('areas_cnt_text %s', areas_cnt_text)
|
contours_biggest = contours_only_text_parent[np.argmax(areas_cnt_text)]
|
||||||
contours_only_text_parent = np.array(contours_only_text_parent)[areas_cnt_text > MIN_AREA_REGION]
|
contours_only_text_parent = [c for jz, c in enumerate(contours_only_text_parent)
|
||||||
areas_cnt_text_parent = areas_cnt_text[areas_cnt_text > MIN_AREA_REGION]
|
if areas_cnt_text[jz] > MIN_AREA_REGION]
|
||||||
|
areas_cnt_text_parent = [area for area in areas_cnt_text if area > MIN_AREA_REGION]
|
||||||
index_con_parents = np.argsort(areas_cnt_text_parent)
|
index_con_parents = np.argsort(areas_cnt_text_parent)
|
||||||
contours_only_text_parent = contours_only_text_parent[index_con_parents]
|
|
||||||
areas_cnt_text_parent = areas_cnt_text_parent[index_con_parents]
|
|
||||||
|
|
||||||
centers = np.stack(find_center_of_contours(contours_only_text_parent)) # [2, N]
|
contours_only_text_parent = self.return_list_of_contours_with_desired_order(
|
||||||
|
contours_only_text_parent, index_con_parents)
|
||||||
|
|
||||||
center0 = centers[:, -1:] # [2, 1]
|
areas_cnt_text_parent = self.return_list_of_contours_with_desired_order(
|
||||||
|
areas_cnt_text_parent, index_con_parents)
|
||||||
|
|
||||||
|
cx_bigest_big, cy_biggest_big, _, _, _, _, _ = find_new_features_of_contours([contours_biggest])
|
||||||
|
cx_bigest, cy_biggest, _, _, _, _, _ = find_new_features_of_contours(contours_only_text_parent)
|
||||||
|
|
||||||
if np.abs(slope_deskew) >= SLOPE_THRESHOLD:
|
if np.abs(slope_deskew) >= SLOPE_THRESHOLD:
|
||||||
contours_only_text_d, hir_on_text_d = return_contours_of_image(text_only_d)
|
contours_only_text_d, hir_on_text_d = return_contours_of_image(text_only_d)
|
||||||
contours_only_text_parent_d = return_parent_contours(contours_only_text_d, hir_on_text_d)
|
contours_only_text_parent_d = return_parent_contours(contours_only_text_d, hir_on_text_d)
|
||||||
|
|
||||||
areas_tot_text_d = np.prod(text_only_d.shape)
|
|
||||||
areas_cnt_text_d = np.array([cv2.contourArea(c) for c in contours_only_text_parent_d])
|
areas_cnt_text_d = np.array([cv2.contourArea(c) for c in contours_only_text_parent_d])
|
||||||
areas_cnt_text_d = areas_cnt_text_d / float(areas_tot_text_d)
|
areas_cnt_text_d = areas_cnt_text_d / float(text_only_d.shape[0] * text_only_d.shape[1])
|
||||||
|
|
||||||
contours_only_text_parent_d = np.array(contours_only_text_parent_d)[areas_cnt_text_d > MIN_AREA_REGION]
|
if len(areas_cnt_text_d)>0:
|
||||||
areas_cnt_text_d = areas_cnt_text_d[areas_cnt_text_d > MIN_AREA_REGION]
|
contours_biggest_d = contours_only_text_parent_d[np.argmax(areas_cnt_text_d)]
|
||||||
|
|
||||||
if len(contours_only_text_parent_d):
|
|
||||||
index_con_parents_d = np.argsort(areas_cnt_text_d)
|
index_con_parents_d = np.argsort(areas_cnt_text_d)
|
||||||
contours_only_text_parent_d = np.array(contours_only_text_parent_d)[index_con_parents_d]
|
contours_only_text_parent_d = self.return_list_of_contours_with_desired_order(
|
||||||
areas_cnt_text_d = areas_cnt_text_d[index_con_parents_d]
|
contours_only_text_parent_d, index_con_parents_d)
|
||||||
|
|
||||||
centers_d = np.stack(find_center_of_contours(contours_only_text_parent_d)) # [2, N]
|
areas_cnt_text_d = self.return_list_of_contours_with_desired_order(
|
||||||
|
areas_cnt_text_d, index_con_parents_d)
|
||||||
|
|
||||||
center0_d = centers_d[:, -1:].copy() # [2, 1]
|
cx_bigest_d_big, cy_biggest_d_big, _, _, _, _, _ = find_new_features_of_contours([contours_biggest_d])
|
||||||
|
cx_bigest_d, cy_biggest_d, _, _, _, _, _ = find_new_features_of_contours(contours_only_text_parent_d)
|
||||||
|
try:
|
||||||
|
if len(cx_bigest_d) >= 5:
|
||||||
|
cx_bigest_d_last5 = cx_bigest_d[-5:]
|
||||||
|
cy_biggest_d_last5 = cy_biggest_d[-5:]
|
||||||
|
dists_d = [math.sqrt((cx_bigest_big[0] - cx_bigest_d_last5[j]) ** 2 +
|
||||||
|
(cy_biggest_big[0] - cy_biggest_d_last5[j]) ** 2)
|
||||||
|
for j in range(len(cy_biggest_d_last5))]
|
||||||
|
ind_largest = len(cx_bigest_d) -5 + np.argmin(dists_d)
|
||||||
|
else:
|
||||||
|
cx_bigest_d_last5 = cx_bigest_d[-len(cx_bigest_d):]
|
||||||
|
cy_biggest_d_last5 = cy_biggest_d[-len(cx_bigest_d):]
|
||||||
|
dists_d = [math.sqrt((cx_bigest_big[0]-cx_bigest_d_last5[j])**2 +
|
||||||
|
(cy_biggest_big[0]-cy_biggest_d_last5[j])**2)
|
||||||
|
for j in range(len(cy_biggest_d_last5))]
|
||||||
|
ind_largest = len(cx_bigest_d) - len(cx_bigest_d) + np.argmin(dists_d)
|
||||||
|
|
||||||
# find the largest among the largest 5 deskewed contours
|
cx_bigest_d_big[0] = cx_bigest_d[ind_largest]
|
||||||
# that is also closest to the largest original contour
|
cy_biggest_d_big[0] = cy_biggest_d[ind_largest]
|
||||||
last5_centers_d = centers_d[:, -5:]
|
except Exception as why:
|
||||||
dists_d = np.linalg.norm(center0 - last5_centers_d, axis=0)
|
self.logger.error(str(why))
|
||||||
ind_largest = len(contours_only_text_parent_d) - last5_centers_d.shape[1] + np.argmin(dists_d)
|
|
||||||
center0_d[:, 0] = centers_d[:, ind_largest]
|
|
||||||
|
|
||||||
# order new contours the same way as the undeskewed contours
|
|
||||||
# (by calculating the offset of the largest contours, respectively,
|
|
||||||
# of the new and undeskewed image; then for each contour,
|
|
||||||
# finding the closest new contour, with proximity calculated
|
|
||||||
# as distance of their centers modulo offset vector)
|
|
||||||
(h, w) = text_only.shape[:2]
|
(h, w) = text_only.shape[:2]
|
||||||
center = (w // 2.0, h // 2.0)
|
center = (w // 2.0, h // 2.0)
|
||||||
M = cv2.getRotationMatrix2D(center, slope_deskew, 1.0)
|
M = cv2.getRotationMatrix2D(center, slope_deskew, 1.0)
|
||||||
M_22 = np.array(M)[:2, :2]
|
M_22 = np.array(M)[:2, :2]
|
||||||
center0 = np.dot(M_22, center0) # [2, 1]
|
p_big = np.dot(M_22, [cx_bigest_big, cy_biggest_big])
|
||||||
offset = center0 - center0_d # [2, 1]
|
x_diff = p_big[0] - cx_bigest_d_big
|
||||||
|
y_diff = p_big[1] - cy_biggest_d_big
|
||||||
|
|
||||||
centers = np.dot(M_22, centers) - offset # [2,N]
|
contours_only_text_parent_d_ordered = []
|
||||||
# add dimension for area (so only contours of similar size will be considered close)
|
for i in range(len(contours_only_text_parent)):
|
||||||
centers = np.append(centers, areas_cnt_text_parent[np.newaxis], axis=0)
|
p = np.dot(M_22, [cx_bigest[i], cy_biggest[i]])
|
||||||
centers_d = np.append(centers_d, areas_cnt_text_d[np.newaxis], axis=0)
|
p[0] = p[0] - x_diff[0]
|
||||||
|
p[1] = p[1] - y_diff[0]
|
||||||
|
dists = [math.sqrt((p[0] - cx_bigest_d[j]) ** 2 +
|
||||||
|
(p[1] - cy_biggest_d[j]) ** 2)
|
||||||
|
for j in range(len(cx_bigest_d))]
|
||||||
|
contours_only_text_parent_d_ordered.append(contours_only_text_parent_d[np.argmin(dists)])
|
||||||
|
else:
|
||||||
|
contours_only_text_parent_d_ordered = []
|
||||||
|
contours_only_text_parent_d = []
|
||||||
|
contours_only_text_parent = []
|
||||||
|
|
||||||
dists = np.zeros((len(contours_only_text_parent), len(contours_only_text_parent_d)))
|
else:
|
||||||
for i in range(len(contours_only_text_parent)):
|
contours_only_text_parent_d_ordered = []
|
||||||
dists[i] = np.linalg.norm(centers[:, i:i + 1] - centers_d, axis=0)
|
contours_only_text_parent_d = []
|
||||||
corresp = np.zeros(dists.shape, dtype=bool)
|
|
||||||
# keep searching next-closest until at least one correspondence on each side
|
|
||||||
while not np.all(corresp.sum(axis=1)) and not np.all(corresp.sum(axis=0)):
|
|
||||||
idx = np.nanargmin(dists)
|
|
||||||
i, j = np.unravel_index(idx, dists.shape)
|
|
||||||
dists[i, j] = np.nan
|
|
||||||
corresp[i, j] = True
|
|
||||||
#print("original/deskewed adjacency", corresp.nonzero())
|
|
||||||
contours_only_text_parent_d_ordered = np.zeros_like(contours_only_text_parent)
|
|
||||||
contours_only_text_parent_d_ordered = contours_only_text_parent_d[np.argmax(corresp, axis=1)]
|
|
||||||
# img1 = np.zeros(text_only_d.shape[:2], dtype=np.uint8)
|
|
||||||
# for i in range(len(contours_only_text_parent)):
|
|
||||||
# cv2.fillPoly(img1, pts=[contours_only_text_parent_d_ordered[i]], color=i + 1)
|
|
||||||
# plt.subplot(2, 2, 1, title="direct corresp contours")
|
|
||||||
# plt.imshow(img1)
|
|
||||||
# img2 = np.zeros(text_only_d.shape[:2], dtype=np.uint8)
|
|
||||||
# join deskewed regions mapping to single original ones
|
|
||||||
for i in range(len(contours_only_text_parent)):
|
|
||||||
if np.count_nonzero(corresp[i]) > 1:
|
|
||||||
indices = np.flatnonzero(corresp[i])
|
|
||||||
#print("joining", indices)
|
|
||||||
polygons_d = [contour2polygon(contour)
|
|
||||||
for contour in contours_only_text_parent_d[indices]]
|
|
||||||
contour_d = polygon2contour(join_polygons(polygons_d))
|
|
||||||
contours_only_text_parent_d_ordered[i] = contour_d
|
|
||||||
# cv2.fillPoly(img2, pts=[contour_d], color=i + 1)
|
|
||||||
# plt.subplot(2, 2, 3, title="joined contours")
|
|
||||||
# plt.imshow(img2)
|
|
||||||
# img3 = np.zeros(text_only_d.shape[:2], dtype=np.uint8)
|
|
||||||
# split deskewed regions mapping to multiple original ones
|
|
||||||
def deskew(polygon):
|
|
||||||
polygon = shapely.affinity.rotate(polygon, -slope_deskew, origin=center)
|
|
||||||
polygon = shapely.affinity.translate(polygon, *offset.squeeze())
|
|
||||||
return polygon
|
|
||||||
for j in range(len(contours_only_text_parent_d)):
|
|
||||||
if np.count_nonzero(corresp[:, j]) > 1:
|
|
||||||
indices = np.flatnonzero(corresp[:, j])
|
|
||||||
#print("splitting along", indices)
|
|
||||||
polygons = [deskew(contour2polygon(contour))
|
|
||||||
for contour in contours_only_text_parent[indices]]
|
|
||||||
polygon_d = contour2polygon(contours_only_text_parent_d[j])
|
|
||||||
polygons_d = [make_intersection(polygon_d, polygon)
|
|
||||||
for polygon in polygons]
|
|
||||||
# ignore where there is no actual overlap
|
|
||||||
indices = indices[np.flatnonzero(polygons_d)]
|
|
||||||
contours_d = [polygon2contour(polygon_d)
|
|
||||||
for polygon_d in polygons_d
|
|
||||||
if polygon_d]
|
|
||||||
contours_only_text_parent_d_ordered[indices] = contours_d
|
|
||||||
# cv2.fillPoly(img3, pts=contours_d, color=j + 1)
|
|
||||||
# plt.subplot(2, 2, 4, title="split contours")
|
|
||||||
# plt.imshow(img3)
|
|
||||||
# img4 = np.zeros(text_only_d.shape[:2], dtype=np.uint8)
|
|
||||||
# for i in range(len(contours_only_text_parent)):
|
|
||||||
# cv2.fillPoly(img4, pts=[contours_only_text_parent_d_ordered[i]], color=i + 1)
|
|
||||||
# plt.subplot(2, 2, 2, title="result contours")
|
|
||||||
# plt.imshow(img4)
|
|
||||||
# plt.show()
|
|
||||||
|
|
||||||
if not len(contours_only_text_parent):
|
if not len(contours_only_text_parent):
|
||||||
# stop early
|
# stop early
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1497,21 +1497,23 @@ def separate_lines_new2(img_crop, thetha, num_col, slope_region, logger=None, pl
|
||||||
|
|
||||||
return img_patch_interest_revised
|
return img_patch_interest_revised
|
||||||
|
|
||||||
@wrap_ndarray_shared(kw='img')
|
def do_image_rotation(queue_of_all_params,angles_per_process, img_resized, sigma_des):
|
||||||
def do_image_rotation(angle, img=None, sigma_des=1.0, logger=None):
|
vars_per_each_subprocess = []
|
||||||
if logger is None:
|
angles_per_each_subprocess = []
|
||||||
logger = getLogger(__package__)
|
for mv in range(len(angles_per_process)):
|
||||||
img_rot = rotate_image(img, angle)
|
img_rot=rotate_image(img_resized,angles_per_process[mv])
|
||||||
img_rot[img_rot!=0] = 1
|
img_rot[img_rot!=0]=1
|
||||||
try:
|
try:
|
||||||
var = find_num_col_deskew(img_rot, sigma_des, 20.3)
|
var_spectrum=find_num_col_deskew(img_rot,sigma_des,20.3 )
|
||||||
except:
|
except:
|
||||||
logger.exception("cannot determine variance for angle %.2f°", angle)
|
var_spectrum=0
|
||||||
var = 0
|
vars_per_each_subprocess.append(var_spectrum)
|
||||||
return var
|
angles_per_each_subprocess.append(angles_per_process[mv])
|
||||||
|
|
||||||
|
queue_of_all_params.put([vars_per_each_subprocess, angles_per_each_subprocess])
|
||||||
|
|
||||||
def return_deskew_slop(img_patch_org, sigma_des,n_tot_angles=100,
|
def return_deskew_slop(img_patch_org, sigma_des,n_tot_angles=100,
|
||||||
main_page=False, logger=None, plotter=None, map=None):
|
main_page=False, logger=None, plotter=None):
|
||||||
if main_page and plotter:
|
if main_page and plotter:
|
||||||
plotter.save_plot_of_textline_density(img_patch_org)
|
plotter.save_plot_of_textline_density(img_patch_org)
|
||||||
|
|
||||||
|
|
@ -1524,71 +1526,76 @@ def return_deskew_slop(img_patch_org, sigma_des,n_tot_angles=100,
|
||||||
onset_x=int((img_resized.shape[1]-img_int.shape[1])/2.)
|
onset_x=int((img_resized.shape[1]-img_int.shape[1])/2.)
|
||||||
onset_y=int((img_resized.shape[0]-img_int.shape[0])/2.)
|
onset_y=int((img_resized.shape[0]-img_int.shape[0])/2.)
|
||||||
|
|
||||||
#img_resized=np.zeros((int( img_int.shape[0]*(1.8) ) , int( img_int.shape[1]*(2.6) ) ))
|
|
||||||
#img_resized[ int( img_int.shape[0]*(.4)):int( img_int.shape[0]*(.4))+img_int.shape[0],
|
|
||||||
# int( img_int.shape[1]*(.8)):int( img_int.shape[1]*(.8))+img_int.shape[1] ]=img_int[:,:]
|
|
||||||
img_resized[ onset_y:onset_y+img_int.shape[0] , onset_x:onset_x+img_int.shape[1] ]=img_int[:,:]
|
img_resized[ onset_y:onset_y+img_int.shape[0] , onset_x:onset_x+img_int.shape[1] ]=img_int[:,:]
|
||||||
|
|
||||||
if main_page and img_patch_org.shape[1] > img_patch_org.shape[0]:
|
if main_page and img_patch_org.shape[1] > img_patch_org.shape[0]:
|
||||||
angles = np.array([-45, 0, 45, 90,])
|
angles = np.array([-45, 0, 45, 90,])
|
||||||
angle, _ = get_smallest_skew(img_resized, sigma_des, angles, map=map, logger=logger, plotter=plotter)
|
angle = get_smallest_skew(img_resized, sigma_des, angles, plotter=plotter)
|
||||||
|
|
||||||
angles = np.linspace(angle - 22.5, angle + 22.5, n_tot_angles)
|
angles = np.linspace(angle - 22.5, angle + 22.5, n_tot_angles)
|
||||||
angle, _ = get_smallest_skew(img_resized, sigma_des, angles, map=map, logger=logger, plotter=plotter)
|
angle = get_smallest_skew(img_resized, sigma_des, angles, plotter=plotter)
|
||||||
elif main_page:
|
elif main_page:
|
||||||
#angles = np.linspace(-12, 12, n_tot_angles)#np.array([0 , 45 , 90 , -45])
|
angles = np.linspace(-12, 12, n_tot_angles)#np.array([0 , 45 , 90 , -45])
|
||||||
angles = np.concatenate((np.linspace(-12, -7, n_tot_angles // 4),
|
angle = get_smallest_skew(img_resized, sigma_des, angles, plotter=plotter)
|
||||||
np.linspace(-6, 6, n_tot_angles // 2),
|
|
||||||
np.linspace(7, 12, n_tot_angles // 4)))
|
|
||||||
angle, var = get_smallest_skew(img_resized, sigma_des, angles, map=map, logger=logger, plotter=plotter)
|
|
||||||
|
|
||||||
early_slope_edge=11
|
early_slope_edge=11
|
||||||
if abs(angle) > early_slope_edge:
|
if abs(angle) > early_slope_edge:
|
||||||
if angle < 0:
|
if angle < 0:
|
||||||
angles2 = np.linspace(-90, -12, n_tot_angles)
|
angles = np.linspace(-90, -12, n_tot_angles)
|
||||||
else:
|
else:
|
||||||
angles2 = np.linspace(90, 12, n_tot_angles)
|
angles = np.linspace(90, 12, n_tot_angles)
|
||||||
angle2, var2 = get_smallest_skew(img_resized, sigma_des, angles2, map=map, logger=logger, plotter=plotter)
|
angle = get_smallest_skew(img_resized, sigma_des, angles, plotter=plotter)
|
||||||
if var2 > var:
|
|
||||||
angle = angle2
|
|
||||||
else:
|
else:
|
||||||
angles = np.linspace(-25, 25, int(0.5 * n_tot_angles) + 10)
|
angles = np.linspace(-25, 25, int(0.5 * n_tot_angles) + 10)
|
||||||
angle, var = get_smallest_skew(img_resized, sigma_des, angles, map=map, logger=logger, plotter=plotter)
|
angle = get_smallest_skew(img_resized, sigma_des, angles, plotter=plotter)
|
||||||
|
|
||||||
early_slope_edge=22
|
early_slope_edge=22
|
||||||
if abs(angle) > early_slope_edge:
|
if abs(angle) > early_slope_edge:
|
||||||
if angle < 0:
|
if angle < 0:
|
||||||
angles2 = np.linspace(-90, -25, int(0.5 * n_tot_angles) + 10)
|
angles = np.linspace(-90, -25, int(0.5 * n_tot_angles) + 10)
|
||||||
else:
|
else:
|
||||||
angles2 = np.linspace(90, 25, int(0.5 * n_tot_angles) + 10)
|
angles = np.linspace(90, 25, int(0.5 * n_tot_angles) + 10)
|
||||||
angle2, var2 = get_smallest_skew(img_resized, sigma_des, angles2, map=map, logger=logger, plotter=plotter)
|
angle = get_smallest_skew(img_resized, sigma_des, angles, plotter=plotter)
|
||||||
if var2 > var:
|
|
||||||
angle = angle2
|
|
||||||
return angle
|
return angle
|
||||||
|
|
||||||
def get_smallest_skew(img, sigma_des, angles, logger=None, plotter=None, map=map):
|
def get_smallest_skew(img_resized, sigma_des, angles, plotter=None):
|
||||||
if logger is None:
|
num_cores = cpu_count()
|
||||||
logger = getLogger(__package__)
|
|
||||||
if map is None:
|
queue_of_all_params = Queue()
|
||||||
results = [do_image_rotation.__wrapped__(angle, img=img, sigma_des=sigma_des, logger=logger)
|
processes = []
|
||||||
for angle in angles]
|
nh = np.linspace(0, len(angles), num_cores + 1)
|
||||||
else:
|
|
||||||
with share_ndarray(img) as img_shared:
|
for i in range(num_cores):
|
||||||
results = list(map(partial(do_image_rotation, img=img_shared, sigma_des=sigma_des, logger=None),
|
angles_per_process = angles[int(nh[i]) : int(nh[i + 1])]
|
||||||
angles))
|
processes.append(Process(target=do_image_rotation, args=(queue_of_all_params, angles_per_process, img_resized, sigma_des)))
|
||||||
|
|
||||||
|
for i in range(num_cores):
|
||||||
|
processes[i].start()
|
||||||
|
|
||||||
|
var_res=[]
|
||||||
|
all_angles = []
|
||||||
|
for i in range(num_cores):
|
||||||
|
list_all_par = queue_of_all_params.get(True)
|
||||||
|
vars_for_subprocess = list_all_par[0]
|
||||||
|
angles_sub_process = list_all_par[1]
|
||||||
|
for j in range(len(vars_for_subprocess)):
|
||||||
|
var_res.append(vars_for_subprocess[j])
|
||||||
|
all_angles.append(angles_sub_process[j])
|
||||||
|
|
||||||
|
for i in range(num_cores):
|
||||||
|
processes[i].join()
|
||||||
|
|
||||||
if plotter:
|
if plotter:
|
||||||
plotter.save_plot_of_rotation_angle(angles, results)
|
plotter.save_plot_of_rotation_angle(all_angles, var_res)
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
var_res = np.array(results)
|
var_res=np.array(var_res)
|
||||||
assert var_res.any()
|
ang_int=all_angles[np.argmax(var_res)]#angels_sorted[arg_final]#angels[arg_sort_early[arg_sort[arg_final]]]#angels[arg_fin]
|
||||||
idx = np.argmax(var_res)
|
|
||||||
angle = angles[idx]
|
|
||||||
var = var_res[idx]
|
|
||||||
except:
|
except:
|
||||||
logger.exception("cannot determine best angle among %s", str(angles))
|
ang_int=0
|
||||||
angle = 0
|
return ang_int
|
||||||
var = 0
|
|
||||||
return angle, var
|
|
||||||
|
|
||||||
@wrap_ndarray_shared(kw='textline_mask_tot_ea')
|
@wrap_ndarray_shared(kw='textline_mask_tot_ea')
|
||||||
def do_work_of_slopes_new(
|
def do_work_of_slopes_new(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue