-
Notifications
You must be signed in to change notification settings - Fork 1
/
WSSegment.cpp
287 lines (220 loc) · 7.74 KB
/
WSSegment.cpp
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
/********************************************************************************
WSSegment segments an image by Allen Soille algorithm of water shed segmentation.
Basin numbers and watersheds are determined by this function and marked in tag
buffer basin number and in ws buffer as zero for watershed..
All buffers must be of size height * width.
The input is pointers to image values sorted in ascending order of image values
to which they point, pointers to buffer where image resides,
tag in which basin numbers will be computed, dist for indicating distance from minima,
and ws where watershed will be recorded as one and rest as 0. image width, image height,
Author V.C.Mohan
Oct 22, 2006, mar 24, 2009, oct 2014(added template)
*********************************************************************************/
#ifndef VCM_WSSEGMENT_CPP
#define VCM_WSSEGMENT_CPP
#include <queue>
template <typename finc>
void WSSegment( const finc **pixelsort, const finc *buf, int * tag,
int * dist, char * ws, int ht, int wd, bool connect4 = true);
template <typename finc>
void WSSegment( const finc **pixelsort, const finc *buf, int * tag,
int * dist, char * ws, int ht, int wd, bool connect4)
{
std::queue <const finc *> fifoq;
// initialize
int init=-1, mask=-2,wshed=0;
int curtag=0, curdist=0;
int psize = ht * wd;
// prepare data for sorting
for(int h=0; h < psize; h++)
{
tag[h] = init;
dist[h]= 0;
ws[h] = init;
}
// minimum and max grey values
int gmin = *(pixelsort[0]) ;
int gmax = *(pixelsort[psize-1]);
int gindex = 0, pindex = 0; // these will hopefully reduce search of pixelsort buffer for a g value
// start flooding
for( int g = gmin; g <= gmax; g++) // geodesic SKIZ of level g-1 inside level g
{
// get pixels having this g value
for(int j = gindex; j < psize; j++)
{
if(*pixelsort[j] < g )
continue; // we already completed this value
if(*pixelsort[j] > g )
break; // we reached next value
// same value pixel. get its original coordinates
// int h = (pixelsort[j] - buf);
tag[pixelsort[j] - buf] = mask; // mask all pixels with this g value. Do I need to mark all prior to rest of code?
// yes. done it by seperating loops
}
for(int j = gindex; j < psize; j++)
{
if(*pixelsort[j] < g )
continue;
if(*pixelsort[j] > g )
{
gindex=j;
break;
}
// same value pixel. get its original coordinates
int h = (pixelsort[j] - buf) / wd;
int w = (pixelsort[j] - buf) % wd;
int hwd = h * wd;
if(h > 0 && h < ht - 1 && w > 0 && w < wd - 1) // if neighbour is in frame
{
// check whether 4 close neighbour tag is >0 or is wshed
if( tag[hwd + wd + w] >0 || ws[hwd + wd + w] == wshed ||
tag[hwd + w -1] >0 || ws[hwd + w - 1] == wshed ||
tag[hwd + w +1] >0 || ws[hwd + w + 1] == wshed ||
tag[hwd - wd + w] >0 || ws[hwd - wd + w] == wshed )
{
dist[hwd + w]=1;
// initialize queue with neighbours at level g of current basins or water sheds
fifoq.push(pixelsort[j]);
}
else if(!connect4) // 8 connect option. so check rest four distant neighbours (at corners) also
{
if( tag[hwd + wd+w-1] > 0 || ws[hwd + wd+w-1] == wshed ||
tag[hwd - wd+w-1] > 0 || ws[hwd - wd+w-1] == wshed ||
tag[hwd + wd+w+1] > 0 || ws[hwd + wd+w+1] == wshed ||
tag[hwd - wd+w+1] > 0 || ws[hwd - wd+w+1] == wshed )
{
dist[hwd + w] = 1;
// initialize queue with neighbours at level g of current basins or water sheds
fifoq.push(pixelsort[j]);
}
}
}
}
// up date curdist
curdist=1;
fifoq.push(NULL); // a fictitous value used as a control marker
// indefinite loop. breaks when queue is empty
while(true) // extend basins
{
const finc * p = fifoq.front();
fifoq.pop();
// if not a real value
if(p == NULL)
{
if(fifoq.empty())
break;
else
{
curdist++;
fifoq.push(NULL); // another marker
p = fifoq.front();
fifoq.pop();
}
}
// get back x, y coordinates and its value
int h = (p - buf) / wd;
int w = (p - buf) % wd;
// check all connected neighbours of point p on dist and tag frame
for(int s = -1; s < 2; s++)
for(int t = -1; t < 2; t++)
{
// check for 4 connectivity
if (connect4)
{
if(s == t || s==-t) // not close neighbours
continue;
}
// check for 8 connectivity
else
if(s == 0 && t == 0) // same point
continue;
if(h + s < 0 || h + s > ht - 1 || w + t < 0 || w + t > wd - 1)
continue; // not in frame. so skip this point
int hwd = h * wd;
int hswd = (h + s) * wd;
if(dist[hswd + (w + t)] < curdist
&& (tag[hswd + (w + t)] > 0
|| ws[hswd + (w + t)] == wshed) )
{
// this neighbour point belongs to existing basin or watershed
if(tag[hswd + (w + t)] > 0)
{
// yes this neighbour belongs to an existing basin
if(tag[hwd + w] == mask || ws[hwd + w] == wshed)
// put same basin tag on p as that of neighbour
tag[hwd + w] = tag[hswd + (w+t)];
else if( tag[hwd + w] != tag[hswd + (w+t)])
// this neighbour belongs to a diff basin. so our point is water shed
ws[hwd + w] = wshed;
}
else
if( tag[hwd + w] == mask)
ws[hwd + w] = wshed;
}
else if( tag[hswd + (w + t)] == mask
&& dist[hswd + (w + t)] == 0)
{
// this neighbour is a plataue pixel
dist[hswd + (w + t)] = curdist + 1;
fifoq.push( buf + hswd + (w + t) );
}
}
} // while(true)
// once again find new minima at this same level g
// get pixels having this g value
// pindex was originally 0.
for(int j = pindex; j < psize; j++)
{
if(*pixelsort[j] < g )
continue;
if(*pixelsort[j] > g )
{
pindex=j;
break;
}
// same value pixel
int h = (pixelsort[j] - buf) / wd;
int w = (pixelsort[j] - buf) % wd;
dist[pixelsort[j] - buf] = 0; // reset to zero
if( h >= 0 && h < ht && w >= 0 && w < wd) // is this reqd? why h>0 and not h>=0 ?
{
if(tag[h * wd + w] == mask) // point is inside new minimum
// check whether 4 neighbour tag is >0 or is wshed
{
curtag++; // create new label
fifoq.push (pixelsort[j]);
tag[h * wd + w] = curtag;
while( ! fifoq.empty())
{
const finc * q = fifoq.front();
fifoq.pop();
int qh = (q - buf) / wd;
int qw = (q - buf) % wd;
for(int qs = -1; qs < 2; qs++)
for(int qt = -1; qt < 2; qt++)
{
if(connect4)
{
if( qs == qt || qs == -qt)
continue;
}
else
if( qs == 0 && qt == 0)
continue;
if( qs + qh < 0 || qs + qh >= ht || qw + qt < 0 || qw + qt >= wd)
continue;
// check the neighbours of this point q
if(tag[(qs+qh) * wd + (qw+qt)] == mask)
{
fifoq.push( buf + (qs+qh) * wd + (qw+qt) );
tag[(qs+qh) * wd + (qw+qt)] = curtag;
}
}
} // while( ! fifoq.empty())
} // if(tag[h * wd + w] == mask)
} //if( h > 0 && h < bht && w > 0 && w < bwd)
} // for(j=pindex;j<psize;j++)
} // for( int g = gmin; g <= gmax; g++)
}
#endif
//--------------------------------------------------------------------------------------------------