diff --git a/modules/ximgproc/doc/pics/superpixels_slic.png b/modules/ximgproc/doc/pics/superpixels_slic.png index 7718c5d26..5c5f39ed6 100644 Binary files a/modules/ximgproc/doc/pics/superpixels_slic.png and b/modules/ximgproc/doc/pics/superpixels_slic.png differ diff --git a/modules/ximgproc/doc/ximgproc.bib b/modules/ximgproc/doc/ximgproc.bib index 08bcbc48d..32ff35604 100644 --- a/modules/ximgproc/doc/ximgproc.bib +++ b/modules/ximgproc/doc/ximgproc.bib @@ -160,6 +160,14 @@ keywords = {Superpixels, segmentation, clustering, k-means} } +@InProceedings{Liu_2016_CVPR, + author = {Liu, Yong-Jin and Yu, Cheng-Chi and Yu, Min-Jing and He, Ying}, + title = {Manifold SLIC: A Fast Method to Compute Content-Sensitive Superpixels}, + booktitle = {The IEEE Conference on Computer Vision and Pattern Recognition (CVPR)}, + month = {June}, + year = {2016} +} + @InProceedings{LiCVPR2015LSC, author = {Li, Zhengqin and Chen, Jiansheng}, title = {Superpixel Segmentation Using Linear Spectral Clustering}, diff --git a/modules/ximgproc/include/opencv2/ximgproc/slic.hpp b/modules/ximgproc/include/opencv2/ximgproc/slic.hpp index 64fc45ce8..8b99a658b 100644 --- a/modules/ximgproc/include/opencv2/ximgproc/slic.hpp +++ b/modules/ximgproc/include/opencv2/ximgproc/slic.hpp @@ -61,6 +61,8 @@ namespace ximgproc //! @addtogroup ximgproc_superpixel //! @{ + enum SLIC { SLIC = 100, SLICO = 101, MSLIC = 102 }; + /** @brief Class implementing the SLIC (Simple Linear Iterative Clustering) superpixels algorithm described in @cite Achanta2012. @@ -68,7 +70,9 @@ SLIC (Simple Linear Iterative Clustering) clusters pixels using pixel channels a to efficiently generate compact, nearly uniform superpixels. The simplicity of approach makes it extremely easy to use a lone parameter specifies the number of superpixels and the efficiency of the algorithm makes it very practical. - +Several optimizations are available for SLIC class: +SLICO stands for "Zero parameter SLIC" and it is an optimization of baseline SLIC descibed in @cite Achanta2012. +MSLIC stands for "Manifold SLIC" and it is an optimization of baseline SLIC described in @cite Liu_2016_CVPR. */ class CV_EXPORTS_W SuperpixelSLIC : public Algorithm @@ -134,26 +138,25 @@ public: }; -/** @brief Class implementing the SLIC (Simple Linear Iterative Clustering) superpixels +/** @brief Initialize a SuperpixelSLIC object @param image Image to segment @param algorithm Chooses the algorithm variant to use: -SLIC segments image using a desired region_size, and in addition -SLICO will choose an adaptive compactness factor. +SLIC segments image using a desired region_size, and in addition SLICO will optimize using adaptive compactness factor, +while MSLIC will optimize using manifold methods resulting in more content-sensitive superpixels. @param region_size Chooses an average superpixel size measured in pixels @param ruler Chooses the enforcement of superpixel smoothness factor of superpixel The function initializes a SuperpixelSLIC object for the input image. It sets the parameters of choosed superpixel algorithm, which are: region_size and ruler. It preallocate some buffers for future -computing iterations over the given image. An example of SLIC versus SLICO is ilustrated in the -following picture. +computing iterations over the given image. For enanched results it is recommended for color images to +preprocess image with little gaussian blur using a small 3 x 3 kernel and additional conversion into +CieLAB color space. An example of SLIC versus SLICO and MSLIC is ilustrated in the following picture. ![image](pics/superpixels_slic.png) */ - enum SLIC { SLIC = 100, SLICO = 101 }; - CV_EXPORTS_W Ptr createSuperpixelSLIC( InputArray image, int algorithm = SLICO, int region_size = 10, float ruler = 10.0f ); diff --git a/modules/ximgproc/samples/slic.cpp b/modules/ximgproc/samples/slic.cpp index 637cbf2c3..c49d9ce06 100644 --- a/modules/ximgproc/samples/slic.cpp +++ b/modules/ximgproc/samples/slic.cpp @@ -19,7 +19,7 @@ static const char* keys = "{h help | | help menu}" "{c camera |0| camera id}" "{i image | | image file}" - "{a algorithm |1| SLIC(0),SLICO(1)}" + "{a algorithm |1| SLIC(0),SLICO(1),MSLIC(2)}" ; int main(int argc, char** argv) @@ -63,7 +63,7 @@ int main(int argc, char** argv) } namedWindow(window_name, 0); - createTrackbar("Algorithm", window_name, &algorithm, 1, 0); + createTrackbar("Algorithm", window_name, &algorithm, 2, 0); createTrackbar("Region size", window_name, ®ion_size, 200, 0); createTrackbar("Ruler", window_name, &ruler, 100, 0); createTrackbar("Connectivity", window_name, &min_element_size, 100, 0); diff --git a/modules/ximgproc/src/slic.cpp b/modules/ximgproc/src/slic.cpp index 0782c7e98..63f25044d 100644 --- a/modules/ximgproc/src/slic.cpp +++ b/modules/ximgproc/src/slic.cpp @@ -1,11 +1,16 @@ /********************************************************************* * Software License Agreement (BSD License) * - * Copyright (c) 2013 + * SLIC, SLICO Copyright (c) 2013 * Radhakrishna Achanta * email : Radhakrishna [dot] Achanta [at] epfl [dot] ch * web : http://ivrl.epfl.ch/people/achanta * + * MSLIC Copyright (c) 2016 + * Yong-Jin Liu + * email : liuyongjin [at] tsinghua [dot] edu [dot] cn + * web : http://cg.cs.tsinghua.edu.cn/people/~Yongjin/yongjin.htm + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -44,6 +49,11 @@ Aurelien Lucchi, Pascal Fua, and Sabine Süsstrunk, EPFL Technical Report no. 149300, June 2010. + "Manifold SLIC: A Fast Method to Compute Content-Sensitive Superpixels" + Yong-Jin Liu, Cheng-Chi Yu, Min-Jing Yu, Ying He, + The IEEE Conference on Computer Vision and Pattern Recognition (CVPR), + 2016, pp. 651-659. + OpenCV port by: Cristian Balint */ @@ -99,6 +109,19 @@ protected: // compactness float m_ruler; + // ratio (MSLIC) + float m_ratio; + + // split (MSLIC) + float m_split; + + // current iter + int m_cur_iter; + + // current iter + int m_iterations; + + private: // labels no @@ -120,6 +143,12 @@ private: // seeds storage vector< vector > m_kseeds; + // adaptive k (MSLIC) + vector m_adaptk; + + // merge threshold (MSLIC) + float m_merge; + // initialization inline void initialize(); @@ -140,6 +169,13 @@ private: // SLICO inline void PerformSLICO( const int& num_iterations ); + + // MSLIC + inline void PerformMSLIC( const int& num_iterations ); + + // MSLIC + inline void SuperpixelSplit(); + }; CV_EXPORTS Ptr createSuperpixelSLIC( InputArray image, int algorithm, int region_size, float ruler ) @@ -221,7 +257,8 @@ void SuperpixelSLICImpl::initialize() if( m_algorithm == SLICO ) GetChSeedsK(); - else if( m_algorithm == SLIC ) + else if( ( m_algorithm == SLIC ) || + ( m_algorithm == MSLIC ) ) GetChSeedsS(); else CV_Error( Error::StsInternal, "No such algorithm" ); @@ -232,6 +269,11 @@ void SuperpixelSLICImpl::initialize() // perturb seeds given edges if ( perturbseeds ) PerturbSeeds( edgemag ); + if( m_algorithm == MSLIC ) + { + m_merge = 4.0f; + m_adaptk.resize( m_numlabels, 1.0f ); + } } void SuperpixelSLICImpl::iterate( int num_iterations ) @@ -240,6 +282,8 @@ void SuperpixelSLICImpl::iterate( int num_iterations ) PerformSLICO( num_iterations ); else if( m_algorithm == SLIC ) PerformSLIC( num_iterations ); + else if( m_algorithm == MSLIC ) + PerformMSLIC( num_iterations ); else CV_Error( Error::StsInternal, "No such algorithm" ); @@ -316,6 +360,13 @@ void SuperpixelSLICImpl::enforceLabelConnectivity( int min_element_size ) if ( min_element_size == 0 ) return; CV_Assert( min_element_size >= 0 && min_element_size <= 100 ); + vector adaptk( m_numlabels, 1.0f ); + + if( m_algorithm == MSLIC ) + { + adaptk.clear(); + } + const int dx4[4] = { -1, 0, 1, 0 }; const int dy4[4] = { 0, -1, 0, 1 }; @@ -331,6 +382,20 @@ void SuperpixelSLICImpl::enforceLabelConnectivity( int min_element_size ) vector xvec(sz); vector yvec(sz); + // MSLIC + int currentlabel; + float diffch = 0.0f; + vector adjch; + vector curch; + map hashtable; + + if( m_algorithm == MSLIC ) + { + hashtable[-1] = 0; + adjch.resize( m_nr_channels, 0 ); + curch.resize( m_nr_channels, 0 ); + } + //adjacent label int adjlabel = 0; @@ -346,6 +411,7 @@ void SuperpixelSLICImpl::enforceLabelConnectivity( int min_element_size ) //-------------------- xvec[0] = k; yvec[0] = j; + currentlabel = m_klabels.at(j,k); //------------------------------------------------------- // Quickly find an adjacent label for use later if needed //------------------------------------------------------- @@ -355,11 +421,35 @@ void SuperpixelSLICImpl::enforceLabelConnectivity( int min_element_size ) int y = yvec[0] + dy4[n]; if( (x >= 0 && x < m_width) && (y >= 0 && y < m_height) ) { - if(nlabels.at(y,x) != INT_MAX) - adjlabel = nlabels.at(y,x); + if( nlabels.at(y,x) != INT_MAX ) + { + adjlabel = nlabels.at(y,x); + if( m_algorithm == MSLIC ) + { + for( int b = 0; b < m_nr_channels; b++ ) + { + adjch[b] = m_kseeds[b][m_klabels.at(y,x)]; + } + } + } } } + if( m_algorithm == MSLIC ) + { + float ssumch = 0.0f; + for( int b = 0; b < m_nr_channels; b++ ) + { + curch[b] = m_kseeds[b][m_klabels.at(j,k)]; + // squared distance + float diff = curch[b] - adjch[b]; + ssumch += diff * diff; + } + // L2 distance with adj + diffch = sqrt( ssumch ); + adaptk.push_back( m_adaptk[currentlabel] ); + } + int count(1); for( int c = 0; c < count; c++ ) { @@ -379,20 +469,74 @@ void SuperpixelSLICImpl::enforceLabelConnectivity( int min_element_size ) count++; } } - } } - //------------------------------------------------------- - // If segment size is less then a limit, assign an - // adjacent label found before, and decrement label count. - //------------------------------------------------------- - if(count <= min_sp_sz) + // MSLIC only + if( m_algorithm == MSLIC ) { - for( int c = 0; c < count; c++ ) - { - nlabels.at(yvec[c],xvec[c]) = adjlabel; - } - label--; + if ( m_cur_iter < m_iterations - 1 ) + { + hashtable[label] = count; + //------------------------------------------------------- + // If segment size is less then a limit, or is very similar + // to it's neighbour assign adjacent label found before, + // and decrement label count. + //------------------------------------------------------- + if( ( count <= min_sp_sz ) || + ( + ( diffch < m_merge ) && + ( hashtable[adjlabel] + hashtable[(int)adaptk.size()-1] + <= 3 * m_region_size * m_region_size ) + ) + ) + { + if( ( diffch < m_merge) && + ( hashtable[adjlabel] + hashtable[(int)adaptk.size()-1] + <= 3 * m_region_size * m_region_size ) + ) + { + adaptk[adjlabel] = min( 2.0f, float(adaptk[adjlabel] + adaptk[(int)adaptk.size()-1]) ); + hashtable[adjlabel] += hashtable[(int)adaptk.size()-1]; + } + + for( int c = 0; c < count; c++ ) + { + nlabels.at(yvec[c],xvec[c]) = adjlabel; + } + + label--; + adaptk.pop_back(); + } + } else + { + //------------------------------------------------------- + // If segment size is less then a limit, assign an + // adjacent label found before, and decrement label count. + //------------------------------------------------------- + if( count <= min_sp_sz ) + { + for( int c = 0; c < count; c++ ) + { + nlabels.at(yvec[c],xvec[c]) = adjlabel; + } + label--; + } + } + // SLIC or SLICO + } else + { + //------------------------------------------------------- + // If segment size is less then a limit, assign an + // adjacent label found before, and decrement label count. + //------------------------------------------------------- + if( count <= min_sp_sz ) + { + for( int c = 0; c < count; c++ ) + { + nlabels.at(yvec[c],xvec[c]) = adjlabel; + } + label--; + } } label++; } @@ -401,6 +545,9 @@ void SuperpixelSLICImpl::enforceLabelConnectivity( int min_element_size ) // replace old m_klabels = nlabels; m_numlabels = label; + + m_adaptk.clear(); + m_adaptk = adaptk; } /* @@ -696,7 +843,7 @@ struct SeedNormInvoker : ParallelLoopBody if( clustersize->at(k) <= 0 ) clustersize->at(k) = 1; for ( int b = 0; b < nr_channels; b++ ) - kseeds->at(b)[k] = sigma->at(b)[k] / float(clustersize->at(k));; + kseeds->at(b)[k] = sigma->at(b)[k] / float(clustersize->at(k)); kseedsx->at(k) = sigmax->at(k) / float(clustersize->at(k)); kseedsy->at(k) = sigmay->at(k) / float(clustersize->at(k)); @@ -1214,5 +1361,420 @@ inline void SuperpixelSLICImpl::PerformSLIC( const int& itrnum ) } } +/* + * PerformSuperpixelMSLIC + * + * + */ +inline void SuperpixelSLICImpl::PerformMSLIC( const int& itrnum ) +{ + vector< vector > sigma(m_nr_channels); + for( int b = 0; b < m_nr_channels; b++ ) + sigma[b].resize(m_numlabels, 0); + + vector sigmax(m_numlabels, 0); + vector sigmay(m_numlabels, 0); + vector clustersize(m_numlabels, 0); + + Mat distvec( m_height, m_width, CV_32F ); + + const float xywt = (m_region_size/m_ruler)*(m_region_size/m_ruler); + + int offset = m_region_size; + + // from paper + m_split = 4.0f; + m_ratio = 5.0f; + + for( int itr = 0; itr < itrnum; itr++ ) + { + m_cur_iter = itr; + + distvec.setTo(FLT_MAX); + for( int n = 0; n < m_numlabels; n++ ) + { + if ( m_adaptk[n] < 1.0f ) + offset = int(m_region_size * m_adaptk[n]); + else + offset = int(m_region_size * m_adaptk[n]); + + int y1 = max(0, (int) m_kseedsy[n] - offset); + int y2 = min(m_height, (int) m_kseedsy[n] + offset); + int x1 = max(0, (int) m_kseedsx[n] - offset); + int x2 = min(m_width, (int) m_kseedsx[n] + offset); + + parallel_for_( Range(y1, y2), SLICGrowInvoker( &m_chvec, &distvec, + &m_klabels, m_kseedsx[n], m_kseedsy[n], xywt, &m_kseeds, + x1, x2, m_nr_channels, n ) ); + } + + //----------------------------------------------------------------- + // Recalculate the centroid and store in the seed values + //----------------------------------------------------------------- + // instead of reassigning memory on each iteration, just reset. + + // parallel reduce structure + SeedsCenters sc( m_chvec, m_klabels, m_numlabels, m_nr_channels ); + + // accumulate center distances + parallel_reduce( BlockedRange(0, m_width), sc ); + + // normalize centers + parallel_for_( Range(0, m_numlabels), SeedNormInvoker( &m_kseeds, &sc.sigma, + &sc.clustersize, &sc.sigmax, &sc.sigmay, &m_kseedsx, &m_kseedsy, m_nr_channels ) ); + + // 13% as in original paper + enforceLabelConnectivity( 13 ); + SuperpixelSplit(); + } +} + +inline void SuperpixelSLICImpl::SuperpixelSplit() +{ + Mat klabels = m_klabels.clone(); + + // parallel reduce structure + SeedsCenters msc( m_chvec, m_klabels, m_numlabels, m_nr_channels ); + + // accumulate center distances + parallel_reduce( BlockedRange(0, m_width), msc ); + + const float invwt = 1.0f / ( (m_region_size/m_ruler)*(m_region_size/m_ruler) ); + const float sqrt_invwt = sqrt(invwt); + + if ( m_cur_iter < m_iterations - 2 ) + { + vector avglabs( m_numlabels, 0 ); + for( int y = 0; y < m_height - 1; y++ ) + { + for( int x = 0; x < m_width - 1; x++ ) + { + if ( klabels.at( y, x ) == klabels.at( y+1, x ) && + klabels.at( y, x ) == klabels.at( y, x+1 ) ) + { + float x1 = 1, y1 = 0; + float x2 = 0, y2 = 1; + + vector ch1(m_nr_channels); + vector ch2(m_nr_channels); + + switch ( m_chvec.at(0).depth() ) + { + case CV_8U: + for( int c = 0; c < m_nr_channels; c++ ) + { + ch1[c] = float( m_chvec[c].at( y+1, x ) + - m_chvec[c].at( y, x ) ); + ch2[c] = float( m_chvec[c].at( y, x+1 ) + - m_chvec[c].at( y, x ) ); + + ch1[c] /= sqrt_invwt; + ch2[c] /= sqrt_invwt; + } + break; + + case CV_8S: + for( int c = 0; c < m_nr_channels; c++ ) + { + ch1[c] = float( m_chvec[c].at( y+1, x ) + - m_chvec[c].at( y, x ) ); + ch2[c] = float( m_chvec[c].at( y, x+1 ) + - m_chvec[c].at( y, x ) ); + + ch1[c] /= sqrt_invwt; + ch2[c] /= sqrt_invwt; + } + break; + + case CV_16U: + for( int c = 0; c < m_nr_channels; c++ ) + { + ch1[c] = float( m_chvec[c].at( y+1, x ) + - m_chvec[c].at( y, x ) ); + ch2[c] = float( m_chvec[c].at( y, x+1 ) + - m_chvec[c].at( y, x ) ); + + ch1[c] /= sqrt_invwt; + ch2[c] /= sqrt_invwt; + } + break; + + case CV_16S: + for( int c = 0; c < m_nr_channels; c++ ) + { + ch1[c] = float( m_chvec[c].at( y+1, x ) + - m_chvec[c].at( y, x ) ); + ch2[c] = float( m_chvec[c].at( y, x+1 ) + - m_chvec[c].at( y, x ) ); + + ch1[c] /= sqrt_invwt; + ch2[c] /= sqrt_invwt; + } + break; + + case CV_32S: + for( int c = 0; c < m_nr_channels; c++ ) + { + ch1[c] = float( m_chvec[c].at( y+1, x ) + - m_chvec[c].at( y, x ) ); + ch2[c] = float( m_chvec[c].at( y, x+1 ) + - m_chvec[c].at( y, x ) ); + + ch1[c] /= sqrt_invwt; + ch2[c] /= sqrt_invwt; + } + break; + + case CV_32F: + for( int c = 0; c < m_nr_channels; c++ ) + { + ch1[c] = m_chvec[c].at( y+1, x ) + - m_chvec[c].at( y, x ); + ch2[c] = m_chvec[c].at( y, x+1 ) + - m_chvec[c].at( y, x ); + + ch1[c] /= sqrt_invwt; + ch2[c] /= sqrt_invwt; + } + break; + + case CV_64F: + for( int c = 0; c < m_nr_channels; c++ ) + { + ch1[c] = float( m_chvec[c].at( y+1, x ) + - m_chvec[c].at( y, x ) ); + ch2[c] = float( m_chvec[c].at( y, x+1 ) + - m_chvec[c].at( y, x ) ); + + ch1[c] /= sqrt_invwt; + ch2[c] /= sqrt_invwt; + } + break; + + default: + CV_Error( Error::StsInternal, "Invalid matrix depth" ); + break; + } + float ch11sqsum = 0.0f; + float ch12sqsum = 0.0f; + float ch22sqsum = 0.0f; + for( int c = 0; c < m_nr_channels; c++ ) + { + ch11sqsum += ch1[c]*ch1[c]; + ch12sqsum += ch1[c]*ch2[c]; + ch22sqsum += ch2[c]*ch2[c]; + } + + // adjacent metric for N channels + avglabs[ klabels.at(y,x) ] + += sqrt( (x1*x1 + y1*y1 + ch11sqsum) * (x2*x2 + y2*y2 + ch22sqsum) + - (x1*x2 + y1*y2 + ch12sqsum) * (x1*x2 + y1*y2 + ch12sqsum) ); + } + } + } + for ( int i = 0; i < m_numlabels; i++ ) + { + avglabs[i] /= m_region_size * m_region_size; + } + + m_kseedsx.clear(); + m_kseedsy.clear(); + m_kseedsx.resize( m_numlabels, 0 ); + m_kseedsy.resize( m_numlabels, 0 ); + for( int c = 0; c < m_nr_channels; c++ ) + { + m_kseeds[c].clear(); + m_kseeds[c].resize( m_numlabels, 0 ); + } + + for( int k = 0; k < m_numlabels; k++ ) + { + m_kseedsx[k] = msc.sigmax[k] / msc.clustersize[k]; + m_kseedsy[k] = msc.sigmay[k] / msc.clustersize[k]; + for( int c = 0; c < m_nr_channels; c++ ) + m_kseeds[c][k] = msc.sigma[c][k] / msc.clustersize[k]; + } + + for( int k = 0; k < m_numlabels; k++ ) + { + int xindex = 0, yindex = 0; + if ( ( m_adaptk[k] <= 0.5f ) || + ( avglabs[k] < (m_split * m_ratio) ) ) + { + m_kseedsx[k] = msc.sigmax[k] / msc.clustersize[k]; + m_kseedsy[k] = msc.sigmay[k] / msc.clustersize[k]; + for( int c = 0; c < m_nr_channels; c++ ) + m_kseeds[c][k] = msc.sigma[c][k] / msc.clustersize[k]; + + m_adaptk[k] = sqrt( m_ratio / avglabs[k] ); + m_adaptk[k] = max( 0.5f, m_adaptk[k] ); + m_adaptk[k] = min( 2.0f, m_adaptk[k] ); + } + // if segment size is too large + // split it and calculate four new seeds + else + { + xindex = (int)( msc.sigmax[k] / msc.clustersize[k] ); + yindex = (int)( msc.sigmay[k] / msc.clustersize[k] ); + m_adaptk[k] = max( 0.5f, m_adaptk[k] / 2 ); + + const float minadaptk = min( 1.0f, m_adaptk[k] ) * m_region_size / 2; + + int x1 = (int)( xindex - minadaptk ); + int x2 = (int)( xindex + minadaptk ); + int x3 = (int)( xindex - minadaptk ); + int x4 = (int)( xindex + minadaptk ); + + int y1 = (int)( yindex + minadaptk ); + int y2 = (int)( yindex + minadaptk ); + int y3 = (int)( yindex - minadaptk ); + int y4 = (int)( yindex - minadaptk ); + + if ( x1 < 0 ) x1 = 0; + if ( x2 >= m_width ) x2 = m_width - 1; + if ( x3 < 0 ) x3 = 0; + if ( x4 >= m_width ) x4 = m_width - 1; + if ( y1 >= m_height ) y1 = m_height - 1; + if ( y2 >= m_height ) y2 = m_height - 1; + if ( y3 < 0 ) y3 = 0; + if ( y4 < 0 ) y4 = 0; + + m_kseedsx[k] = (float)x1; + m_kseedsy[k] = (float)y1; + for( int c = 0; c < m_nr_channels; c++ ) + { + switch ( m_chvec[c].depth() ) + { + case CV_8U: + m_kseeds[c][k] = m_chvec[c].at(y1,x1); + break; + + case CV_8S: + m_kseeds[c][k] = m_chvec[c].at(y1,x1); + break; + + case CV_16U: + m_kseeds[c][k] = m_chvec[c].at(y1,x1); + break; + + case CV_16S: + m_kseeds[c][k] = m_chvec[c].at(y1,x1); + break; + + case CV_32S: + m_kseeds[c][k] = float(m_chvec[c].at(y1,x1)); + break; + + case CV_32F: + m_kseeds[c][k] = m_chvec[c].at(y1,x1); + break; + + case CV_64F: + m_kseeds[c][k] = float(m_chvec[c].at(y1,x1)); + break; + + default: + CV_Error( Error::StsInternal, "Invalid matrix depth" ); + break; + } + } + + m_kseedsx.push_back( (float)x2 ); + m_kseedsx.push_back( (float)x3 ); + m_kseedsx.push_back( (float)x4 ); + m_kseedsy.push_back( (float)y2 ); + m_kseedsy.push_back( (float)y3 ); + m_kseedsy.push_back( (float)y4 ); + + for( int c = 0; c < m_nr_channels; c++ ) + { + switch ( m_chvec[c].depth() ) + { + case CV_8U: + m_kseeds[c].push_back( m_chvec[c].at(y2,x2) ); + m_kseeds[c].push_back( m_chvec[c].at(y3,x3) ); + m_kseeds[c].push_back( m_chvec[c].at(y4,x4) ); + break; + + case CV_8S: + m_kseeds[c].push_back( m_chvec[c].at(y2,x2) ); + m_kseeds[c].push_back( m_chvec[c].at(y3,x3) ); + m_kseeds[c].push_back( m_chvec[c].at(y4,x4) ); + break; + + case CV_16U: + m_kseeds[c].push_back( m_chvec[c].at(y2,x2) ); + m_kseeds[c].push_back( m_chvec[c].at(y3,x3) ); + m_kseeds[c].push_back( m_chvec[c].at(y4,x4) ); + break; + + case CV_16S: + m_kseeds[c].push_back( m_chvec[c].at(y2,x2) ); + m_kseeds[c].push_back( m_chvec[c].at(y3,x3) ); + m_kseeds[c].push_back( m_chvec[c].at(y4,x4) ); + break; + + case CV_32S: + m_kseeds[c].push_back( float(m_chvec[c].at(y2,x2)) ); + m_kseeds[c].push_back( float(m_chvec[c].at(y3,x3)) ); + m_kseeds[c].push_back( float(m_chvec[c].at(y4,x4)) ); + break; + + case CV_32F: + m_kseeds[c].push_back( m_chvec[c].at(y2,x2) ); + m_kseeds[c].push_back( m_chvec[c].at(y3,x3) ); + m_kseeds[c].push_back( m_chvec[c].at(y4,x4) ); + break; + + case CV_64F: + m_kseeds[c].push_back( float(m_chvec[c].at(y2,x2)) ); + m_kseeds[c].push_back( float(m_chvec[c].at(y3,x3)) ); + m_kseeds[c].push_back( float(m_chvec[c].at(y4,x4)) ); + break; + + default: + CV_Error( Error::StsInternal, "Invalid matrix depth" ); + break; + } + } + m_adaptk.push_back( m_adaptk[k] ); + m_adaptk.push_back( m_adaptk[k] ); + m_adaptk.push_back( m_adaptk[k] ); + msc.clustersize.push_back( 1 ); + msc.clustersize.push_back( 1 ); + msc.clustersize.push_back( 1 ); + } + } + } + else + { + m_kseedsx.clear(); + m_kseedsy.clear(); + m_kseedsx.resize( m_numlabels, 0 ); + m_kseedsy.resize( m_numlabels, 0 ); + for( int c = 0; c < m_nr_channels; c++ ) + { + m_kseeds[c].clear(); + m_kseeds[c].resize( m_numlabels, 0 ); + } + + for( int k = 0; k < m_numlabels; k++ ) + { + m_kseedsx[k] = msc.sigmax[k] / msc.clustersize[k]; + m_kseedsy[k] = msc.sigmay[k] / msc.clustersize[k]; + for( int c = 0; c < m_nr_channels; c++ ) + m_kseeds[c][k] = msc.sigma[c][k] / msc.clustersize[k]; + } + } + + m_klabels.release(); + m_klabels = klabels.clone(); + + // re-update amount of labels + m_numlabels = (int)m_kseeds[0].size(); + +} + + } // namespace ximgproc } // namespace cv