版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/abcvincent/article/details/79223377
之前有写过直方图,这里补充一些实验代码和总结,另外补充直方图匹配的代码;
分通道计算和绘制直方图:
void imgHistogram()//直方图-一维灰度直方图
{
///一维灰度直方图
//1.计算直方图
Mat srcImg = imread("D:/2.jpg");
// Mat srcImg = imread("D:/ImageTest/pic3.png");
int channels=0;//需要统计通道的索引
Mat mask = Mat();
Mat histImg;//存放输出的直方图
int dims = 1;//需要计算的直方图的维度
int histSize = 256;//计算的直方图的分组数
float range[] = { 0, 256 };//表示直方图每一维度的取值范围[0,256)
const float* ranges[] = { range };//参数形式需要,表示每一维度数值的取值范围
//计算直方图
calcHist(&srcImg, //输入的图像的指针,可以是多幅图像,所有的图像必须有同样的深度
1, //输入的图像的个数
&channels, //图像channels的数组,Mat存储顺序是:BGR
mask, //掩码。
histImg, //计算出来的直方图
dims, //计算出来的直方图的维数。
&histSize, //在每一维上直方图的个数
ranges); //用来进行统计的范围
// 原函数:void calcHist( InputArrayOfArrays images,
// const std::vector<int>& channels,
// InputArray mask, OutputArray hist,
// const std::vector<int>& histSize,
// const std::vector<float>& ranges,
// bool accumulate = false );
// calcHist函数的channels参数和narrays以及dims共同来确定用于计算直方图的图像;
// 首先dims是最终的直方图维数,narrays指出了arrays数组中图像的个数,
// 其中每一幅图像都可以是任意通道的【只要最终dims不超过32即可】
// 如果channels参数为0,则narrays和dims必须相等,否则弹出assert,
// 此时计算直方图的时候取数组中每幅图像的第0通道。
// 当channels不是0的时候,用于计算直方图的图像是arrays中由channels指定的通道的图像,
// channels与arrays中的图像的对应关系,如channels的参数说明的,
// 将arrays中的图像从第0幅开始按照通道摊开排列起来,
// 然后channels中的指定的用于计算直方图的就是这些摊开的通道;
// 假设有arrays中只有一幅三通道的图像image,那么narrays应该为1,
// 如果是想计算3维直方图【最大也只能是3维的】,想将image的通道2作为第一维,
// 通道0作为第二维,通道1作为第三维,则可以将channels设置为channesl={2,0,1};
// 这样calcHist函数计算时就按照这个顺序来统计直方图。
//2.绘制直方图
double minValue = 0;
double maxValue = 0;
minMaxLoc(histImg,&minValue,&maxValue);//得到计算出的直方图中的最小值和最大值
int width = histSize*2;//定义绘制直方图的宽度,令其等于histSize
int height = 256*2;//定义绘制直方图的高度
Mat dstImg = Mat::zeros(Size(width,height),CV_8UC3);//宽为histSize,高为height
for (int i = 0; i < histSize;i++)//遍历histImg
{
float binValue = histImg.at<float>(i);//得到histImg中每一分组的值
// cout <<"i: "<<i<<" ,binValue: "<<binValue<< endl;
float realValue = (binValue / maxValue)*height;//归一化数据,缩放到图像的height之内
// cout << "i: " << i << " ,realValue: " << realValue << endl;
//用直线方法绘制直方图,注意两端点坐标的计算
line(dstImg, Point(i*2, height - 1), Point(i*2, height - 1 - realValue), Scalar(255,0,0), 1);//统计的是第一通道蓝色
}
imshow("srcImg",srcImg);
imshow("Histogram", dstImg);
waitKey(0);
}
效果:
分将bgr像素分开统计:
void imgHistogram3()//直方图-直方图
{
// Mat srcImg = imread("D:/2.jpg");
Mat srcImg = imread("D:/ImageTest/pic3.png");
/// 分割成3个单通道图像 (B, G 和 R )
vector<Mat> bgr_planes;
split(srcImg, bgr_planes );
/// 设定bin数目
int histSize = 256;
/// 设定取值范围 ( B,G,R) )
float range[] = { 0, 255 } ;
const float* histRange = { range };
bool uniform = true;
bool accumulate = false;
Mat b_hist, g_hist, r_hist;
/// 计算直方图:
calcHist( &bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate );
calcHist( &bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate );
calcHist( &bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate );
// 创建直方图画布
int hist_h =256;
int hist_w = histSize*3;
// int bin_w = cvRound( (double) hist_w/histSize );
Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );
/// 将直方图归一化到范围 [ 0, histImage.rows ]
normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
/// 在直方图画布上画出直方图
for( int i = 1; i < histSize; i++ )
{
line( histImage, Point( i,hist_h-1) ,Point( i, hist_h-cvRound(b_hist.at<float>(i)) ), Scalar( 255, 0, 0),1 );
line( histImage, Point( histSize+i,hist_h-1) ,Point(histSize+i, hist_h-cvRound(g_hist.at<float>(i)) ), Scalar( 0, 255, 0),1 );
line( histImage, Point( histSize*2+i,hist_h-1) ,Point( histSize*2+i, hist_h-cvRound(r_hist.at<float>(i)) ), Scalar( 0, 0, 255),1 );
}
/// 显示直方图
imshow("RGB Histogram", histImage );//窗口中显示直方图
imshow("original image", srcImg );//窗口中显示原图
waitKey(0);
}
效果:
直方图匹配:
void HistogramCompare()//直方图匹配
{
// Mat srcImg = imread("D:/ImageTest/mubiao.jpg");
// Mat srcImg2 = imread("D:/ImageTest/mubiao1.jpg");
Mat srcImg = imread("D:/ImageTest/2.jpg");
Mat srcImg2 = imread("D:/ImageTest/lena.png");
imshow("original image1", srcImg );//窗口中显示原图
imshow("original image2", srcImg2 );//窗口中显示原图
cvtColor(srcImg,srcImg, CV_BGR2GRAY);
cvtColor(srcImg2,srcImg2, CV_BGR2GRAY);
int histSize = 256;
/// 设定取值范围 ( B,G,R) )
float range[] = { 0, 255 } ;
const float* histRange = { range };
bool uniform = true;
bool accumulate = false;
Mat hist1, hist2;
/// 计算直方图:
calcHist( &srcImg, 1, 0, Mat(), hist1, 1, &histSize, &histRange, uniform, accumulate );
calcHist( &srcImg2, 1, 0, Mat(), hist2, 1, &histSize, &histRange, uniform, accumulate );
//直方图对比,注意是依据两源图像所计算出的直方图进行相似度对比.
double num1 = compareHist(hist1, hist2, CV_COMP_CORREL);//相关性方法(值越大匹配度越高)
double num2 = compareHist(hist1, hist2, CV_COMP_CHISQR);//卡方测量法(值越小匹配度越高)
double num3 = compareHist(hist1, hist2, CV_COMP_INTERSECT);//直方图相交法(值越大匹配度越高)
double num4 = compareHist(hist1, hist2, CV_COMP_BHATTACHARYYA);//Bhattacharyya测量法(小)
cout << "CV_COMP_CORREL(max_best): " << num1 << endl;
cout << "CV_COMP_CHISQR(min_best): " << num2 << endl;
cout << "CV_COMP_INTERSECT(max_best): " << num3 << endl;
cout << "CV_COMP_BHATTACHARYYA(min_best): " << num4 << endl;
// 创建直方图画布
int hist_h =256*2;
int hist_w = histSize*2*2;
Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );
/// 将直方图归一化到范围 [ 0, histImage.rows ]
normalize(hist1, hist1, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(hist2, hist2, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
/// 在直方图画布上画出直方图
for( int i = 1; i < histSize; i++ )
{
line( histImage, Point( i*2,hist_h-1) ,Point( i*2, hist_h-cvRound(hist1.at<float>(i)) ), Scalar( 255, 255, 0),1 );
line( histImage, Point( histSize*2+i*2,hist_h-1) ,Point(histSize*2+i*2, hist_h-cvRound(hist2.at<float>(i)) ), Scalar( 0, 255, 255),1 );
}
// //添加文字
QString strg1=QString::number(num1,10,3);
QString str1=QString("CV_COMP_CORREL(max_best):%1").arg(strg1);
QByteArray cStr1 = str1.toLocal8Bit(); // 注意,这个QByteArray 对象一定要建立
char *p1 = cStr1.data();
putText(histImage,p1, Point(30, 30),CV_FONT_HERSHEY_COMPLEX, 0.8, Scalar(0, 0, 255), 1, 8);
QString strg2=QString::number(num2,10,3);
QString str2=QString("CV_COMP_CHISQR(min_best):%1").arg(strg2);
QByteArray cStr2 = str2.toLocal8Bit(); // 注意,这个QByteArray 对象一定要建立
char *p2 = cStr2.data();
putText(histImage,p2, Point(30, 30*2),CV_FONT_HERSHEY_COMPLEX,0.8, Scalar(0, 0, 255), 1, 8);
QString strg3=QString::number(num3,10,3);
QString str3=QString("CV_COMP_INTERSECT(max_best):%1").arg(strg3);
QByteArray cStr3 = str3.toLocal8Bit(); // 注意,这个QByteArray 对象一定要建立
char *p3 = cStr3.data();
putText(histImage,p3, Point(30, 30*3),CV_FONT_HERSHEY_COMPLEX, 0.8, Scalar(0, 0, 255), 1, 8);
QString strg4=QString::number(num4,10,3);
QString str4=QString("CV_COMP_BHATTACHARYYA(min_best):%1").arg(strg4);
QByteArray cStr4 = str4.toLocal8Bit(); // 注意,这个QByteArray 对象一定要建立
char *p4 = cStr4.data();
putText(histImage,p4, Point(30, 30*4),CV_FONT_HERSHEY_COMPLEX, 0.8, Scalar(0, 0, 255), 1, 8);
/// 显示直方图
imshow("RGB Histogram", histImage );//窗口中显示直方图
waitKey(0);
}
相似图像组效果:
非相似图匹配效果: