//=========================================================================== /// PerformSupervoxelSLIC /// /// Performs k mean segmentation. It is fast because it searches locally, not /// over the entire image. //=========================================================================== void SLIC::PerformSupervoxelSLIC( vector<double>& kseedsl, vector<double>& kseedsa, vector<double>& kseedsb, vector<double>& kseedsx, vector<double>& kseedsy, vector<double>& kseedsz, int**& klabels, const int& STEP, const double& compactness) { int sz = m_width*m_height; const int numk = kseedsl.size(); //int numitr(0); //---------------- int offset = STEP; //if(STEP < 8) offset = STEP*1.5;//to prevent a crash due to a very small step size //---------------- vector<double> clustersize(numk, 0); vector<double> inv(numk, 0);//to store 1/clustersize[k] values 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<double> sigmaz(numk, 0); vector< double > initdouble(sz, DBL_MAX); vector< vector<double> > distvec(m_depth, initdouble); //vector<double> distvec(sz, DBL_MAX); double invwt = 1.0/((STEP/compactness)*(STEP/compactness));//compactness = 20.0 is usually good. int x1, y1, x2, y2, z1, z2; double l, a, b; double dist; double distxyz; for( int itr = 0; itr < 5; itr++ ) { distvec.assign(m_depth, initdouble); for( int n = 0; n < numk; n++ ) { y1 = max(0.0, kseedsy[n]-offset); y2 = min((double)m_height, kseedsy[n]+offset); x1 = max(0.0, kseedsx[n]-offset); x2 = min((double)m_width, kseedsx[n]+offset); z1 = max(0.0, kseedsz[n]-offset); z2 = min((double)m_depth, kseedsz[n]+offset); for( int z = z1; z < z2; z++ ) { for( int y = y1; y < y2; y++ ) { for( int x = x1; x < x2; x++ ) { int i = y*m_width + x; l = m_lvecvec[z][i]; a = m_avecvec[z][i]; b = m_bvecvec[z][i]; dist = (l - kseedsl[n])*(l - kseedsl[n]) + (a - kseedsa[n])*(a - kseedsa[n]) + (b - kseedsb[n])*(b - kseedsb[n]); distxyz = (x - kseedsx[n])*(x - kseedsx[n]) + (y - kseedsy[n])*(y - kseedsy[n]) + (z - kseedsz[n])*(z - kseedsz[n]); //------------------------------------------------------------------------ dist += distxyz*invwt; //------------------------------------------------------------------------ if( dist < distvec[z][i] ) { distvec[z][i] = dist; klabels[z][i] = n; } } } } } //----------------------------------------------------------------- // Recalculate the centroid and store in the seed values //----------------------------------------------------------------- //instead of reassigning memory on each iteration, just reset. sigmal.assign(numk, 0); sigmaa.assign(numk, 0); sigmab.assign(numk, 0); sigmax.assign(numk, 0); sigmay.assign(numk, 0); sigmaz.assign(numk, 0); clustersize.assign(numk, 0); for( int d = 0; d < m_depth; d++ ) { int ind(0); for( int r = 0; r < m_height; r++ ) { for( int c = 0; c < m_width; c++ ) { sigmal[klabels[d][ind]] += m_lvecvec[d][ind]; sigmaa[klabels[d][ind]] += m_avecvec[d][ind]; sigmab[klabels[d][ind]] += m_bvecvec[d][ind]; sigmax[klabels[d][ind]] += c; sigmay[klabels[d][ind]] += r; sigmaz[klabels[d][ind]] += d; clustersize[klabels[d][ind]] += 1.0; ind++; } } } { for( int k = 0; k < numk; k++ ) { if( clustersize[k] <= 0 ) clustersize[k] = 1; inv[k] = 1.0/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]; kseedsz[k] = sigmaz[k]*inv[k]; } } } }
//=========================================================================== /// 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] values vector<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 10 vector<double> maxxy(numk, STEP*STEP);//THIS IS THE VARIABLE VALUE OF M, just start with 10 double invxywt = 1.0/(STEP*STEP);//NOTE: this is different from how usual SLIC/LKM works while( numitr < NUMITR ) { //------ //cumerr = 0; numitr++; //------ distvec.assign(sz, DBL_MAX); for( int n = 0; n < numk; n++ ) { int y1 = max(0, static_cast<int>(kseedsy[n])-offset); int y2 = min(m_height, static_cast<int>(kseedsy[n])+offset); int x1 = max(0, static_cast<int>(kseedsx[n])-offset); int x2 = min(m_width, static_cast<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]; }} } }
//=========================================================================== /// PerformSuperpixelSLIC /// /// Performs k mean segmentation. It is fast because it looks locally, not /// over the entire image. //=========================================================================== void SLIC::PerformSuperpixelSLIC( vector<double>& kseedsl, vector<double>& kseedsa, vector<double>& kseedsb, vector<double>& kseedsx, vector<double>& kseedsy, int*& klabels, const int& STEP, const vector<double>& edgemag, const double& M) { int sz = m_width*m_height; const int numk = kseedsl.size(); //---------------- int offset = STEP; //if(STEP < 8) offset = STEP*1.5;//to prevent a crash due to a very small step size //---------------- vector<double> clustersize(numk, 0); vector<double> inv(numk, 0);//to store 1/clustersize[k] values 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<double> distvec(sz, DBL_MAX); double invwt = 1.0/((STEP/M)*(STEP/M)); int x1, y1, x2, y2; double l, a, b; double dist; double distxy; for( int itr = 0; itr < 10; itr++ ) { distvec.assign(sz, DBL_MAX); for( int n = 0; n < numk; n++ ) { y1 = max(0.0, kseedsy[n]-offset); y2 = min((double)m_height, kseedsy[n]+offset); x1 = max(0.0, kseedsx[n]-offset); x2 = min((double)m_width, kseedsx[n]+offset); for( int y = y1; y < y2; y++ ) { for( int x = x1; x < x2; x++ ) { int i = y*m_width + x; l = m_lvec[i]; a = m_avec[i]; b = m_bvec[i]; dist = (l - kseedsl[n])*(l - kseedsl[n]) + (a - kseedsa[n])*(a - kseedsa[n]) + (b - kseedsb[n])*(b - kseedsb[n]); distxy = (x - kseedsx[n])*(x - kseedsx[n]) + (y - kseedsy[n])*(y - kseedsy[n]); //------------------------------------------------------------------------ dist += distxy*invwt;//dist = sqrt(dist) + sqrt(distxy*invwt);//this is more exact //------------------------------------------------------------------------ if( dist < distvec[i] ) { distvec[i] = dist; klabels[i] = n; } } } } //----------------------------------------------------------------- // Recalculate the centroid and store in the seed values //----------------------------------------------------------------- //instead of reassigning memory on each iteration, just reset. sigmal.assign(numk, 0); sigmaa.assign(numk, 0); sigmab.assign(numk, 0); sigmax.assign(numk, 0); sigmay.assign(numk, 0); clustersize.assign(numk, 0); //------------------------------------ //edgesum.assign(numk, 0); //------------------------------------ { int ind(0); for( int r = 0; r < m_height; r++ ) { for( int c = 0; c < m_width; c++ ) { sigmal[klabels[ind]] += m_lvec[ind]; sigmaa[klabels[ind]] += m_avec[ind]; sigmab[klabels[ind]] += m_bvec[ind]; sigmax[klabels[ind]] += c; sigmay[klabels[ind]] += r; //------------------------------------ //edgesum[klabels[ind]] += edgemag[ind]; //------------------------------------ clustersize[klabels[ind]] += 1.0; ind++; } } } { for( int k = 0; k < numk; k++ ) { if( clustersize[k] <= 0 ) clustersize[k] = 1; inv[k] = 1.0/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]; //------------------------------------ //edgesum[k] *= inv[k]; //------------------------------------ } } } }
cv::Mat performSuperpixelSegmentation_VariableSandM(std::vector<std::vector<double> > &kseeds, std::vector<double> &kseedsx, std::vector<double> &kseedsy, const std::vector<cv::Mat> &vec, const cv::Size &size, const int &STEP, const int &NUMITR = 10) { int sz = size.width*size.height; const int numk = (int) kseedsx.size(); int numitr = 0; int offset = (STEP < 10) ? STEP*1.5 : STEP; cv::Mat klabels = cv::Mat(size, cv::DataType<int>::type); klabels = -1; std::vector<std::vector<double> > sigmac(0); for (int c = 0; c < vec.size(); c++) { sigmac.push_back(std::vector<double>(numk, 0)); } std::vector<double> sigmax(numk, 0); std::vector<double> sigmay(numk, 0); std::vector<int> clustersize(numk, 0); std::vector<double> inv(numk, 0);//to store 1/clustersize[k] values std::vector<double> distxy(sz, DBL_MAX); std::vector<double> distc(sz, DBL_MAX); std::vector<double> distvec(sz, DBL_MAX); std::vector<double> maxc(numk, 10*10);//THIS IS THE VARIABLE VALUE OF M, just start with 10 std::vector<double> maxxy(numk, STEP*STEP);//THIS IS THE VARIABLE VALUE OF M, just start with 10 double invxywt = 1.0/(STEP*STEP);//NOTE: this is different from how usual SLIC/LKM works while( numitr < NUMITR ) { //------ //cumerr = 0; numitr++; //------ distvec.assign(sz, DBL_MAX); for( int n = 0; n < numk; n++ ) { int y1 = std::max(double(0), kseedsy[n]-offset); int y2 = std::min(double(size.height), kseedsy[n]+offset); int x1 = std::max(double(0), kseedsx[n]-offset); int x2 = std::min(double(size.width), kseedsx[n]+offset); for( int y = y1; y < y2; y++ ) { for( int x = x1; x < x2; x++ ) { int i = y*size.width + x; if( !(y < size.height && x < size.width && y >= 0 && x >= 0) ) { throw cv::Exception(); } distc[i] = 0; for (int c = 0; c < vec.size(); c++) { distc[i] += (vec[c].ptr<double>()[i] - kseeds[c][n]) * (vec[c].ptr<double>()[i] - kseeds[c][n]); } distxy[i] = (x - kseedsx[n])*(x - kseedsx[n]) + (y - kseedsy[n])*(y - kseedsy[n]); double dist = distc[i]/maxc[n] + distxy[i]*invxywt;//only varying m, prettier superpixels if( dist < distvec[i] ) { distvec[i] = dist; klabels.ptr<int>()[i] = n; } } } } //----------------------------------------------------------------- // Assign the max color distance for a cluster //----------------------------------------------------------------- if(0 == numitr) { maxc.assign(numk,1); maxxy.assign(numk,1); } {for( int i = 0; i < sz; i++ ) { if(maxc[klabels.ptr<int>()[i]] < distc[i]) maxc[klabels.ptr<int>()[i]] = distc[i]; if(maxxy[klabels.ptr<int>()[i]] < distxy[i]) maxxy[klabels.ptr<int>()[i]] = distxy[i]; }} //----------------------------------------------------------------- // Recalculate the centroid and store in the seed values //----------------------------------------------------------------- for (int c = 0; c < sigmac.size(); c++) { sigmac[c].assign(numk, 0); } sigmax.assign(numk, 0); sigmay.assign(numk, 0); clustersize.assign(numk, 0); for( int j = 0; j < sz; j++ ) { if(!(klabels.ptr<int>()[j] >= 0)) throw cv::Exception(); for (int c = 0; c < sigmac.size(); c++) { sigmac[c][klabels.ptr<int>()[j]] += vec[c].ptr<double>()[j]; } sigmax[klabels.ptr<int>()[j]] += (j%size.width); sigmay[klabels.ptr<int>()[j]] += (j/size.width); clustersize[klabels.ptr<int>()[j]]++; } {for( int k = 0; k < numk; k++ ) { 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++ ) { for (int c = 0; c < kseeds.size(); c++) { kseeds[c][k] = sigmac[c][k] * inv[k]; } kseedsx[k] = sigmax[k]*inv[k]; kseedsy[k] = sigmay[k]*inv[k]; }} } return klabels; }