Introduce CV_COMP_CHISQR_ALT, an alternative method to calculate ChiSquare Histogram...
authorkocheganovvm <kocheganovvm@kocheganovvm-System-Product-Name.(none)>
Sat, 10 Aug 2013 17:02:09 +0000 (21:02 +0400)
committerkocheganovvm <kocheganovvm@kocheganovvm-System-Product-Name.(none)>
Mon, 12 Aug 2013 09:51:52 +0000 (13:51 +0400)
There's some disagreement about the correct formula.
has its supporters, however, for texture analysis, the newly introduced formula became
standard. The commit enables both uses without breaking backward compatibility.

First contributor of this commit was sperrholz.

modules/imgproc/doc/histograms.rst
modules/imgproc/include/opencv2/imgproc/types_c.h
modules/imgproc/src/histogram.cpp
modules/imgproc/test/test_histograms.cpp

index 1ec6a01..2240e04 100644 (file)
@@ -173,6 +173,8 @@ Compares two histograms.
 
             * **CV_COMP_CHISQR**     Chi-Square
 
+            * **CV_COMP_CHISQR_ALT**     Alternative Chi-Square
+
             * **CV_COMP_INTERSECT**     Intersection
 
             * **CV_COMP_BHATTACHARYYA**     Bhattacharyya distance
@@ -202,6 +204,14 @@ The functions ``compareHist`` compare two dense or two sparse histograms using t
 
         d(H_1,H_2) =  \sum _I  \frac{\left(H_1(I)-H_2(I)\right)^2}{H_1(I)}
 
+* Alternative Chi-Square (``method=CV_COMP_CHISQR_ALT``)
+
+    .. math::
+
+        d(H_1,H_2) =  2 * \sum _I  \frac{\left(H_1(I)-H_2(I)\right)^2}{H_1(I)+H_2(I)}
+
+    This alternative formula is regularly used for texture comparison. See e.g. [Puzicha1997]_.
+
 * Intersection (``method=CV_COMP_INTERSECT``)
 
     .. math::
@@ -493,3 +503,4 @@ The function clears histogram bins that are below the specified threshold.
 
 
 .. [RubnerSept98] Y. Rubner. C. Tomasi, L.J. Guibas. *The Earth Mover’s Distance as a Metric for Image Retrieval*. Technical Report STAN-CS-TN-98-86, Department of Computer Science, Stanford University, September 1998.
+.. [Puzicha1997] Puzicha, J., Hofmann, T., and Buhmann, J. *Non-parametric similarity measures for unsupervised texture segmentation and image retrieval.* In Proc. IEEE Conf. Computer Vision and Pattern Recognition, San Juan, Puerto Rico, pp. 267-272, 1997.
index 2b1d072..dd0d8b8 100644 (file)
@@ -508,7 +508,8 @@ enum
     CV_COMP_CHISQR        =1,
     CV_COMP_INTERSECT     =2,
     CV_COMP_BHATTACHARYYA =3,
-    CV_COMP_HELLINGER     =CV_COMP_BHATTACHARYYA
+    CV_COMP_HELLINGER     =CV_COMP_BHATTACHARYYA,
+    CV_COMP_CHISQR_ALT    =4
 };
 
 /* Mask size for distance transform */
index 0825258..f0a7818 100644 (file)
@@ -1990,12 +1990,12 @@ double cv::compareHist( InputArray _H1, InputArray _H2, int method )
         const float* h2 = (const float*)it.planes[1].data;
         len = it.planes[0].rows*it.planes[0].cols*H1.channels();
 
-        if( method == CV_COMP_CHISQR )
+        if( (method == CV_COMP_CHISQR) || (method == CV_COMP_CHISQR_ALT))
         {
             for( j = 0; j < len; j++ )
             {
                 double a = h1[j] - h2[j];
-                double b = h1[j];
+                double b = (method == CV_COMP_CHISQR) ? h1[j] : h1[j] + h2[j];
                 if( fabs(b) > DBL_EPSILON )
                     result += a*a/b;
             }
@@ -2034,7 +2034,9 @@ double cv::compareHist( InputArray _H1, InputArray _H2, int method )
             CV_Error( CV_StsBadArg, "Unknown comparison method" );
     }
 
-    if( method == CV_COMP_CORREL )
+    if( method == CV_COMP_CHISQR_ALT )
+        result *= 2;
+    else if( method == CV_COMP_CORREL )
     {
         size_t total = H1.total();
         double scale = 1./total;
@@ -2063,13 +2065,13 @@ 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 )
+    if( PH1->nzcount() > PH2->nzcount() && method != CV_COMP_CHISQR && method != CV_COMP_CHISQR_ALT)
         std::swap(PH1, PH2);
 
     SparseMatConstIterator it = PH1->begin();
     int N1 = (int)PH1->nzcount(), N2 = (int)PH2->nzcount();
 
