@@ -92,118 +92,71 @@ static uint8_t lut_guo_iter1[] = {
92
92
1 , 1 , 1 , 1 };
93
93
94
94
// Applies a thinning iteration to a binary image
95
- static void thinningIteration (Mat img, int iter, int thinningType){
96
- Mat marker = Mat::zeros (img.size (), CV_8UC1);
95
+ static void thinningIteration (Mat &img, Mat &marker, const uint8_t * const lut, bool &changed) {
97
96
int rows = img.rows ;
98
97
int cols = img.cols ;
99
- marker.col (0 ).setTo (1 );
100
- marker.col (cols - 1 ).setTo (1 );
101
- marker.row (0 ).setTo (1 );
102
- marker.row (rows - 1 ).setTo (1 );
103
-
104
- if (thinningType == THINNING_ZHANGSUEN){
105
- marker.forEach <uchar>([=](uchar& value, const int postion[]) {
106
- int i = postion[0 ];
107
- int j = postion[1 ];
108
- if (i == 0 || j == 0 || i == rows - 1 || j == cols - 1 )
109
- return ;
110
-
111
- auto ptr = img.ptr (i, j); // p1
112
-
113
- // p9 p2 p3
114
- // p8 p1 p4
115
- // p7 p6 p5
116
- uchar p2 = ptr[-cols];
117
- uchar p3 = ptr[-cols + 1 ];
118
- uchar p4 = ptr[1 ];
119
- uchar p5 = ptr[cols + 1 ];
120
- uchar p6 = ptr[cols];
121
- uchar p7 = ptr[cols - 1 ];
122
- uchar p8 = ptr[-1 ];
123
- uchar p9 = ptr[-cols - 1 ];
124
-
125
- int neighbors = p9 | (p2 << 1 ) | (p3 << 2 ) | (p4 << 3 ) | (p5 << 4 ) | (p6 << 5 ) | (p7 << 6 ) | (p8 << 7 );
126
-
127
- if (iter == 0 )
128
- value = lut_zhang_iter0[neighbors];
129
- else
130
- value = lut_zhang_iter1[neighbors];
131
-
132
- // int A = (p2 == 0 && p3 == 1) + (p3 == 0 && p4 == 1) +
133
- // (p4 == 0 && p5 == 1) + (p5 == 0 && p6 == 1) +
134
- // (p6 == 0 && p7 == 1) + (p7 == 0 && p8 == 1) +
135
- // (p8 == 0 && p9 == 1) + (p9 == 0 && p2 == 1);
136
- // int B = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
137
- // int m1 = iter == 0 ? (p2 * p4 * p6) : (p2 * p4 * p8);
138
- // int m2 = iter == 0 ? (p4 * p6 * p8) : (p2 * p6 * p8);
139
- // if (A == 1 && (B >= 2 && B <= 6) && m1 == 0 && m2 == 0) value = 0;
140
- // else value = 1;
141
- });
142
- }
143
- if (thinningType == THINNING_GUOHALL){
144
- marker.forEach <uchar>([=](uchar& value, const int postion[]) {
145
- int i = postion[0 ];
146
- int j = postion[1 ];
147
- if (i == 0 || j == 0 || i == rows - 1 || j == cols - 1 )
148
- return ;
149
-
150
- auto ptr = img.ptr (i, j); // p1
151
-
152
- // p9 p2 p3
153
- // p8 p1 p4
154
- // p7 p6 p5
155
- uchar p2 = ptr[-cols];
156
- uchar p3 = ptr[-cols + 1 ];
157
- uchar p4 = ptr[1 ];
158
- uchar p5 = ptr[cols + 1 ];
159
- uchar p6 = ptr[cols];
160
- uchar p7 = ptr[cols - 1 ];
161
- uchar p8 = ptr[-1 ];
162
- uchar p9 = ptr[-cols - 1 ];
163
-
164
- int neighbors = p9 | (p2 << 1 ) | (p3 << 2 ) | (p4 << 3 ) | (p5 << 4 ) | (p6 << 5 ) | (p7 << 6 ) | (p8 << 7 );
165
-
166
- if (iter == 0 )
167
- value = lut_guo_iter0[neighbors];
168
- else
169
- value = lut_guo_iter1[neighbors];
170
-
171
- // int C = ((!p2) & (p3 | p4)) + ((!p4) & (p5 | p6)) +
172
- // ((!p6) & (p7 | p8)) + ((!p8) & (p9 | p2));
173
- // int N1 = (p9 | p2) + (p3 | p4) + (p5 | p6) + (p7 | p8);
174
- // int N2 = (p2 | p3) + (p4 | p5) + (p6 | p7) + (p8 | p9);
175
- // int N = N1 < N2 ? N1 : N2;
176
- // int m = iter == 0 ? ((p6 | p7 | (!p9)) & p8) : ((p2 | p3 | (!p5)) & p4);
177
- // if ((C == 1) && ((N >= 2) && ((N <= 3)) & (m == 0))) value = 0;
178
- // else value = 1;
179
- });
180
- }
98
+
99
+ // Parallelized iteration over pixels excluding the boundary
100
+ parallel_for_ (Range (1 , rows - 1 ), [&](const Range& range) {
101
+ for (int i = range.start ; i < range.end ; i++) {
102
+ const uchar* imgRow = img.ptr (i);
103
+ uchar* markerRow = marker.ptr (i);
104
+ for (int j = 1 ; j < cols - 1 ; j++) {
105
+ if (imgRow[j]) {
106
+ uchar p2 = imgRow[j - cols] != 0 ;
107
+ uchar p3 = imgRow[j - cols + 1 ] != 0 ;
108
+ uchar p4 = imgRow[j + 1 ] != 0 ;
109
+ uchar p5 = imgRow[j + cols + 1 ] != 0 ;
110
+ uchar p6 = imgRow[j + cols] != 0 ;
111
+ uchar p7 = imgRow[j + cols - 1 ] != 0 ;
112
+ uchar p8 = imgRow[j - 1 ] != 0 ;
113
+ uchar p9 = imgRow[j - cols - 1 ] != 0 ;
114
+
115
+ int neighbors = p9 | (p2 << 1 ) | (p3 << 2 ) | (p4 << 3 ) | (p5 << 4 ) | (p6 << 5 ) | (p7 << 6 ) | (p8 << 7 );
116
+ uchar lut_value = lut[neighbors];
117
+
118
+ if (lut_value == 0 )
119
+ {
120
+ markerRow[j] = lut_value;
121
+ changed = true ;
122
+ }
123
+ }
124
+ }
125
+ }
126
+ });
181
127
182
128
img &= marker;
183
129
}
184
130
185
131
// Apply the thinning procedure to a given image
186
132
void thinning (InputArray input, OutputArray output, int thinningType){
187
- Mat processed = input.getMat ().clone ();
188
- CV_CheckTypeEQ (processed.type (), CV_8UC1, " " );
189
- // Enforce the range of the input image to be in between 0 - 255
190
- processed /= 255 ;
133
+ Mat input_ = input.getMat ();
134
+ CV_Assert (!input_.empty ());
135
+ CV_CheckTypeEQ (input_.type (), CV_8UC1, " " );
191
136
137
+ Mat processed = input_ / 255 ;
192
138
Mat prev = processed.clone ();
193
- Mat diff;
194
139
195
- do {
196
- thinningIteration (processed, 0 , thinningType);
197
- thinningIteration (processed, 1 , thinningType);
198
- absdiff (processed, prev, diff);
199
- if (!hasNonZero (diff)) break ;
200
- processed.copyTo (prev);
201
- }
202
- while (true );
140
+ Mat marker;
141
+ Mat marker_inner = processed (Rect (1 , 1 , processed.cols - 2 , processed.rows - 2 ));
142
+ copyMakeBorder (marker_inner, marker, 1 , 1 , 1 , 1 , BORDER_ISOLATED | BORDER_CONSTANT, Scalar (255 ));
203
143
204
- processed *= 255 ;
144
+ const auto lutIter0 = (thinningType == THINNING_GUOHALL) ? lut_guo_iter0 : lut_zhang_iter0;
145
+ const auto lutIter1 = (thinningType == THINNING_GUOHALL) ? lut_guo_iter1 : lut_zhang_iter1;
205
146
206
- output.assign (processed);
147
+ do {
148
+ bool changed0 = false ;
149
+ bool changed1 = false ;
150
+ thinningIteration (processed, marker, lutIter0, changed0);
151
+ thinningIteration (processed, marker, lutIter1, changed1);
152
+
153
+ if (changed0 | changed1)
154
+ processed.copyTo (prev);
155
+ else
156
+ break ;
157
+ } while (true );
158
+
159
+ output.assign (processed * 255 );
207
160
}
208
161
209
162
} // namespace ximgproc
0 commit comments