opencv中用calHist函数得到直方图信息后,需要将其绘制出来,但是有些像素点的统计次数可能几千次甚至上万次,为了将其在一个预先确定大小的图(设为dstImage)中绘制出来,需要将得到的直方图各个像素点的次数归一化到 [o,dstImage.rows] 这个范围内,再进行绘制。
可以使用函数:
结合修改的官方参考程序进行解释。
#include "opencv2/highgui.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv){
Mat srcImage = imread("miao.png", 0);
imshow("hi", srcImage);
if (srcImage.empty())cout << "source image is empty" << endl;
MatND dstHist;
float hrange[] = { 0, 255 }; //所有的的灰度值范围
const float* ranges[] = { hrange };
int dims = 1;
int size = 256;
/*如果是彩色图像的话,传入的参数可以是 [0], [1], [2] 它们分别对应着通道 B, G, R。*/
int channels = 0; //如果输入图像是灰度图,它的值就是 [0];
//输出的直方图dstHist 为一个一维数组[1*256] 其值为灰度值[0-256]对应点的出现频次
calcHist(&srcImage, 1, &channels, Mat(), dstHist, dims, &size, ranges);
//直方图绘制
int scale = 1;
int hist_h = scale*size, hist_w = size;
int bin_w= hist_w/size; //即bin_w=1;
Mat dstImage(hist_h, hist_w, CV_8U, Scalar(0)); //展示直方图的图纸的大小,颜色为黑色
//将 dstHist 归一化到[0,dstHist.rows]
normalize(dstHist, dstHist, 0, dstHist.rows, NORM_MINMAX, -1, Mat());//归一化结果存在dstHist
/*这个for循环可以遍历下归一化后的直方图统计数值,看看是不是都在指定范围内*/
for (int i = 0; i < size; i++){
cout << cvRound(dstHist.at<float>(i)) << endl;
}
for (int i = 1; i < size; i++){
line(dstImage,
Point(bin_w*(i - 1), hist_h-cvRound(dstHist.at<float>(i - 1))),
Point(bin_w*(i), hist_h-cvRound(dstHist.at<float>(i))),
Scalar(255, 255, 255), 2, 8, 0);
}
imshow("1-Dhistogram ", dstImage);
waitKey(0);
return 0;
}
效果如图:
当然对于归一化处理官方参考的程序里还提供了另一种人工计算方式,在此一并给出。
int scale = 1;
Mat dstImage (size*scale, size, CV_8U, Scalar(0)); //直方图 h=size*scale, w=size;
double minValue = 0;
double maxValue = 0;
minMaxLoc(dstHist, &minValue, &maxValue, 0, 0);
//绘制直方图方法一
for (int i = 0; i < size; i++){
float binValue = dstHist.at<float>(i); //依次取出0-256个灰度值
int realValue = saturate_cast<int>(binValue*256 / maxValue);
rectangle(dstImage,
Point(scale*i, size - 1),
Point(scale*(i + 1) - 1, size - realValue),
Scalar(255));
cout << "i::" << i << "\tbinValue:" << binValue << "\trealValue:" << realValue << endl;
}
可将这个计算得到的统计次数与上面方法一得到的统计次数进行比较,会发现二者是一致的,数据相同。其直方图为: