Skip to content

Commit 7683925

Browse files
authored
Update thinning.cpp
1 parent 5a981fa commit 7683925

File tree

1 file changed

+28
-203
lines changed

1 file changed

+28
-203
lines changed

modules/ximgproc/src/thinning.cpp

Lines changed: 28 additions & 203 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ void bitwiseANDInPlace(uint8_t* a, const uint8_t* b, size_t size) {
2525
* Performs a single iteration of the Guo-Hall algorithm.
2626
* See http://opencv-code.com/quick-tips/implementation-of-guo-hall-thinning-algorithm/
2727
* and the original paper http://dx.doi.org/10.1145/62065.62074 for details.
28-
*
28+
*
2929
* Compared to the opencv-code.com implementation, we also count the number of
3030
* changes during the iteration in order to avoid the cv::absdiff() call and the
3131
* super-expensive whole-image (possibly multi-Mibibyte) copy to prev.
@@ -36,23 +36,22 @@ int guo_hall_iteration(uint8_t* img, uint8_t* mask, size_t width, size_t height,
3636
for (unsigned int x = 1; x < width - 1; x++) {
3737
if (IMG_XY(img, x, y) == 0) continue;
3838

39-
bool p2 = IMG_XY(img, x, y - 1);
40-
bool p3 = IMG_XY(img, x + 1, y - 1);
41-
bool p4 = IMG_XY(img, x + 1, y);
42-
bool p5 = IMG_XY(img, x + 1, y + 1);
43-
bool p6 = IMG_XY(img, x, y + 1);
44-
bool p7 = IMG_XY(img, x - 1, y + 1);
45-
bool p8 = IMG_XY(img, x - 1, y);
46-
bool p9 = IMG_XY(img, x - 1, y - 1);
47-
48-
unsigned int N1 = (p9 || p2) + (p3 || p4) + (p5 || p6) + (p7 || p8);
49-
unsigned int N2 = (p2 || p3) + (p4 || p5) + (p6 || p7) + (p8 || p9);
50-
unsigned int N = (N1 < N2) ? N1 : N2;
51-
52-
unsigned int m = oddIteration ? (p8 && (p6 || p7 || !p9)) : (p4 && (p2 || p3 || !p5));
53-
unsigned int C = (!p2 && (p3 || p4)) + (!p4 && (p5 || p6)) + (!p6 && (p7 || p8)) + (!p8 && (p9 || p2));
54-
55-
if (C == 1 && N >= 2 && N <= 3 && m == 0) {
39+
uchar p2 = IMG_XY(img, x, y - 1);
40+
uchar p3 = IMG_XY(img, x + 1, y - 1);
41+
uchar p4 = IMG_XY(img, x + 1, y);
42+
uchar p5 = IMG_XY(img, x + 1, y + 1);
43+
uchar p6 = IMG_XY(img, x, y + 1);
44+
uchar p7 = IMG_XY(img, x - 1, y + 1);
45+
uchar p8 = IMG_XY(img, x - 1, y);
46+
uchar p9 = IMG_XY(img, x - 1, y - 1);
47+
48+
int C = ((!p2) & (p3 | p4)) + ((!p4) & (p5 | p6)) +
49+
((!p6) & (p7 | p8)) + ((!p8) & (p9 | p2));
50+
int N1 = (p9 | p2) + (p3 | p4) + (p5 | p6) + (p7 | p8);
51+
int N2 = (p2 | p3) + (p4 | p5) + (p6 | p7) + (p8 | p9);
52+
int N = N1 < N2 ? N1 : N2;
53+
int m = oddIteration ? ((p6 | p7 | (!p9)) & p8) : ((p2 | p3 | (!p5)) & p4);
54+
if ((C == 1) && ((N >= 2) && ((N <= 3)) & (m == 0))) {
5655
IMG_XY(mask, x, y) = 0; // Mask is computed in an inverted way
5756
changed++;
5857
}
@@ -74,14 +73,14 @@ int zhang_suen_iteration(uint8_t* img, uint8_t* mask, size_t width, size_t heigh
7473
for (unsigned int x = 1; x < width - 1; x++) {
7574
if (IMG_XY(img, x, y) == 0) continue;
7675

77-
bool p2 = IMG_XY(img, x, y - 1);
78-
bool p3 = IMG_XY(img, x + 1, y - 1);
79-
bool p4 = IMG_XY(img, x + 1, y);
80-
bool p5 = IMG_XY(img, x + 1, y + 1);
81-
bool p6 = IMG_XY(img, x, y + 1);
82-
bool p7 = IMG_XY(img, x - 1, y + 1);
83-
bool p8 = IMG_XY(img, x - 1, y);
84-
bool p9 = IMG_XY(img, x - 1, y - 1);
76+
uchar p2 = IMG_XY(img, x, y - 1);
77+
uchar p3 = IMG_XY(img, x + 1, y - 1);
78+
uchar p4 = IMG_XY(img, x + 1, y);
79+
uchar p5 = IMG_XY(img, x + 1, y + 1);
80+
uchar p6 = IMG_XY(img, x, y + 1);
81+
uchar p7 = IMG_XY(img, x - 1, y + 1);
82+
uchar p8 = IMG_XY(img, x - 1, y);
83+
uchar p9 = IMG_XY(img, x - 1, y - 1);
8584

8685
int A = (p2 == 0 && p3 == 1) + (p3 == 0 && p4 == 1) +
8786
(p4 == 0 && p5 == 1) + (p5 == 0 && p6 == 1) +
@@ -146,194 +145,20 @@ int zhang_suen_thinning(uint8_t* binary_image, size_t width, size_t height) {
146145
return 0;
147146
}
148147

149-
// look up table - there is one entry for each of the 2^8=256 possible
150-
// combinations of 8 binary neighbors.
151-
static uint8_t lut_zhang_iter0[] = {
152-
1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1,
153-
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
154-
0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
155-
1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1,
156-
0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
157-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
158-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,
159-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
160-
0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1,
161-
1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1,
162-
1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
163-
1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
164-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
165-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0,
166-
1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1,
167-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
168-
0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
169-
1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
170-
1, 1, 1, 1};
171-
172-
static uint8_t lut_zhang_iter1[] = {
173-
1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1,
174-
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
175-
0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
176-
1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1,
177-
0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1,
178-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
179-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,
180-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
181-
0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1,
182-
0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1,
183-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
184-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
185-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
186-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0,
187-
1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
188-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
189-
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
190-
1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1,
191-
0, 1, 1, 1};
192-
193-
static uint8_t lut_guo_iter0[] = {
194-
1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1,
195-
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
196-
0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,
197-
0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
198-
0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1,
199-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
200-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
201-
1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,
202-
0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1,
203-
0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0,
204-
1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
205-
1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
206-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
207-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
208-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
209-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
210-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
211-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
212-
1, 1, 1, 1};
213-
214-
static uint8_t lut_guo_iter1[] = {
215-
1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
216-
1, 1, 1, 1, 1, 1, 1, 1, 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-
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
220-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
221-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
222-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
223-
0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,
224-
1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 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, 0, 0, 0, 0, 1, 1, 0, 0,
227-
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1,
228-
1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
229-
1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
230-
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
231-
0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1,
232-
1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1,
233-
1, 1, 1, 1};
234-
235-
// Applies a thinning iteration to a binary image
236-
static void thinningIteration(Mat img, int iter, int thinningType){
237-
Mat marker = Mat::zeros(img.size(), CV_8UC1);
238-
int rows = img.rows;
239-
int cols = img.cols;
240-
marker.col(0).setTo(1);
241-
marker.col(cols - 1).setTo(1);
242-
marker.row(0).setTo(1);
243-
marker.row(rows - 1).setTo(1);
244-
245-
if(thinningType == THINNING_ZHANGSUEN){
246-
marker.forEach<uchar>([=](uchar& value, const int postion[]) {
247-
int i = postion[0];
248-
int j = postion[1];
249-
if (i == 0 || j == 0 || i == rows - 1 || j == cols - 1)
250-
return;
251-
252-
auto ptr = img.ptr(i, j); // p1
253-
254-
// p9 p2 p3
255-
// p8 p1 p4
256-
// p7 p6 p5
257-
uchar p2 = ptr[-cols];
258-
uchar p3 = ptr[-cols + 1];
259-
uchar p4 = ptr[1];
260-
uchar p5 = ptr[cols + 1];
261-
uchar p6 = ptr[cols];
262-
uchar p7 = ptr[cols - 1];
263-
uchar p8 = ptr[-1];
264-
uchar p9 = ptr[-cols - 1];
265-
266-
int neighbors = p9 | (p2 << 1) | (p3 << 2) | (p4 << 3) | (p5 << 4) | (p6 << 5) | (p7 << 6) | (p8 << 7);
267-
268-
if (iter == 0)
269-
value = lut_zhang_iter0[neighbors];
270-
else
271-
value = lut_zhang_iter1[neighbors];
272-
273-
//int A = (p2 == 0 && p3 == 1) + (p3 == 0 && p4 == 1) +
274-
// (p4 == 0 && p5 == 1) + (p5 == 0 && p6 == 1) +
275-
// (p6 == 0 && p7 == 1) + (p7 == 0 && p8 == 1) +
276-
// (p8 == 0 && p9 == 1) + (p9 == 0 && p2 == 1);
277-
//int B = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
278-
//int m1 = iter == 0 ? (p2 * p4 * p6) : (p2 * p4 * p8);
279-
//int m2 = iter == 0 ? (p4 * p6 * p8) : (p2 * p6 * p8);
280-
//if (A == 1 && (B >= 2 && B <= 6) && m1 == 0 && m2 == 0) value = 0;
281-
// else value = 1;
282-
});
283-
}
284-
if(thinningType == THINNING_GUOHALL){
285-
marker.forEach<uchar>([=](uchar& value, const int postion[]) {
286-
int i = postion[0];
287-
int j = postion[1];
288-
if (i == 0 || j == 0 || i == rows - 1 || j == cols - 1)
289-
return;
290-
291-
auto ptr = img.ptr(i, j); // p1
292-
293-
// p9 p2 p3
294-
// p8 p1 p4
295-
// p7 p6 p5
296-
uchar p2 = ptr[-cols];
297-
uchar p3 = ptr[-cols + 1];
298-
uchar p4 = ptr[1];
299-
uchar p5 = ptr[cols + 1];
300-
uchar p6 = ptr[cols];
301-
uchar p7 = ptr[cols - 1];
302-
uchar p8 = ptr[-1];
303-
uchar p9 = ptr[-cols - 1];
304-
305-
int neighbors = p9 | (p2 << 1) | (p3 << 2) | (p4 << 3) | (p5 << 4) | (p6 << 5) | (p7 << 6) | (p8 << 7);
306-
307-
if (iter == 0)
308-
value = lut_guo_iter0[neighbors];
309-
else
310-
value = lut_guo_iter1[neighbors];
311-
312-
//int C = ((!p2) & (p3 | p4)) + ((!p4) & (p5 | p6)) +
313-
// ((!p6) & (p7 | p8)) + ((!p8) & (p9 | p2));
314-
//int N1 = (p9 | p2) + (p3 | p4) + (p5 | p6) + (p7 | p8);
315-
//int N2 = (p2 | p3) + (p4 | p5) + (p6 | p7) + (p8 | p9);
316-
//int N = N1 < N2 ? N1 : N2;
317-
//int m = iter == 0 ? ((p6 | p7 | (!p9)) & p8) : ((p2 | p3 | (!p5)) & p4);
318-
//if ((C == 1) && ((N >= 2) && ((N <= 3)) & (m == 0))) value = 0;
319-
// else value = 1;
320-
});
321-
}
322-
323-
img &= marker;
324-
}
325-
326148
// Apply the thinning procedure to a given image
327149
void thinning(InputArray input, OutputArray output, int thinningType){
328150
Mat processed = input.getMat().clone();
329151
CV_CheckTypeEQ(processed.type(), CV_8UC1, "");
330152

153+
processed /= 255;
154+
331155
if(thinningType == THINNING_ZHANGSUEN)
332156
zhang_suen_thinning(processed.data, processed.cols, processed.rows);
333157

334158
if(thinningType == THINNING_GUOHALL)
335159
guo_hall_thinning(processed.data, processed.cols, processed.rows);
336160

161+
processed *= 255;
337162
output.assign(processed);
338163
}
339164

0 commit comments

Comments
 (0)