Bläddra i källkod

Fix fundamental frequency detection.

Andrew Klopper 6 år sedan
förälder
incheckning
fdcb9b4d78
3 ändrade filer med 15 tillägg och 42 borttagningar
  1. 14 38
      home/xword.py
  2. 0 1
      requirements.in
  3. 1 3
      requirements.txt

+ 14 - 38
home/xword.py

@@ -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

+ 0 - 1
requirements.in

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

+ 1 - 3
requirements.txt

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