并行计算 SLIC超像素算法(二) 代码分析
这一篇文章主要介绍了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.计算像素点与聚类中心的距离+分类+重新分类聚类中心
大致分析:
距离使用的是欧式距离,总距离 D
由 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超像素算法(二) 代码分析相关推荐
- SLIC与目前最优超像素算法的比较
SLIC与目前最优超像素算法的比较 Radhakrishna Achanta, Appu Shaji, Kevin Smith, Aurelien Lucchi, Pascal Fua, and Sa ...
- SLIC与目前最优超像素算法的比较 SLIC Superpixels Compared to State-of-the-art Superpixel Methods
SLIC与目前最优超像素算法的比较 Radhakrishna Achanta, Appu Shaji, Kevin Smith, Aurelien Lucchi, Pascal Fua, and Sa ...
- 【youcans 的 OpenCV 例程200篇】172.SLIC 超像素区域分割算法比较
OpenCV 例程200篇 总目录-202205更新 [youcans 的 OpenCV 例程200篇]172.SLIC 超像素区域分割算法比较 5. 区域分割之聚类方法 5.3 SLIC 超像素区域 ...
- SLIC超像素分割方法
为了方便查找,记录SLIC超像素分割方法的介绍 简介 关键代码分析 应用
- 图像分割:Python的SLIC超像素分割
图像分割:Python的SLIC超像素分割 1. 什么是超像素? 2. 为什么超像素在计算机视觉方面有重要的作用? 3. 简单线性迭代聚类(SLIC) 4. 效果图 5. 源码 参考 1. 什么是超像 ...
- VLFeat SLIC超像素分割(Cpp版)
这段时间对VLFeat的C接口非常的感兴趣,以前用的都是其Matlab接口,虽然很方便,而且提供的Matlab接口要比C接口功能更强大,但Matlab终归只能用来做一下快速的方法验证,所以想比较完整的 ...
- SLIC超像素分割详解
SLIC超像素分割详解(一) 超像素概念是2003年Xiaofeng Ren提出和发展起来的图像分割技术,是指具有相似纹理.颜色.亮度等特征的相邻像素构成的有一定视觉意义的不规则像素块.它利用像素之间 ...
- SLIC超像素分割的算法介绍和源码分析
前述 最近在看显著性检测,发现很多算法的基础是超像素分割,而正在看的Saliency Optimization from Robust Background Detection算法的预处理是SLIC算 ...
- SLIC超像素生成算法
SLIC算法是simple linear iterative cluster的简称,该算法用来生成超像素(superpixel). 基本思想 算法大致思想是这样的,将图像从RGB颜色空间转换到CIE- ...
- SLIC 超像素分割详解(三):应用
看过上面的介绍后,我们应该思考一下:分割好的超像素有什么用?怎么用?用到哪里? 首先,超像素可以用来做跟踪,可以参考卢湖川课题组发表在IEEE TIP上的<Robust superpixeltr ...
最新文章
- 一次失败的尝试:paxosstore示例编译
- 【收藏】Vue+elementUI的this.$refs.对象名.方法名的理解
- 【计算机就业-后端开发工程师】校招想去互联网公司担任后端开发工程师该怎么准备
- 修复IE下列表 li 底部空行Bug
- How GPUs Work
- linux mint 19新功能,Linux Mint 19.3将在2019年12月正式发布,附新功能简介
- 18 Python 模块引入
- python中定义字典数据类型使用什么符号_python数据类型之字典类型-dict
- 屏幕共享的实现与应用
- Redis:列表LPUSH、LPUSHX、RPUSH、RPUSHX、LPOP、RPOP命令介绍
- OpenWrt固件实现路由器定时重启方法
- 牧码客(卢益贵):专业取名软件——吉名宝
- Hadoop HA (四) --------- YARN-HA 配置
- android oreo 老机型,Android Oreo 通知新特性,这坑老夫先踩了
- JAVA向client打印一行_java8 httpclient NameValuePair转换14行代码一行搞定!
- 口碑好的食材配送信息化管理系统怎么样?
- 到底是为什么而读书?一名武汉大学毕业生的反思
- SUSCTF2022misc——Tanner
- FPGA和usb2.0 CY7C68013通信实现bulkloop
- 数据分享|R语言主成分PCA、因子分析、聚类对地区经济研究分析重庆市经济指标...
热门文章
- 【爬虫学习笔记day51】6.1. scrapy-redis的官方文档源码分析参考:Connection
- Windows下XMake编译imgui成功之DX11
- 香港房地产业发展历程、现状、问题及对策探究
- 计算机管理制度上墙,机房日常管理制度(上墙
- 输入电容及DCM-CCM-QR变压器计算
- ApacheCN 翻译/校对/笔记整理活动进度公告 2019.9.20
- 【应急响应】————7、服务器大量发包
- Asp.NET之入门
- 巧做“士兵突击”的个性日历
- 【HarmonyOS HiSpark IPC DIY Camera试用连载2 】一天内极速完成从开箱编译烧写到跑通hello world