00001
00006
00007
00008
00009
00010
00011
00012
00013
00145 #include "slic.h"
00146 #include "mathop.h"
00147 #include <math.h>
00148 #include <string.h>
00149
00169 void
00170 vl_slic_segment (vl_uint32 * segmentation,
00171 float const * image,
00172 vl_size width,
00173 vl_size height,
00174 vl_size numChannels,
00175 vl_size regionSize,
00176 float regularization,
00177 vl_size minRegionSize)
00178 {
00179 vl_index i, x, y, u, v, k, region ;
00180 vl_uindex iter ;
00181 vl_size const numRegionsX = (vl_size) ceil((double) width / regionSize) ;
00182 vl_size const numRegionsY = (vl_size) ceil((double) height / regionSize) ;
00183 vl_size const numRegions = numRegionsX * numRegionsY ;
00184 vl_size const numPixels = width * height ;
00185 float * centers ;
00186 float * edgeMap ;
00187 float previousEnergy = VL_INFINITY_F ;
00188 float startingEnergy ;
00189 vl_uint32 * masses ;
00190 vl_size const maxNumIterations = 100 ;
00191
00192 assert(segmentation) ;
00193 assert(image) ;
00194 assert(width >= 1) ;
00195 assert(height >= 1) ;
00196 assert(numChannels >= 1) ;
00197 assert(regionSize >= 1) ;
00198 assert(regularization >= 0) ;
00199
00200 #define atimage(x,y,k) image[(x)+(y)*width+(k)*width*height]
00201 #define atEdgeMap(x,y) edgeMap[(x)+(y)*width]
00202
00203 edgeMap = vl_calloc(numPixels, sizeof(float)) ;
00204 masses = vl_malloc(sizeof(vl_uint32) * numPixels) ;
00205 centers = vl_malloc(sizeof(float) * (2 + numChannels) * numRegions) ;
00206
00207
00208 for (k = 0 ; k < (signed)numChannels ; ++k) {
00209 for (y = 1 ; y < (signed)height-1 ; ++y) {
00210 for (x = 1 ; x < (signed)width-1 ; ++x) {
00211 float a = atimage(x-1,y,k) ;
00212 float b = atimage(x+1,y,k) ;
00213 float c = atimage(x,y+1,k) ;
00214 float d = atimage(x,y-1,k) ;
00215 atEdgeMap(x,y) += (a - b) * (a - b) + (c - d) * (c - d) ;
00216 }
00217 }
00218 }
00219
00220
00221 i = 0 ;
00222 for (v = 0 ; v < (signed)numRegionsY ; ++v) {
00223 for (u = 0 ; u < (signed)numRegionsX ; ++u) {
00224 vl_index xp ;
00225 vl_index yp ;
00226 vl_index centerx = 0 ;
00227 vl_index centery = 0 ;
00228 float minEdgeValue = VL_INFINITY_F ;
00229
00230 x = (vl_index) vl_round_d(regionSize * (u + 0.5)) ;
00231 y = (vl_index) vl_round_d(regionSize * (v + 0.5)) ;
00232
00233 x = VL_MAX(VL_MIN(x, (signed)width-1),0) ;
00234 y = VL_MAX(VL_MIN(y, (signed)height-1),0) ;
00235
00236
00237 for (yp = VL_MAX(0, y-1) ; yp <= VL_MIN((signed)height-1, y+1) ; ++ yp) {
00238 for (xp = VL_MAX(0, x-1) ; xp <= VL_MIN((signed)width-1, x+1) ; ++ xp) {
00239 float thisEdgeValue = atEdgeMap(xp,yp) ;
00240 if (thisEdgeValue < minEdgeValue) {
00241 minEdgeValue = thisEdgeValue ;
00242 centerx = xp ;
00243 centery = yp ;
00244 }
00245 }
00246 }
00247
00248
00249 centers[i++] = (float) centerx ;
00250 centers[i++] = (float) centery ;
00251 for (k = 0 ; k < (signed)numChannels ; ++k) {
00252 centers[i++] = atimage(centerx,centery,k) ;
00253 }
00254 }
00255 }
00256
00257
00258 for (iter = 0 ; iter < maxNumIterations ; ++iter) {
00259 float factor = regularization / (regionSize * regionSize) ;
00260 float energy = 0 ;
00261
00262
00263 for (y = 0 ; y < (signed)height ; ++y) {
00264 for (x = 0 ; x < (signed)width ; ++x) {
00265 vl_index u = floor((double)x / regionSize - 0.5) ;
00266 vl_index v = floor((double)y / regionSize - 0.5) ;
00267 vl_index up, vp ;
00268 float minDistance = VL_INFINITY_F ;
00269
00270 for (vp = VL_MAX(0, v) ; vp <= VL_MIN((signed)numRegionsY-1, v+1) ; ++vp) {
00271 for (up = VL_MAX(0, u) ; up <= VL_MIN((signed)numRegionsX-1, u+1) ; ++up) {
00272 vl_index region = up + vp * numRegionsX ;
00273 float centerx = centers[(2 + numChannels) * region + 0] ;
00274 float centery = centers[(2 + numChannels) * region + 1] ;
00275 float spatial = (x - centerx) * (x - centerx) + (y - centery) * (y - centery) ;
00276 float appearance = 0 ;
00277 float distance ;
00278 for (k = 0 ; k < (signed)numChannels ; ++k) {
00279 float centerz = centers[(2 + numChannels) * region + k + 2] ;
00280 float z = atimage(x,y,k) ;
00281 appearance += (z - centerz) * (z - centerz) ;
00282 }
00283 distance = appearance + factor * spatial ;
00284 if (minDistance > distance) {
00285 minDistance = distance ;
00286 segmentation[x + y * width] = (vl_uint32)region ;
00287 }
00288 }
00289 }
00290 energy += minDistance ;
00291 }
00292 }
00293
00294
00295
00296
00297
00298
00299 if (iter == 0) {
00300 startingEnergy = energy ;
00301 } else {
00302 if ((previousEnergy - energy) < 1e-5 * (startingEnergy - energy)) {
00303 break ;
00304 }
00305 }
00306 previousEnergy = energy ;
00307
00308
00309 memset(masses, 0, sizeof(vl_uint32) * width * height) ;
00310 memset(centers, 0, sizeof(float) * (2 + numChannels) * numRegions) ;
00311
00312 for (y = 0 ; y < (signed)height ; ++y) {
00313 for (x = 0 ; x < (signed)width ; ++x) {
00314 vl_index pixel = x + y * width ;
00315 vl_index region = segmentation[pixel] ;
00316 masses[region] ++ ;
00317 centers[region * (2 + numChannels) + 0] += x ;
00318 centers[region * (2 + numChannels) + 1] += y ;
00319 for (k = 0 ; k < (signed)numChannels ; ++k) {
00320 centers[region * (2 + numChannels) + k + 2] += atimage(x,y,k) ;
00321 }
00322 }
00323 }
00324
00325 for (region = 0 ; region < (signed)numRegions ; ++region) {
00326 float mass = VL_MAX(masses[region], 1e-8) ;
00327 for (i = (2 + numChannels) * region ;
00328 i < (signed)(2 + numChannels) * (region + 1) ;
00329 ++i) {
00330 centers[i] /= mass ;
00331 }
00332 }
00333 }
00334
00335 vl_free(masses) ;
00336 vl_free(centers) ;
00337 vl_free(edgeMap) ;
00338
00339
00340 {
00341 vl_uint32 * cleaned = vl_calloc(numPixels, sizeof(vl_uint32)) ;
00342 vl_uindex * segment = vl_malloc(sizeof(vl_uindex) * numPixels) ;
00343 vl_size segmentSize ;
00344 vl_uint32 label ;
00345 vl_uint32 cleanedLabel ;
00346 vl_size numExpanded ;
00347 vl_index const dx [] = {+1, -1, 0, 0} ;
00348 vl_index const dy [] = { 0, 0, +1, -1} ;
00349 vl_index direction ;
00350 vl_index pixel ;
00351
00352 for (pixel = 0 ; pixel < (signed)numPixels ; ++pixel) {
00353 if (cleaned[pixel]) continue ;
00354 label = segmentation[pixel] ;
00355 numExpanded = 0 ;
00356 segmentSize = 0 ;
00357 segment[segmentSize++] = pixel ;
00358
00359
00360
00361
00362
00363 cleanedLabel = label + 1 ;
00364 cleaned[pixel] = label + 1 ;
00365 x = pixel % width ;
00366 y = pixel / width ;
00367 for (direction = 0 ; direction < 4 ; ++direction) {
00368 vl_index xp = x + dx[direction] ;
00369 vl_index yp = y + dy[direction] ;
00370 vl_index neighbor = xp + yp * width ;
00371 if (0 <= xp && xp < (signed)width &&
00372 0 <= yp && yp < (signed)height &&
00373 cleaned[neighbor]) {
00374 cleanedLabel = cleaned[neighbor] ;
00375 }
00376 }
00377
00378
00379 while (numExpanded < segmentSize) {
00380 vl_index open = segment[numExpanded++] ;
00381 x = open % width ;
00382 y = open / width ;
00383 for (direction = 0 ; direction < 4 ; ++direction) {
00384 vl_index xp = x + dx[direction] ;
00385 vl_index yp = y + dy[direction] ;
00386 vl_index neighbor = xp + yp * width ;
00387 if (0 <= xp && xp < (signed)width &&
00388 0 <= yp && yp < (signed)height &&
00389 cleaned[neighbor] == 0 &&
00390 segmentation[neighbor] == label) {
00391 cleaned[neighbor] = label + 1 ;
00392 segment[segmentSize++] = neighbor ;
00393 }
00394 }
00395 }
00396
00397
00398 if (segmentSize < minRegionSize) {
00399 while (segmentSize > 0) {
00400 cleaned[segment[--segmentSize]] = cleanedLabel ;
00401 }
00402 }
00403 }
00404
00405 for (pixel = 0 ; pixel < (signed)numPixels ; ++pixel) cleaned[pixel] -- ;
00406
00407 memcpy(segmentation, cleaned, numPixels * sizeof(vl_uint32)) ;
00408 vl_free(cleaned) ;
00409 vl_free(segment) ;
00410 }
00411 }