-    if( method == CV_COMP_CHISQR )
+    if( (method == CV_COMP_CHISQR) || (method == CV_COMP_CHISQR_ALT) )
     {
         for( i = 0; i < N1; i++, ++it )
         {
@@ -2077,7 +2079,7 @@ double cv::compareHist( const SparseMat& H1, const SparseMat& H2, int method )
             const SparseMat::Node* node = it.node();
             float v2 = PH2->value<float>(node->idx, (size_t*)&node->hashval);
             double a = v1 - v2;
-            double b = v1;
+            double b = (method == CV_COMP_CHISQR) ? v1 : v1 + v2;
             if( fabs(b) > DBL_EPSILON )
                 result += a*a/b;
         }
@@ -2146,6 +2148,9 @@ double cv::compareHist( const SparseMat& H1, const SparseMat& H2, int method )
     else
         CV_Error( CV_StsBadArg, "Unknown comparison method" );
 
+    if( method == CV_COMP_CHISQR_ALT )
+        result *= 2;
+
     return result;
 }
 
@@ -2485,13 +2490,13 @@ cvCompareHist( const CvHistogram* hist1,
     CvSparseMatIterator iterator;
     CvSparseNode *node1, *node2;
 
-    if( mat1->heap->active_count > mat2->heap->active_count && method != CV_COMP_CHISQR )
+    if( mat1->heap->active_count > mat2->heap->active_count && method != CV_COMP_CHISQR && method != CV_COMP_CHISQR_ALT)
     {
         CvSparseMat* t;
         CV_SWAP( mat1, mat2, t );
     }
 
-    if( method == CV_COMP_CHISQR )
+    if( (method == CV_COMP_CHISQR) || (method == CV_COMP_CHISQR_ALT) )
     {
         for( node1 = cvInitSparseMatIterator( mat1, &iterator );
              node1 != 0; node1 = cvGetNextSparseNode( &iterator ))
@@ -2500,7 +2505,7 @@ cvCompareHist( const CvHistogram* hist1,
             uchar* node2_data = cvPtrND( mat2, CV_NODE_IDX(mat1,node1), 0, 0, &node1->hashval );
             double v2 = node2_data ? *(float*)node2_data : 0.f;
             double a = v1 - v2;
-            double b = v1;
+            double b = (method == CV_COMP_CHISQR) ? v1 : v1 + v2;
             if( fabs(b) > DBL_EPSILON )
                 result += a*a/b;
         }
@@ -2590,6 +2595,9 @@ cvCompareHist( const CvHistogram* hist1,
     else
         CV_Error( CV_StsBadArg, "Unknown comparison method" );
 
+    if( method == CV_COMP_CHISQR_ALT )
+        result *= 2;
+
     return result;
 }
 
index ccdaa74..19ccc65 100644 (file)
@@ -948,7 +948,7 @@ int CV_ThreshHistTest::validate_test_results( int /*test_case_idx*/ )
 class CV_CompareHistTest : public CV_BaseHistTest
 {
 public:
-    enum { MAX_METHOD = 4 };
+    enum { MAX_METHOD = 5 };
 
     CV_CompareHistTest();
 protected:
@@ -1014,6 +1014,8 @@ int CV_CompareHistTest::validate_test_results( int /*test_case_idx*/ )
             result0[CV_COMP_INTERSECT] += MIN(v0,v1);
             if( fabs(v0) > DBL_EPSILON )
                 result0[CV_COMP_CHISQR] += (v0 - v1)*(v0 - v1)/v0;
+            if( fabs(v0 + v1) > DBL_EPSILON )
+                result0[CV_COMP_CHISQR_ALT] += (v0 - v1)*(v0 - v1)/(v0 + v1);
             s0 += v0;
             s1 += v1;
             sq0 += v0*v0;
@@ -1039,6 +1041,8 @@ int CV_CompareHistTest::validate_test_results( int /*test_case_idx*/ )
             result0[CV_COMP_INTERSECT] += MIN(v0,v1);
             if( fabs(v0) > DBL_EPSILON )
                 result0[CV_COMP_CHISQR] += (v0 - v1)*(v0 - v1)/v0;
+            if( fabs(v0 + v1) > DBL_EPSILON )
+                result0[CV_COMP_CHISQR_ALT] += (v0 - v1)*(v0 - v1)/(v0 + v1);
             s0 += v0;
             sq0 += v0*v0;
             result0[CV_COMP_BHATTACHARYYA] += sqrt(v0*v1);
@@ -1053,6 +1057,8 @@ int CV_CompareHistTest::validate_test_results( int /*test_case_idx*/ )
         }
     }
 
+    result0[CV_COMP_CHISQR_ALT] *= 2;
+
     t = (sq0 - s0*s0/total_size)*(sq1 - s1*s1/total_size);
     result0[CV_COMP_CORREL] = fabs(t) > DBL_EPSILON ?
         (result0[CV_COMP_CORREL] - s0*s1/total_size)/sqrt(t) : 1;
@@ -1067,6 +1073,7 @@ int CV_CompareHistTest::validate_test_results( int /*test_case_idx*/ )
         double v = result[i], v0 = result0[i];
         const char* method_name =
             i == CV_COMP_CHISQR ? "Chi-Square" :
+            i == CV_COMP_CHISQR_ALT ? "Alternative Chi-Square" :
             i == CV_COMP_CORREL ? "Correlation" :
             i == CV_COMP_INTERSECT ? "Intersection" :
             i == CV_COMP_BHATTACHARYYA ? "Bhattacharyya" : "Unknown";