直方图匹配、对比:calcHist ,minMaxLoc,compareHist
参考博客:
灰度直方图(一维直方图)calcHist()函数、minMaxLoc()函数、normalize()函数
直方图(Histogram)又称柱状图、质量分布图,是一种统计报告图。直方图由一系列高度不等的纵向条纹或线段表示数据分布的情况。一般用横轴表示数据类型,纵轴表示分布情况。在图像处理上,直方图是图像信息统计的有力工具
1、calcHist()函数
用于计算一个或者多个这列的直方图
void calcHist(
const Mat* images, // 输入的数组或数组集 CV_8U 或CV_32F
int nimages, // 输入数组的个数 (几幅图像)
const int* channels, // 需要统计直方图的第几通道(dim)
InputArray mask, // 掩膜,计算掩膜内的直方图
OutputArray hist, // 输出的直方图数组,一个二维数组
int dims, // 需要统计直方图通道的个数(需要统计的特征的数目)
const int* histSize, // bin的个数,指的是直方图分成多少个区间
const float** ranges, // 每一维数值的取值范围,统计像素值得区间如:[0,255]
bool uniform=true, // 是否对得到的直方图数组进行归一化处理
bool accumulate=false // 在多个图像时,是否累计计算像素值得个数
)
2、归一化:normalize()函数
查找数组中的全局最小值和最大值。
void normalize(
InputArray src, // 输入数组(图像)
OutputArray dst, // 输出数组(图像),与输入图像类型尺寸一样
double alpha=1, // 表示range normalization模式的最小值。
double beta=0, // 表示range normalization模式的最大值,不用于norm normalization(范数归一化)模式。
int norm_type=NORM_L2, // 表示归一化的类型,可以有以下的取值:
// NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化,一般较常用。
// NORM_INF:此类型的定义没有查到,根据OpenCV 1的对应项,可能是归一化数组的C-范数(绝对值的最大值)。
// NORM_L1:归一化数组的L1-范数(绝对值的和)。
// NORM_L2:归一化数组的(欧几里德)L2-范数。
int dtype=-1, // dtype为负数时,输出数组的type与输入数组的type相同;否则,输出数组与输入数组只是通道数相同,而tpye=CV_MAT_DEPTH(dtype)。
InputArray mask=noArray() // 操作掩膜,用于指示函数是否仅仅对指定的元素进行操作。
);
3、minMaxLoc()函数
寻找矩阵(一维数组当作向量,用Mat定义) 中最小值和最大值的位置。
minMaxLoc函数的其他应用:
寻找一幅图像的匹配的模板,可以在一段视频里寻找出我们感兴趣的东西,比如条形码的识别就可能需要这样类似的一个工作提取出条形码区域(当然这样的方法并不鲁棒)。而OpenCV已经为我们集成好了相关的功能。函数为matchTemplate。
所谓模板匹配就是在一幅图像中寻找和模板图像(patch)最相似的区域。该函数的功能为,在输入源图像Source image(I)中滑动框,寻找各个位置与模板图像Template image(T)的相似度,并将结果保存在结果矩阵result matrix(R)中。该矩阵的每一个点的亮度表示与模板T的匹配程度。然后可以通过函数minMaxLoc定位矩阵R中的最大值(该函数也可以确定最小值)。
void cv::minMaxLoc(
InputArray src, // 输入单通道阵列
double * minVal, // 指向返回的最小值的指针;如果不需要,则使用NULL。
double * maxVal = 0, // 指向返回的最大值的指针;如果不需要,则使用NULL。
Point * minLoc = 0, // 指向返回的最小位置的指针(二维情况下);如果不需要,则使用NULL。
Point * maxLoc = 0, // 指向返回的最大位置的指针(二维情况下);如果不需要,则使用NULL。
InputArray mask = noArray() // 用于选择子数组的可选掩码。
)
4、compareHist()函数
对输入的两张图像进行直方图均衡化及直方图计算步骤后,可以对两个图像的直方图进行对比,并通过对比的结果得到一些我们想要的结论。
直方图比较应用
1)图像相似度比较
如果我们有两张图像,并且这两张图像的直方图一样,或者有极高的相似度,那么在一定程度上,我们可以认为这两幅图是一样的,这就是直方图比较的应用之一。
2)分析图像之间关系
两张图像的直方图反映了该图像像素的分布情况,可以利用图像的直方图,来分析两张图像的关系。
// 原型一
double compareHist(
InputArray H1, // 第一个直方图
InputArray H2, // 第二,比较与H1大小相同的直方图(直方图尺寸相同,图片可以不同)
int method //
)
// 原型二
double compareHist(
const SparseMat &H1,
const SparseMat &H2,
int method
)
4种衡量直方图相似度的对比标准:(H1表示第一直方图,H2第二直方图)
OpenCv提供了5种对比直方图的方式:CORREL(相关)、CHISQR(卡方)、INTERSECT(相交)、BHATTACHARYYA、EMD(最小工作距离),其中CHISQR速度最快,EMD速度最慢且有诸多限制,但是EMD的效果最好
1).相关系数的标准,Correlation(method=CV_COMP_CORREL)值越大,相关度越高,最大值为1,最小值为0;且N等于直方图中bin的个数。
2).卡方系数的标准(method=CV_COMP_CHISQR)值越小,相关度越高,最大值无上界,最小值0;
c.相交系数的标准(method=CV_COMP_INTERSECT)值越大,相关度越高,最大值为9.455319,最小值为0;
d.巴氏系数(Bhattacharyya)的标准(method=CV_COMP_BHATTACHARYYA)值越小,相关度越高,最大值为1,最小值为0
5、示例一:H-S彩色图像的色调、饱和度二维直方图绘制
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
//1、载入源图,转化为HSV颜色空间(2通道,故统计两中特征两:色调,饱和度)
Mat srcImage, hsvImage;
srcImage = imread("F:/C++/2. OPENCV 3.1.0/TEST/1.jpg", 1);
if(!srcImage.data ) {
printf("读取图片错误,请确定目录下是否有imread函数指定图片存在~! \n"); return false; }
cvtColor(srcImage,hsvImage, CV_BGR2HSV);
// 2、参数准备
//将色调量化为30个等级,将饱和度量化为32个等级
int hueBinNum = 30; // 色调的直方图直条数量
int saturationBinNum = 32; // 饱和度的直方图直条数量
int histSize[ ] = {
hueBinNum, saturationBinNum};
// 定义色调的变化范围为0到179
// 定义饱和度的变化范围为0(黑、白、灰)到255(纯光谱颜色)
float hueRanges[] = {
0, 180 };
float saturationRanges[] = {
0, 256 };
const float* ranges[] = {
hueRanges, saturationRanges };
MatND dstHist;
//参数准备,calcHist函数中将计算第0通道和第1通道的直方图
int channels[] = {
0, 1};
// 3、正式调用calcHist,进行直方图计算
calcHist( &hsvImage, // 输入的数组
1, // 数组个数为1
channels, // 通道索引 0, 1 通道
Mat(), // 不使用掩膜
dstHist, // 输出的目标直方图
2, // 需要计算的直方图的维度为2
histSize, // 存放每个维度的直方图尺寸的数组
ranges, // 每一维数值的取值范围数组
true, // 指示直方图是否均匀的标识符,true表示均匀的直方图
false ); // 累计标识符,false表示直方图在配置阶段会被清零
// 4、为绘制直方图准备参数