@@ -9,6 +9,9 @@ namespace ximgproc {
9
9
10
10
int guo_hall_thinning (uint8_t * binary_image, size_t width, size_t height);
11
11
int zhang_suen_thinning (uint8_t * binary_image, size_t width, size_t height);
12
+ void bitwiseANDInPlace (uint8_t * a, const uint8_t * b, size_t size);
13
+
14
+ void thinninggh (InputArray input, OutputArray output, int thinningType);
12
15
13
16
/* *
14
17
* Perform a logical AND on a memory array (a), ANDing it with another array (b).
@@ -147,6 +150,8 @@ int zhang_suen_thinning(uint8_t* binary_image, size_t width, size_t height) {
147
150
148
151
// Apply the thinning procedure to a given image
149
152
void thinning (InputArray input, OutputArray output, int thinningType){
153
+ if (thinningType == THINNING_GUOHALL)
154
+ return thinninggh (input, output, thinningType);
150
155
Mat processed = input.getMat ().clone ();
151
156
CV_CheckTypeEQ (processed.type (), CV_8UC1, " " );
152
157
@@ -155,8 +160,145 @@ void thinning(InputArray input, OutputArray output, int thinningType){
155
160
if (thinningType == THINNING_ZHANGSUEN)
156
161
zhang_suen_thinning (processed.data , processed.cols , processed.rows );
157
162
158
- if (thinningType == THINNING_GUOHALL)
159
- guo_hall_thinning (processed.data , processed.cols , processed.rows );
163
+ processed *= 255 ;
164
+ output.assign (processed);
165
+ }
166
+
167
+ // look up table - there is one entry for each of the 2^8=256 possible
168
+ // combinations of 8 binary neighbors.
169
+ static uint8_t lut_zhang_iter0[] = {
170
+ 1 , 1 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 ,
171
+ 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 ,
172
+ 0 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
173
+ 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
174
+ 0 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
175
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
176
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 ,
177
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
178
+ 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 0 , 1 ,
179
+ 1 , 1 , 1 , 0 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 ,
180
+ 1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
181
+ 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
182
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
183
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 1 , 0 ,
184
+ 1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 ,
185
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
186
+ 0 , 0 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 1 ,
187
+ 1 , 1 , 0 , 0 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
188
+ 1 , 1 , 1 , 1 };
189
+
190
+ static uint8_t lut_zhang_iter1[] = {
191
+ 1 , 1 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 ,
192
+ 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 ,
193
+ 0 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
194
+ 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
195
+ 0 , 1 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 ,
196
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
197
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 ,
198
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
199
+ 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 0 , 1 ,
200
+ 0 , 1 , 1 , 0 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 ,
201
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
202
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
203
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
204
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 1 , 0 ,
205
+ 1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
206
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
207
+ 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
208
+ 1 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 1 , 1 ,
209
+ 0 , 1 , 1 , 1 };
210
+
211
+ static uint8_t lut_guo_iter0[] = {
212
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 1 ,
213
+ 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 ,
214
+ 0 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 ,
215
+ 0 , 0 , 0 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
216
+ 0 , 1 , 0 , 0 , 0 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 ,
217
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
218
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
219
+ 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 0 , 1 , 0 , 1 ,
220
+ 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 0 , 1 ,
221
+ 0 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 0 ,
222
+ 1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
223
+ 1 , 0 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
224
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
225
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
226
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
227
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
228
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
229
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
230
+ 1 , 1 , 1 , 1 };
231
+
232
+ static uint8_t lut_guo_iter1[] = {
233
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 1 ,
234
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
235
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
236
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
237
+ 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
238
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
239
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
240
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
241
+ 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 , 1 ,
242
+ 1 , 1 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 1 , 1 ,
243
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
244
+ 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 ,
245
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 1 , 1 ,
246
+ 1 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 ,
247
+ 1 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
248
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
249
+ 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 ,
250
+ 1 , 1 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 , 1 , 1 ,
251
+ 1 , 1 , 1 , 1 };
252
+
253
+ // Applies a thinning iteration to a binary image
254
+ static void thinningIteration (Mat &img, Mat &marker, const uint8_t * const lut) {
255
+ int rows = img.rows ;
256
+ int cols = img.cols ;
257
+ marker.col (0 ).setTo (1 );
258
+ marker.col (cols - 1 ).setTo (1 );
259
+ marker.row (0 ).setTo (1 );
260
+ marker.row (rows - 1 ).setTo (1 );
261
+
262
+ marker.forEach <uchar>([=](uchar& value, const int postion[]) {
263
+ int i = postion[0 ];
264
+ int j = postion[1 ];
265
+ if (i == 0 || j == 0 || i == rows - 1 || j == cols - 1 ) { return ; }
266
+
267
+ auto ptr = img.ptr (i, j); // p1
268
+ uchar p2 = ptr[-cols];
269
+ uchar p3 = ptr[-cols + 1 ];
270
+ uchar p4 = ptr[1 ];
271
+ uchar p5 = ptr[cols + 1 ];
272
+ uchar p6 = ptr[cols];
273
+ uchar p7 = ptr[cols - 1 ];
274
+ uchar p8 = ptr[-1 ];
275
+ uchar p9 = ptr[-cols - 1 ];
276
+
277
+ int neighbors = p9 | (p2 << 1 ) | (p3 << 2 ) | (p4 << 3 ) | (p5 << 4 ) | (p6 << 5 ) | (p7 << 6 ) | (p8 << 7 );
278
+ value = lut[neighbors];
279
+ });
280
+
281
+ img &= marker;
282
+ marker.setTo (0 );
283
+ }
284
+
285
+ // Apply the thinning procedure to a given image
286
+ void thinninggh (InputArray input, OutputArray output, int thinningType){
287
+ Mat processed = input.getMat ().clone ();
288
+ CV_CheckTypeEQ (processed.type (), CV_8UC1, " " );
289
+ // Enforce the range of the input image to be in between 0 - 255
290
+ processed /= 255 ;
291
+ Mat prev = processed.clone ();
292
+ Mat marker = Mat::zeros (processed.size (), CV_8UC1);
293
+ const auto lutIter0 = (thinningType == THINNING_GUOHALL) ? lut_guo_iter0 : lut_zhang_iter0;
294
+ const auto lutIter1 = (thinningType == THINNING_GUOHALL) ? lut_guo_iter1 : lut_zhang_iter1;
295
+ do {
296
+ thinningIteration (processed, marker, lutIter0);
297
+ thinningIteration (processed, marker, lutIter1);
298
+ const auto res = cv::norm (processed, prev, cv::NORM_L1);
299
+ if (res <= 0 ) { break ; }
300
+ processed.copyTo (prev);
301
+ } while (true );
160
302
161
303
processed *= 255 ;
162
304
output.assign (processed);
0 commit comments