OpenCvSharp 学习笔记24--直方图比较

一,直方图比较方法概述:

对输入的两张图像计算得到直方图H1和H2,归一化到相同的尺度空间(如果比较的两个图像的大小不一致,计算直方图后得到的像素频次不一致,无法比较,必须归一化到相同的尺度空间才可以比较) 然后通过计算H1和H2的之间的距离得到两个直返图的相似程度进而比较图像本身的相似程度.OpenCV提供的比较方法有四种:

1:Correlation 相关性比较:
d c o r r e l ( H 1 , H 2 ) = ∑ I ( H 1 ( I ) − H ˉ 1 ) ( H 2 ( H ) − H ˉ 2 ) ∑ I ( H 1 ( I ) − H ˉ 1 ) 2 ∑ ( H 2 ( I ) − H ˉ 2 ) 2 d_{correl}(H_1,H_2)=\frac{\sum_I(H_1(I)-\bar H_1)(H_2(H)-\bar H_2)}{\sqrt {\sum_I{(H_1(I)-\bar H_1)^2 \sum(H_2(I)- \bar H_2)^2}}} dcorrel(H1,H2)=I(H1(I)Hˉ1)2(H2(I)Hˉ2)2 I(H1(I)Hˉ1)(H2(H)Hˉ2)

H ˉ \bar H Hˉ :是均值 H ˉ k = ∑ J H K ( J ) N \bar H_k=\frac{\sum_JH_K(J)}{N} Hˉk=NJHK(J) N : N: N:为直方图区间(bins)的个数。
H 1 ; H 2 H_1 ;H_2 H1;H2 :比较的两个直方图数据集(梯度范围一致)

分子: H 1 H_1 H1 的直方图每个值 减去它的均值, H 2 H_2 H2 的直方图每个值 减去它的均值 得到两个值相乘,再求总和
分母: 和分子计算方式差不多,求的是方差总和,然后再开平方。

结论: 大相关性系数要比小相关性系数匹配的好。完全匹配的相关性系数为1,而完全 不匹配会得到 -1。而 0 对应着两个分布没有关系(随机组合)。

2:Chi- Square 卡方比较:

d C h i − S q u a r e ( H 1 , H 2 ) = ∑ I ( H 1 ( I ) − H 2 ( I ) ) 2 H 1 ( I ) d_{Chi- Square}(H_1,H_2)=\sum_I \frac{(H_1(I)-H_2(I))^2}{H_1(I)} dChiSquare(H1,H2)=IH1(I)(H1(I)H2(I))2

H 1 , H 2 H_1,H_2 H1,H2:表示两个直方图数据集,梯度范围一致)。 I I I :直方图bins级别中的每一个值。
由上面的公式可以推到处:低分值表示直方图匹配的很好。如果两幅图像一样则 为 0 。而完全不匹配的值无下限(依赖直方图的大小)。

3:Intersection 交集法:
直方图交集法,简单基于两个直方图的交集,该方法对两个直方图中的共同部分求和。

d I n t e r s e c t i o n ( H 1 , H 2 ) = ∑ I min ⁡ ( H 1 ( I ) , H 2 ( I ) ) d_{Intersection }(H_1,H_2)=\sum_I \min(H_1(I),H_2(I)) dIntersection(H1,H2)=Imin(H1(I),H2(I))
H 1 , H 2 H_1,H_2 H1,H2:表示两个直方图数据集,梯度范围一致)。

这个公式比较简单。对于该度量方法,高分值意味着匹配较好,如果两个直方图都进行了归一化,完全匹配对应的值是1 ,完全不匹配对应的值是 0 。

4:Bhattacharyya distance method 巴氏距离:
是对两个分布重叠度的一种度量方法。
d c o r r e l ( H 1 , H 2 ) = 1 − ∑ I H 1 ( I ) ∗ H 2 ( I ) H ˉ 1 H ˉ 2 N 2 d_{correl}(H_1,H_2)={\sqrt {1-\frac{\sum_I \sqrt {H_1(I)*H_2(I)}}{\sqrt{\bar H_1 \bar H_2 N^2}}}} dcorrel(H1,H2)=1Hˉ1Hˉ2N2 IH1(I)H2(I)
H 1 , H 2 H_1,H_2 H1,H2:表示两个直方图数据集,梯度范围一致)。
H ˉ \bar H Hˉ :是均值
N : N: N:为直方图区间(bins)的个数。

结论: 匹配效果越好 ,值越小。效果越差,值越大。完全匹配是 0 ,而完全不匹配是1。

二 ,使用步骤和API:

  1. 首先把图像从RGB色彩空间转换到HSV色彩空间
  2. 计算图像的直方图,然后归一化到 ( 0 ~ 1) 之间
  3. 使用上面介绍的4中方法比较 ,API: Cv2.CompareHist

