From c5b4b99350d570117801a2274e84beb78773307c Mon Sep 17 00:00:00 2001 From: pradeep Date: Sat, 17 May 2014 23:44:31 +0800 Subject: [PATCH 1/4] Implemented Kullback-Leibler divergence --- modules/imgproc/doc/histograms.rst | 8 ++++++++ modules/imgproc/include/opencv2/imgproc.hpp | 3 ++- .../imgproc/include/opencv2/imgproc/types_c.h | 3 ++- modules/imgproc/src/histogram.cpp | 12 ++++++++++++ modules/imgproc/test/test_histograms.cpp | 17 +++++++++++++++-- 5 files changed, 39 insertions(+), 4 deletions(-) diff --git a/modules/imgproc/doc/histograms.rst b/modules/imgproc/doc/histograms.rst index 91199f3781..5ebf168611 100644 --- a/modules/imgproc/doc/histograms.rst +++ b/modules/imgproc/doc/histograms.rst @@ -181,6 +181,8 @@ Compares two histograms. * **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: * Correlation (``method=CV_COMP_CORREL``) @@ -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)}} +* 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 :math:`d(H_1, H_2)` . diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index 7928ae0fe8..76d65c2802 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -204,7 +204,8 @@ enum { HISTCMP_CORREL = 0, HISTCMP_INTERSECT = 2, HISTCMP_BHATTACHARYYA = 3, HISTCMP_HELLINGER = HISTCMP_BHATTACHARYYA, - HISTCMP_CHISQR_ALT = 4 + HISTCMP_CHISQR_ALT = 4, + HISTCMP_KL_DIV = 5 }; //! the color conversion code diff --git a/modules/imgproc/include/opencv2/imgproc/types_c.h b/modules/imgproc/include/opencv2/imgproc/types_c.h index dd0d8b8a6e..de8fb62038 100644 --- a/modules/imgproc/include/opencv2/imgproc/types_c.h +++ b/modules/imgproc/include/opencv2/imgproc/types_c.h @@ -509,7 +509,8 @@ enum CV_COMP_INTERSECT =2, CV_COMP_BHATTACHARYYA =3, 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 */ diff --git a/modules/imgproc/src/histogram.cpp b/modules/imgproc/src/histogram.cpp index e7e03ceeb2..1be7315acb 100644 --- a/modules/imgproc/src/histogram.cpp +++ b/modules/imgproc/src/histogram.cpp @@ -2323,6 +2323,18 @@ double cv::compareHist( InputArray _H1, InputArray _H2, int method ) s2 += b; } } + else if( method == CV_COMP_KL_DIV ) + { + for( j = 0; j < len; j++ ){ + double p = h1[j]; + double q = h2[j]; + if( p == 0.0 ) + continue; + if( q == 0.0 ) + q += 1e-10; + result += p * cv::log( p / q ); + } + } else CV_Error( CV_StsBadArg, "Unknown comparison method" ); } diff --git a/modules/imgproc/test/test_histograms.cpp b/modules/imgproc/test/test_histograms.cpp index 19ccc656b5..55f4df03c1 100644 --- a/modules/imgproc/test/test_histograms.cpp +++ b/modules/imgproc/test/test_histograms.cpp @@ -948,7 +948,7 @@ int CV_ThreshHistTest::validate_test_results( int /*test_case_idx*/ ) class CV_CompareHistTest : public CV_BaseHistTest { public: - enum { MAX_METHOD = 5 }; + enum { MAX_METHOD = 6 }; CV_CompareHistTest(); protected: @@ -1021,6 +1021,12 @@ int CV_CompareHistTest::validate_test_results( int /*test_case_idx*/ ) sq0 += v0*v0; sq1 += v1*v1; result0[CV_COMP_BHATTACHARYYA] += sqrt(v0*v1); + if( fabs(v0) > DBL_EPSILON ) + { + if( fabs(v1) < DBL_EPSILON ) + v1 += 1e-10; + result0[CV_COMP_KL_DIV] += v0 * cv::log( v0 / v1 ); + } } } else @@ -1046,6 +1052,12 @@ int CV_CompareHistTest::validate_test_results( int /*test_case_idx*/ ) s0 += v0; sq0 += v0*v0; result0[CV_COMP_BHATTACHARYYA] += sqrt(v0*v1); + if( fabs(v0) > DBL_EPSILON ) + { + if( fabs(v1) < DBL_EPSILON ) + v1 += 1e-10; + result0[CV_COMP_KL_DIV] += v0 * cv::log( v0 / v1 ); + } } for( node = cvInitSparseMatIterator( sparse1, &iterator ); @@ -1076,7 +1088,8 @@ int CV_CompareHistTest::validate_test_results( int /*test_case_idx*/ ) i == CV_COMP_CHISQR_ALT ? "Alternative Chi-Square" : i == CV_COMP_CORREL ? "Correlation" : 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) ) { From f8b23cff18abbc5c3f7f9117a242b7298dbaa7f2 Mon Sep 17 00:00:00 2001 From: pradeep Date: Wed, 9 Jul 2014 13:39:40 +0800 Subject: [PATCH 2/4] Fixed test errors, added support for C data types. --- modules/imgproc/src/histogram.cpp | 34 +++++++++++++++++++----- modules/imgproc/test/test_histograms.cpp | 18 +++++++------ 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/modules/imgproc/src/histogram.cpp b/modules/imgproc/src/histogram.cpp index 1be7315acb..c16386e1a7 100644 --- a/modules/imgproc/src/histogram.cpp +++ b/modules/imgproc/src/histogram.cpp @@ -2325,13 +2325,16 @@ double cv::compareHist( InputArray _H1, InputArray _H2, int method ) } else if( method == CV_COMP_KL_DIV ) { - for( j = 0; j < len; j++ ){ + for( j = 0; j < len; j++ ) + { double p = h1[j]; double q = h2[j]; - if( p == 0.0 ) + if( fabs(p) <= DBL_EPSILON ) { continue; - if( q == 0.0 ) - q += 1e-10; + } + if( fabs(q) <= DBL_EPSILON ) { + q = 1e-10; + } result += p * cv::log( p / q ); } } @@ -2370,7 +2373,7 @@ double cv::compareHist( const SparseMat& H1, const SparseMat& H2, int method ) CV_Assert( H1.size(i) == H2.size(i) ); 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); SparseMatConstIterator it = PH1->begin(); @@ -2450,6 +2453,18 @@ double cv::compareHist( const SparseMat& H1, const SparseMat& H2, int method ) s1 = fabs(s1) > FLT_EPSILON ? 1./std::sqrt(s1) : 1.; result = std::sqrt(std::max(1. - result*s1, 0.)); } + else if( method == CV_COMP_KL_DIV ) + { + for( i = 0; i < N1; i++, ++it ) + { + float v1 = it.value(); + const SparseMat::Node* node = it.node(); + float v2 = PH2->value(node->idx, (size_t*)&node->hashval); + if( !v2 ) + v2 = 1e-10; + result += v1 * cv::log( v1 / v2 ); + } + } else CV_Error( CV_StsBadArg, "Unknown comparison method" ); @@ -2795,7 +2810,7 @@ cvCompareHist( const CvHistogram* hist1, CvSparseMatIterator iterator; 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; CV_SWAP( mat1, mat2, t ); @@ -2897,6 +2912,13 @@ cvCompareHist( const CvHistogram* hist1, result = 1. - result*s1; 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 CV_Error( CV_StsBadArg, "Unknown comparison method" ); diff --git a/modules/imgproc/test/test_histograms.cpp b/modules/imgproc/test/test_histograms.cpp index 55f4df03c1..51c3aab985 100644 --- a/modules/imgproc/test/test_histograms.cpp +++ b/modules/imgproc/test/test_histograms.cpp @@ -1021,11 +1021,12 @@ int CV_CompareHistTest::validate_test_results( int /*test_case_idx*/ ) sq0 += v0*v0; sq1 += v1*v1; result0[CV_COMP_BHATTACHARYYA] += sqrt(v0*v1); - if( fabs(v0) > DBL_EPSILON ) { - if( fabs(v1) < DBL_EPSILON ) - v1 += 1e-10; - result0[CV_COMP_KL_DIV] += v0 * cv::log( 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 ); } } } @@ -1052,11 +1053,12 @@ int CV_CompareHistTest::validate_test_results( int /*test_case_idx*/ ) s0 += v0; sq0 += v0*v0; result0[CV_COMP_BHATTACHARYYA] += sqrt(v0*v1); - if( fabs(v0) > DBL_EPSILON ) { - if( fabs(v1) < DBL_EPSILON ) - v1 += 1e-10; - result0[CV_COMP_KL_DIV] += v0 * cv::log( v0 / v1 ); + if (v0 <= DBL_EPSILON) + continue; + if (!v1) + v1 = 1e-10; + result0[CV_COMP_KL_DIV] += v0 * cv::log( v0 / v1 ); } } From 0d49f97128b852040d44048bc4cf9a8764fc38a9 Mon Sep 17 00:00:00 2001 From: pradeep Date: Wed, 9 Jul 2014 15:29:47 +0800 Subject: [PATCH 3/4] Fixed truncation warning --- modules/imgproc/src/histogram.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/imgproc/src/histogram.cpp b/modules/imgproc/src/histogram.cpp index c16386e1a7..97ca3deda5 100644 --- a/modules/imgproc/src/histogram.cpp +++ b/modules/imgproc/src/histogram.cpp @@ -2457,9 +2457,9 @@ double cv::compareHist( const SparseMat& H1, const SparseMat& H2, int method ) { for( i = 0; i < N1; i++, ++it ) { - float v1 = it.value(); + double v1 = it.value(); const SparseMat::Node* node = it.node(); - float v2 = PH2->value(node->idx, (size_t*)&node->hashval); + double v2 = PH2->value(node->idx, (size_t*)&node->hashval); if( !v2 ) v2 = 1e-10; result += v1 * cv::log( v1 / v2 ); From 7171431e7c6095e3a59bbea49d15e8f58f0e6c23 Mon Sep 17 00:00:00 2001 From: pradeep Date: Tue, 15 Jul 2014 12:32:53 +0800 Subject: [PATCH 4/4] Changed cv::log to std::log --- modules/imgproc/src/histogram.cpp | 4 ++-- modules/imgproc/test/test_histograms.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/imgproc/src/histogram.cpp b/modules/imgproc/src/histogram.cpp index 97ca3deda5..909601fd22 100644 --- a/modules/imgproc/src/histogram.cpp +++ b/modules/imgproc/src/histogram.cpp @@ -2335,7 +2335,7 @@ double cv::compareHist( InputArray _H1, InputArray _H2, int method ) if( fabs(q) <= DBL_EPSILON ) { q = 1e-10; } - result += p * cv::log( p / q ); + result += p * std::log( p / q ); } } else @@ -2462,7 +2462,7 @@ double cv::compareHist( const SparseMat& H1, const SparseMat& H2, int method ) double v2 = PH2->value(node->idx, (size_t*)&node->hashval); if( !v2 ) v2 = 1e-10; - result += v1 * cv::log( v1 / v2 ); + result += v1 * std::log( v1 / v2 ); } } else diff --git a/modules/imgproc/test/test_histograms.cpp b/modules/imgproc/test/test_histograms.cpp index 51c3aab985..e9db6fcde0 100644 --- a/modules/imgproc/test/test_histograms.cpp +++ b/modules/imgproc/test/test_histograms.cpp @@ -1058,7 +1058,7 @@ int CV_CompareHistTest::validate_test_results( int /*test_case_idx*/ ) continue; if (!v1) v1 = 1e-10; - result0[CV_COMP_KL_DIV] += v0 * cv::log( v0 / v1 ); + result0[CV_COMP_KL_DIV] += v0 * std::log( v0 / v1 ); } }