前面我们说了图像的本质是一堆数据,计算机可不认识图像中的各种人物、景色,只认识0,1,而所有这些都是人为打的标签,计算机看到的都是一个个像素点的像素值,而这些像素值又有一定的取值范围,对于RGB来说就是0-255的取值范围,我们就可以利用直方图统计在这区间内哪一个出现的频率低,哪一个频率高。
calcHist函数
作用:计算一维或多维图像直方图
c++原型:
参数:
- images:输入图像的指针,一定是同样的深度(CV_8U or CV_32F)。且一个图像可以有多个channes。
- nimages:输入图像的个数
- channels:计算直方图的channes的数组。如果输入的图像的个数为2,第一张图像有0,1,2共三个channel,第二张图像只有0一个channel,那么输入就一共有4个通道,如果int channels[3] = {3, 0, 1},那么就表示是使用第二张图像的第一个通道和第一张图像的第0和第1个通道来算
- mask:掩码。跟前面说的mask一致,非0区域才会用来做直方图的计算。如果不用就表示完整计算整张图像,这时Mat()参数为空。如果要用mask,那么它必须是一个8位(CV_8U)的数组,并且它的大小的和images[i]的大小相同,值为1的点用来计算
- hist:计算出来的直方图
- dims:计算出来的直方图的维数,这里是一维的,如果想要二维可以定义一个数组,数组里有两个值
- histSize:在每一维上直方图的个数。简单把直方图看作一个一个的竖条的话,就是每一维上竖条的个数。
- ranges:用来进行统计的范围 例如:float scope[] = {100, 255};const float *rangs[1] = { scope };那么就是对100-255的范围的值进行统计。多个范围可再定义数组
- uniform:每一个竖条的宽度是否相等
- accumulate:是否累加。如果为true,在下次计算的时候不会首先清空直方图
1、思路
2、效果
从直方图可以看出,直方图最左边的一块应该对应头发那块黑色,直方图中最高的那一块应该对应灰色的背景,脸部的亮度主要对应在直方图右边区域
void test1::hist_drawing(Mat &image)
{
// 分离三通道
vector bgr_passage;
split(image, bgr_passage);
// 定义参数变量
const int channels[1] = { 0 };
const int bins[1] = { 256 };
float scope[2] = { 0,255 };
const float* ranges[1] = { scope };
Mat b_hist;
Mat g_hist;
Mat r_hist;
// 计算B, G, R通道的直方图
calcHist(&bgr_passage[0], 1, 0, Mat(), b_hist, 1, bins, ranges);
calcHist(&bgr_passage[1], 1, 0, Mat(), g_hist, 1, bins, ranges);
calcHist(&bgr_passage[2], 1, 0, Mat(), r_hist, 1, bins, ranges);
// 显示直方图
int hist_w = 512;
int hist_h = 400;
int bin_w = cvRound((double)hist_w / bins[0]);
Mat histImg = Mat::zeros(hist_h, hist_w, CV_8UC3);
// 归一化直方图数据
normalize(b_hist, b_hist, 0, histImg.rows, NORM_MINMAX, -1, Mat());
normalize(g_hist, g_hist, 0, histImg.rows, NORM_MINMAX, -1, Mat());
normalize(r_hist, r_hist, 0, histImg.rows, NORM_MINMAX, -1, Mat());
// 绘制直方图曲线
for (int i = 1; i < bins[0]; i++)
{
line(histImg, Point(bin_w*(i - 1), hist_h - cvRound(b_hist.at(i - 1))),
Point(bin_w*(i), hist_h - cvRound(b_hist.at(i))), Scalar(255, 0, 0), 2, 8, 0);
line(histImg, Point(bin_w*(i - 1), hist_h - cvRound(g_hist.at(i - 1))),
Point(bin_w*(i), hist_h - cvRound(g_hist.at(i))), Scalar(0, 255, 0), 2, 8, 0);
line(histImg, Point(bin_w*(i - 1), hist_h - cvRound(r_hist.at(i - 1))),
Point(bin_w*(i), hist_h - cvRound(r_hist.at(i))), Scalar(0, 0, 255), 2, 8, 0);
}
// 显示直方图
// namedWindow("input", WINDOW_FREERATIO);
imshow("hist_drawing", histImg);
}
原创不易,转载请注明出处:
Qt+OpenCV联合开发(二十三)--图像直方图