Cv2.CompareHist(): 返回比较结果 double 类型。

参数 描述
InputArray h1 比较的第一个直方图
InputArray h2 比较的第二个直方图
HistCompMethods method 直方图的比较方法,枚举类型

三, 代码:

static Mat baseMat, src1, src2;
        private static void HistogarmToComparison(string path1, string path2, string path3)
        {
            using (baseMat = new Mat(path1, ImreadModes.AnyColor | ImreadModes.AnyDepth))
            using (src1 = new Mat(path2, ImreadModes.AnyColor | ImreadModes.AnyDepth))
            using (src2 = new Mat(path3, ImreadModes.AnyColor | ImreadModes.AnyDepth))
            {
                //1:从BGR空间转换到HSV色彩空间


                Mat baseHSV = new Mat();
                Mat src1HSV = new Mat();
                Mat src2HSV = new Mat();


                Cv2.CvtColor(baseMat, baseHSV, ColorConversionCodes.BGR2HSV);
                Cv2.CvtColor(src1, src1HSV, ColorConversionCodes.BGR2HSV);
                Cv2.CvtColor(src2, src2HSV, ColorConversionCodes.BGR2HSV);
                //Mat[] mats = new Mat[] { baseHSV, src1HSV, src2HSV };
                Mat[] mats1 = Cv2.Split(baseHSV);
                Mat[] mats2 = Cv2.Split(src1HSV);
                Mat[] mats3 = Cv2.Split(src2HSV);

                //计算直方图并归一化数据

                int bin1 = 50; //灰度等级
                int bin2 = 60;//灰度等级
                int[] histSiz = { bin1, bin2 };

                int[] channels = { 0, 1 };//图像通道数
                Rangef[] rangefs = new Rangef[] //梯度值范围
               {
                    new Rangef(0, 180),
                    new Rangef(0,256)
               };

                Mat baseHist = new Mat(baseMat.Size(), MatType.CV_32FC2);
                Mat src1Hist = new Mat(src1.Size(), MatType.CV_32FC2);
                Mat src2Hist = new Mat(src2.Size(), MatType.CV_32FC2);

                Cv2.CalcHist(mats1, channels, new Mat(), baseHist, 2, histSiz, rangefs, true, false);
                Cv2.Normalize(baseHist, baseHist, 0, 1, NormTypes.MinMax, -1, null);

                Cv2.CalcHist(mats2, channels, new Mat(), src1Hist, 2, histSiz, rangefs, true, false);
                Cv2.Normalize(src1Hist, src1Hist, 0, 1, NormTypes.MinMax, -1, null);

                Cv2.CalcHist(mats3, channels, new Mat(), src2Hist, 2, histSiz, rangefs, true, false);
                Cv2.Normalize(src2Hist, src2Hist, 0, 1, NormTypes.MinMax, -1, null);

                //比较直方图
                double bcomb = Cv2.CompareHist(baseHist, baseHist, HistCompMethods.Correl);
                double s1coms2 = Cv2.CompareHist(src1Hist, src2Hist, HistCompMethods.Correl);
                double bcoms1 = Cv2.CompareHist(baseHist, src1Hist, HistCompMethods.Correl);
                double bcoms2 = Cv2.CompareHist(baseHist, src2Hist, HistCompMethods.Correl);

                Mat mats1Ands2 = new Mat();
                src2.CopyTo(mats1Ands2);

                Cv2.PutText(baseMat, bcomb.ToString(), new Point(30, 30), HersheyFonts.HersheyComplex, 1, new Scalar(0, 255, 0), 2, LineTypes.AntiAlias);

                Cv2.PutText(src1, bcoms1.ToString(), new Point(30, 30), HersheyFonts.HersheyComplex, 1, new Scalar(0, 255, 0), 2, LineTypes.AntiAlias);

                Cv2.PutText(src2, bcoms2.ToString(), new Point(30, 30), HersheyFonts.HersheyComplex, 1, new Scalar(0, 255, 0), 2, LineTypes.AntiAlias);

                Cv2.PutText(mats1Ands2, s1coms2.ToString(), new Point(30, 30), HersheyFonts.HersheyComplex, 1, new Scalar(0, 255, 0), 2, LineTypes.AntiAlias);

                using (new Window("b_com_b :baseMat", WindowMode.Normal, baseMat))
                using (new Window("b_com_s1 :src1", WindowMode.Normal, src1))
                using (new Window("b_com_s2 :src2", WindowMode.Normal, src2))
                using (new Window("s1_com_s2 :mats1Ands2", WindowMode.Normal, mats1Ands2))
                {
                    Cv2.WaitKey(0);
                }

            }
        }

输出比较结果:

你可能感兴趣的:(学习笔记)