这一篇文章主要介绍了SLIC算法的大致分析和理解,提供了源码,供大家复制下载。

目录

部分代码分析

1.RGB -> XYZ

大致分析:

详细代码:

2.RGB -> LAB

大致分析:

具体代码:

3.将一个图像中的全部点进行二次转化

大致分析:

具体代码:

4.计算图像中每个像素点的梯度

大致分析:

具体代码:

5.在 3*3 的领域内选择梯度最小的点作为中心节点

大致思路:

具体代码:

6.移动聚类中心到 3*3 领域中梯度最小的位置

大致分析:

具体代码:

7.计算像素点与聚类中心的距离+分类+重新分类聚类中心

大致分析:

具体代码:

8.提取图片中每个像素点的R、G、B的值

具体代码:

9.给定K个超像素的SLIC算法

具体代码:

完整代码

SLIC.cpp

SLIC.h

运行结果:


部分代码分析

1.RGB -> XYZ

大致分析:

详细代码:

void SLIC::RGB2XYZ(const int&        sR,const int&       sG,const int&       sB,double&          X,double&           Y,double&           Z)
{double R = sR/255.0;double G = sG/255.0;double B = sB/255.0;double r, g, b;if(R <= 0.04045) r = R/12.92;else               r = pow((R+0.055)/1.055,2.4);if(G <= 0.04045) g = G/12.92;else               g = pow((G+0.055)/1.055,2.4);if(B <= 0.04045) b = B/12.92;else               b = pow((B+0.055)/1.055,2.4);X = r*0.4124564 + g*0.3575761 + b*0.1804375;Y = r*0.2126729 + g*0.7151522 + b*0.0721750;Z = r*0.0193339 + g*0.1191920 + b*0.9503041;
}

2.RGB -> LAB

大致分析:

具体代码:

void SLIC::RGB2LAB(const int& sR, const int& sG, const int& sB, double& lval, double& aval, double& bval)
{//------------------------// sRGB to XYZ conversion//------------------------double X, Y, Z;RGB2XYZ(sR, sG, sB, X, Y, Z);//------------------------// XYZ to LAB conversion//------------------------double epsilon = 0.008856;   //actual CIE standarddouble kappa   = 903.3;       //actual CIE standarddouble Xr = 0.950456; //reference whitedouble Yr = 1.0;      //reference whitedouble Zr = 1.088754; //reference whitedouble xr = X/Xr;double yr = Y/Yr;double zr = Z/Zr;double fx, fy, fz;if(xr > epsilon)    fx = pow(xr, 1.0/3.0);else             fx = (kappa*xr + 16.0)/116.0;if(yr > epsilon)  fy = pow(yr, 1.0/3.0);else             fy = (kappa*yr + 16.0)/116.0;if(zr > epsilon)  fz = pow(zr, 1.0/3.0);else             fz = (kappa*zr + 16.0)/116.0;lval = 116.0*fy-16.0;aval = 500.0*(fx-fy);bval = 200.0*(fy-fz);
}

3.将一个图像中的全部点进行二次转化

大致分析:

去一个数组的24位的 23~16位, 15~8位,7~0位作为 R、G、B 的值。采用第四步中的方法将其转化为 L、 A、 B的值。

具体代码:

