1.什么是直方图?
举个例子:
2.直方图均衡化
代码:
//先要将图像转换为灰度图像
cvtColor(src, gray_src, CV_BGR2GRAY);
namedWindow("input_image", WINDOW_AUTOSIZE);
namedWindow("output_Img", WINDOW_AUTOSIZE);
imshow("input_image", gray_src);
//直方图均衡化--一般用于提高图像对比度
equalizeHist(gray_src, dst);
imshow("output_Img", dst);
3.计算直方图及绘制直方图
具体使用:
//计算并绘制直方图
//先将多通道图片分通道表示--分成b,g,r
vector<Mat> bgr_planes;
split(src, bgr_planes);//分割好的图像,分别存在Mat数组的0,1,2位置
//计算直方图
int histSize = 256;//划分为256个等级
float range[] = { 0,255 };//范围定义为0-255
const float* histRanges = { range };
Mat b_hist, g_hist, r_hist;//定义三个数组存储
calcHist(&bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRanges, true, false);//计算直方图并存储到对应数组
calcHist(&bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRanges, true, false);//计算直方图并存储到对应数组
calcHist(&bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRanges, true, false);//计算直方图并存储到对应数组
//图像归一化
//归一化就是要把需要处理的数据经过处理后(通过某种算法)限制在你需要的一定范围内。
//归一化数据
int hist_h = 400;
int hist_w = 512;
int bin_w = hist_w / histSize;
Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));
normalize(b_hist, b_hist, 0, hist_h, NORM_MINMAX, -1, Mat());//0-下限 , hist_h归一化范围上限
normalize(g_hist, g_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
normalize(r_hist, r_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
//画出直方图
for (int i = 1; i < histSize; i++)
{
//直方图从左下角开始
//cvRound():返回跟参数最接近的整数值,即四舍五入
line(histImage, Point((i - 1) * bin_w, hist_h - cvRound(b_hist.at<float>(i - 1))),
Point((i)*bin_w, hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, LINE_AA);
line(histImage, Point((i - 1) * bin_w, hist_h - cvRound(g_hist.at<float>(i - 1))),
Point((i)*bin_w, hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), 2, LINE_AA);
line(histImage, Point((i - 1) * bin_w, hist_h - cvRound(r_hist.at<float>(i - 1))),
Point((i)*bin_w, hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255), 2, LINE_AA);
}
imshow("output_img", histImage);
在完成以上步骤后,就可以通过API画出一个分别对于BGR三通道的直方图
4.直方图比较
具体直方图对比步骤:
具体代码:
//直方图比较
Mat base, test1, test2;
Mat hsvbase, hsvtest1, hsvtest2;
base = imread("C:/Users/18929/Desktop/博客项目/项目图片/08.jpg");
test1 = imread("C:/Users/18929/Desktop/博客项目/项目图片/01.jpg");
test2 = imread("C:/Users/18929/Desktop/博客项目/项目图片/07.jpg");
//1.先转换为HSV图像
cvtColor(base, hsvbase, CV_BGR2HSV);
cvtColor(test1, hsvtest1, CV_BGR2HSV);
cvtColor(test2, hsvtest2, CV_BGR2HSV);
//设置hue大小为50,saturation(饱和度)值为60
int h_bins = 50; int s_bins = 60;
int histSize[] = { h_bins,s_bins };
//hue值的范围从0-179,饱和度从0-255
float h_ranges[] = { 0,180 };
float s_ranges[] = { 0,256 };
const float* ranges[] = { h_ranges,s_ranges };//范围要用const声明
//使用第零通道到第一通道
int channels[] = { 0,1 };
//MatND -- 多维的Mat对象 Mat-二维,存放直方图的值
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());
//比较直方图
double basebase = compareHist(hist_base, hist_base, CV_COMP_CORREL);//相关性比较,越接近1越相似
double basetest1 = compareHist(hist_base, hist_test1, CV_COMP_BHATTACHARYYA);//巴氏比较,越接近1越相似
double basetest2 = compareHist(hist_base, hist_test2, CV_COMP_BHATTACHARYYA);
double test1test2 = compareHist(hist_test1, hist_test2, CV_COMP_BHATTACHARYYA);
//在图上写结果
Mat test12;
test2.copyTo(test12);//做一张和test2一样的图
putText(base, convertToString(basebase), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, LINE_AA);
putText(test1, convertToString(basetest1), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, LINE_AA);
putText(test2, convertToString(basetest2), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, LINE_AA);
putText(test12, convertToString(test1test2), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, LINE_AA);
namedWindow("base", CV_WINDOW_AUTOSIZE);
namedWindow("test1", CV_WINDOW_AUTOSIZE);
namedWindow("test2", CV_WINDOW_AUTOSIZE);
namedWindow("test12", CV_WINDOW_AUTOSIZE);
imshow("base", base);
imshow("test1", test1);
imshow("test2", test2);
imshow("test12", test12);
waitKey(0);
return 0;
}
//将计算出来的double值转换为字符串打印
string convertToString(double d) {
ostringstream os;
if (os << d)
return os.str();
return "invalid conversion";
}
*/
5.直方图反向映射
https://blog.csdn.net/keith_bb/article/details/70154219
#include<opencv2/opencv.hpp>
#include<math.h>
#include<iostream>
using namespace cv;
using namespace std;
Mat src,dst,gray_src,hsv,hue;
int bins = 12;//定义维度,即分成多少份定义直方图
void Hist_And_Backprojection(int, void*);
int main(int argc, char** argv) {
src = imread("C:/Users/18929/Desktop/博客项目/项目图片/01.jpg");
if (src.empty()) {
printf("could not load image");
return -1;
}
const char* window_image = "input image";
namedWindow(window_image, WINDOW_AUTOSIZE);
//直方图反向映射
//1.转换图片为hsv类图片
cvtColor(src, hsv, CV_BGR2HSV);
//2.将hsv图像的第一通道拷贝到hue图片的第一通道,且拷贝一组
hue.create(hsv.size(), hsv.depth());
int nchannels[] = { 0,0 };//定义从第一通道拷贝到第一通道
mixChannels(&hsv, 1, &hue, 1, nchannels, 1);//1个hsv图像,1个hue图像,按nchannels规则拷贝一组
createTrackbar("Histogram Bins:",window_image,&bins,180,Hist_And_Backprojection);
Hist_And_Backprojection(0, 0);
imshow(window_image, src);
waitKey(0);
return 0;
}
void Hist_And_Backprojection(int, void*) {
//计算直方图
float range[] = { 0,180 };//定义划分直方图范围
const float* histRanges = { range };
Mat h_hist;
calcHist(&hue, 1, 0, Mat(), h_hist, 1, &bins, &histRanges, true, false);
normalize(h_hist, h_hist, 0, 255, NORM_MINMAX, -1, Mat());
//绘制直方反向映射图
Mat backPrjImage;//直方映射图
calcBackProject(&hue, 1, 0, h_hist, backPrjImage, &histRanges, 1, true);
/*
参数解释:
1.const Mat* images:输入图像,图像深度必须位CV_8U,CV_16U或CV_32F中的一种,尺寸相同,每一幅图像都可以有任意的通道数
2.int nimages:输入图像的数量
3.const int* channels:用于计算反向投影的通道列表,通道数必须与直方图维度相匹配,第一个数组的通道是从0到image[0].channels()-1,第二个数组通道从图像image[0].channels()到image[0].channels()+image[1].channels()-1计数
4.InputArray hist:输入的直方图,直方图的bin可以是密集(dense)或稀疏(sparse)
5.OutputArray backProject:目标反向投影输出图像,是一个单通道图像,与原图像有相同的尺寸和深度
6.const float ranges**:直方图中每个维度bin的取值范围
7.double scale=1:可选输出反向投影的比例因子
8.bool uniform=true:直方图是否均匀分布(uniform)的标识符,有默认值true
*/
imshow("BackProj", backPrjImage);
//绘制直方图
int hist_h = 400;
int hist_w = 400;
Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));
int bin_w = (hist_w / bins);//每个bins的宽度
for (int i = 1; i < bins; i++) {
rectangle(histImage, Point((i - 1) * bin_w, (hist_h - cvRound(h_hist.at<float>(i - 1) * 400 / 255))),
Point((i)*bin_w, (hist_h - cvRound(h_hist.at<float>(i) * 400 / 255))), Scalar(0, 0, 255), -1);
}
imshow("Histogram", histImage);
}