Line data Source code
1 : // SLIC.cpp: implementation of the SLIC class.
2 : //===========================================================================
3 : // This code implements the zero parameter superpixel segmentation technique
4 : // described in:
5 : //
6 : //
7 : //
8 : // "SLIC Superpixels Compared to State-of-the-art Superpixel Methods"
9 : //
10 : // Radhakrishna Achanta, Appu Shaji, Kevin Smith, Aurelien Lucchi, Pascal Fua,
11 : // and Sabine Susstrunk,
12 : //
13 : // IEEE TPAMI, Volume 34, Issue 11, Pages 2274-2282, November 2012.
14 : //
15 : // https://www.epfl.ch/labs/ivrl/research/slic-superpixels/
16 : //===========================================================================
17 : // Copyright (c) 2013 Radhakrishna Achanta.
18 : //
19 : // For commercial use please contact the author:
20 : //
21 : // Email: firstname.lastname@epfl.ch
22 : //===========================================================================
23 :
24 : #include <stdio.h>
25 : #include <cfloat>
26 : #include <cmath>
27 : #include <iostream>
28 : #include <fstream>
29 : #include "SLIC.h"
30 : #include <chrono>
31 :
32 : typedef chrono::high_resolution_clock Clock;
33 :
34 : // For superpixels
35 : const int dx4[4] = {-1, 0, 1, 0};
36 : const int dy4[4] = { 0, -1, 0, 1};
37 : //const int dx8[8] = {-1, -1, 0, 1, 1, 1, 0, -1};
38 : //const int dy8[8] = { 0, -1, -1, -1, 0, 1, 1, 1};
39 :
40 : // For supervoxels
41 : const int dx10[10] = {-1, 0, 1, 0, -1, 1, 1, -1, 0, 0};
42 : const int dy10[10] = { 0, -1, 0, 1, -1, -1, 1, 1, 0, 0};
43 : const int dz10[10] = { 0, 0, 0, 0, 0, 0, 0, 0, -1, 1};
44 :
45 : //////////////////////////////////////////////////////////////////////
46 : // Construction/Destruction
47 : //////////////////////////////////////////////////////////////////////
48 :
49 1 : SLIC::SLIC()
50 : {
51 1 : m_lvec = NULL;
52 1 : m_avec = NULL;
53 1 : m_bvec = NULL;
54 :
55 1 : m_lvecvec = NULL;
56 1 : m_avecvec = NULL;
57 1 : m_bvecvec = NULL;
58 1 : }
59 :
60 1 : SLIC::~SLIC()
61 : {
62 1 : if(m_lvec) delete [] m_lvec;
63 1 : if(m_avec) delete [] m_avec;
64 1 : if(m_bvec) delete [] m_bvec;
65 :
66 :
67 1 : if(m_lvecvec)
68 : {
69 0 : for( int d = 0; d < m_depth; d++ ) delete [] m_lvecvec[d];
70 0 : delete [] m_lvecvec;
71 : }
72 1 : if(m_avecvec)
73 : {
74 0 : for( int d = 0; d < m_depth; d++ ) delete [] m_avecvec[d];
75 0 : delete [] m_avecvec;
76 : }
77 1 : if(m_bvecvec)
78 : {
79 0 : for( int d = 0; d < m_depth; d++ ) delete [] m_bvecvec[d];
80 0 : delete [] m_bvecvec;
81 : }
82 1 : }
83 :
84 : //==============================================================================
85 : /// RGB2XYZ
86 : ///
87 : /// sRGB (D65 illuninant assumption) to XYZ conversion
88 : //==============================================================================
89 10130902 : void SLIC::RGB2XYZ(
90 : const int& sR,
91 : const int& sG,
92 : const int& sB,
93 : double& X,
94 : double& Y,
95 : double& Z)
96 : {
97 10130902 : double R = sR/255.0;
98 10130902 : double G = sG/255.0;
99 10130902 : double B = sB/255.0;
100 :
101 : double r, g, b;
102 :
103 10130902 : if(R <= 0.04045) r = R/12.92;
104 9593232 : else r = pow((R+0.055)/1.055,2.4);
105 10130902 : if(G <= 0.04045) g = G/12.92;
106 9896286 : else g = pow((G+0.055)/1.055,2.4);
107 10130902 : if(B <= 0.04045) b = B/12.92;
108 9712489 : else b = pow((B+0.055)/1.055,2.4);
109 :
110 10130902 : X = r*0.4124564 + g*0.3575761 + b*0.1804375;
111 10130902 : Y = r*0.2126729 + g*0.7151522 + b*0.0721750;
112 10130902 : Z = r*0.0193339 + g*0.1191920 + b*0.9503041;
113 10130902 : }
114 :
115 : //===========================================================================
116 : /// RGB2LAB
117 : //===========================================================================
118 10130902 : void SLIC::RGB2LAB(const int& sR, const int& sG, const int& sB, double& lval, double& aval, double& bval)
119 : {
120 : //------------------------
121 : // sRGB to XYZ conversion
122 : //------------------------
123 : double X, Y, Z;
124 10130902 : RGB2XYZ(sR, sG, sB, X, Y, Z);
125 :
126 : //------------------------
127 : // XYZ to LAB conversion
128 : //------------------------
129 10130902 : double epsilon = 0.008856; //actual CIE standard
130 10130902 : double kappa = 903.3; //actual CIE standard
131 :
132 10130902 : double Xr = 0.950456; //reference white
133 10130902 : double Yr = 1.0; //reference white
134 10130902 : double Zr = 1.088754; //reference white
135 :
136 10130902 : double xr = X/Xr;
137 10130902 : double yr = Y/Yr;
138 10130902 : double zr = Z/Zr;
139 :
140 : double fx, fy, fz;
141 10130902 : if(xr > epsilon) fx = pow(xr, 1.0/3.0);
142 669542 : else fx = (kappa*xr + 16.0)/116.0;
143 10130902 : if(yr > epsilon) fy = pow(yr, 1.0/3.0);
144 512690 : else fy = (kappa*yr + 16.0)/116.0;
145 10130902 : if(zr > epsilon) fz = pow(zr, 1.0/3.0);
146 766636 : else fz = (kappa*zr + 16.0)/116.0;
147 :
148 10130902 : lval = 116.0*fy-16.0;
149 10130902 : aval = 500.0*(fx-fy);
150 10130902 : bval = 200.0*(fy-fz);
151 10130902 : }
152 :
153 : //===========================================================================
154 : /// DoRGBtoLABConversion
155 : ///
156 : /// For whole image: overlaoded floating point version
157 : //===========================================================================
158 1 : void SLIC::DoRGBtoLABConversion(
159 : const unsigned int*& ubuff,
160 : double*& lvec,
161 : double*& avec,
162 : double*& bvec)
163 : {
164 1 : int sz = m_width*m_height;
165 1 : lvec = new double[sz];
166 1 : avec = new double[sz];
167 1 : bvec = new double[sz];
168 :
169 10130903 : for( int j = 0; j < sz; j++ )
170 : {
171 10130902 : int r = (ubuff[j] >> 16) & 0xFF;
172 10130902 : int g = (ubuff[j] >> 8) & 0xFF;
173 10130902 : int b = (ubuff[j] ) & 0xFF;
174 :
175 10130902 : RGB2LAB( r, g, b, lvec[j], avec[j], bvec[j] );
176 : }
177 1 : }
178 :
179 : //==============================================================================
180 : /// DetectLabEdges
181 : //==============================================================================
182 1 : void SLIC::DetectLabEdges(
183 : const double* lvec,
184 : const double* avec,
185 : const double* bvec,
186 : const int& width,
187 : const int& height,
188 : vector<double>& edges)
189 : {
190 1 : int sz = width*height;
191 :
192 1 : edges.resize(sz,0);
193 3897 : for( int j = 1; j < height-1; j++ )
194 : {
195 10121808 : for( int k = 1; k < width-1; k++ )
196 : {
197 10117912 : int i = j*width+k;
198 :
199 20235824 : double dx = (lvec[i-1]-lvec[i+1])*(lvec[i-1]-lvec[i+1]) +
200 10117912 : (avec[i-1]-avec[i+1])*(avec[i-1]-avec[i+1]) +
201 10117912 : (bvec[i-1]-bvec[i+1])*(bvec[i-1]-bvec[i+1]);
202 :
203 20235824 : double dy = (lvec[i-width]-lvec[i+width])*(lvec[i-width]-lvec[i+width]) +
204 10117912 : (avec[i-width]-avec[i+width])*(avec[i-width]-avec[i+width]) +
205 10117912 : (bvec[i-width]-bvec[i+width])*(bvec[i-width]-bvec[i+width]);
206 :
207 : //edges[i] = (sqrt(dx) + sqrt(dy));
208 10117912 : edges[i] = (dx + dy);
209 : }
210 : }
211 1 : }
212 :
213 : //===========================================================================
214 : /// PerturbSeeds
215 : //===========================================================================
216 1 : void SLIC::PerturbSeeds(
217 : vector<double>& kseedsl,
218 : vector<double>& kseedsa,
219 : vector<double>& kseedsb,
220 : vector<double>& kseedsx,
221 : vector<double>& kseedsy,
222 : const vector<double>& edges)
223 : {
224 1 : const int dx8[8] = {-1, -1, 0, 1, 1, 1, 0, -1};
225 1 : const int dy8[8] = { 0, -1, -1, -1, 0, 1, 1, 1};
226 :
227 1 : int numseeds = kseedsl.size();
228 :
229 197 : for( int n = 0; n < numseeds; n++ )
230 : {
231 196 : int ox = kseedsx[n];//original x
232 196 : int oy = kseedsy[n];//original y
233 196 : int oind = oy*m_width + ox;
234 :
235 196 : int storeind = oind;
236 1764 : for( int i = 0; i < 8; i++ )
237 : {
238 1568 : int nx = ox+dx8[i];//new x
239 1568 : int ny = oy+dy8[i];//new y
240 :
241 1568 : if( nx >= 0 && nx < m_width && ny >= 0 && ny < m_height)
242 : {
243 1568 : int nind = ny*m_width + nx;
244 1568 : if( edges[nind] < edges[storeind])
245 : {
246 259 : storeind = nind;
247 : }
248 : }
249 : }
250 196 : if(storeind != oind)
251 : {
252 138 : kseedsx[n] = storeind%m_width;
253 138 : kseedsy[n] = storeind/m_width;
254 138 : kseedsl[n] = m_lvec[storeind];
255 138 : kseedsa[n] = m_avec[storeind];
256 138 : kseedsb[n] = m_bvec[storeind];
257 : }
258 : }
259 1 : }
260 :
261 : //===========================================================================
262 : /// GetLABXYSeeds_ForGivenK
263 : ///
264 : /// The k seed values are taken as uniform spatial pixel samples.
265 : //===========================================================================
266 1 : void SLIC::GetLABXYSeeds_ForGivenK(
267 : vector<double>& kseedsl,
268 : vector<double>& kseedsa,
269 : vector<double>& kseedsb,
270 : vector<double>& kseedsx,
271 : vector<double>& kseedsy,
272 : const int& K,
273 : const bool& perturbseeds,
274 : const vector<double>& edgemag)
275 : {
276 1 : int sz = m_width*m_height;
277 1 : double step = sqrt(double(sz)/double(K));
278 1 : int T = step;
279 1 : int xoff = step/2;
280 1 : int yoff = step/2;
281 :
282 1 : int n(0);int r(0);
283 18 : for( int y = 0; y < m_height; y++ )
284 : {
285 18 : int Y = y*step + yoff;
286 18 : if( Y > m_height-1 ) break;
287 :
288 213 : for( int x = 0; x < m_width; x++ )
289 : {
290 : //int X = x*step + xoff;//square grid
291 213 : int X = x*step + (xoff<<(r&0x1));//hex grid
292 213 : if(X > m_width-1) break;
293 :
294 196 : int i = Y*m_width + X;
295 :
296 : //_ASSERT(n < K);
297 :
298 : //kseedsl[n] = m_lvec[i];
299 : //kseedsa[n] = m_avec[i];
300 : //kseedsb[n] = m_bvec[i];
301 : //kseedsx[n] = X;
302 : //kseedsy[n] = Y;
303 196 : kseedsl.push_back(m_lvec[i]);
304 196 : kseedsa.push_back(m_avec[i]);
305 196 : kseedsb.push_back(m_bvec[i]);
306 196 : kseedsx.push_back(X);
307 196 : kseedsy.push_back(Y);
308 196 : n++;
309 : }
310 17 : r++;
311 : }
312 :
313 1 : if(perturbseeds)
314 : {
315 1 : PerturbSeeds(kseedsl, kseedsa, kseedsb, kseedsx, kseedsy, edgemag);
316 : }
317 1 : }
318 :
319 : //===========================================================================
320 : /// PerformSuperpixelSegmentation_VariableSandM
321 : ///
322 : /// Magic SLIC - no parameters
323 : ///
324 : /// Performs k mean segmentation. It is fast because it looks locally, not
325 : /// over the entire image.
326 : /// This function picks the maximum value of color distance as compact factor
327 : /// M and maximum pixel distance as grid step size S from each cluster (13 April 2011).
328 : /// So no need to input a constant value of M and S. There are two clear
329 : /// advantages:
330 : ///
331 : /// [1] The algorithm now better handles both textured and non-textured regions
332 : /// [2] There is not need to set any parameters!!!
333 : ///
334 : /// SLICO (or SLIC Zero) dynamically varies only the compactness factor S,
335 : /// not the step size S.
336 : //===========================================================================
337 1 : void SLIC::PerformSuperpixelSegmentation_VariableSandM(
338 : vector<double>& kseedsl,
339 : vector<double>& kseedsa,
340 : vector<double>& kseedsb,
341 : vector<double>& kseedsx,
342 : vector<double>& kseedsy,
343 : int* klabels,
344 : const int& STEP,
345 : const int& NUMITR)
346 : {
347 1 : int sz = m_width*m_height;
348 1 : const int numk = kseedsl.size();
349 : //double cumerr(99999.9);
350 1 : int numitr(0);
351 :
352 : //----------------
353 1 : int offset = STEP;
354 1 : if(STEP < 10) offset = STEP*1.5;
355 : //----------------
356 :
357 1 : vector<double> sigmal(numk, 0);
358 2 : vector<double> sigmaa(numk, 0);
359 2 : vector<double> sigmab(numk, 0);
360 2 : vector<double> sigmax(numk, 0);
361 2 : vector<double> sigmay(numk, 0);
362 2 : vector<int> clustersize(numk, 0);
363 2 : vector<double> inv(numk, 0);//to store 1/clustersize[k] values
364 2 : vector<double> distxy(sz, DBL_MAX);
365 2 : vector<double> distlab(sz, DBL_MAX);
366 2 : vector<double> distvec(sz, DBL_MAX);
367 2 : vector<double> maxlab(numk, 10*10);//THIS IS THE VARIABLE VALUE OF M, just start with 10
368 2 : vector<double> maxxy(numk, STEP*STEP);//THIS IS THE VARIABLE VALUE OF M, just start with 10
369 :
370 1 : double invxywt = 1.0/(STEP*STEP);//NOTE: this is different from how usual SLIC/LKM works
371 :
372 12 : while( numitr < NUMITR )
373 : {
374 : //------
375 : //cumerr = 0;
376 10 : numitr++;
377 : //------
378 :
379 10 : distvec.assign(sz, DBL_MAX);
380 1970 : for( int n = 0; n < numk; n++ )
381 : {
382 1960 : int y1 = max(0, (int)(kseedsy[n]-offset));
383 1960 : int y2 = min(m_height, (int)(kseedsy[n]+offset));
384 1960 : int x1 = max(0, (int)(kseedsx[n]-offset));
385 1960 : int x2 = min(m_width, (int)(kseedsx[n]+offset));
386 :
387 867855 : for( int y = y1; y < y2; y++ )
388 : {
389 377486194 : for( int x = x1; x < x2; x++ )
390 : {
391 376620299 : int i = y*m_width + x;
392 : //_ASSERT( y < m_height && x < m_width && y >= 0 && x >= 0 );
393 :
394 376620299 : double l = m_lvec[i];
395 376620299 : double a = m_avec[i];
396 376620299 : double b = m_bvec[i];
397 :
398 753240598 : distlab[i] = (l - kseedsl[n])*(l - kseedsl[n]) +
399 753240598 : (a - kseedsa[n])*(a - kseedsa[n]) +
400 753240598 : (b - kseedsb[n])*(b - kseedsb[n]);
401 :
402 753240598 : distxy[i] = (x - kseedsx[n])*(x - kseedsx[n]) +
403 753240598 : (y - kseedsy[n])*(y - kseedsy[n]);
404 :
405 : //------------------------------------------------------------------------
406 376620299 : double dist = distlab[i]/maxlab[n] + distxy[i]*invxywt;//only varying m, prettier superpixels
407 : //double dist = distlab[i]/maxlab[n] + distxy[i]/maxxy[n];//varying both m and S
408 : //------------------------------------------------------------------------
409 :
410 376620299 : if( dist < distvec[i] )
411 : {
412 206398438 : distvec[i] = dist;
413 206398438 : klabels[i] = n;
414 : }
415 : }
416 : }
417 : }
418 : //-----------------------------------------------------------------
419 : // Assign the max color distance for a cluster
420 : //-----------------------------------------------------------------
421 10 : if(0 == numitr)
422 : {
423 0 : maxlab.assign(numk,1);
424 0 : maxxy.assign(numk,1);
425 : }
426 101309030 : {for( int i = 0; i < sz; i++ )
427 : {
428 101309020 : if(maxlab[klabels[i]] < distlab[i]) maxlab[klabels[i]] = distlab[i];
429 101309020 : if(maxxy[klabels[i]] < distxy[i]) maxxy[klabels[i]] = distxy[i];
430 : }}
431 : //-----------------------------------------------------------------
432 : // Recalculate the centroid and store in the seed values
433 : //-----------------------------------------------------------------
434 10 : sigmal.assign(numk, 0);
435 10 : sigmaa.assign(numk, 0);
436 10 : sigmab.assign(numk, 0);
437 10 : sigmax.assign(numk, 0);
438 10 : sigmay.assign(numk, 0);
439 10 : clustersize.assign(numk, 0);
440 :
441 101309030 : for( int j = 0; j < sz; j++ )
442 : {
443 101309020 : int temp = klabels[j];
444 : //_ASSERT(klabels[j] >= 0);
445 101309020 : sigmal[klabels[j]] += m_lvec[j];
446 101309020 : sigmaa[klabels[j]] += m_avec[j];
447 101309020 : sigmab[klabels[j]] += m_bvec[j];
448 101309020 : sigmax[klabels[j]] += (j%m_width);
449 101309020 : sigmay[klabels[j]] += (j/m_width);
450 :
451 101309020 : clustersize[klabels[j]]++;
452 : }
453 :
454 1970 : {for( int k = 0; k < numk; k++ )
455 : {
456 : //_ASSERT(clustersize[k] > 0);
457 1960 : if( clustersize[k] <= 0 ) clustersize[k] = 1;
458 1960 : inv[k] = 1.0/double(clustersize[k]);//computing inverse now to multiply, than divide later
459 : }}
460 :
461 1970 : {for( int k = 0; k < numk; k++ )
462 : {
463 1960 : kseedsl[k] = sigmal[k]*inv[k];
464 1960 : kseedsa[k] = sigmaa[k]*inv[k];
465 1960 : kseedsb[k] = sigmab[k]*inv[k];
466 1960 : kseedsx[k] = sigmax[k]*inv[k];
467 1960 : kseedsy[k] = sigmay[k]*inv[k];
468 : }}
469 1 : }
470 1 : }
471 :
472 : //===========================================================================
473 : /// SaveSuperpixelLabels2PGM
474 : ///
475 : /// Save labels to PGM in raster scan order.
476 : //===========================================================================
477 1 : void SLIC::SaveSuperpixelLabels2PPM(
478 : char* filename,
479 : int * labels,
480 : const int width,
481 : const int height)
482 : {
483 : FILE* fp;
484 : char header[20];
485 :
486 1 : fp = fopen(filename, "wb");
487 :
488 : // write the PPM header info, such as type, width, height and maximum
489 1 : fprintf(fp,"P6\n%d %d\n255\n", width, height);
490 :
491 : // write the RGB data
492 1 : unsigned char *rgb = new unsigned char [ (width)*(height)*3 ];
493 1 : int k = 0;
494 1 : unsigned char c = 0;
495 3899 : for ( int i = 0; i < (height); i++ ) {
496 10134800 : for ( int j = 0; j < (width); j++ ) {
497 10130902 : c = (unsigned char)(labels[k]);
498 10130902 : rgb[i*(width)*3 + j*3 + 2] = labels[k] >> 16 & 0xff; // r
499 10130902 : rgb[i*(width)*3 + j*3 + 1] = labels[k] >> 8 & 0xff; // g
500 10130902 : rgb[i*(width)*3 + j*3 + 0] = labels[k] & 0xff; // b
501 :
502 : // rgb[i*(width) + j + 0] = c;
503 10130902 : k++;
504 : }
505 : }
506 1 : fwrite(rgb, width*height*3, 1, fp);
507 :
508 1 : delete [] rgb;
509 :
510 1 : fclose(fp);
511 :
512 1 : }
513 :
514 : //===========================================================================
515 : /// EnforceLabelConnectivity
516 : ///
517 : /// 1. finding an adjacent label for each new component at the start
518 : /// 2. if a certain component is too small, assigning the previously found
519 : /// adjacent label to this component, and not incrementing the label.
520 : //===========================================================================
521 1 : void SLIC::EnforceLabelConnectivity(
522 : const int* labels,//input labels that need to be corrected to remove stray labels
523 : const int& width,
524 : const int& height,
525 : int* nlabels,//new labels
526 : int& numlabels,//the number of labels changes in the end if segments are removed
527 : const int& K) //the number of superpixels desired by the user
528 : {
529 : // const int dx8[8] = {-1, -1, 0, 1, 1, 1, 0, -1};
530 : // const int dy8[8] = { 0, -1, -1, -1, 0, 1, 1, 1};
531 :
532 1 : const int dx4[4] = {-1, 0, 1, 0};
533 1 : const int dy4[4] = { 0, -1, 0, 1};
534 :
535 1 : const int sz = width*height;
536 1 : const int SUPSZ = sz/K;
537 : //nlabels.resize(sz, -1);
538 1 : for( int i = 0; i < sz; i++ ) nlabels[i] = -1;
539 1 : int label(0);
540 1 : int* xvec = new int[sz];
541 1 : int* yvec = new int[sz];
542 1 : int oindex(0);
543 1 : int adjlabel(0);//adjacent label
544 3899 : for( int j = 0; j < height; j++ )
545 : {
546 10134800 : for( int k = 0; k < width; k++ )
547 : {
548 10130902 : if( 0 > nlabels[oindex] )
549 : {
550 579 : nlabels[oindex] = label;
551 : //--------------------
552 : // Start a new segment
553 : //--------------------
554 579 : xvec[0] = k;
555 579 : yvec[0] = j;
556 : //-------------------------------------------------------
557 : // Quickly find an adjacent label for use later if needed
558 : //-------------------------------------------------------
559 2895 : {for( int n = 0; n < 4; n++ )
560 : {
561 2316 : int x = xvec[0] + dx4[n];
562 2316 : int y = yvec[0] + dy4[n];
563 2316 : if( (x >= 0 && x < width) && (y >= 0 && y < height) )
564 : {
565 2296 : int nindex = y*width + x;
566 2296 : if(nlabels[nindex] >= 0) adjlabel = nlabels[nindex];
567 : }
568 : }}
569 :
570 579 : int count(1);
571 10131481 : for( int c = 0; c < count; c++ )
572 : {
573 50654510 : for( int n = 0; n < 4; n++ )
574 : {
575 40523608 : int x = xvec[c] + dx4[n];
576 40523608 : int y = yvec[c] + dy4[n];
577 :
578 40523608 : if( (x >= 0 && x < width) && (y >= 0 && y < height) )
579 : {
580 40510614 : int nindex = y*width + x;
581 :
582 40510614 : if( 0 > nlabels[nindex] && labels[oindex] == labels[nindex] )
583 : {
584 10130323 : xvec[count] = x;
585 10130323 : yvec[count] = y;
586 10130323 : nlabels[nindex] = label;
587 10130323 : count++;
588 : }
589 : }
590 :
591 : }
592 : }
593 : //-------------------------------------------------------
594 : // If segment size is less then a limit, assign an
595 : // adjacent label found before, and decrement label count.
596 : //-------------------------------------------------------
597 579 : if(count <= SUPSZ >> 2)
598 : {
599 47277 : for( int c = 0; c < count; c++ )
600 : {
601 46894 : int ind = yvec[c]*width+xvec[c];
602 46894 : nlabels[ind] = adjlabel;
603 : }
604 383 : label--;
605 : }
606 579 : label++;
607 : }
608 10130902 : oindex++;
609 : }
610 : }
611 1 : numlabels = label;
612 :
613 1 : if(xvec) delete [] xvec;
614 1 : if(yvec) delete [] yvec;
615 1 : }
616 :
617 : //===========================================================================
618 : /// PerformSLICO_ForGivenK
619 : ///
620 : /// Zero parameter SLIC algorithm for a given number K of superpixels.
621 : //===========================================================================
622 1 : void SLIC::PerformSLICO_ForGivenK(
623 : const unsigned int* ubuff,
624 : const int width,
625 : const int height,
626 : int* klabels,
627 : int& numlabels,
628 : const int& K,//required number of superpixels
629 : const double& m)//weight given to spatial distance
630 : {
631 1 : vector<double> kseedsl(0);
632 2 : vector<double> kseedsa(0);
633 2 : vector<double> kseedsb(0);
634 2 : vector<double> kseedsx(0);
635 2 : vector<double> kseedsy(0);
636 :
637 : //--------------------------------------------------
638 1 : m_width = width;
639 1 : m_height = height;
640 1 : int sz = m_width*m_height;
641 : //--------------------------------------------------
642 : //if(0 == klabels) klabels = new int[sz];
643 1 : for( int s = 0; s < sz; s++ ) klabels[s] = -1;
644 : //--------------------------------------------------
645 : if(1)//LAB
646 : {
647 1 : DoRGBtoLABConversion(ubuff, m_lvec, m_avec, m_bvec);
648 : }
649 : else//RGB
650 : {
651 : m_lvec = new double[sz]; m_avec = new double[sz]; m_bvec = new double[sz];
652 : for( int i = 0; i < sz; i++ )
653 : {
654 : m_lvec[i] = ubuff[i] >> 16 & 0xff;
655 : m_avec[i] = ubuff[i] >> 8 & 0xff;
656 : m_bvec[i] = ubuff[i] & 0xff;
657 : }
658 : }
659 : //--------------------------------------------------
660 :
661 1 : bool perturbseeds(true);
662 2 : vector<double> edgemag(0);
663 1 : if(perturbseeds) DetectLabEdges(m_lvec, m_avec, m_bvec, m_width, m_height, edgemag);
664 1 : GetLABXYSeeds_ForGivenK(kseedsl, kseedsa, kseedsb, kseedsx, kseedsy, K, perturbseeds, edgemag);
665 :
666 1 : int STEP = sqrt(double(sz)/double(K)) + 2.0;//adding a small value in the even the STEP size is too small.
667 1 : PerformSuperpixelSegmentation_VariableSandM(kseedsl,kseedsa,kseedsb,kseedsx,kseedsy,klabels,STEP,10);
668 1 : numlabels = kseedsl.size();
669 :
670 1 : int* nlabels = new int[sz];
671 1 : EnforceLabelConnectivity(klabels, m_width, m_height, nlabels, numlabels, K);
672 1 : {for(int i = 0; i < sz; i++ ) klabels[i] = nlabels[i];}
673 2 : if(nlabels) delete [] nlabels;
674 1 : }
675 :
676 : //===========================================================================
677 : /// Load PPM file
678 : ///
679 : ///
680 : //===========================================================================
681 1 : void LoadPPM(char* filename, unsigned int** data, int* width, int* height)
682 : {
683 : char header[1024];
684 1 : FILE* fp = NULL;
685 1 : int line = 0;
686 :
687 1 : fp = fopen(filename, "rb");
688 :
689 : // read the image type, such as: P6
690 : // skip the comment lines
691 4 : while (line < 2) {
692 2 : fgets(header, 1024, fp);
693 2 : if (header[0] != '#') {
694 2 : ++line;
695 : }
696 : }
697 : // read width and height
698 1 : sscanf(header,"%d %d\n", width, height);
699 :
700 : // read the maximum of pixels
701 1 : fgets(header, 20, fp);
702 :
703 : // get rgb data
704 1 : unsigned char *rgb = new unsigned char [ (*width)*(*height)*3 ];
705 1 : fread(rgb, (*width)*(*height)*3, 1, fp);
706 :
707 1 : *data = new unsigned int [ (*width)*(*height)*4 ];
708 1 : int k = 0;
709 3899 : for ( int i = 0; i < (*height); i++ ) {
710 10134800 : for ( int j = 0; j < (*width); j++ ) {
711 10130902 : unsigned char *p = rgb + i*(*width)*3 + j*3;
712 : // a ( skipped )
713 10130902 : (*data)[k] = p[2] << 16; // r
714 10130902 : (*data)[k] |= p[1] << 8; // g
715 10130902 : (*data)[k] |= p[0]; // b
716 10130902 : k++;
717 : }
718 : }
719 :
720 : // ofc, later, you'll have to cleanup
721 1 : delete [] rgb;
722 :
723 1 : fclose(fp);
724 1 : }
725 :
726 : //===========================================================================
727 : /// Load PPM file
728 : ///
729 : ///
730 : //===========================================================================
731 1 : int CheckLabelswithPPM(char* filename, int* labels, int width, int height)
732 : {
733 : char header[1024];
734 1 : FILE* fp = NULL;
735 1 : int line = 0, ground = 0;
736 :
737 1 : fp = fopen(filename, "rb");
738 :
739 : // read the image type, such as: P6
740 : // skip the comment lines
741 4 : while (line < 2) {
742 2 : fgets(header, 1024, fp);
743 2 : if (header[0] != '#') {
744 2 : ++line;
745 : }
746 : }
747 : // read width and height
748 1 : int w(0);
749 1 : int h(0);
750 1 : sscanf(header,"%d %d\n", &w, &h);
751 1 : if (w != width || h != height) return -1;
752 :
753 : // read the maximum of pixels
754 1 : fgets(header, 20, fp);
755 :
756 : // get rgb data
757 1 : unsigned char *rgb = new unsigned char [ (w)*(h)*3 ];
758 1 : fread(rgb, (w)*(h)*3, 1, fp);
759 :
760 1 : int num = 0, k = 0;
761 3899 : for ( int i = 0; i < (h); i++ ) {
762 10134800 : for ( int j = 0; j < (w); j++ ) {
763 10130902 : unsigned char *p = rgb + i*(w)*3 + j*3;
764 : // a ( skipped )
765 10130902 : ground = p[2] << 16; // r
766 10130902 : ground |= p[1] << 8; // g
767 10130902 : ground |= p[0]; // b
768 :
769 10130902 : if (ground != labels[k])
770 0 : num++;
771 :
772 10130902 : k++;
773 : }
774 : }
775 :
776 : // ofc, later, you'll have to cleanup
777 1 : delete [] rgb;
778 :
779 1 : fclose(fp);
780 :
781 1 : return num;
782 : }
783 :
784 : //===========================================================================
785 : /// The main function
786 : ///
787 : //===========================================================================
788 1 : int main (int argc, char **argv)
789 : {
790 1 : unsigned int* img = NULL;
791 1 : int width(0);
792 1 : int height(0);
793 :
794 1 : LoadPPM((char *)"input_image.ppm", &img, &width, &height);
795 1 : if (width == 0 || height == 0) return -1;
796 :
797 1 : int sz = width*height;
798 1 : int* labels = new int[sz];
799 1 : int numlabels(0);
800 1 : SLIC slic;
801 : int m_spcount;
802 : double m_compactness;
803 1 : m_spcount = 200;
804 1 : m_compactness = 10.0;
805 1 : auto startTime = Clock::now();
806 1 : slic.PerformSLICO_ForGivenK(img, width, height, labels, numlabels, m_spcount, m_compactness);//for a given number K of superpixels
807 1 : auto endTime = Clock::now();
808 1 : auto compTime = chrono::duration_cast<chrono::microseconds>(endTime - startTime);
809 1 : cout << "Computing time=" << compTime.count()/1000 << " ms" << endl;
810 :
811 1 : int num = CheckLabelswithPPM((char *)"check.ppm", labels, width, height);
812 1 : if (num < 0) {
813 0 : cout << "The result for labels is different from output_labels.ppm." << endl;
814 : } else {
815 1 : cout << "There are " << num << " points' labels are different from original file." << endl;
816 : }
817 :
818 1 : slic.SaveSuperpixelLabels2PPM((char *)"output_labels.ppm", labels, width, height);
819 1 : if(labels) delete [] labels;
820 :
821 1 : if(img) delete [] img;
822 :
823 1 : return 0;
824 3 : }
|