Sfoglia il codice sorgente

Fix fundamental frequency detection.

Andrew Klopper 6 anni fa
parent
commit
fdcb9b4d78
3 ha cambiato i file con 15 aggiunte e 42 eliminazioni
  1. 14 38
      home/xword.py
  2. 0 1
      requirements.in
  3. 1 3
      requirements.txt

+ 14 - 38
home/xword.py

88
     return cv2.warpPerspective(img, m, (int(longest), int(longest)))
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
 def get_threshold_from_quantile(img, quantile):
97
 def get_threshold_from_quantile(img, quantile):
199
     gaussian_blur_size=11,
172
     gaussian_blur_size=11,
200
     adaptive_threshold_block_size=11,
173
     adaptive_threshold_block_size=11,
201
     adaptive_threshold_mean_adjustment=2,
174
     adaptive_threshold_mean_adjustment=2,
202
-    not_square=False,
175
+    square=True,
203
     num_dilations=1,
176
     num_dilations=1,
204
     contour_erosion_kernel_size=5,
177
     contour_erosion_kernel_size=5,
205
     contour_erosion_iterations=5,
178
     contour_erosion_iterations=5,
211
     grid_square_size=64,
184
     grid_square_size=64,
212
     grid_border_size=20,
185
     grid_border_size=20,
213
 ):
186
 ):
187
+    warnings = []
188
+
214
     original = cv2.imread(file_name, cv2.IMREAD_GRAYSCALE)
189
     original = cv2.imread(file_name, cv2.IMREAD_GRAYSCALE)
215
     if original is None:
190
     if original is None:
216
         raise RuntimeError("Failed to load image")
191
         raise RuntimeError("Failed to load image")
235
     row_fft = np.fft.fft(np.sum(horiz_lines, axis=1))
210
     row_fft = np.fft.fft(np.sum(horiz_lines, axis=1))
236
     col_fft = np.fft.fft(np.sum(vert_lines, axis=0))
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
     block_img = extract_square(original, top_left, top_right, bottom_right, bottom_left)
218
     block_img = extract_square(original, top_left, top_right, bottom_right, bottom_left)
245
 
219
 
250
 
224
 
251
     grid_colours = extract_grid_colours(block_img, num_rows, num_cols, sampling_block_size_ratio)
225
     grid_colours = extract_grid_colours(block_img, num_rows, num_cols, sampling_block_size_ratio)
252
     warning, grid = grid_colours_to_blocks(grid_colours, num_rows, num_cols, sampling_threshold)
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
     step = grid_square_size + grid_line_thickness
230
     step = grid_square_size + grid_line_thickness
255
     grid_height = num_rows * step + grid_line_thickness
231
     grid_height = num_rows * step + grid_line_thickness
264
                 cv2.rectangle(output, (x, y), (x + grid_square_size - 1, y + grid_square_size - 1), 255, -1)
240
                 cv2.rectangle(output, (x, y), (x + grid_square_size - 1, y + grid_square_size - 1), 255, -1)
265
 
241
 
266
     _, png = cv2.imencode('.png', output)
242
     _, png = cv2.imencode('.png', output)
267
-    return png.tobytes(), warning
243
+    return png.tobytes(), warnings

+ 0 - 1
requirements.in

1
 chaussette
1
 chaussette
2
 django
2
 django
3
 opencv-python
3
 opencv-python
4
-peakutils
5
 pip-tools
4
 pip-tools

+ 1 - 3
requirements.txt

8
 chaussette==1.3.0
8
 chaussette==1.3.0
9
 click==7.0                # via pip-tools
9
 click==7.0                # via pip-tools
10
 django==3.0.2
10
 django==3.0.2
11
-numpy==1.18.1             # via opencv-python, peakutils, scipy
11
+numpy==1.18.1             # via opencv-python
12
 opencv-python==4.1.2.30
12
 opencv-python==4.1.2.30
13
-peakutils==1.3.3
14
 pip-tools==4.4.0
13
 pip-tools==4.4.0
15
 pytz==2019.3              # via django
14
 pytz==2019.3              # via django
16
-scipy==1.4.1              # via peakutils
17
 six==1.14.0               # via chaussette, pip-tools
15
 six==1.14.0               # via chaussette, pip-tools
18
 sqlparse==0.3.0           # via django
16
 sqlparse==0.3.0           # via django