OpenCV图像处理教程C++(十八) 直方图均衡化、计算、比较、反向投影
直方图均衡化:
直方图(Histogram): 是指对整个图像像在灰度范围内的像素值(0~255)统计出现频率次数,据此生成的直方图,称为图像直方图-直方图。
直方图反映了图像灰度的分布情况。是图像的统计学特征。
直方图均衡化: 是一种提高图像对比度的方法,拉伸图像灰度值范围。让图像更均衡。对于图像的特征提取是非常有用的
通过remap我们知道可以将图像灰度分布从一个分布映射到另外一个分布,然后在得到映射后的像素值即可。
提升对比度:就是图像中所有的像素值之间的差异都比较明显
API:
equalizeHist( src,8单通道 dst) */
代码:
#include <opencv2/opencv.hpp> #include<iostream> #include<math.h> #include <string> #include<fstream> using namespace cv; using namespace std; int main() { Mat src, graysrc,dst; src = imread("C:\\Users\\Administrator\\Desktop\\pic\\z2.jpg"); imshow("input", src); cvtColor(src, graysrc,CV_RGB2GRAY); imshow("graysrc", graysrc); equalizeHist(graysrc, dst); imshow("dst", dst); waitKey(0); }
结果:
直方图计算:
我们队图像灰度,梯度,每个像素的角度,等一切图像的属性值都可以建立直方图,基于图像像素灰度直方图最常见。
直方图的几个常见属性:
dims表示维度。对灰度图像来说只有一个通道值dims=1
bins表示维度中子区域大小划分,bins=256,划分为256个等级
range表示值的范围,灰度值范围0-255
API:
calcHist( const Mat*src,//输入图像的指针 int images,//图像数目, 这些图像要有相同大大小,相同的深度(CV_8U CV_16U CV_32F) const int*channels,//通道数 mask,//可选的掩码 可选的掩码,不使用时可设为空。要和输入图像具有相同的大小,在进行直方图计算的时候,只会统计该掩码不为0的对应像素 hist,//输出直方图数据 int dims,//维数 const int*histsize,//直方图级数 const float*ranges,//值域范围 bool uniform,//默认true 是否进行归一化 bool accumulate)//默认false 累积标志
代码:
#include <opencv2/opencv.hpp> #include<iostream> #include<math.h> #include <string> #include<fstream> using namespace cv; using namespace std; int main() { Mat src,b_hist,g_hist,r_hist; src = imread("C:\\Users\\Administrator\\Desktop\\pic\\1-H.jpg"); imshow("input", src); //分通道显示 vector<Mat> bgr_palnes; split(src, bgr_palnes); imshow("bgr_planes", bgr_palnes[0]); //计算直方图 int histSize = 256; float range[] = { 0,256 }; const float *histRange = { range }; calcHist(&bgr_palnes[0], // 要计算图像的 1,// 只计算一幅图像的直方图 0,// 通道数量 Mat(),//不用掩码 b_hist, // 存放直方图 1,// 1D直方图 &histSize,// 统计的灰度的个数 &histRange);// 灰度值的范围 calcHist(&bgr_palnes[1], 1,0,Mat(),g_hist, 1,&histSize,&histRange); calcHist(&bgr_palnes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange); //归一化 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()); 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 ++ ) { 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(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(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); } imshow("dst", histimage); waitKey(0); }
结果:
直方图比较:
对输入的两张图像计算得到直方图H1和H2,归一化到相同的空间然后可以通过计算H1和H2之间的距离得到两个直方图的相似度进而比较图像本身的相似度,opencv提供四种比较方法:
- Correlation:相关性比较(就是最小二乘法r的取值公式)计算结果范围为 -1到1 -1很不相关,1完全一样
- Chi-Square:卡方比较计算 结果越接近0,两个直方图越相似
- Intersection:十字交叉性 公式为取两个直方图每个相同位置的值的最小值,然后求和,这个比较方式不是很好,不建议使用
- Bhattacharyya distance:巴氏距离 比较结果是很准的,计算结果范围为 0-,0表示两个直方图非常相关,1最不相似
步骤:
- 首先把图像从RGB色彩空间转换到HSV色彩空间cvtColor; 色调(H),饱和度(S),明度(V)
- 计算图像的直方图,然后归一化到0-1之间caHist和normalize;
使用上述四种比较方法之一进行比较compareHist;
API:
compareHist( InputArray h1, // 直方图数据,下同 InputArray H2, int method// 比较方法,上述四种方法之一 )
代码:
#include <opencv2/opencv.hpp> #include<iostream> #include<math.h> #include <string> #include<fstream> using namespace cv; using namespace std; string convertToString(double d) { // << 运算符重载了,将double转成string ostringstream os; if (os << d) return os.str(); return "invalid conversion"; } int main() { Mat base, test1, test2, basehsv, test1hsv, test2hsv; base = imread("C:\\Users\\Administrator\\Desktop\\pic\\z1.jpg"); test1 = imread("C:\\Users\\Administrator\\Desktop\\pic\\z2.jpg"); test2 = imread("C:\\Users\\Administrator\\Desktop\\pic\\z3.jpg"); cvtColor(base, basehsv, CV_RGB2HSV); cvtColor(test1, test1hsv, CV_RGB2HSV); cvtColor(test2, test2hsv, CV_RGB2HSV); int h_bin = 50, s_bin = 60; int histBins[] = { h_bin,s_bin }; // float h_ranges[] = { 0,180 }; float s_ranges[] = { 0,256 }; const float *ranges[] = { h_ranges,s_ranges }; // int channels[] = { 0,1 }; //ND表示二维或者多维的Mat, //归一化 Mat hist_base, hist_test1, hist_test2; calcHist(&basehsv, 1, channels, Mat(), hist_base, 2, histBins, ranges); normalize(hist_base, hist_base, 0, 1, NORM_MINMAX); calcHist(&test1hsv, 1, channels, Mat(), hist_test1, 2, histBins, ranges); normalize(hist_test1, hist_test1, 0, 1, NORM_MINMAX); calcHist(&test2hsv, 1, channels, Mat(), hist_test2, 2, histBins, ranges); normalize(hist_test2, hist_test2, 0, 1, NORM_MINMAX); int compareType = CV_COMP_BHATTACHARYYA; double basebase = compareHist(hist_base, hist_base, compareType); double basetest1 = compareHist(hist_base, hist_test1, compareType); double basetest2 = compareHist(hist_base, hist_test2, compareType); double test1test2 = compareHist(hist_test1, hist_test2, compareType); Mat test12; test2.copyTo(test12); //将比较的结果转换为string,然后以文字的方式绘制到图形上 putText(base, convertToString(basebase), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255)); putText(test1, convertToString(basetest1), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255)); putText(test2, convertToString(basetest2), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255)); putText(test12, convertToString(test1test2), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255)); imshow("basebase", base); imshow("basetest1", test1); imshow("basetest2", test2); imshow("test11test2", test12); waitKey(0); }
结果:
直方图反向投影:
反向投影是反映直方图模型在目标图像中的分布情况
简单点说就是直方图模型去目标图像中寻找是否相似的对象
通常用HSV色彩空间的HS两个通道直方图模型
步骤:
建立直方图模型
计算待检测图像直方图并映射到模型中
从模型反向计算生成图像
API步骤:
加载imread
RGB转到HSV, cvtColor
计算直方图和归一化calHist与normalize
Mat与MatND其中Mat表示二维数组,MatND表示三维或者多维数据,此处都可以用
计算反向投影图像,calcBackProject
calcBackProject ( // 反向投影 const Mat * images, // 输入图像,图像深度必须位CV_8U,CV_16U或CV_32F中的一种,尺寸相同,每一幅图像都可以有任意的通道数 int nimages, // 输入图像的数量 const int * channels, // 用于计算反向投影的通道列表,通道数必须与直方图维度相匹配,第一个数组的通道是从0到image[0].channels()-1, 第二个数组通道从图像image[0].channels()到image[0].channels()+image[1].channels()-1计数 InputArray hist, // 输入的直方图,直方图的bin可以是密集(dense)或稀疏(sparse) OutputArray backProject, // 目标反向投影输出图像,是一个单通道图像,与原图像有相同的尺寸和深度 const float ** ranges, // 直方图中每个维度bin的取值范围 double scale = 1, // 可选输出反向投影的比例因子 bool uniform = true // 直方图是否均匀分布(uniform)的标识符,默认值true
代码:
#include <opencv2/opencv.hpp> #include<iostream> #include<math.h> #include <string> #include<fstream> using namespace cv; using namespace std; Mat src, hsv, hue; int bins = 12; void Hist_and_Backprojection(int, void*) { if (bins == 0) return; float range[] = { 0,180 }; const float*histRanges = { range }; Mat h_hist; calcHist(&hue, 1, 0, Mat(), h_hist, 1, &bins, &histRanges); normalize(h_hist, h_hist, 0, 255,NORM_MINMAX,-1,Mat()); Mat backpriIamge; calcBackProject(&hue, 1, 0, h_hist, backpriIamge, &histRanges, 1); imshow("output", backpriIamge); //绘制直方图 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; 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 ), Scalar(0, 0, 255),-1);//-1表示填充矩形 } imshow("zhifangtu", histImage); } int main() { src = imread("C:\\Users\\Administrator\\Desktop\\pic\\6.jpeg"); imshow("input", src); cvtColor(src, hsv, CV_RGB2HSV); hue.create(hsv.size(), hsv.depth()); int channels[] = { 0,0 }; mixChannels(&hsv, 1,&hue, 1, channels, 1); Hist_and_Backprojection(0, 0); createTrackbar("zhifangtubins", "output", &bins, 180, Hist_and_Backprojection); waitKey(0); }
结果:
- OpenCV之imgproc 模块. 图像处理(4)直方图均衡化 直方图计算 直方图对比 反向投影 模板匹配
- OpenCV_颜色直方图的计算、显示、处理、对比及反向投影
- 【OpenCV图像处理入门学习教程三】基于SIFT特征和SURF特征的微旋转图像拼接与融合生成全景图像的比较
- 基于opencv和c++的图像处理:直方图均衡化
- OpenCV图像处理教程C++(二十)轮廓发现、凸包、轮廓周围绘制圆和矩形
- OpenCV_颜色直方图的计算、显示、处理、对比及反向投影
- Python-OpenCV 处理图像(四):图像直方图和反向投影
- OpenCV图像处理教程C++(二十一)图像矩、点多边形测试
- OpenCV图像处理教程C++(二十二)基于距离变换与分水岭的图像分割
- OpenCV_颜色直方图的计算、显示、处理、对比及反向投影
- 基于opencv和c++的图像处理:直方图均衡化
- OpenCV_颜色直方图的计算、显示、处理、对比及反向投影【转】
- OpenCV图像处理教程C++(十九)模板匹配
- 【OpenCV入门教程之十一】 形态学图像处理(二):开运算、闭运算、形态学梯度、顶帽、黑帽合辑
- python深度学习库pytorch::transforms练习:opencv,scikit-image,PIL图像处理库比较
- 【OpenCV入门教程之十一】 形态学图像处理(二):开运算、闭运算、形态学梯度、顶帽、黑帽合辑
- Python3与OpenCV3.3 图像处理(十三)--反射投影
- 【OpenCV图像处理入门学习教程二】不同阈值二值化图像
- 【OpenCV入门教程之十】 形态学图像处理(一):膨胀与腐蚀
- OpenCV之彩色直方图反向投影(图像相似性检测)