void SLIC::DoRGBtoLABConversion(const unsigned int*&     ubuff,double*&                  lvec,double*&                   avec,double*&                   bvec)
{int sz = m_width*m_height;lvec = new double[sz];avec = new double[sz];bvec = new double[sz];for( int j = 0; j < sz; j++ ){int r = (ubuff[j] >> 16) & 0xFF;    //取高16位的八位int g = (ubuff[j] >>  8) & 0xFF;    //取高8位的八位int b = (ubuff[j]      ) & 0xFF;    //取低位的八位RGB2LAB( r, g, b, lvec[j], avec[j], bvec[j] );}
}

4.计算图像中每个像素点的梯度

大致分析:

具体代码:

void SLIC::DetectLabEdges(const double*              lvec,const double*              avec,const double*              bvec,const int&                 width,const int&                    height,vector<double>&                edges)
{int sz = width*height;edges.resize(sz,0);for( int j = 1; j < height-1; j++ ){for( int k = 1; k < width-1; k++ ){int i = j*width+k;double dx = (lvec[i-1]-lvec[i+1])*(lvec[i-1]-lvec[i+1]) +(avec[i-1]-avec[i+1])*(avec[i-1]-avec[i+1]) +(bvec[i-1]-bvec[i+1])*(bvec[i-1]-bvec[i+1]);double dy = (lvec[i-width]-lvec[i+width])*(lvec[i-width]-lvec[i+width]) +(avec[i-width]-avec[i+width])*(avec[i-width]-avec[i+width]) +(bvec[i-width]-bvec[i+width])*(bvec[i-width]-bvec[i+width]);//edges[i] = (sqrt(dx) + sqrt(dy));edges[i] = (dx + dy);}}
}

5.在 3*3 的领域内选择梯度最小的点作为中心节点

大致思路:

用for循环来遍历图像中的每一个像素点,利用数组来锁定 3*3 的领域。在调用第6步的方法进行对比,如果梯度小的话,就更换中心节点,否则就不变。

具体代码:

void SLIC::PerturbSeeds(vector<double>&                kseedsl,vector<double>&               kseedsa,vector<double>&               kseedsb,vector<double>&               kseedsx,vector<double>&               kseedsy,const vector<double>&     edges)
{const int dx8[8] = {-1, -1,  0,  1, 1, 1, 0, -1};const int dy8[8] = { 0, -1, -1, -1, 0, 1, 1,  1};int numseeds = kseedsl.size();for( int n = 0; n < numseeds; n++ ){int ox = kseedsx[n];//original xint oy = kseedsy[n];//original yint oind = oy*m_width + ox;int storeind = oind;for( int i = 0; i < 8; i++ ){int nx = ox+dx8[i];//new xint ny = oy+dy8[i];//new yif( nx >= 0 && nx < m_width && ny >= 0 && ny < m_height){int nind = ny*m_width + nx;if( edges[nind] < edges[storeind]){storeind = nind;}}}if(storeind != oind){kseedsx[n] = storeind%m_width;kseedsy[n] = storeind/m_width;kseedsl[n] = m_lvec[storeind];kseedsa[n] = m_avec[storeind];kseedsb[n] = m_bvec[storeind];}}
}

6.移动聚类中心到 3*3 领域中梯度最小的位置

大致分析:

利用Sqr(N/K)来遍历整个像素点,然后调用第7步中方法来实现聚类中心的移动。

具体代码:

void SLIC::GetLABXYSeeds_ForGivenK(vector<double>&             kseedsl,vector<double>&               kseedsa,vector<double>&               kseedsb,vector<double>&               kseedsx,vector<double>&               kseedsy,const int&                  K,const bool&                   perturbseeds,const vector<double>&        edgemag)
{int sz = m_width*m_height;double step = sqrt(double(sz)/double(K));int T = step;int xoff = step/2;int yoff = step/2;int n(0);int r(0);for( int y = 0; y < m_height; y++ ){int Y = y*step + yoff;if( Y > m_height-1 ) break;for( int x = 0; x < m_width; x++ ){//int X = x*step + xoff;//square gridint X = x*step + (xoff<<(r&0x1));//hex gridif(X > m_width-1) break;int i = Y*m_width + X;//_ASSERT(n < K);//kseedsl[n] = m_lvec[i];//kseedsa[n] = m_avec[i];//kseedsb[n] = m_bvec[i];//kseedsx[n] = X;//kseedsy[n] = Y;kseedsl.push_back(m_lvec[i]);kseedsa.push_back(m_avec[i]);kseedsb.push_back(m_bvec[i]);kseedsx.push_back(X);kseedsy.push_back(Y);n++;}r++;}if(perturbseeds){PerturbSeeds(kseedsl, kseedsa, kseedsb, kseedsx, kseedsy, edgemag);}
}

7.计算像素点与聚类中心的距离+分类+重新分类聚类中心

大致分析:

距离使用的是欧式距离,总距离 由 dc颜色距离与 ds空间距离两部分组成。公式如下:

标记每个像素点的类别为距离其最小的聚类中心的类别。

计算属于同一个聚类的所有像素点的平均向量值,重新得到聚类中心 。

具体代码:

void SLIC::PerformSuperpixelSegmentation_VariableSandM(vector<double>&             kseedsl,vector<double>&               kseedsa,vector<double>&               kseedsb,vector<double>&               kseedsx,vector<double>&               kseedsy,int*                        klabels,const int&                  STEP,const int&                 NUMITR)
{int sz = m_width*m_height;const int numk = kseedsl.size();//double cumerr(99999.9);int numitr(0);//----------------int offset = STEP;if(STEP < 10) offset = STEP*1.5;//----------------vector<double> sigmal(numk, 0);vector<double> sigmaa(numk, 0);vector<double> sigmab(numk, 0);vector<double> sigmax(numk, 0);vector<double> sigmay(numk, 0);vector<int> clustersize(numk, 0);vector<double> inv(numk, 0);//to store 1/clustersize[k] valuesvector<double> distxy(sz, DBL_MAX);vector<double> distlab(sz, DBL_MAX);vector<double> distvec(sz, DBL_MAX);vector<double> maxlab(numk, 10*10);//THIS IS THE VARIABLE VALUE OF M, just start with 10vector<double> maxxy(numk, STEP*STEP);//THIS IS THE VARIABLE VALUE OF M, just start with 10double invxywt = 1.0/(STEP*STEP);//NOTE: this is different from how usual SLIC/LKM workswhile( numitr < NUMITR ){//------//cumerr = 0;numitr++;//------distvec.assign(sz, DBL_MAX);for( int n = 0; n < numk; n++ ){int y1 = max(0,         (int)(kseedsy[n]-offset));int y2 = min(m_height,   (int)(kseedsy[n]+offset));int x1 = max(0,         (int)(kseedsx[n]-offset));int x2 = min(m_width,    (int)(kseedsx[n]+offset));for( int y = y1; y < y2; y++ ){for( int x = x1; x < x2; x++ ){int i = y*m_width + x;//_ASSERT( y < m_height && x < m_width && y >= 0 && x >= 0 );double l = m_lvec[i];double a = m_avec[i];double b = m_bvec[i];distlab[i] = (l - kseedsl[n])*(l - kseedsl[n]) +(a - kseedsa[n])*(a - kseedsa[n]) +(b - kseedsb[n])*(b - kseedsb[n]);distxy[i] =      (x - kseedsx[n])*(x - kseedsx[n]) +(y - kseedsy[n])*(y - kseedsy[n]);//------------------------------------------------------------------------double dist = distlab[i]/maxlab[n] + distxy[i]*invxywt;//only varying m, prettier superpixels//double dist = distlab[i]/maxlab[n] + distxy[i]/maxxy[n];//varying both m and S//------------------------------------------------------------------------if( dist < distvec[i] ){distvec[i] = dist;klabels[i]  = n;}}}}//-----------------------------------------------------------------// Assign the max color distance for a cluster//-----------------------------------------------------------------if(0 == numitr){maxlab.assign(numk,1);maxxy.assign(numk,1);}{for( int i = 0; i < sz; i++ ){if(maxlab[klabels[i]] < distlab[i]) maxlab[klabels[i]] = distlab[i];if(maxxy[klabels[i]] < distxy[i]) maxxy[klabels[i]] = distxy[i];}}//-----------------------------------------------------------------// Recalculate the centroid and store in the seed values//-----------------------------------------------------------------sigmal.assign(numk, 0);sigmaa.assign(numk, 0);sigmab.assign(numk, 0);sigmax.assign(numk, 0);sigmay.assign(numk, 0);clustersize.assign(numk, 0);for( int j = 0; j < sz; j++ ){int temp = klabels[j];//_ASSERT(klabels[j] >= 0);sigmal[klabels[j]] += m_lvec[j];sigmaa[klabels[j]] += m_avec[j];sigmab[klabels[j]] += m_bvec[j];sigmax[klabels[j]] += (j%m_width);sigmay[klabels[j]] += (j/m_width);clustersize[klabels[j]]++;}{for( int k = 0; k < numk; k++ ){//_ASSERT(clustersize[k] > 0);if( clustersize[k] <= 0 ) clustersize[k] = 1;inv[k] = 1.0/double(clustersize[k]);//computing inverse now to multiply, than divide later}}{for( int k = 0; k < numk; k++ ){kseedsl[k] = sigmal[k]*inv[k];kseedsa[k] = sigmaa[k]*inv[k];kseedsb[k] = sigmab[k]*inv[k];kseedsx[k] = sigmax[k]*inv[k];kseedsy[k] = sigmay[k]*inv[k];}}}
}

8.提取图片中每个像素点的R、G、B的值

具体代码:

void SLIC::SaveSuperpixelLabels2PPM(char*                           filename, int *                           labels, const int                       width, const int                       height)
{FILE* fp;char header[20];fp = fopen(filename, "wb");// write the PPM header info, such as type, width, height and maximumfprintf(fp,"P6\n%d %d\n255\n", width, height);// write the RGB dataunsigned char *rgb = new unsigned char [ (width)*(height)*3 ];int k = 0;unsigned char c = 0;for ( int i = 0; i < (height); i++ ) {for ( int j = 0; j < (width); j++ ) {c = (unsigned char)(labels[k]);rgb[i*(width)*3 + j*3 + 2] = labels[k] >> 16 & 0xff;  // rrgb[i*(width)*3 + j*3 + 1] = labels[k] >> 8  & 0xff;  // grgb[i*(width)*3 + j*3 + 0] = labels[k]       & 0xff;  // b// rgb[i*(width) + j + 0] = c;k++;}}fwrite(rgb, width*height*3, 1, fp);delete [] rgb;fclose(fp);}

9.给定K个超像素的SLIC算法

具体代码:

void SLIC::PerformSLICO_ForGivenK(const unsigned int*            ubuff,const int                 width,const int                 height,int*                     klabels,int&                        numlabels,const int&                    K,//required number of superpixelsconst double&             m)//weight given to spatial distance
{vector<double> kseedsl(0);vector<double> kseedsa(0);vector<double> kseedsb(0);vector<double> kseedsx(0);vector<double> kseedsy(0);//--------------------------------------------------m_width  = width;m_height = height;int sz = m_width*m_height;//--------------------------------------------------//if(0 == klabels) klabels = new int[sz];for( int s = 0; s < sz; s++ ) klabels[s] = -1;//--------------------------------------------------if(1)//LAB{DoRGBtoLABConversion(ubuff, m_lvec, m_avec, m_bvec); //RGB->LAB}else//RGB{m_lvec = new double[sz]; m_avec = new double[sz]; m_bvec = new double[sz];for( int i = 0; i < sz; i++ ){m_lvec[i] = ubuff[i] >> 16 & 0xff;m_avec[i] = ubuff[i] >>  8 & 0xff;m_bvec[i] = ubuff[i]       & 0xff;}}//--------------------------------------------------bool perturbseeds(true);vector<double> edgemag(0);if(perturbseeds) DetectLabEdges(m_lvec, m_avec, m_bvec, m_width, m_height, edgemag);//计算每个点的像素梯度GetLABXYSeeds_ForGivenK(kseedsl, kseedsa, kseedsb, kseedsx, kseedsy, K, perturbseeds, edgemag);//移动聚类中心到 3*3 领域中梯度最小的位置int STEP = sqrt(double(sz)/double(K)) + 2.0;//adding a small value in the even the STEP size is too small.PerformSuperpixelSegmentation_VariableSandM(kseedsl,kseedsa,kseedsb,kseedsx,kseedsy,klabels,STEP,10);//分类numlabels = kseedsl.size();int* nlabels = new int[sz];EnforceLabelConnectivity(klabels, m_width, m_height, nlabels, numlabels, K);{for(int i = 0; i < sz; i++ ) klabels[i] = nlabels[i];}if(nlabels) delete [] nlabels;
}

完整代码

SLIC.cpp

// SLIC.cpp: implementation of the SLIC class.
//===========================================================================
// This code implements the zero parameter superpixel segmentation technique
// described in:
//
//
//
// "SLIC Superpixels Compared to State-of-the-art Superpixel Methods"
//
// Radhakrishna Achanta, Appu Shaji, Kevin Smith, Aurelien Lucchi, Pascal Fua,
// and Sabine Susstrunk,
//
// IEEE TPAMI, Volume 34, Issue 11, Pages 2274-2282, November 2012.
//
// https://www.epfl.ch/labs/ivrl/research/slic-superpixels/
//===========================================================================
// Copyright (c) 2013 Radhakrishna Achanta.
//
// For commercial use please contact the author:
//
// Email: firstname.lastname@epfl.ch
//===========================================================================#include <stdio.h>
#include <cfloat>
#include <cmath>
#include <iostream>
#include <fstream>
#include "SLIC.h"
#include <chrono>
#include <windows.h>typedef chrono::high_resolution_clock Clock;// For superpixels
const int dx4[4] = {-1,  0,  1,  0};
const int dy4[4] = { 0, -1,  0,  1};
//const int dx8[8] = {-1, -1,  0,  1, 1, 1, 0, -1};
//const int dy8[8] = { 0, -1, -1, -1, 0, 1, 1,  1};// For supervoxels
const int dx10[10] = {-1,  0,  1,  0, -1,  1,  1, -1,  0, 0};
const int dy10[10] = { 0, -1,  0,  1, -1, -1,  1,  1,  0, 0};
const int dz10[10] = { 0,  0,  0,  0,  0,  0,  0,  0, -1, 1};//
// Construction/Destruction
//SLIC::SLIC()
{m_lvec = NULL;m_avec = NULL;m_bvec = NULL;m_lvecvec = NULL;m_avecvec = NULL;m_bvecvec = NULL;
}SLIC::~SLIC()
{if(m_lvec) delete [] m_lvec;if(m_avec) delete [] m_avec;if(m_bvec) delete [] m_bvec;if(m_lvecvec){for( int d = 0; d < m_depth; d++ ) delete [] m_lvecvec[d];delete [] m_lvecvec;}if(m_avecvec){for( int d = 0; d < m_depth; d++ ) delete [] m_avecvec[d];delete [] m_avecvec;}if(m_bvecvec){for( int d = 0; d < m_depth; d++ ) delete [] m_bvecvec[d];delete [] m_bvecvec;}
}//==============================================================================
/// RGB2XYZ
///
/// sRGB (D65 illuninant assumption) to XYZ conversion
//==============================================================================
void SLIC::RGB2XYZ(const int&       sR,const int&       sG,const int&       sB,double&          X,double&           Y,double&           Z)
{double R = sR/255.0;double G = sG/255.0;double B = sB/255.0;double r, g, b;if(R <= 0.04045) r = R/12.92;else               r = pow((R+0.055)/1.055,2.4);if(G <= 0.04045) g = G/12.92;else               g = pow((G+0.055)/1.055,2.4);if(B <= 0.04045) b = B/12.92;else               b = pow((B+0.055)/1.055,2.4);X = r*0.4124564 + g*0.3575761 + b*0.1804375;Y = r*0.2126729 + g*0.7151522 + b*0.0721750;Z = r*0.0193339 + g*0.1191920 + b*0.9503041;
}//===========================================================================
/// RGB2LAB
//===========================================================================
void SLIC::RGB2LAB(const int& sR, const int& sG, const int& sB, double& lval, double& aval, double& bval)
{//------------------------// sRGB to XYZ conversion//------------------------double X, Y, Z;RGB2XYZ(sR, sG, sB, X, Y, Z);//------------------------// XYZ to LAB conversion//------------------------double epsilon = 0.008856;   //actual CIE standarddouble kappa   = 903.3;       //actual CIE standarddouble Xr = 0.950456; //reference whitedouble Yr = 1.0;      //reference whitedouble Zr = 1.088754; //reference whitedouble xr = X/Xr;double yr = Y/Yr;double zr = Z/Zr;double fx, fy, fz;if(xr > epsilon)    fx = pow(xr, 1.0/3.0);else             fx = (kappa*xr + 16.0)/116.0;if(yr > epsilon)  fy = pow(yr, 1.0/3.0);else             fy = (kappa*yr + 16.0)/116.0;if(zr > epsilon)  fz = pow(zr, 1.0/3.0);else             fz = (kappa*zr + 16.0)/116.0;lval = 116.0*fy-16.0;aval = 500.0*(fx-fy);bval = 200.0*(fy-fz);
}//===========================================================================
/// DoRGBtoLABConversion
///
/// For whole image: overlaoded floating point version
//===========================================================================
void SLIC::DoRGBtoLABConversion(const unsigned int*&        ubuff,double*&                  lvec,double*&                   avec,double*&                   bvec)
{int sz = m_width*m_height;lvec = new double[sz];avec = new double[sz];bvec = new double[sz];for( int j = 0; j < sz; j++ ){int r = (ubuff[j] >> 16) & 0xFF;    //取高16位的八位int g = (ubuff[j] >>  8) & 0xFF;    //取高8位的八位int b = (ubuff[j]      ) & 0xFF;    //取低位的八位RGB2LAB( r, g, b, lvec[j], avec[j], bvec[j] );}
}//==============================================================================
/// DetectLabEdges
//==============================================================================
void SLIC::DetectLabEdges(const double*             lvec,const double*              avec,const double*              bvec,const int&                 width,const int&                    height,vector<double>&                edges)
{int sz = width*height;edges.resize(sz,0);for( int j = 1; j < height-1; j++ ){for( int k = 1; k < width-1; k++ ){int i = j*width+k;double dx = (lvec[i-1]-lvec[i+1])*(lvec[i-1]-lvec[i+1]) +(avec[i-1]-avec[i+1])*(avec[i-1]-avec[i+1]) +(bvec[i-1]-bvec[i+1])*(bvec[i-1]-bvec[i+1]);double dy = (lvec[i-width]-lvec[i+width])*(lvec[i-width]-lvec[i+width]) +(avec[i-width]-avec[i+width])*(avec[i-width]-avec[i+width]) +(bvec[i-width]-bvec[i+width])*(bvec[i-width]-bvec[i+width]);//edges[i] = (sqrt(dx) + sqrt(dy));edges[i] = (dx + dy);}}
}//===========================================================================
/// PerturbSeeds
//===========================================================================
void SLIC::PerturbSeeds(vector<double>&               kseedsl,vector<double>&               kseedsa,vector<double>&               kseedsb,vector<double>&               kseedsx,vector<double>&               kseedsy,const vector<double>&     edges)
{const int dx8[8] = {-1, -1,  0,  1, 1, 1, 0, -1};const int dy8[8] = { 0, -1, -1, -1, 0, 1, 1,  1};int numseeds = kseedsl.size();for( int n = 0; n < numseeds; n++ ){int ox = kseedsx[n];//original xint oy = kseedsy[n];//original yint oind = oy*m_width + ox;int storeind = oind;for( int i = 0; i < 8; i++ ){int nx = ox+dx8[i];//new xint ny = oy+dy8[i];//new yif( nx >= 0 && nx < m_width && ny >= 0 && ny < m_height){int nind = ny*m_width + nx;if( edges[nind] < edges[storeind]){storeind = nind;}}}if(storeind != oind){kseedsx[n] = storeind%m_width;kseedsy[n] = storeind/m_width;kseedsl[n] = m_lvec[storeind];kseedsa[n] = m_avec[storeind];kseedsb[n] = m_bvec[storeind];}}
}//===========================================================================
/// GetLABXYSeeds_ForGivenK
///
/// The k seed values are taken as uniform spatial pixel samples.
//===========================================================================
void SLIC::GetLABXYSeeds_ForGivenK(vector<double>&                kseedsl,vector<double>&               kseedsa,vector<double>&               kseedsb,vector<double>&               kseedsx,vector<double>&               kseedsy,const int&                  K,const bool&                   perturbseeds,const vector<double>&        edgemag)
{int sz = m_width*m_height;double step = sqrt(double(sz)/double(K));int T = step;int xoff = step/2;int yoff = step/2;int n(0);int r(0);for( int y = 0; y < m_height; y++ ){int Y = y*step + yoff;if( Y > m_height-1 ) break;for( int x = 0; x < m_width; x++ ){//int X = x*step + xoff;//square gridint X = x*step + (xoff<<(r&0x1));//hex gridif(X > m_width-1) break;int i = Y*m_width + X;//_ASSERT(n < K);//kseedsl[n] = m_lvec[i];//kseedsa[n] = m_avec[i];//kseedsb[n] = m_bvec[i];//kseedsx[n] = X;//kseedsy[n] = Y;kseedsl.push_back(m_lvec[i]);kseedsa.push_back(m_avec[i]);kseedsb.push_back(m_bvec[i]);kseedsx.push_back(X);kseedsy.push_back(Y);n++;}r++;}if(perturbseeds){PerturbSeeds(kseedsl, kseedsa, kseedsb, kseedsx, kseedsy, edgemag);}
}//===========================================================================
/// PerformSuperpixelSegmentation_VariableSandM
///
/// Magic SLIC - no parameters
///
/// Performs k mean segmentation. It is fast because it looks locally, not
/// over the entire image.
/// This function picks the maximum value of color distance as compact factor
/// M and maximum pixel distance as grid step size S from each cluster (13 April 2011).
/// So no need to input a constant value of M and S. There are two clear
/// advantages:
///
/// [1] The algorithm now better handles both textured and non-textured regions
/// [2] There is not need to set any parameters!!!
///
/// SLICO (or SLIC Zero) dynamically varies only the compactness factor S,
/// not the step size S.
//===========================================================================
void SLIC::PerformSuperpixelSegmentation_VariableSandM(vector<double>&                kseedsl,vector<double>&               kseedsa,vector<double>&               kseedsb,vector<double>&               kseedsx,vector<double>&               kseedsy,int*                        klabels,const int&                  STEP,const int&                 NUMITR)
{int sz = m_width*m_height;const int numk = kseedsl.size();//double cumerr(99999.9);int numitr(0);//----------------int offset = STEP;if(STEP < 10) offset = STEP*1.5;//----------------vector<double> sigmal(numk, 0);vector<double> sigmaa(numk, 0);vector<double> sigmab(numk, 0);vector<double> sigmax(numk, 0);vector<double> sigmay(numk, 0);vector<int> clustersize(numk, 0);vector<double> inv(numk, 0);//to store 1/clustersize[k] valuesvector<double> distxy(sz, DBL_MAX);vector<double> distlab(sz, DBL_MAX);vector<double> distvec(sz, DBL_MAX);vector<double> maxlab(numk, 10*10);//THIS IS THE VARIABLE VALUE OF M, just start with 10vector<double> maxxy(numk, STEP*STEP);//THIS IS THE VARIABLE VALUE OF M, just start with 10double invxywt = 1.0/(STEP*STEP);//NOTE: this is different from how usual SLIC/LKM workswhile( numitr < NUMITR ){//------//cumerr = 0;numitr++;//------distvec.assign(sz, DBL_MAX);for( int n = 0; n < numk; n++ ){int y1 = max(0,         (int)(kseedsy[n]-offset));int y2 = min(m_height,   (int)(kseedsy[n]+offset));int x1 = max(0,         (int)(kseedsx[n]-offset));int x2 = min(m_width,    (int)(kseedsx[n]+offset));for( int y = y1; y < y2; y++ ){for( int x = x1; x < x2; x++ ){int i = y*m_width + x;//_ASSERT( y < m_height && x < m_width && y >= 0 && x >= 0 );double l = m_lvec[i];double a = m_avec[i];double b = m_bvec[i];distlab[i] = (l - kseedsl[n])*(l - kseedsl[n]) +(a - kseedsa[n])*(a - kseedsa[n]) +(b - kseedsb[n])*(b - kseedsb[n]);distxy[i] =      (x - kseedsx[n])*(x - kseedsx[n]) +(y - kseedsy[n])*(y - kseedsy[n]);//------------------------------------------------------------------------double dist = distlab[i]/maxlab[n] + distxy[i]*invxywt;//only varying m, prettier superpixels//double dist = distlab[i]/maxlab[n] + distxy[i]/maxxy[n];//varying both m and S//------------------------------------------------------------------------if( dist < distvec[i] ){distvec[i] = dist;klabels[i]  = n;}}}}//-----------------------------------------------------------------// Assign the max color distance for a cluster//-----------------------------------------------------------------if(0 == numitr){maxlab.assign(numk,1);maxxy.assign(numk,1);}{for( int i = 0; i < sz; i++ ){if(maxlab[klabels[i]] < distlab[i]) maxlab[klabels[i]] = distlab[i];if(maxxy[klabels[i]] < distxy[i]) maxxy[klabels[i]] = distxy[i];}}//-----------------------------------------------------------------// Recalculate the centroid and store in the seed values//-----------------------------------------------------------------sigmal.assign(numk, 0);sigmaa.assign(numk, 0);sigmab.assign(numk, 0);sigmax.assign(numk, 0);sigmay.assign(numk, 0);clustersize.assign(numk, 0);for( int j = 0; j < sz; j++ ){int temp = klabels[j];//_ASSERT(klabels[j] >= 0);sigmal[klabels[j]] += m_lvec[j];sigmaa[klabels[j]] += m_avec[j];sigmab[klabels[j]] += m_bvec[j];sigmax[klabels[j]] += (j%m_width);sigmay[klabels[j]] += (j/m_width);clustersize[klabels[j]]++;}{for( int k = 0; k < numk; k++ ){//_ASSERT(clustersize[k] > 0);if( clustersize[k] <= 0 ) clustersize[k] = 1;inv[k] = 1.0/double(clustersize[k]);//computing inverse now to multiply, than divide later}}{for( int k = 0; k < numk; k++ ){kseedsl[k] = sigmal[k]*inv[k];kseedsa[k] = sigmaa[k]*inv[k];kseedsb[k] = sigmab[k]*inv[k];kseedsx[k] = sigmax[k]*inv[k];kseedsy[k] = sigmay[k]*inv[k];}}}
}//===========================================================================
/// SaveSuperpixelLabels2PGM
///
/// Save labels to PGM in raster scan order.
//===========================================================================
void SLIC::SaveSuperpixelLabels2PPM(char*                           filename, int *                           labels, const int                       width, const int                       height)
{FILE* fp;char header[20];fp = fopen(filename, "wb");// write the PPM header info, such as type, width, height and maximumfprintf(fp,"P6\n%d %d\n255\n", width, height);// write the RGB dataunsigned char *rgb = new unsigned char [ (width)*(height)*3 ];int k = 0;unsigned char c = 0;for ( int i = 0; i < (height); i++ ) {for ( int j = 0; j < (width); j++ ) {c = (unsigned char)(labels[k]);rgb[i*(width)*3 + j*3 + 2] = labels[k] >> 16 & 0xff;  // rrgb[i*(width)*3 + j*3 + 1] = labels[k] >> 8  & 0xff;  // grgb[i*(width)*3 + j*3 + 0] = labels[k]       & 0xff;  // b// rgb[i*(width) + j + 0] = c;k++;}}fwrite(rgb, width*height*3, 1, fp);delete [] rgb;fclose(fp);}//===========================================================================
/// EnforceLabelConnectivity
///
///     1. finding an adjacent label for each new component at the start
///     2. if a certain component is too small, assigning the previously found
///         adjacent label to this component, and not incrementing the label.
//===========================================================================
void SLIC::EnforceLabelConnectivity(const int*                  labels,//input labels that need to be corrected to remove stray labelsconst int&                    width,const int&                    height,int*                     nlabels,//new labelsint&                        numlabels,//the number of labels changes in the end if segments are removedconst int&                   K) //the number of superpixels desired by the user
{
//  const int dx8[8] = {-1, -1,  0,  1, 1, 1, 0, -1};
//  const int dy8[8] = { 0, -1, -1, -1, 0, 1, 1,  1};const int dx4[4] = {-1,  0,  1,  0};const int dy4[4] = { 0, -1,  0,  1};const int sz = width*height;const int SUPSZ = sz/K;//nlabels.resize(sz, -1);for( int i = 0; i < sz; i++ ) nlabels[i] = -1;int label(0);int* xvec = new int[sz];int* yvec = new int[sz];int oindex(0);int adjlabel(0);//adjacent labelfor( int j = 0; j < height; j++ ){for( int k = 0; k < width; k++ ){if( 0 > nlabels[oindex] ){nlabels[oindex] = label;//--------------------// Start a new segment//--------------------xvec[0] = k;yvec[0] = j;//-------------------------------------------------------// Quickly find an adjacent label for use later if needed//-------------------------------------------------------{for( int n = 0; n < 4; n++ ){int x = xvec[0] + dx4[n];int y = yvec[0] + dy4[n];if( (x >= 0 && x < width) && (y >= 0 && y < height) ){int nindex = y*width + x;if(nlabels[nindex] >= 0) adjlabel = nlabels[nindex];}}}int count(1);for( int c = 0; c < count; c++ ){for( int n = 0; n < 4; n++ ){int x = xvec[c] + dx4[n];int y = yvec[c] + dy4[n];if( (x >= 0 && x < width) && (y >= 0 && y < height) ){int nindex = y*width + x;if( 0 > nlabels[nindex] && labels[oindex] == labels[nindex] ){xvec[count] = x;yvec[count] = y;nlabels[nindex] = label;count++;}}}}//-------------------------------------------------------// If segment size is less then a limit, assign an// adjacent label found before, and decrement label count.//-------------------------------------------------------if(count <= SUPSZ >> 2){for( int c = 0; c < count; c++ ){int ind = yvec[c]*width+xvec[c];nlabels[ind] = adjlabel;}label--;}label++;}oindex++;}}numlabels = label;if(xvec) delete [] xvec;if(yvec) delete [] yvec;
}//===========================================================================
/// PerformSLICO_ForGivenK
///
/// Zero parameter SLIC algorithm for a given number K of superpixels.
//===========================================================================
void SLIC::PerformSLICO_ForGivenK(const unsigned int*           ubuff,const int                 width,const int                 height,int*                     klabels,int&                        numlabels,const int&                    K,//required number of superpixelsconst double&             m)//weight given to spatial distance
{vector<double> kseedsl(0);vector<double> kseedsa(0);vector<double> kseedsb(0);vector<double> kseedsx(0);vector<double> kseedsy(0);//--------------------------------------------------m_width  = width;m_height = height;int sz = m_width*m_height;//--------------------------------------------------//if(0 == klabels) klabels = new int[sz];for( int s = 0; s < sz; s++ ) klabels[s] = -1;//--------------------------------------------------if(1)//LAB{DoRGBtoLABConversion(ubuff, m_lvec, m_avec, m_bvec); //RGB->LAB}else//RGB{m_lvec = new double[sz]; m_avec = new double[sz]; m_bvec = new double[sz];for( int i = 0; i < sz; i++ ){m_lvec[i] = ubuff[i] >> 16 & 0xff;m_avec[i] = ubuff[i] >>  8 & 0xff;m_bvec[i] = ubuff[i]       & 0xff;}}//--------------------------------------------------bool perturbseeds(true);vector<double> edgemag(0);if(perturbseeds) DetectLabEdges(m_lvec, m_avec, m_bvec, m_width, m_height, edgemag);//计算每个点的像素梯度GetLABXYSeeds_ForGivenK(kseedsl, kseedsa, kseedsb, kseedsx, kseedsy, K, perturbseeds, edgemag);//移动聚类中心到 3*3 领域中梯度最小的位置int STEP = sqrt(double(sz)/double(K)) + 2.0;//adding a small value in the even the STEP size is too small.PerformSuperpixelSegmentation_VariableSandM(kseedsl,kseedsa,kseedsb,kseedsx,kseedsy,klabels,STEP,10);//分类numlabels = kseedsl.size();int* nlabels = new int[sz];EnforceLabelConnectivity(klabels, m_width, m_height, nlabels, numlabels, K);{for(int i = 0; i < sz; i++ ) klabels[i] = nlabels[i];}if(nlabels) delete [] nlabels;
}//===========================================================================
/// Load PPM file
///
///
//===========================================================================
void LoadPPM(char* filename, unsigned int** data, int* width, int* height)
{char header[1024];FILE* fp = NULL;int line = 0;fp = fopen(filename, "rb");// read the image type, such as: P6// skip the comment lineswhile (line < 2) {    fgets(header, 1024, fp);if (header[0] != '#') {++line;}}// read width and heightsscanf(header,"%d %d\n", width, height);// read the maximum of pixelsfgets(header, 20, fp);// get rgb dataunsigned char *rgb = new unsigned char [ (*width)*(*height)*3 ];fread(rgb, (*width)*(*height)*3, 1, fp);*data = new unsigned int [ (*width)*(*height)*4 ];int k = 0;for ( int i = 0; i < (*height); i++ ) {for ( int j = 0; j < (*width); j++ ) {unsigned char *p = rgb + i*(*width)*3 + j*3;// a ( skipped )(*data)[k]  = p[2] << 16; // r(*data)[k] |= p[1] << 8;  // g(*data)[k] |= p[0];       // bk++;}}// ofc, later, you'll have to cleanupdelete [] rgb;fclose(fp);
}//===========================================================================
/// Load PPM file
///
///
//===========================================================================
int CheckLabelswithPPM(char* filename, int* labels, int width, int height)
{char header[1024];FILE* fp = NULL;int line = 0, ground = 0;fp = fopen(filename, "rb");// read the image type, such as: P6// skip the comment lineswhile (line < 2) {    fgets(header, 1024, fp);if (header[0] != '#') {++line;}}// read width and heightint w(0);int h(0);sscanf(header,"%d %d\n", &w, &h);if (w != width || h != height) return -1;// read the maximum of pixelsfgets(header, 20, fp);// get rgb dataunsigned char *rgb = new unsigned char [ (w)*(h)*3 ];fread(rgb, (w)*(h)*3, 1, fp);int num = 0, k = 0;for ( int i = 0; i < (h); i++ ) {for ( int j = 0; j < (w); j++ ) {unsigned char *p = rgb + i*(w)*3 + j*3;// a ( skipped )ground  = p[2] << 16; // rground |= p[1] << 8;  // gground |= p[0];       // bif (ground != labels[k])num++;k++;}}// ofc, later, you'll have to cleanupdelete [] rgb;fclose(fp);return num;
}//===========================================================================
/// The main function
///
//===========================================================================
int main (int argc, char **argv)
{unsigned int* img = NULL;int width(0);int height(0);LoadPPM((char *)"../input_image.ppm", &img, &width, &height);if (width == 0 || height == 0) return -1;
//    cout << "sss" << endl;int sz = width*height;int* labels = new int[sz];int numlabels(0);SLIC slic;int m_spcount;double m_compactness;m_spcount = 200;m_compactness = 10.0;auto startTime = Clock::now();slic.PerformSLICO_ForGivenK(img, width, height, labels, numlabels, m_spcount, m_compactness);//for a given number K of superpixelsauto endTime = Clock::now();auto compTime = chrono::duration_cast<chrono::microseconds>(endTime - startTime);cout <<  "Computing time=" << compTime.count()/1000 << " ms" << endl;int num = CheckLabelswithPPM((char *)"../check.ppm", labels, width, height);if (num < 0) {cout <<  "The result for labels is different from output_labels.ppm." << endl;} else {cout <<  "There are " << num << " points' labels are different from original file." << endl;}slic.SaveSuperpixelLabels2PPM((char *)"../output_labels.ppm", labels, width, height);if(labels) delete [] labels;if(img) delete [] img;return 0;
}

SLIC.h

// SLIC.h: interface for the SLIC class.
//===========================================================================
// This code implements the zero parameter superpixel segmentation technique
// described in:
//
//
//
// "SLIC Superpixels Compared to State-of-the-art Superpixel Methods"
//
// Radhakrishna Achanta, Appu Shaji, Kevin Smith, Aurelien Lucchi, Pascal Fua,
// and Sabine Susstrunk,
//
// IEEE TPAMI, Volume 34, Issue 11, Pages 2274-2282, November 2012.
//
//
//===========================================================================
// Copyright (c) 2013 Radhakrishna Achanta.
//
// For commercial use please contact the author:
//
// Email: firstname.lastname@epfl.ch
//===========================================================================#if !defined(_SLIC_H_INCLUDED_)
#define _SLIC_H_INCLUDED_#include <vector>
#include <string>
#include <algorithm>
using namespace std;class SLIC
{
public:SLIC();virtual ~SLIC();//============================================================================// Superpixel segmentation for a given number of superpixels//============================================================================void PerformSLICO_ForGivenK(const unsigned int*           ubuff,//Each 32 bit unsigned int contains ARGB pixel values.const int                   width,const int                 height,int*                     klabels,int&                        numlabels,const int&                    K,const double&             m);//============================================================================// Save superpixel labels to pgm in raster scan order//============================================================================void SaveSuperpixelLabels2PPM(char*                       filename, int *                       labels, const int                   width, const int                   height);private://============================================================================// Magic SLIC. No need to set M (compactness factor) and S (step size).// SLICO (SLIC Zero) varies only M dynamicaly, not S.//============================================================================void PerformSuperpixelSegmentation_VariableSandM(vector<double>&               kseedsl,vector<double>&               kseedsa,vector<double>&               kseedsb,vector<double>&               kseedsx,vector<double>&               kseedsy,int*                        klabels,const int&                  STEP,const int&                 NUMITR);//============================================================================// Pick seeds for superpixels when number of superpixels is input.//============================================================================void GetLABXYSeeds_ForGivenK(vector<double>&                kseedsl,vector<double>&               kseedsa,vector<double>&               kseedsb,vector<double>&               kseedsx,vector<double>&               kseedsy,const int&                  STEP,const bool&                    perturbseeds,const vector<double>&        edges);//============================================================================// Move the seeds to low gradient positions to avoid putting seeds at region boundaries.//============================================================================void PerturbSeeds(vector<double>&              kseedsl,vector<double>&               kseedsa,vector<double>&               kseedsb,vector<double>&               kseedsx,vector<double>&               kseedsy,const vector<double>&     edges);//============================================================================// Detect color edges, to help PerturbSeeds()//============================================================================void DetectLabEdges(const double*               lvec,const double*              avec,const double*              bvec,const int&                 width,const int&                    height,vector<double>&                edges);//============================================================================// xRGB to XYZ conversion; helper for RGB2LAB()//============================================================================void RGB2XYZ(const int&                   sR,const int&                   sG,const int&                   sB,double&                      X,double&                       Y,double&                       Z);//============================================================================// sRGB to CIELAB conversion//============================================================================void RGB2LAB(const int&                  sR,const int&                   sG,const int&                   sB,double&                      lval,double&                        aval,double&                        bval);//============================================================================// sRGB to CIELAB conversion for 2-D images//============================================================================void DoRGBtoLABConversion(const unsigned int*&     ubuff,double*&                  lvec,double*&                   avec,double*&                   bvec);//============================================================================// Post-processing of SLIC segmentation, to avoid stray labels.//============================================================================void EnforceLabelConnectivity(const int*                   labels,const int&                   width,const int&                    height,int*                     nlabels,//input labels that need to be corrected to remove stray labelsint&                     numlabels,//the number of labels changes in the end if segments are removedconst int&                   K); //the number of superpixels desired by the userprivate:int                                      m_width;int                                     m_height;int                                        m_depth;double*                                 m_lvec;double*                                  m_avec;double*                                  m_bvec;double**                             m_lvecvec;double**                              m_avecvec;double**                              m_bvecvec;
};#endif // !defined(_SLIC_H_INCLUDED_)

运行结果:

并行计算 SLIC超像素算法(二) 代码分析相关推荐

  1. SLIC与目前最优超像素算法的比较

    SLIC与目前最优超像素算法的比较 Radhakrishna Achanta, Appu Shaji, Kevin Smith, Aurelien Lucchi, Pascal Fua, and Sa ...

  2. SLIC与目前最优超像素算法的比较 SLIC Superpixels Compared to State-of-the-art Superpixel Methods

    SLIC与目前最优超像素算法的比较 Radhakrishna Achanta, Appu Shaji, Kevin Smith, Aurelien Lucchi, Pascal Fua, and Sa ...

  3. 【youcans 的 OpenCV 例程200篇】172.SLIC 超像素区域分割算法比较

    OpenCV 例程200篇 总目录-202205更新 [youcans 的 OpenCV 例程200篇]172.SLIC 超像素区域分割算法比较 5. 区域分割之聚类方法 5.3 SLIC 超像素区域 ...

  4. SLIC超像素分割方法

    为了方便查找,记录SLIC超像素分割方法的介绍 简介 关键代码分析 应用

  5. 图像分割:Python的SLIC超像素分割

    图像分割:Python的SLIC超像素分割 1. 什么是超像素? 2. 为什么超像素在计算机视觉方面有重要的作用? 3. 简单线性迭代聚类(SLIC) 4. 效果图 5. 源码 参考 1. 什么是超像 ...

  6. VLFeat SLIC超像素分割(Cpp版)

    这段时间对VLFeat的C接口非常的感兴趣,以前用的都是其Matlab接口,虽然很方便,而且提供的Matlab接口要比C接口功能更强大,但Matlab终归只能用来做一下快速的方法验证,所以想比较完整的 ...

  7. SLIC超像素分割详解

    SLIC超像素分割详解(一) 超像素概念是2003年Xiaofeng Ren提出和发展起来的图像分割技术,是指具有相似纹理.颜色.亮度等特征的相邻像素构成的有一定视觉意义的不规则像素块.它利用像素之间 ...

  8. SLIC超像素分割的算法介绍和源码分析

    前述 最近在看显著性检测,发现很多算法的基础是超像素分割,而正在看的Saliency Optimization from Robust Background Detection算法的预处理是SLIC算 ...

  9. SLIC超像素生成算法

    SLIC算法是simple linear iterative cluster的简称,该算法用来生成超像素(superpixel). 基本思想 算法大致思想是这样的,将图像从RGB颜色空间转换到CIE- ...

  10. SLIC 超像素分割详解(三):应用

    看过上面的介绍后,我们应该思考一下:分割好的超像素有什么用?怎么用?用到哪里? 首先,超像素可以用来做跟踪,可以参考卢湖川课题组发表在IEEE TIP上的<Robust superpixeltr ...

最新文章

  1. 一次失败的尝试:paxosstore示例编译
  2. 【收藏】Vue+elementUI的this.$refs.对象名.方法名的理解
  3. 【计算机就业-后端开发工程师】校招想去互联网公司担任后端开发工程师该怎么准备
  4. 修复IE下列表 li 底部空行Bug
  5. How GPUs Work
  6. linux mint 19新功能,Linux Mint 19.3将在2019年12月正式发布,附新功能简介
  7. 18 Python 模块引入
  8. python中定义字典数据类型使用什么符号_python数据类型之字典类型-dict
  9. 屏幕共享的实现与应用
  10. Redis:列表LPUSH、LPUSHX、RPUSH、RPUSHX、LPOP、RPOP命令介绍
  11. OpenWrt固件实现路由器定时重启方法
  12. 牧码客(卢益贵):专业取名软件——吉名宝
  13. Hadoop HA (四) --------- YARN-HA 配置
  14. android oreo 老机型,Android Oreo 通知新特性,这坑老夫先踩了
  15. JAVA向client打印一行_java8 httpclient NameValuePair转换14行代码一行搞定!
  16. 口碑好的食材配送信息化管理系统怎么样?
  17. 到底是为什么而读书?一名武汉大学毕业生的反思
  18. SUSCTF2022misc——Tanner
  19. FPGA和usb2.0 CY7C68013通信实现bulkloop
  20. 数据分享|R语言主成分PCA、因子分析、聚类对地区经济研究分析重庆市经济指标...

热门文章

  1. 【爬虫学习笔记day51】6.1. scrapy-redis的官方文档源码分析参考:Connection
  2. Windows下XMake编译imgui成功之DX11
  3. 香港房地产业发展历程、现状、问题及对策探究
  4. 计算机管理制度上墙,机房日常管理制度(上墙
  5. 输入电容及DCM-CCM-QR变压器计算
  6. ApacheCN 翻译/校对/笔记整理活动进度公告 2019.9.20
  7. 【应急响应】————7、服务器大量发包
  8. Asp.NET之入门
  9. 巧做“士兵突击”的个性日历
  10. 【HarmonyOS HiSpark IPC DIY Camera试用连载2 】一天内极速完成从开箱编译烧写到跑通hello world