-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhysteresis.c
350 lines (307 loc) · 8.37 KB
/
hysteresis.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
#include <stdio.h>
#include <stdlib.h>
#include "delogo.h"
/*
* Recursive routine that traces edgs along all paths whose magnitude values
* remain above some specifyable lower threshhold.
*/
void
follow_edges( u8 * edgemapptr, short *edgemagptr, short lowval, int cols )
{
short *tempmagptr;
u8 *tempmapptr;
int i;
int x[8] = { 1, 1, 0, -1, -1, -1, 0, 1 }, y[8] =
{
0, 1, 1, 1, 0, -1, -1, -1};
for( i = 0; i < 8; i++ )
{
tempmapptr = edgemapptr - y[i] * cols + x[i];
tempmagptr = edgemagptr - y[i] * cols + x[i];
if( ( *tempmapptr == POSSIBLE_EDGE ) && ( *tempmagptr > lowval ) )
{
*tempmapptr = ( u8 ) EDGE;
follow_edges( tempmapptr, tempmagptr, lowval, cols );
}
}
}
/*
* Finds edges that are above some high threshhold or are connected to a
* high pixel by a path of pixels greater than a low threshold.
*/
void
apply_hysteresis( short int *mag, u8 * nms, int rows, int cols,
float tlow, float thigh, u8 * edge )
{
int r, c, pos, numedges, highcount, lowthreshold,
highthreshold, hist[32768];
short int maximum_mag;
maximum_mag = 0;
/*
* Initialize the edge map to possible edges everywhere the non-maximal
* suppression suggested there could be an edge except for the border. At
* the border we say there can not be an edge because it makes the
* follow_edges algorithm more efficient to not worry about tracking an
* edge off the side of the image.
*/
for( r = 0, pos = 0; r < rows; r++ )
{
for( c = 0; c < cols; c++, pos++ )
{
if( nms[pos] == POSSIBLE_EDGE )
edge[pos] = POSSIBLE_EDGE;
else
edge[pos] = NOEDGE;
}
}
for( r = 0, pos = 0; r < rows; r++, pos += cols )
{
edge[pos] = NOEDGE;
edge[pos + cols - 1] = NOEDGE;
}
pos = ( rows - 1 ) * cols;
for( c = 0; c < cols; c++, pos++ )
{
edge[c] = NOEDGE;
edge[pos] = NOEDGE;
}
/*
* Compute the histogram of the magnitude image. Then use the histogram to
* compute hysteresis thresholds.
*/
for( r = 0; r < 32768; r++ )
hist[r] = 0;
for( r = 0, pos = 0; r < rows; r++ )
{
for( c = 0; c < cols; c++, pos++ )
{
if( edge[pos] == POSSIBLE_EDGE )
hist[mag[pos]]++;
}
}
// Compute the number of pixels that passed the nonmaximal suppression.
for( r = 1, numedges = 0; r < 32768; r++ )
{
if( hist[r] != 0 )
maximum_mag = r;
numedges += hist[r];
}
highcount = ( int ) ( numedges * thigh + 0.5 );
/*
* Compute the high threshold value as the (100 * thigh) percentage point
* in the magnitude of the gradient histogram of all the pixels that passes
* non-maximal suppression. Then calculate the low threshold as a fraction
* of the computed high threshold value. John Canny said in his paper
* "A Computational Approach to Edge Detection" that "The ratio of the
* high to low threshold in the implementation is in the range two or three
* to one." That means that in terms of this implementation, we should
* choose tlow ~= 0.5 or 0.33333.
*/
r = 1;
numedges = hist[1];
while( ( r < ( maximum_mag - 1 ) ) && ( numedges < highcount ) )
{
r++;
numedges += hist[r];
}
highthreshold = r;
lowthreshold = ( int ) ( highthreshold * tlow + 0.5 );
/*
* This loop looks for pixels above the highthreshold to locate edges and
* then calls follow_edges to continue the edge.
*/
for( r = 0, pos = 0; r < rows; r++ )
{
for( c = 0; c < cols; c++, pos++ )
{
if( ( edge[pos] == POSSIBLE_EDGE ) && ( mag[pos] >= highthreshold ) )
{
edge[pos] = EDGE;
follow_edges( ( edge + pos ), ( mag + pos ), lowthreshold, cols );
}
}
}
// Set all the remaining possible edges to non-edges.
for( r = 0, pos = 0; r < rows; r++ )
{
for( c = 0; c < cols; c++, pos++ )
if( edge[pos] != EDGE )
edge[pos] = NOEDGE;
}
}
// Applies non-maximal suppression to the magnitude of the gradient image.
void
non_max_supp( short *mag, short *gradx, short *grady, int nrows, int ncols,
u8 * result )
{
int rowcount, colcount, count;
short *magrowptr, *magptr;
short *gxrowptr, *gxptr;
short *gyrowptr, *gyptr, z1, z2;
short m00, gx, gy;
float mag1, mag2, xperp, yperp;
u8 *resultrowptr, *resultptr;
gx = gy = 0;
xperp = yperp = 0;
// Zero the edges of the result image.
for( count = 0, resultrowptr = result, resultptr =
result + ncols * ( nrows - 1 ); count < ncols;
resultptr++, resultrowptr++, count++ )
{
*resultrowptr = *resultptr = ( u8 ) 0;
}
for( count = 0, resultptr = result, resultrowptr = result + ncols - 1;
count < nrows; count++, resultptr += ncols, resultrowptr += ncols )
{
*resultptr = *resultrowptr = ( u8 ) 0;
}
// Suppress non-maximum points.
for( rowcount = 1, magrowptr = mag + ncols + 1, gxrowptr =
gradx + ncols + 1, gyrowptr = grady + ncols + 1, resultrowptr =
result + ncols + 1; rowcount < nrows - 2;
rowcount++, magrowptr += ncols, gyrowptr += ncols, gxrowptr +=
ncols, resultrowptr += ncols )
{
for( colcount = 1, magptr = magrowptr, gxptr = gxrowptr, gyptr =
gyrowptr, resultptr = resultrowptr; colcount < ncols - 2;
colcount++, magptr++, gxptr++, gyptr++, resultptr++ )
{
m00 = *magptr;
if( m00 == 0 )
{
*resultptr = ( u8 ) NOEDGE;
}
else
{
xperp = -( gx = *gxptr ) / ( ( float ) m00 );
yperp = ( gy = *gyptr ) / ( ( float ) m00 );
}
if( gx >= 0 )
{
if( gy >= 0 )
{
if( gx >= gy )
{
// 111
// Left point
z1 = *( magptr - 1 );
z2 = *( magptr - ncols - 1 );
mag1 = ( m00 - z1 ) * xperp + ( z2 - z1 ) * yperp;
// Right point
z1 = *( magptr + 1 );
z2 = *( magptr + ncols + 1 );
mag2 = ( m00 - z1 ) * xperp + ( z2 - z1 ) * yperp;
}
else
{
// 110
// Left point
z1 = *( magptr - ncols );
z2 = *( magptr - ncols - 1 );
mag1 = ( z1 - z2 ) * xperp + ( z1 - m00 ) * yperp;
// Right point
z1 = *( magptr + ncols );
z2 = *( magptr + ncols + 1 );
mag2 = ( z1 - z2 ) * xperp + ( z1 - m00 ) * yperp;
}
}
else
{
if( gx >= -gy )
{
// 101
// Left point
z1 = *( magptr - 1 );
z2 = *( magptr + ncols - 1 );
mag1 = ( m00 - z1 ) * xperp + ( z1 - z2 ) * yperp;
// Right point
z1 = *( magptr + 1 );
z2 = *( magptr - ncols + 1 );
mag2 = ( m00 - z1 ) * xperp + ( z1 - z2 ) * yperp;
}
else
{
// 100
// Left point
z1 = *( magptr + ncols );
z2 = *( magptr + ncols - 1 );
mag1 = ( z1 - z2 ) * xperp + ( m00 - z1 ) * yperp;
// Right point
z1 = *( magptr - ncols );
z2 = *( magptr - ncols + 1 );
mag2 = ( z1 - z2 ) * xperp + ( m00 - z1 ) * yperp;
}
}
}
else
{
if( ( gy = *gyptr ) >= 0 )
{
if( -gx >= gy )
{
// 011
// Left point
z1 = *( magptr + 1 );
z2 = *( magptr - ncols + 1 );
mag1 = ( z1 - m00 ) * xperp + ( z2 - z1 ) * yperp;
// Right point
z1 = *( magptr - 1 );
z2 = *( magptr + ncols - 1 );
mag2 = ( z1 - m00 ) * xperp + ( z2 - z1 ) * yperp;
}
else
{
// 010
// Left point
z1 = *( magptr - ncols );
z2 = *( magptr - ncols + 1 );
mag1 = ( z2 - z1 ) * xperp + ( z1 - m00 ) * yperp;
// Right point
z1 = *( magptr + ncols );
z2 = *( magptr + ncols - 1 );
mag2 = ( z2 - z1 ) * xperp + ( z1 - m00 ) * yperp;
}
}
else
{
if( -gx > -gy )
{
// 001
// Left point
z1 = *( magptr + 1 );
z2 = *( magptr + ncols + 1 );
mag1 = ( z1 - m00 ) * xperp + ( z1 - z2 ) * yperp;
// Right point
z1 = *( magptr - 1 );
z2 = *( magptr - ncols - 1 );
mag2 = ( z1 - m00 ) * xperp + ( z1 - z2 ) * yperp;
}
else
{
// 000
// Left point
z1 = *( magptr + ncols );
z2 = *( magptr + ncols + 1 );
mag1 = ( z2 - z1 ) * xperp + ( m00 - z1 ) * yperp;
// Right point
z1 = *( magptr - ncols );
z2 = *( magptr - ncols - 1 );
mag2 = ( z2 - z1 ) * xperp + ( m00 - z1 ) * yperp;
}
}
}
// Now determine if the current point is a maximum point
if( ( mag1 > 0.0 ) || ( mag2 > 0.0 ) )
{
*resultptr = ( u8 ) NOEDGE;
}
else
{
if( mag2 == 0.0 )
*resultptr = ( u8 ) NOEDGE;
else
*resultptr = ( u8 ) POSSIBLE_EDGE;
}
}
}
}