Commit 40370345 authored by Vadim Pisarevsky's avatar Vadim Pisarevsky

Merge pull request #2765 from pradeep-pyro:kullback_leibler

parents b1793e2f 7171431e
...@@ -181,6 +181,8 @@ Compares two histograms. ...@@ -181,6 +181,8 @@ Compares two histograms.
* **CV_COMP_HELLINGER** Synonym for ``CV_COMP_BHATTACHARYYA`` * **CV_COMP_HELLINGER** Synonym for ``CV_COMP_BHATTACHARYYA``
* **CV_COMP_KL_DIV** Kullback-Leibler divergence
The functions ``compareHist`` compare two dense or two sparse histograms using the specified method: The functions ``compareHist`` compare two dense or two sparse histograms using the specified method:
* Correlation (``method=CV_COMP_CORREL``) * Correlation (``method=CV_COMP_CORREL``)
...@@ -224,6 +226,12 @@ The functions ``compareHist`` compare two dense or two sparse histograms using t ...@@ -224,6 +226,12 @@ The functions ``compareHist`` compare two dense or two sparse histograms using t
d(H_1,H_2) = \sqrt{1 - \frac{1}{\sqrt{\bar{H_1} \bar{H_2} N^2}} \sum_I \sqrt{H_1(I) \cdot H_2(I)}} d(H_1,H_2) = \sqrt{1 - \frac{1}{\sqrt{\bar{H_1} \bar{H_2} N^2}} \sum_I \sqrt{H_1(I) \cdot H_2(I)}}
* Kullback-Leibler divergence (``method=CV_COMP_KL_DIV``).
.. math::
d(H_1,H_2) = \sum _I H_1(I) \log \left(\frac{H_1(I)}{H_2(I)}\right)
The function returns The function returns
:math:`d(H_1, H_2)` . :math:`d(H_1, H_2)` .
......
...@@ -204,7 +204,8 @@ enum { HISTCMP_CORREL = 0, ...@@ -204,7 +204,8 @@ enum { HISTCMP_CORREL = 0,
HISTCMP_INTERSECT = 2, HISTCMP_INTERSECT = 2,
HISTCMP_BHATTACHARYYA = 3, HISTCMP_BHATTACHARYYA = 3,
HISTCMP_HELLINGER = HISTCMP_BHATTACHARYYA, HISTCMP_HELLINGER = HISTCMP_BHATTACHARYYA,
HISTCMP_CHISQR_ALT = 4 HISTCMP_CHISQR_ALT = 4,
HISTCMP_KL_DIV = 5
}; };
//! the color conversion code //! the color conversion code
......
...@@ -509,7 +509,8 @@ enum ...@@ -509,7 +509,8 @@ enum
CV_COMP_INTERSECT =2, CV_COMP_INTERSECT =2,
CV_COMP_BHATTACHARYYA =3, CV_COMP_BHATTACHARYYA =3,
CV_COMP_HELLINGER =CV_COMP_BHATTACHARYYA, CV_COMP_HELLINGER =CV_COMP_BHATTACHARYYA,
CV_COMP_CHISQR_ALT =4 CV_COMP_CHISQR_ALT =4,
CV_COMP_KL_DIV =5
}; };
/* Mask size for distance transform */ /* Mask size for distance transform */
......
...@@ -2325,6 +2325,21 @@ double cv::compareHist( InputArray _H1, InputArray _H2, int method ) ...@@ -2325,6 +2325,21 @@ double cv::compareHist( InputArray _H1, InputArray _H2, int method )
s2 += b; s2 += b;
} }
} }
else if( method == CV_COMP_KL_DIV )
{
for( j = 0; j < len; j++ )
{
double p = h1[j];
double q = h2[j];
if( fabs(p) <= DBL_EPSILON ) {
continue;
}
if( fabs(q) <= DBL_EPSILON ) {
q = 1e-10;
}
result += p * std::log( p / q );
}
}
else else
CV_Error( CV_StsBadArg, "Unknown comparison method" ); CV_Error( CV_StsBadArg, "Unknown comparison method" );
} }
...@@ -2360,7 +2375,7 @@ double cv::compareHist( const SparseMat& H1, const SparseMat& H2, int method ) ...@@ -2360,7 +2375,7 @@ double cv::compareHist( const SparseMat& H1, const SparseMat& H2, int method )
CV_Assert( H1.size(i) == H2.size(i) ); CV_Assert( H1.size(i) == H2.size(i) );
const SparseMat *PH1 = &H1, *PH2 = &H2; const SparseMat *PH1 = &H1, *PH2 = &H2;
if( PH1->nzcount() > PH2->nzcount() && method != CV_COMP_CHISQR && method != CV_COMP_CHISQR_ALT) if( PH1->nzcount() > PH2->nzcount() && method != CV_COMP_CHISQR && method != CV_COMP_CHISQR_ALT && method != CV_COMP_KL_DIV )
std::swap(PH1, PH2); std::swap(PH1, PH2);
SparseMatConstIterator it = PH1->begin(); SparseMatConstIterator it = PH1->begin();
...@@ -2440,6 +2455,18 @@ double cv::compareHist( const SparseMat& H1, const SparseMat& H2, int method ) ...@@ -2440,6 +2455,18 @@ double cv::compareHist( const SparseMat& H1, const SparseMat& H2, int method )
s1 = fabs(s1) > FLT_EPSILON ? 1./std::sqrt(s1) : 1.; s1 = fabs(s1) > FLT_EPSILON ? 1./std::sqrt(s1) : 1.;
result = std::sqrt(std::max(1. - result*s1, 0.)); result = std::sqrt(std::max(1. - result*s1, 0.));
} }
else if( method == CV_COMP_KL_DIV )
{
for( i = 0; i < N1; i++, ++it )
{
double v1 = it.value<float>();
const SparseMat::Node* node = it.node();
double v2 = PH2->value<float>(node->idx, (size_t*)&node->hashval);
if( !v2 )
v2 = 1e-10;
result += v1 * std::log( v1 / v2 );
}
}
else else
CV_Error( CV_StsBadArg, "Unknown comparison method" ); CV_Error( CV_StsBadArg, "Unknown comparison method" );
...@@ -2785,7 +2812,7 @@ cvCompareHist( const CvHistogram* hist1, ...@@ -2785,7 +2812,7 @@ cvCompareHist( const CvHistogram* hist1,
CvSparseMatIterator iterator; CvSparseMatIterator iterator;
CvSparseNode *node1, *node2; CvSparseNode *node1, *node2;
if( mat1->heap->active_count > mat2->heap->active_count && method != CV_COMP_CHISQR && method != CV_COMP_CHISQR_ALT) if( mat1->heap->active_count > mat2->heap->active_count && method != CV_COMP_CHISQR && method != CV_COMP_CHISQR_ALT && method != CV_COMP_KL_DIV )
{ {
CvSparseMat* t; CvSparseMat* t;
CV_SWAP( mat1, mat2, t ); CV_SWAP( mat1, mat2, t );
...@@ -2887,6 +2914,13 @@ cvCompareHist( const CvHistogram* hist1, ...@@ -2887,6 +2914,13 @@ cvCompareHist( const CvHistogram* hist1,
result = 1. - result*s1; result = 1. - result*s1;
result = sqrt(MAX(result,0.)); result = sqrt(MAX(result,0.));
} }
else if( method == CV_COMP_KL_DIV )
{
cv::SparseMat sH1, sH2;
((const CvSparseMat*)hist1->bins)->copyToSparseMat(sH1);
((const CvSparseMat*)hist2->bins)->copyToSparseMat(sH2);
result = cv::compareHist( sH1, sH2, CV_COMP_KL_DIV );
}
else else
CV_Error( CV_StsBadArg, "Unknown comparison method" ); CV_Error( CV_StsBadArg, "Unknown comparison method" );
......
...@@ -948,7 +948,7 @@ int CV_ThreshHistTest::validate_test_results( int /*test_case_idx*/ ) ...@@ -948,7 +948,7 @@ int CV_ThreshHistTest::validate_test_results( int /*test_case_idx*/ )
class CV_CompareHistTest : public CV_BaseHistTest class CV_CompareHistTest : public CV_BaseHistTest
{ {
public: public:
enum { MAX_METHOD = 5 }; enum { MAX_METHOD = 6 };
CV_CompareHistTest(); CV_CompareHistTest();
protected: protected:
...@@ -1021,6 +1021,13 @@ int CV_CompareHistTest::validate_test_results( int /*test_case_idx*/ ) ...@@ -1021,6 +1021,13 @@ int CV_CompareHistTest::validate_test_results( int /*test_case_idx*/ )
sq0 += v0*v0; sq0 += v0*v0;
sq1 += v1*v1; sq1 += v1*v1;
result0[CV_COMP_BHATTACHARYYA] += sqrt(v0*v1); result0[CV_COMP_BHATTACHARYYA] += sqrt(v0*v1);
{
if( fabs(v0) <= DBL_EPSILON )
continue;
if( fabs(v1) <= DBL_EPSILON )
v1 = 1e-10;
result0[CV_COMP_KL_DIV] += v0 * std::log( v0 / v1 );
}
} }
} }
else else
...@@ -1046,6 +1053,13 @@ int CV_CompareHistTest::validate_test_results( int /*test_case_idx*/ ) ...@@ -1046,6 +1053,13 @@ int CV_CompareHistTest::validate_test_results( int /*test_case_idx*/ )
s0 += v0; s0 += v0;
sq0 += v0*v0; sq0 += v0*v0;
result0[CV_COMP_BHATTACHARYYA] += sqrt(v0*v1); result0[CV_COMP_BHATTACHARYYA] += sqrt(v0*v1);
{
if (v0 <= DBL_EPSILON)
continue;
if (!v1)
v1 = 1e-10;
result0[CV_COMP_KL_DIV] += v0 * std::log( v0 / v1 );
}
} }
for( node = cvInitSparseMatIterator( sparse1, &iterator ); for( node = cvInitSparseMatIterator( sparse1, &iterator );
...@@ -1076,7 +1090,8 @@ int CV_CompareHistTest::validate_test_results( int /*test_case_idx*/ ) ...@@ -1076,7 +1090,8 @@ int CV_CompareHistTest::validate_test_results( int /*test_case_idx*/ )
i == CV_COMP_CHISQR_ALT ? "Alternative Chi-Square" : i == CV_COMP_CHISQR_ALT ? "Alternative Chi-Square" :
i == CV_COMP_CORREL ? "Correlation" : i == CV_COMP_CORREL ? "Correlation" :
i == CV_COMP_INTERSECT ? "Intersection" : i == CV_COMP_INTERSECT ? "Intersection" :
i == CV_COMP_BHATTACHARYYA ? "Bhattacharyya" : "Unknown"; i == CV_COMP_BHATTACHARYYA ? "Bhattacharyya" :
i == CV_COMP_KL_DIV ? "Kullback-Leibler" : "Unknown";
if( cvIsNaN(v) || cvIsInf(v) ) if( cvIsNaN(v) || cvIsInf(v) )
{ {
......
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