OpenCV学习二十三:calcHist,直方图

版权声明:共享知识,欢迎转载 https://blog.csdn.net/kakiebu/article/details/79431523

其中C++的函数原型如下:

void calcHist(const Mat* arrays, int narrays, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool uniform=true, bool accumulate=false );

arrays。输入的图像的指针,可以是多幅图像,所有的图像必须有同样的深度(CV_8U or CV_32F)。同时一副图像可以有多个channes。
narrays。输入的图像的个数。
channels。用来计算直方图的channes的数组。比如输入是2副图像,第一副图像有0,1,2共三个channel,第二幅图像只有0一个channel,那么输入就一共有4个channes,如果int channels[3] = {3, 2, 0},那么就表示是使用第二副图像的第一个通道和第一副图像的第2和第0个通道来计算直方图。
mask。掩码。如果mask不为空,那么它必须是一个8位(CV_8U)的数组,并且它的大小的和arrays[i]的大小相同,值为1的点将用来计算直方图。
hist。计算出来的直方图
dims。计算出来的直方图的维数。
histSize。在每一维上直方图的个数。简单把直方图看作一个一个的竖条的话,就是每一维上竖条的个数。
ranges。用来进行统计的范围。比如

float rang1[] = {0, 20};
float rang2[] = {30, 40};
const float *rangs[] = {rang1, rang2};那么就是对0,20和30,40范围的值进行统计。

uniform。每一个竖条的宽度是否相等。
accumulate。存在多个图像时,是否累计计算像素值得个数。

#include <opencv2/opencv.hpp>  
#include <stdio.h>  
#include <stdlib.h>  

using namespace cv;  
using namespace std;  

char file[] = "1.jpg";
int main(int argc, char** argv)  
{  
	Mat img = imread(file, -1);
	pyrDown(img, img, Size(img.cols/2, img.rows/2));
	imshow("1",img);

	//创建映射关系表
	vector<Mat> RGBpaltes;
	split(img, RGBpaltes);

	//直方图的相关参数设定
	Mat b_hist, g_hist, r_hist;
	float range[] = {0, 255};
	const float * Hrange = {range};
	int histSize = 256;
	calcHist(&RGBpaltes[0], 1, 0, Mat(), b_hist, 1, &histSize, &Hrange, true, false);
	calcHist(&RGBpaltes[1], 1, 0, Mat(), g_hist, 1, &histSize, &Hrange, true, false);
	calcHist(&RGBpaltes[2], 1, 0, Mat(), r_hist, 1, &histSize, &Hrange, true, false);

	//归一化
	normalize(b_hist, b_hist, 0, 400, NORM_MINMAX, -1, Mat());
	normalize(g_hist, g_hist, 0, 400, NORM_MINMAX, -1, Mat());
	normalize(r_hist, r_hist, 0, 400, NORM_MINMAX, -1, Mat());

	//画出图片。
	int img_h = 700;//图片的高(行数)
	int img_w = 512;//图片的宽(列数)
	int line_w = img_w/histSize;//线宽
	Mat histImage(img_h, img_w, CV_8UC3, Scalar(0,0,0));//图片(画布)大小

	for (int i=1; i<histSize; i++)
	{
		// 两个点的规则。
		// x坐标:条线*线宽;
		// y坐标:由于图片的行计数是从上开始的而我们习惯从下开始计算y轴递增,因此我用图片的高 - 当前像素的累计计数值 - 最底下黑边高度。
		line(histImage, Point((i-1)*line_w, img_h - cvRound(r_hist.at<float>(i-1)) - 200),
			Point(i*line_w, img_h - cvRound(r_hist.at<float>(i)) - 200),Scalar(0,0,255), 2);
		line(histImage, Point((i-1)*line_w, img_h - cvRound(g_hist.at<float>(i-1)) - 200),
			Point(i*line_w, img_h - cvRound(g_hist.at<float>(i)) - 200),Scalar(0,255,0), 2);
		line(histImage, Point((i-1)*line_w, img_h - cvRound(b_hist.at<float>(i-1)) - 200),
			Point(i*line_w, img_h - cvRound(b_hist.at<float>(i)) - 200),Scalar(255,0,0), 2);
	}

	imshow("结果", histImage);imwrite("final.jpg", histImage);
	//结果一的图中有一个问题:RGB 各通道的曲线会在一张图中,三个通道的最值不同,但却在同一个标准下归一化。
	//换句话说,由于是会在一张图中,最终结果中达到最值的在三个通道中只能有一个点,而不能是三个通道有三个点。
	//解决办法:找到每个通道的最大值:r_max g_max b_max, 然后再找出这三个值的最大值 MAX ,将
	// cvRound(r_hist.at<float>(i-1)) 改为 cvRound( r_hist.at<float>(i-1)*r_max/MAX )

	waitKey();
	return 1;
} 
原图

结果

猜你喜欢

转载自blog.csdn.net/kakiebu/article/details/79431523