File size: 6,263 Bytes
79914f7 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
import cv2
import numpy as np
def apply_adaptive_threshold(image: np.ndarray) -> np.ndarray:
"""
Applies adaptive threshold to the given image
"""
return cv2.adaptiveThreshold(image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 5, 0)
def is_contour_rectangular(contour: np.ndarray) -> bool:
"""
Returns whether the given contour is rectangular or not
"""
num_sides = 4
perimeter = cv2.arcLength(contour, True)
approx = cv2.approxPolyDP(contour, 0.01 * perimeter, True)
return len(approx) == num_sides
def adaptive_vconcat(images: list[np.ndarray], fill_color: tuple[int, int, int] = (255, 255, 255)) -> np.ndarray:
max_width = max(img.shape[1] for img in images)
# Resize each image to match the largest dimensions
resized_images = []
for img in images:
resized_img = cv2.copyMakeBorder(img,
top=0, bottom=0,
left=0, right=max_width - img.shape[1],
borderType=cv2.BORDER_CONSTANT,
value=fill_color)
resized_images.append(resized_img)
# Concatenate vertically
return np.vstack(resized_images)
def adaptive_hconcat(images: list[np.ndarray], fill_color: tuple[int, int, int] = (255, 255, 255)) -> np.ndarray:
max_height = max(img.shape[0] for img in images)
# Resize each image to match the largest dimensions
resized_images = []
for img in images:
resized_img = cv2.copyMakeBorder(img,
top=0, bottom=max_height - img.shape[0],
left=0, right=0,
borderType=cv2.BORDER_CONSTANT,
value=fill_color)
resized_images.append(resized_img)
# Concatenate horizontally
return np.hstack(resized_images)
def group_contours_vertically(contours) -> list[list[np.ndarray]]:
"""
Groups the given contours vertically
"""
ERROR_THRESHOLD = 0.05
contours = sorted(contours, key=lambda c: cv2.boundingRect(c)[1])
grouped_contours = [[contours[0]]]
for contour in contours[1:]:
found_group = False
contour_x, contour_y, contour_w, contour_h = cv2.boundingRect(contour)
for group in grouped_contours[::-1]:
group_x, group_y, group_w, group_h = cv2.boundingRect(group[-1])
y_diff = abs(contour_y - group_y) - group_h
if y_diff < 0 or y_diff > min(contour_h, group_h):
continue
group_x_center = group_x + group_w / 2
contour_x_center = contour_x + contour_w / 2
if abs(group_x_center - contour_x_center) < ERROR_THRESHOLD * min(group_w, contour_w):
group.append(contour)
found_group = True
break
if not found_group:
grouped_contours.append([contour])
return grouped_contours
def group_contours_horizontally(contours) -> list[list[np.ndarray]]:
"""
Groups the given contours horizontally
"""
ERROR_THRESHOLD = 0.05
contours = sorted(contours, key=lambda c: cv2.boundingRect(c)[0])
grouped_contours = [[contours[0]]]
for contour in contours[1:]:
found_group = False
contour_x, contour_y, contour_w, contour_h = cv2.boundingRect(contour)
for group in grouped_contours[::-1]:
group_x, group_y, group_w, group_h = cv2.boundingRect(group[-1])
x_diff = abs(contour_x - group_x) - group_w
if x_diff < 0 or x_diff > min(contour_w, group_w):
continue
group_y_center = group_y + group_h / 2
contour_y_center = contour_y + contour_h / 2
if abs(group_y_center - contour_y_center) < ERROR_THRESHOLD * min(group_h, contour_h):
group.append(contour)
found_group = True
break
if not found_group:
grouped_contours.append([contour])
return grouped_contours
def group_bounding_boxes_vertically(bounding_boxes) -> list[list[tuple[int, int, int, int]]]:
"""
Groups the given bounding boxes vertically
"""
ERROR_THRESHOLD = 0.05
bounding_boxes = sorted(bounding_boxes, key=lambda bb: bb[1])
grouped_bounding_boxes = [[bounding_boxes[0]]]
for bounding_box in bounding_boxes[1:]:
found_group = False
bb_x, bb_y, bb_w, bb_h = bounding_box
for group in grouped_bounding_boxes[::-1]:
group_x, group_y, group_w, group_h = group[-1]
y_diff = abs(bb_y - group_y) - group_h
if y_diff < 0 or y_diff > min(bb_h, group_h):
continue
group_x_center = group_x + group_w / 2
bb_x_center = bb_x + bb_w / 2
if abs(group_x_center - bb_x_center) < ERROR_THRESHOLD * min(group_w, bb_w):
group.append(bounding_box)
found_group = True
break
if not found_group:
grouped_bounding_boxes.append([bounding_box])
return grouped_bounding_boxes
def group_bounding_boxes_horizontally(bounding_boxes) -> list[list[tuple[int, int, int, int]]]:
"""
Groups the given bounding boxes horizontally
"""
ERROR_THRESHOLD = 0.05
bounding_boxes = sorted(bounding_boxes, key=lambda bb: bb[0])
grouped_bounding_boxes = [[bounding_boxes[0]]]
for bounding_box in bounding_boxes[1:]:
found_group = False
bb_x, bb_y, bb_w, bb_h = bounding_box
for group in grouped_bounding_boxes[::-1]:
group_x, group_y, group_w, group_h = group[-1]
x_diff = abs(bb_x - group_x) - group_w
if x_diff < 0 or x_diff > min(bb_w, group_w):
continue
group_y_center = group_y + group_h / 2
bb_y_center = bb_y + bb_h / 2
if abs(group_y_center - bb_y_center) < ERROR_THRESHOLD * min(group_h, bb_h):
group.append(bounding_box)
found_group = True
break
if not found_group:
grouped_bounding_boxes.append([bounding_box])
return grouped_bounding_boxes |