相关理论
-
直方图概念
- 按照灰度等级进行统计
- 上述直方图概念是基于图像像素值,其实对图像梯度、每个像素的角度等一切图像的属性值,我们都可以建立直方图。这个才是直方图的概念真正意义,不过是基于图像像素灰度直方图是最常见的。
- 直方图最常见的几个属性:
- dims 表示维度,对灰度图像来说只有一个通道值dims=1
- bins 表示在维度中子区域大小划分,bins=256,划分为256个级别
- range 表示值得范围,灰度值范围为[0~255]之间
-
API学习
split(// 把多通道图像分为多个单通道图像 const Mat &src, //输入图像 Mat* mvbegin)// 输出的通道图像数组 calcHist( const Mat* images,//输入图像指针 int images,// 图像数目 const int* channels,// 通道数 InputArray mask,// 输入mask,可选,不用 OutputArray hist,//输出的直方图数据 int dims,// 维数 const int* histsize,// 直方图级数 const float* ranges,// 值域范围 bool uniform,// true by default bool accumulate// false by default )
-
直方图比较方法
- 对输入的两张图像计算得到直方图H1与H2,归一化到相同的尺度空间,然后可以通过计算H1与H2的之间的距离得到两个直方图的相似程度进而比较图像本身的相似程度、图像的相关性。即,先使用
calcHist
计算得到直方图H1 与 H2,然后通过下面几种方法计算H1、H2的相似程度。 - Opencv提供的比较方法有四种:
- Correlation 相关性比较
- Chi-Square 卡方比较
- Intersection 十字交叉性
- Bhattacharyya distance 巴氏距离
- 对输入的两张图像计算得到直方图H1与H2,归一化到相同的尺度空间,然后可以通过计算H1与H2的之间的距离得到两个直方图的相似程度进而比较图像本身的相似程度、图像的相关性。即,先使用
-
直方图比较方法:相关性计算(CV_COMP_CORREL)
d ( H 1 , H 2 ) = ∑ I ( H 1 ( I ) − H ˉ 1 ) ( H 2 ( I ) − H ˉ 2 ) ∑ I ( H 1 ( I ) − H ˉ 1 ) 2 ∑ I ( H 2 ( I ) − H ˉ 2 ) 2 d\left(H_{1}, H_{2}\right)=\frac{\sum_{I}\left(H_{1}(I)-\bar{H}_{1}\right)\left(H_{2}(I)-\bar{H}_{2}\right)}{\sqrt{\sum_{I}\left(H_{1}(I)-\bar{H}_{1}\right)^{2} \sum_{I}\left(H_{2}(I)-\bar{H}_{2}\right)^{2}}} d(H1,H2)=∑I(H1(I)−Hˉ1)2∑I(H2(I)−Hˉ2)2∑I(H1(I)−Hˉ1)(H2(I)−Hˉ2),其中 H ˉ k = 1 N ∑ J H k ( J ) \bar{H}_{k}=\frac{1}{N} \sum_{J} H_{k}(J) Hˉk=N1∑JHk(J),其中N是直方图的BIN个数, H ˉ \bar{H} Hˉ是均值。 -
直方图比较方法-卡方计算(CV_COMP_CHISQR)
- d ( H 1 , H 2 ) = ∑ I ( H 1 ( I ) − H 2 ( I ) ) 2 H 1 ( I ) d\left(H_{1}, H_{2}\right)=\sum_{I} \frac{\left(H_{1}(I)-H_{2}(I)\right)^{2}}{H_{1}(I)} d(H1,H2)=∑IH1(I)(H1(I)−H2(I))2
- H1,H2分别表示两个图像的直方图数据
-
直方图比较方法-十字计算(CV_COMP_INTERSECT)
- d ( H 1 , H 2 ) = ∑ I min ( H 1 ( I ) , H 2 ( I ) ) d\left(H_{1}, H_{2}\right)=\sum_{I} \min \left(H_{1}(I), H_{2}(I)\right) d(H1,H2)=∑Imin(H1(I),H2(I)), H ˉ \bar{H} Hˉ是均值。
- H1,H2分别表示两个图像的直方图数据
-
直方图比较方法-巴氏距离计算(CV_COMP_BHATTACHARYYA )
- d ( H 1 , H 2 ) = 1 − 1 H 1 H 2 N 2 ∑ I H 1 ( I ) ⋅ H 2 ( I ) d\left(H_{1}, H_{2}\right)=\sqrt{1-\frac{1}{\sqrt{H_{1} H_{2} N^{2}}} \sum_{I} \sqrt{H_{1}(I) \cdot H_{2}(I)}} d(H1,H2)=1−H1H2N21∑IH1(I)⋅H2(I), H ˉ \bar{H} Hˉ是均值。
- H1,H2分别表示两个图像的直方图数据
-
相关API
- 首先把图像从RGB色彩空间转换到HSV色彩空间cvtColor
- 计算图像的直方图,然后归一化到[0~1]之间calcHist和normalize;
- 使用上述四种比较方法之一进行比较compareHist
-
相关API cv::compareHist
compareHist( InputArray h1, // 直方图数据,下同 InputArray H2, int method// 比较方法,上述四种方法之一 )
完整代码 & 运行效果
calcHist
函数在直方图比较的时候会用到,下面给出直方图比较的完整例子,已经使用到了calcHist
函数,不再单独列出。
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/types_c.h>
using namespace std;
using namespace cv;
#ifndef P25
#define P25 25
#endif
int main() {
std::string path = "../color_line.JPG";
cv::Mat img = cv::imread(path, 5);
if(img.empty())
{
std::cout << "open file failed" << std::endl;
return -1;
}
#if P25
#if P26 //直方图比较
Mat hsvbase, hsvtest1, hsvtest2;
Mat test1, test2,base;
base = img;
test1 = imread("../color_line.jpg");
test2 = imread("../circle.jpg");
cvtColor(base, hsvbase, CV_BGR2HSV);
cvtColor(test1, hsvtest1, CV_BGR2HSV);
cvtColor(test2, hsvtest2, CV_BGR2HSV);
int h_bins = 50; int s_bins = 60;
int histSize[] = { h_bins, s_bins };
// hue varies from 0 to 179, saturation from 0 to 255
float h_ranges[] = { 0, 180 };
float s_ranges[] = { 0, 256 };
const float* ranges[] = { h_ranges, s_ranges };
// Use the o-th and 1-st channels
int channels[] = { 0, 1 };
MatND hist_base;
MatND hist_test1;
MatND hist_test2;
calcHist(&hsvbase, 1, channels, Mat(), hist_base, 2, histSize, ranges, true, false);
normalize(hist_base, hist_base, 0, 1, NORM_MINMAX, -1, Mat());
calcHist(&hsvtest1, 1, channels, Mat(), hist_test1, 2, histSize, ranges, true, false);
normalize(hist_test1, hist_test1, 0, 1, NORM_MINMAX, -1, Mat());
calcHist(&hsvtest2, 1, channels, Mat(), hist_test2, 2, histSize, ranges, true, false);
normalize(hist_test2, hist_test2, 0, 1, NORM_MINMAX, -1, Mat());
//使用宏定义,避免每次都修改compareHist函数中的参数
#define COMP_WAY CV_COMP_CORREL
//#define COMP_WAY CV_COMP_INTERSECT
//#define COMP_WAY CV_COMP_CHISQR
//#define COMP_WAY CV_COMP_BHATTACHARYYA
double basebase = compareHist(hist_base, hist_base, COMP_WAY);
double basetest1 = compareHist(hist_base, hist_test1, COMP_WAY);
double basetest2 = compareHist(hist_base, hist_test2, COMP_WAY);
double tes1test2 = compareHist(hist_test1, hist_test2, COMP_WAY);
printf("test1 compare with test2 correlation value :%f", tes1test2);
Mat test12;
test2.copyTo(test12);
putText(base, convertToString(basebase), Point(50, 50), FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, LINE_AA);
putText(test1, convertToString(basetest1), Point(50, 50), FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, LINE_AA);
putText(test2, convertToString(basetest2), Point(50, 50), FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, LINE_AA);
putText(test12, convertToString(tes1test2), Point(50, 50), FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, LINE_AA);
namedWindow("base", WINDOW_AUTOSIZE);
namedWindow("test1", WINDOW_AUTOSIZE);
namedWindow("test2", WINDOW_AUTOSIZE);
imshow("base", base);
imshow("test1", test1);
imshow("test2", test2);
imshow("test12", test12);
#endif
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
下面几个宏定义显示了直方图H1与H2的距离的集中不同计算方法,为了方便使用,所以使用了宏定义,将自己需要使用的方法去掉注释即可使用。
//使用宏定义,避免每次都修改compareHist函数中的参数
#define COMP_WAY CV_COMP_CORREL
//#define COMP_WAY CV_COMP_INTERSECT
//#define COMP_WAY CV_COMP_CHISQR
//#define COMP_WAY CV_COMP_BHATTACHARYYA
基于相关性计算的运行效果: