Skip to content

Commit 6058217

Browse files
authored
Update thinning.cpp
1 parent 7683925 commit 6058217

File tree

1 file changed

+144
-2
lines changed

1 file changed

+144
-2
lines changed

modules/ximgproc/src/thinning.cpp

Lines changed: 144 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ namespace ximgproc {
99

1010
int guo_hall_thinning(uint8_t* binary_image, size_t width, size_t height);
1111
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);
1215

1316
/**
1417
* 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) {
147150

148151
// Apply the thinning procedure to a given image
149152
void thinning(InputArray input, OutputArray output, int thinningType){
153+
if(thinningType == THINNING_GUOHALL)
154+
return thinninggh(input, output, thinningType);
150155
Mat processed = input.getMat().clone();
151156
CV_CheckTypeEQ(processed.type(), CV_8UC1, "");
152157

@@ -155,8 +160,145 @@ void thinning(InputArray input, OutputArray output, int thinningType){
155160
if(thinningType == THINNING_ZHANGSUEN)
156161
zhang_suen_thinning(processed.data, processed.cols, processed.rows);
157162

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);
160302

161303
processed *= 255;
162304
output.assign(processed);

0 commit comments

Comments
 (0)