(一)直方图均衡化
图像直方图是指对整个图像在灰度范围内的像素值(0~255)统计出现频率次数,据此生成的直方图,称为图像直方图。直方图反映了图像灰度的分布情况。是图像的统计学特征。
直方图均衡化API说明
直方图均衡化的demo如下所示:
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
Mat src, dst;
src = imread("D:/studytest/lena.jpg");
if (src.empty())
{
printf("could not load image...\n");
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
namedWindow("output image", CV_WINDOW_AUTOSIZE);
Mat gray_src;
cvtColor(src, gray_src, CV_BGR2GRAY);//转化为灰度图像
equalizeHist(gray_src, dst);//直方图均衡化
imshow("input image", src);
imshow("gray image", gray_src);
imshow("output image", dst);
waitKey(0);
return 0;
}
(二)直方图计算
API学习:
split(const Mat &src,Mat *mvbegin);//把多通道图像分为多个单通道图像
其中,src是输入图像,mvbegin是输出的通道图像数组
calcHist(const Mat* images, int images, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool uniform=true, bool accumulate=false );//计算图像直方图
参数说明:
const Mat* images:输入图像
int images:输入图像的个数
const int* channels:需要统计直方图的第几通道
InputArray mask:掩膜,计算掩膜内的直方图 …Mat()
OutputArray hist:输出的直方图数组
int dims:需要统计直方图通道的个数
const int* histSize:直方图级数,指的是直方图分成多少个区间,就是 bin的个数
const float** ranges: 统计像素值得区间
bool uniform=true:是否对得到的直方图数组进行归一化处理
bool accumulate=false:在多个图像时,是否累计计算像素值得个数
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
Mat src, dst;
src = imread("D:/studytest/lena.jpg");//读取一张图像
if (src.empty())//判断是否成功读取一张图像
{
printf("could not load image...\n");
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
namedWindow("output image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);//显示输入的图像
//分通道显示
vector<Mat> bgr_planes; //定义一个Mat数组
split(src, bgr_planes);//将src划分到各个同道中
//计算直方图
int histSize = 256;//直方图级数
float range[] = { 0,256 };
const float *histRanges = { range };//像素区间
Mat b_hist, g_hist, r_hist;//b,g,r的直方图图像
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));//一张纯黑色的3通道大小宽为hist_w,高为hist_h的图像
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++)
{ //cvRound()是四舍五入,cvFloor()是向下取整,cvCeil()是向上取整
//直角坐标系(x从左到右增加,y从下到上增加)、屏幕坐标系(x从左到右增加,y从上到下增加),人眼看的是直角坐标系,而电脑采用屏幕坐标系,所以方便人眼去看,我们将屏幕坐标系转换为直角坐标系
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 image", histImage);
waitKey(0);
return 0;
}
输出图像如下图所示:
(三)直方图的比较
直方图比较方法——概述
对输入的两张图像计算得到直方图H1与H2,归一化到相同的尺度空间,然后可以通过计算H1与H2之间的距离得到两个直方图的相似程度进而比较图像本身的相似程度。opencv提供的比较方法有四种:
①Correlation 相关性比较
②Chi-Square 卡方比较
③Intersection 十字交叉性
④Bhattacharyya distance 巴氏距离
直方图比较方法——相关性计算(CV_COMP_CORREL)
从上面公式可以看出,H1、H2越相近,d的值越靠近1。
直方图比较方法——卡方计算(CV_COMP_CHISQR)
从上面公式可以看出,H1、H2越相近,d的值越靠近0。
直方图比较方法——十字计算(CV_COMP_INTERSECT)
直方图比较方法——巴氏距离计算(CV_COMP_BHATTACHARYYA)
从上面公式可以看出,H1、H2越相近,d的值越靠近0。
#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>
using namespace std;
using namespace cv;
string convertToString(double d);//把double的值变为string
int main(int argc, char **argv)
{
Mat base, test1, test2;//其中base是lena原图,test1是有噪声的lena图像,test2是lena的灰度图像。
Mat hsvbase, hsvtest1, hsvtest2;
base = imread("D:/studytest/lena.jpg");
if (!base.data)
{
printf("could not load image...\n");
return -1;
}
test1 = imread("D:/studytest/lenanoise.jpg");
test2 = imread("D:/studytest/graylena.jpg");
//将图像转换为HSV图像
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,255 };
const float* ranges[] = { h_ranges,s_ranges };
//use the o-th and 1-st channels
int channels[] = { 0,1 };
MatND hist_base;//MatND表示多维
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());
Mat test12;
test2.copyTo(test12);//将test12复制成test2
//进行CORREL比较
double basebase = compareHist(hist_base, hist_base, CV_COMP_CORREL);
double basetest1 = compareHist(hist_base, hist_test1, CV_COMP_CORREL);
double basetest2 = compareHist(hist_base, hist_test2, CV_COMP_CORREL);
double test1test2 = compareHist(hist_test1, hist_test2, CV_COMP_CORREL);
printf("test1 compare with test2 correlation value :%f", test1test2);
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);
}
string convertToString(double d)
{
ostringstream os;
if (os << d)
return os.str();
return "invalid conversion";
}