|
|
@@ -88,37 +88,10 @@ def extract_square(img, top_left, top_right, bottom_right, bottom_left):
|
|
88
|
88
|
return cv2.warpPerspective(img, m, (int(longest), int(longest)))
|
|
89
|
89
|
|
|
90
|
90
|
|
|
91
|
|
-def get_fundamental_frequency(ffts):
|
|
92
|
|
- all_peak_indexes = []
|
|
93
|
|
- max_peak_count = None
|
|
94
|
|
- f_est = None
|
|
95
|
|
- for fft in ffts:
|
|
96
|
|
- # Use the upper half of the fft array, since this seems to always exclude the DC component.
|
|
97
|
|
- peak_indexes = peakutils.indexes(np.flip(abs(fft[len(fft) // 2:])), thres=0.3)
|
|
98
|
|
- peak_count = len(peak_indexes)
|
|
99
|
|
- if peak_count < 1:
|
|
100
|
|
- return None
|
|
101
|
|
- if (max_peak_count is None) or (peak_count > max_peak_count):
|
|
102
|
|
- max_peak_count = peak_count
|
|
103
|
|
- f_est = round(peak_indexes[peak_count - 1] / peak_count)
|
|
104
|
|
- all_peak_indexes.append(peak_indexes)
|
|
105
|
|
-
|
|
106
|
|
- if f_est < 2:
|
|
107
|
|
- return None
|
|
108
|
|
-
|
|
109
|
|
- min_err = None
|
|
110
|
|
- f = None
|
|
111
|
|
- for delta in range(-2, 3):
|
|
112
|
|
- err = 0
|
|
113
|
|
- f_current = f_est + delta
|
|
114
|
|
- for peak_indexes in all_peak_indexes:
|
|
115
|
|
- for i, peak_index in enumerate(peak_indexes):
|
|
116
|
|
- err += (peak_index - f_current * (i + 1)) ** 2
|
|
117
|
|
- if (min_err is None) or (err < min_err):
|
|
118
|
|
- min_err = err
|
|
119
|
|
- f = f_current
|
|
120
|
|
-
|
|
121
|
|
- return int(f)
|
|
|
91
|
+def get_fundamental_frequency(fft):
|
|
|
92
|
+ mag = abs(fft[0:len(fft) // 2])
|
|
|
93
|
+ mag[0] = 0
|
|
|
94
|
+ return int(np.argmax(mag))
|
|
122
|
95
|
|
|
123
|
96
|
|
|
124
|
97
|
def get_threshold_from_quantile(img, quantile):
|
|
|
@@ -199,7 +172,7 @@ def extract_crossword(
|
|
199
|
172
|
gaussian_blur_size=11,
|
|
200
|
173
|
adaptive_threshold_block_size=11,
|
|
201
|
174
|
adaptive_threshold_mean_adjustment=2,
|
|
202
|
|
- not_square=False,
|
|
|
175
|
+ square=True,
|
|
203
|
176
|
num_dilations=1,
|
|
204
|
177
|
contour_erosion_kernel_size=5,
|
|
205
|
178
|
contour_erosion_iterations=5,
|
|
|
@@ -211,6 +184,8 @@ def extract_crossword(
|
|
211
|
184
|
grid_square_size=64,
|
|
212
|
185
|
grid_border_size=20,
|
|
213
|
186
|
):
|
|
|
187
|
+ warnings = []
|
|
|
188
|
+
|
|
214
|
189
|
original = cv2.imread(file_name, cv2.IMREAD_GRAYSCALE)
|
|
215
|
190
|
if original is None:
|
|
216
|
191
|
raise RuntimeError("Failed to load image")
|
|
|
@@ -235,11 +210,10 @@ def extract_crossword(
|
|
235
|
210
|
row_fft = np.fft.fft(np.sum(horiz_lines, axis=1))
|
|
236
|
211
|
col_fft = np.fft.fft(np.sum(vert_lines, axis=0))
|
|
237
|
212
|
|
|
238
|
|
- if not_square:
|
|
239
|
|
- num_rows = get_fundamental_frequency([row_fft])
|
|
240
|
|
- num_cols = get_fundamental_frequency([col_fft])
|
|
241
|
|
- else:
|
|
242
|
|
- num_rows = num_cols = get_fundamental_frequency([row_fft, col_fft])
|
|
|
213
|
+ num_rows = get_fundamental_frequency(row_fft)
|
|
|
214
|
+ num_cols = get_fundamental_frequency(col_fft)
|
|
|
215
|
+ if square and (num_rows != num_cols):
|
|
|
216
|
+ warnings.append("Crossword is not square")
|
|
243
|
217
|
|
|
244
|
218
|
block_img = extract_square(original, top_left, top_right, bottom_right, bottom_left)
|
|
245
|
219
|
|
|
|
@@ -250,6 +224,8 @@ def extract_crossword(
|
|
250
|
224
|
|
|
251
|
225
|
grid_colours = extract_grid_colours(block_img, num_rows, num_cols, sampling_block_size_ratio)
|
|
252
|
226
|
warning, grid = grid_colours_to_blocks(grid_colours, num_rows, num_cols, sampling_threshold)
|
|
|
227
|
+ if warning:
|
|
|
228
|
+ warnings.append("Some blocks may be the wrong colour")
|
|
253
|
229
|
|
|
254
|
230
|
step = grid_square_size + grid_line_thickness
|
|
255
|
231
|
grid_height = num_rows * step + grid_line_thickness
|
|
|
@@ -264,4 +240,4 @@ def extract_crossword(
|
|
264
|
240
|
cv2.rectangle(output, (x, y), (x + grid_square_size - 1, y + grid_square_size - 1), 255, -1)
|
|
265
|
241
|
|
|
266
|
242
|
_, png = cv2.imencode('.png', output)
|
|
267
|
|
- return png.tobytes(), warning
|
|
|
243
|
+ return png.tobytes(), warnings
|