绘制直方图
令表示一幅L级灰度数字图像f(x,y)的灰度。非归一化直方图定义为:
是图像f中灰度为的像素数量。
多数情况下我们处理的是归一化直方图。
计算直方图API:
void calcHist( const Mat*images,
int nimages,
const int*channels,
InputArray mask,
OutputArray hist,
int dims,
const int*histSize,
const float**ranges,
bool uniform=true,
boll accumulate=false
);
参数解析:
//const Mat*images:源数组(图像)。输入的数组(图像)都应该有相同的深度(CV_8U,CV_16U,CV32F)和一样的尺寸。它们可以是不同通道;
//int nimages:源数组(图像)的数量;
//const int*channels:选择输入源数组(图像)的通道,计算该通道的直方图;
//InputArray mask:掩膜,不使用掩膜则为:Mat();
// OutputArray hist:输出直方图;
//int dims:直方图维度;
//const int*histSize:输出直方图尺寸;
如果dims=1,则输出的直方图为一个 1 X histSizedede 的矩阵,这个矩阵存放像素出现的次数;
如果dims=2,则输出的直方图为一个 hSize X wSize 的矩阵;
//const float**ranges:表示要计算直方图的通道的取值范围;
//bool uniform = true:表示直方图是否归一化的标志;
//bool accumulate = false:在多个图象时,是否积累计算像素值的个数;
归一化直方图API:
void normalize(InputArray src,
InputOutpurArray dst,
double alpha=1,
double beta=0,
int norm_type,
int dtype,
InputArray mask
)
参数解析:
//InputArray src:输入需要归一化数组(图像);
//InputOutputArray dst:输出已归一化的数组(图像);
//double alpha=1:在范围归一化的情况下,要归一化到的范数值或较低的范围边界;
//double beta=0:在范围归一化的情况下的上范围边界;它不用于范数归一化;
//int norm_type:归一化类型;
NORM_INF:
NORM_L1:
NORM_L2 :
NORM_MINMAX:数组的的数组被归一化到指定范围
//int dtype:输出图像的类型;
//InputArray mask:掩膜,不使用掩膜则为:Mat();
绘制一维直方图:
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace cv;
int main(int argc, char** argv)
{
Mat src = imread("C:/picture/source.jpg");
//选着需要计算直方图的通道
int channels = 0;
//设定直方图有多少个bin
int bins= 32;
int histsize[] = { bins };
//计算通道像素的取值范围
float range[] = { 0,256 };
const float* ranges[]= { range };
//计算直方图
Mat hist;
calcHist(&src, 1, &channels, Mat(), hist, 1, histsize, ranges, true, false);
//归一化直方图
normalize(hist, hist, 0,histImg.rows , NORM_MINMAX, -1, Mat());
//绘制直方图并显示
int scale=10;
Mat histImg = Mat::zeros(Size(32*scale, 32*scale), CV_8UC3);
for (int i = 0; i < bins-1 ;i++)
line(histImg, Point(i*scale, histImg.rows-cvRound(hist.at<float>(i))), Point((i + 1)*scale, histImg.rows-cvRound(hist.at<float>(i + 1))), Scalar(255, 0, 0), 1,LINE_AA);
imshow("histImge", histImg);
waitKey();
return 0;
}
直方图比较
直方图比较用于比较两张图像的相似程度。直方图比较可以用于图像分类、特征提取和匹配等应用领域。
直方图比较API:
double compareHist(InputArray H1,
InputArray H2,
int method );
参数解析:
//InputArray H1:第一个需要比较的直方图;
//InputArray H2: 第二个比较直方图,大小与第一个直方图相同;
//int method:两个直方图比较的方法;
HISTCMP_CORREL :
相关性比较,越接近1越相似;
HISTCMP_CHISQR :
卡方比较,越接近0越相似;
HISTCMP_INTERSECT :
十字交叉性比较,这个方法用于相似度比较不太好;
HISTCMP_BHATTACHARYYA :
巴氏距离,越接近1越相似;
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
int main(int argc, char** argv)
{
Mat test1, test2;
test1 = imread("C:/picture/study1.jpg");
test2 = imread("C:/picture/study2.jpg");
cvtColor(test1, test1, CV_BGR2HSV);
cvtColor(test2, test2, CV_BGR2HSV);
imshow("test1", test1);
imshow("test2", test2);
int channel[] = { 0,1 };
int histSize[] = { 30,32 };
float s_ranges[] = { 0,180 };
float h_ranges[] = { 0,256 };
const float* ranges[] = { s_ranges,h_ranges };
Mat test1_Hist;
calcHist(&test1,1,channel,Mat(),test1_Hist,2,histSize,ranges,true,false);
normalize(test1_Hist, test1_Hist, 0, 1, NORM_MINMAX);
Mat test2_Hist;
calcHist(&test2, 1, channel, Mat(), test2_Hist,2, histSize, ranges, true, false);
normalize(test2_Hist, test2_Hist, 0, 1, NORM_MINMAX);
double correlation= compareHist(test1_Hist, test2_Hist, HISTCMP_CORREL);
std::cout << "correlation: " << correlation << std::endl;
waitKey(0);
return 0;
}
直方图反向投影
直方图反向投影可以根据一张参考图像的直方图分布来寻找目标图像中具有相似分布的像素。该技术常用于计算机视觉中的物体检测和跟踪。
反向投影图像的像素值表示的是每个像素点在特定图像特征的空间上与目标物体相关的概率值,即越高的概率值表示该像素点越可能属于目标物体。
直方图反向投影API:
void cv::calcBackProject(const Mat*images,
int nimages,
const int*channels,
InputArray hist,
OutputArray backProject,
const float**ranges,
double scale = 1,
bool uniform = true )
参数解析:
//const Mat*images:源数组(图像)。输入的数组(图像)都应该有相同的深度(CV_8U,CV_16U,CV32F)和一样的尺寸。它们可以是不同通道;
//int nimages:源数组(图像)的数量;
//const int*channels:选择输入源数组(图像)的通道,计算该通道的直方图;
//InputArray hist:用于计算反向投影的通道列表,通道数必须与直方图维度匹配;
//OutputArray backProject:反向投影图像,它与源数组(图像)相同的大小和深度,但它是单通道的;
//const float**ranges:直方图每个维度的取值范围;
//double scale = 1:输出反向投影的比例因子;
//bool uniform = true: 表示直方图是否归一化的标志;
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main(int agrc,char**agcv)
{
Mat tempImg=imread("C:/picture/template.jpg");
cvtColor(tempImg, tempImg, CV_BGR2HSV);
int channels[] = { 0,1 };
int h_bins = 30, s_bins = 32;
int histSize[] = { h_bins,s_bins };
float h_ranges[] = { 0,180 };
float s_ranges[] = { 0,255 };
const float* ranges[] = { h_ranges,s_ranges };
Mat tempImg_Hist;
calcHist(&tempImg, 1, channels, Mat(), tempImg_Hist, 2, histSize, ranges, true, false);
normalize(tempImg_Hist, tempImg_Hist, 0, 255, NORM_MINMAX, -1, Mat());
Mat source_targetImg = imread("C:/picture/source.jpg");
Mat targetImg;
cvtColor(source_targetImg, targetImg, CV_BGR2HSV);
Mat targetImg_Hist;
calcHist(&targetImg, 1, channels, Mat(), targetImg_Hist, 2, histSize, ranges, true, false);
normalize(tempImg_Hist, tempImg_Hist, 0, 255, NORM_MINMAX, -1, Mat());
Mat backproj;
calcBackProject(&targetImg, 1, channels, tempImg_Hist, backproj, ranges, 1, true);
Mat mask(source_targetImg.size(), CV_8UC1);
threshold(backproj, mask, 100, 255, THRESH_BINARY);
erode(mask, mask, getStructuringElement(MORPH_CROSS, Size(3, 3), Point(-1, -1)));
imshow("backproj",mask);
Mat resultImg;
source_targetImg.copyTo(resultImg);
resultImg.setTo(Scalar(0,0,255), mask);
imshow("resultImg", resultImg);
waitKey();
return -1;
}