mirror of
https://github.com/opencv/opencv_contrib.git
synced 2025-10-22 16:08:41 +08:00
Add MSLIC (Manifold SLIC).
This commit is contained in:
Binary file not shown.
Before Width: | Height: | Size: 757 KiB After Width: | Height: | Size: 966 KiB |
@@ -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},
|
||||
|
@@ -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.
|
||||
|
||||

|
||||
|
||||
*/
|
||||
|
||||
enum SLIC { SLIC = 100, SLICO = 101 };
|
||||
|
||||
CV_EXPORTS_W Ptr<SuperpixelSLIC> createSuperpixelSLIC( InputArray image, int algorithm = SLICO,
|
||||
int region_size = 10, float ruler = 10.0f );
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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 <cristian dot balint at gmail dot com>
|
||||
*/
|
||||
|
||||
@@ -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<float> > m_kseeds;
|
||||
|
||||
// adaptive k (MSLIC)
|
||||
vector<float> 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<SuperpixelSLIC> 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<float> 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<int> xvec(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
|
||||
int adjlabel = 0;
|
||||
|
||||
@@ -346,6 +411,7 @@ void SuperpixelSLICImpl::enforceLabelConnectivity( int min_element_size )
|
||||
//--------------------
|
||||
xvec[0] = k;
|
||||
yvec[0] = j;
|
||||
currentlabel = m_klabels.at<int>(j,k);
|
||||
//-------------------------------------------------------
|
||||
// Quickly find an adjacent label for use later if needed
|
||||
//-------------------------------------------------------
|
||||
@@ -356,9 +422,33 @@ void SuperpixelSLICImpl::enforceLabelConnectivity( int min_element_size )
|
||||
if( (x >= 0 && x < m_width) && (y >= 0 && y < m_height) )
|
||||
{
|
||||
if( nlabels.at<int>(y,x) != INT_MAX )
|
||||
{
|
||||
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);
|
||||
for( int c = 0; c < count; c++ )
|
||||
@@ -379,9 +469,46 @@ void SuperpixelSLICImpl::enforceLabelConnectivity( int min_element_size )
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// MSLIC only
|
||||
if( m_algorithm == MSLIC )
|
||||
{
|
||||
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<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.
|
||||
@@ -394,6 +521,23 @@ void SuperpixelSLICImpl::enforceLabelConnectivity( int min_element_size )
|
||||
}
|
||||
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++;
|
||||
}
|
||||
}
|
||||
@@ -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<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 cv
|
||||
|
Reference in New Issue
Block a user