Commit 6891d778 authored by Alexander Alekhin's avatar Alexander Alekhin Committed by GitHub

Merge pull request #923 from cbalint13:mslic

Add MSLIC (Manifold SLIC)
parents 04ad07c0 ce2fd8e3
...@@ -160,6 +160,14 @@ ...@@ -160,6 +160,14 @@
keywords = {Superpixels, segmentation, clustering, k-means} 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, @InProceedings{LiCVPR2015LSC,
author = {Li, Zhengqin and Chen, Jiansheng}, author = {Li, Zhengqin and Chen, Jiansheng},
title = {Superpixel Segmentation Using Linear Spectral Clustering}, title = {Superpixel Segmentation Using Linear Spectral Clustering},
......
...@@ -61,6 +61,8 @@ namespace ximgproc ...@@ -61,6 +61,8 @@ namespace ximgproc
//! @addtogroup ximgproc_superpixel //! @addtogroup ximgproc_superpixel
//! @{ //! @{
enum SLIC { SLIC = 100, SLICO = 101, MSLIC = 102 };
/** @brief Class implementing the SLIC (Simple Linear Iterative Clustering) superpixels /** @brief Class implementing the SLIC (Simple Linear Iterative Clustering) superpixels
algorithm described in @cite Achanta2012. algorithm described in @cite Achanta2012.
...@@ -68,7 +70,9 @@ SLIC (Simple Linear Iterative Clustering) clusters pixels using pixel channels a ...@@ -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 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 extremely easy to use a lone parameter specifies the number of superpixels and the efficiency of
the algorithm makes it very practical. 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 class CV_EXPORTS_W SuperpixelSLIC : public Algorithm
...@@ -134,26 +138,25 @@ public: ...@@ -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 image Image to segment
@param algorithm Chooses the algorithm variant to use: @param algorithm Chooses the algorithm variant to use:
SLIC segments image using a desired region_size, and in addition SLIC segments image using a desired region_size, and in addition SLICO will optimize using adaptive compactness factor,
SLICO will choose an 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 region_size Chooses an average superpixel size measured in pixels
@param ruler Chooses the enforcement of superpixel smoothness factor of superpixel @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 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 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 computing iterations over the given image. For enanched results it is recommended for color images to
following picture. 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) ![image](pics/superpixels_slic.png)
*/ */
enum SLIC { SLIC = 100, SLICO = 101 };
CV_EXPORTS_W Ptr<SuperpixelSLIC> createSuperpixelSLIC( InputArray image, int algorithm = SLICO, CV_EXPORTS_W Ptr<SuperpixelSLIC> createSuperpixelSLIC( InputArray image, int algorithm = SLICO,
int region_size = 10, float ruler = 10.0f ); int region_size = 10, float ruler = 10.0f );
......
...@@ -19,7 +19,7 @@ static const char* keys = ...@@ -19,7 +19,7 @@ static const char* keys =
"{h help | | help menu}" "{h help | | help menu}"
"{c camera |0| camera id}" "{c camera |0| camera id}"
"{i image | | image file}" "{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) int main(int argc, char** argv)
...@@ -63,7 +63,7 @@ int main(int argc, char** argv) ...@@ -63,7 +63,7 @@ int main(int argc, char** argv)
} }
namedWindow(window_name, 0); namedWindow(window_name, 0);
createTrackbar("Algorithm", window_name, &algorithm, 1, 0); createTrackbar("Algorithm", window_name, &algorithm, 2, 0);
createTrackbar("Region size", window_name, &region_size, 200, 0); createTrackbar("Region size", window_name, &region_size, 200, 0);
createTrackbar("Ruler", window_name, &ruler, 100, 0); createTrackbar("Ruler", window_name, &ruler, 100, 0);
createTrackbar("Connectivity", window_name, &min_element_size, 100, 0); createTrackbar("Connectivity", window_name, &min_element_size, 100, 0);
......
/********************************************************************* /*********************************************************************
* Software License Agreement (BSD License) * Software License Agreement (BSD License)
* *
* Copyright (c) 2013 * SLIC, SLICO Copyright (c) 2013
* Radhakrishna Achanta * Radhakrishna Achanta
* email : Radhakrishna [dot] Achanta [at] epfl [dot] ch * email : Radhakrishna [dot] Achanta [at] epfl [dot] ch
* web : http://ivrl.epfl.ch/people/achanta * 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 * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
* are met: * are met:
...@@ -44,6 +49,11 @@ ...@@ -44,6 +49,11 @@
Aurelien Lucchi, Pascal Fua, and Sabine Süsstrunk, EPFL Technical Aurelien Lucchi, Pascal Fua, and Sabine Süsstrunk, EPFL Technical
Report no. 149300, June 2010. 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 <cristian dot balint at gmail dot com> OpenCV port by: Cristian Balint <cristian dot balint at gmail dot com>
*/ */
...@@ -99,6 +109,19 @@ protected: ...@@ -99,6 +109,19 @@ protected:
// compactness // compactness
float m_ruler; 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: private:
// labels no // labels no
...@@ -120,6 +143,12 @@ private: ...@@ -120,6 +143,12 @@ private:
// seeds storage // seeds storage
vector< vector<float> > m_kseeds; vector< vector<float> > m_kseeds;
// adaptive k (MSLIC)
vector<float> m_adaptk;
// merge threshold (MSLIC)
float m_merge;
// initialization // initialization
inline void initialize(); inline void initialize();
...@@ -140,6 +169,13 @@ private: ...@@ -140,6 +169,13 @@ private:
// SLICO // SLICO
inline void PerformSLICO( const int& num_iterations ); inline void PerformSLICO( const int& num_iterations );
// MSLIC
inline void PerformMSLIC( const int& num_iterations );
// MSLIC
inline void SuperpixelSplit();
}; };
CV_EXPORTS Ptr<SuperpixelSLIC> createSuperpixelSLIC( InputArray image, int algorithm, int region_size, float ruler ) CV_EXPORTS Ptr<SuperpixelSLIC> createSuperpixelSLIC( InputArray image, int algorithm, int region_size, float ruler )
...@@ -221,7 +257,8 @@ void SuperpixelSLICImpl::initialize() ...@@ -221,7 +257,8 @@ void SuperpixelSLICImpl::initialize()
if( m_algorithm == SLICO ) if( m_algorithm == SLICO )
GetChSeedsK(); GetChSeedsK();
else if( m_algorithm == SLIC ) else if( ( m_algorithm == SLIC ) ||
( m_algorithm == MSLIC ) )
GetChSeedsS(); GetChSeedsS();
else else
CV_Error( Error::StsInternal, "No such algorithm" ); CV_Error( Error::StsInternal, "No such algorithm" );
...@@ -232,6 +269,11 @@ void SuperpixelSLICImpl::initialize() ...@@ -232,6 +269,11 @@ void SuperpixelSLICImpl::initialize()
// perturb seeds given edges // perturb seeds given edges
if ( perturbseeds ) PerturbSeeds( edgemag ); 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 ) void SuperpixelSLICImpl::iterate( int num_iterations )
...@@ -240,6 +282,8 @@ void SuperpixelSLICImpl::iterate( int num_iterations ) ...@@ -240,6 +282,8 @@ void SuperpixelSLICImpl::iterate( int num_iterations )
PerformSLICO( num_iterations ); PerformSLICO( num_iterations );
else if( m_algorithm == SLIC ) else if( m_algorithm == SLIC )
PerformSLIC( num_iterations ); PerformSLIC( num_iterations );
else if( m_algorithm == MSLIC )
PerformMSLIC( num_iterations );
else else
CV_Error( Error::StsInternal, "No such algorithm" ); CV_Error( Error::StsInternal, "No such algorithm" );
...@@ -316,6 +360,13 @@ void SuperpixelSLICImpl::enforceLabelConnectivity( int min_element_size ) ...@@ -316,6 +360,13 @@ void SuperpixelSLICImpl::enforceLabelConnectivity( int min_element_size )
if ( min_element_size == 0 ) return; if ( min_element_size == 0 ) return;
CV_Assert( min_element_size >= 0 && min_element_size <= 100 ); CV_Assert( min_element_size >= 0 && min_element_size <= 100 );
vector<float> adaptk( m_numlabels, 1.0f );
if( m_algorithm == MSLIC )
{
adaptk.clear();
}
const int dx4[4] = { -1, 0, 1, 0 }; const int dx4[4] = { -1, 0, 1, 0 };
const int dy4[4] = { 0, -1, 0, 1 }; const int dy4[4] = { 0, -1, 0, 1 };
...@@ -331,6 +382,20 @@ void SuperpixelSLICImpl::enforceLabelConnectivity( int min_element_size ) ...@@ -331,6 +382,20 @@ void SuperpixelSLICImpl::enforceLabelConnectivity( int min_element_size )
vector<int> xvec(sz); vector<int> xvec(sz);
vector<int> yvec(sz); vector<int> yvec(sz);
// MSLIC
int currentlabel;
float diffch = 0.0f;
vector<float> adjch;
vector<float> curch;
map<int,int> hashtable;
if( m_algorithm == MSLIC )
{
hashtable[-1] = 0;
adjch.resize( m_nr_channels, 0 );
curch.resize( m_nr_channels, 0 );
}
//adjacent label //adjacent label
int adjlabel = 0; int adjlabel = 0;
...@@ -346,6 +411,7 @@ void SuperpixelSLICImpl::enforceLabelConnectivity( int min_element_size ) ...@@ -346,6 +411,7 @@ void SuperpixelSLICImpl::enforceLabelConnectivity( int min_element_size )
//-------------------- //--------------------
xvec[0] = k; xvec[0] = k;
yvec[0] = j; yvec[0] = j;
currentlabel = m_klabels.at<int>(j,k);
//------------------------------------------------------- //-------------------------------------------------------
// Quickly find an adjacent label for use later if needed // Quickly find an adjacent label for use later if needed
//------------------------------------------------------- //-------------------------------------------------------
...@@ -355,11 +421,35 @@ void SuperpixelSLICImpl::enforceLabelConnectivity( int min_element_size ) ...@@ -355,11 +421,35 @@ void SuperpixelSLICImpl::enforceLabelConnectivity( int min_element_size )
int y = yvec[0] + dy4[n]; int y = yvec[0] + dy4[n];
if( (x >= 0 && x < m_width) && (y >= 0 && y < m_height) ) if( (x >= 0 && x < m_width) && (y >= 0 && y < m_height) )
{ {
if(nlabels.at<int>(y,x) != INT_MAX) if( nlabels.at<int>(y,x) != INT_MAX )
adjlabel = nlabels.at<int>(y,x); {
adjlabel = nlabels.at<int>(y,x);
if( m_algorithm == MSLIC )
{
for( int b = 0; b < m_nr_channels; b++ )
{
adjch[b] = m_kseeds[b][m_klabels.at<int>(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<int>(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); int count(1);
for( int c = 0; c < count; c++ ) for( int c = 0; c < count; c++ )
{ {
...@@ -379,20 +469,74 @@ void SuperpixelSLICImpl::enforceLabelConnectivity( int min_element_size ) ...@@ -379,20 +469,74 @@ void SuperpixelSLICImpl::enforceLabelConnectivity( int min_element_size )
count++; count++;
} }
} }
} }
} }
//------------------------------------------------------- // MSLIC only
// If segment size is less then a limit, assign an if( m_algorithm == MSLIC )
// adjacent label found before, and decrement label count.
//-------------------------------------------------------
if(count <= min_sp_sz)
{ {
for( int c = 0; c < count; c++ ) if ( m_cur_iter < m_iterations - 1 )
{ {
nlabels.at<int>(yvec[c],xvec[c]) = adjlabel; hashtable[label] = count;
} //-------------------------------------------------------
label--; // 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<int>(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<int>(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<int>(yvec[c],xvec[c]) = adjlabel;
}
label--;
}
} }
label++; label++;
} }
...@@ -401,6 +545,9 @@ void SuperpixelSLICImpl::enforceLabelConnectivity( int min_element_size ) ...@@ -401,6 +545,9 @@ void SuperpixelSLICImpl::enforceLabelConnectivity( int min_element_size )
// replace old // replace old
m_klabels = nlabels; m_klabels = nlabels;
m_numlabels = label; m_numlabels = label;
m_adaptk.clear();
m_adaptk = adaptk;
} }
/* /*
...@@ -696,7 +843,7 @@ struct SeedNormInvoker : ParallelLoopBody ...@@ -696,7 +843,7 @@ struct SeedNormInvoker : ParallelLoopBody
if( clustersize->at(k) <= 0 ) clustersize->at(k) = 1; if( clustersize->at(k) <= 0 ) clustersize->at(k) = 1;
for ( int b = 0; b < nr_channels; b++ ) 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)); kseedsx->at(k) = sigmax->at(k) / float(clustersize->at(k));
kseedsy->at(k) = sigmay->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 ) ...@@ -1214,5 +1361,420 @@ inline void SuperpixelSLICImpl::PerformSLIC( const int& itrnum )
} }
} }
/*
* PerformSuperpixelMSLIC
*
*
*/
inline void SuperpixelSLICImpl::PerformMSLIC( const int& itrnum )
{
vector< vector<float> > sigma(m_nr_channels);
for( int b = 0; b < m_nr_channels; b++ )
sigma[b].resize(m_numlabels, 0);
vector<float> sigmax(m_numlabels, 0);
vector<float> sigmay(m_numlabels, 0);
vector<int> 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<float> 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<int>( y, x ) == klabels.at<int>( y+1, x ) &&
klabels.at<int>( y, x ) == klabels.at<int>( y, x+1 ) )
{
float x1 = 1, y1 = 0;
float x2 = 0, y2 = 1;
vector<float> ch1(m_nr_channels);
vector<float> 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<uchar>( y+1, x )
- m_chvec[c].at<uchar>( y, x ) );
ch2[c] = float( m_chvec[c].at<uchar>( y, x+1 )
- m_chvec[c].at<uchar>( 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<char>( y+1, x )
- m_chvec[c].at<char>( y, x ) );
ch2[c] = float( m_chvec[c].at<char>( y, x+1 )
- m_chvec[c].at<char>( 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<ushort>( y+1, x )
- m_chvec[c].at<ushort>( y, x ) );
ch2[c] = float( m_chvec[c].at<ushort>( y, x+1 )
- m_chvec[c].at<ushort>( 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<short>( y+1, x )
- m_chvec[c].at<short>( y, x ) );
ch2[c] = float( m_chvec[c].at<short>( y, x+1 )
- m_chvec[c].at<short>( 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<int>( y+1, x )
- m_chvec[c].at<int>( y, x ) );
ch2[c] = float( m_chvec[c].at<int>( y, x+1 )
- m_chvec[c].at<int>( 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<float>( y+1, x )
- m_chvec[c].at<float>( y, x );
ch2[c] = m_chvec[c].at<float>( y, x+1 )
- m_chvec[c].at<float>( 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<double>( y+1, x )
- m_chvec[c].at<double>( y, x ) );
ch2[c] = float( m_chvec[c].at<double>( y, x+1 )
- m_chvec[c].at<double>( 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<int>(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<uchar>(y1,x1);
break;
case CV_8S:
m_kseeds[c][k] = m_chvec[c].at<char>(y1,x1);
break;
case CV_16U:
m_kseeds[c][k] = m_chvec[c].at<ushort>(y1,x1);
break;
case CV_16S:
m_kseeds[c][k] = m_chvec[c].at<short>(y1,x1);
break;
case CV_32S:
m_kseeds[c][k] = float(m_chvec[c].at<int>(y1,x1));
break;
case CV_32F:
m_kseeds[c][k] = m_chvec[c].at<float>(y1,x1);
break;
case CV_64F:
m_kseeds[c][k] = float(m_chvec[c].at<double>(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<uchar>(y2,x2) );
m_kseeds[c].push_back( m_chvec[c].at<uchar>(y3,x3) );
m_kseeds[c].push_back( m_chvec[c].at<uchar>(y4,x4) );
break;
case CV_8S:
m_kseeds[c].push_back( m_chvec[c].at<char>(y2,x2) );
m_kseeds[c].push_back( m_chvec[c].at<char>(y3,x3) );
m_kseeds[c].push_back( m_chvec[c].at<char>(y4,x4) );
break;
case CV_16U:
m_kseeds[c].push_back( m_chvec[c].at<ushort>(y2,x2) );
m_kseeds[c].push_back( m_chvec[c].at<ushort>(y3,x3) );
m_kseeds[c].push_back( m_chvec[c].at<ushort>(y4,x4) );
break;
case CV_16S:
m_kseeds[c].push_back( m_chvec[c].at<short>(y2,x2) );
m_kseeds[c].push_back( m_chvec[c].at<short>(y3,x3) );
m_kseeds[c].push_back( m_chvec[c].at<short>(y4,x4) );
break;
case CV_32S:
m_kseeds[c].push_back( float(m_chvec[c].at<int>(y2,x2)) );
m_kseeds[c].push_back( float(m_chvec[c].at<int>(y3,x3)) );
m_kseeds[c].push_back( float(m_chvec[c].at<int>(y4,x4)) );
break;
case CV_32F:
m_kseeds[c].push_back( m_chvec[c].at<float>(y2,x2) );
m_kseeds[c].push_back( m_chvec[c].at<float>(y3,x3) );
m_kseeds[c].push_back( m_chvec[c].at<float>(y4,x4) );
break;
case CV_64F:
m_kseeds[c].push_back( float(m_chvec[c].at<double>(y2,x2)) );
m_kseeds[c].push_back( float(m_chvec[c].at<double>(y3,x3)) );
m_kseeds[c].push_back( float(m_chvec[c].at<double>(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 ximgproc
} // namespace cv } // namespace cv
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment