Opencv学习----图像处理-直方图

6.4 直方图

6.4.1Opencv直方图定义

       直方图是对数据的集合统计,并将统计结果分布于一系列预定义的bins中。这里的数据不仅仅指的是灰度值, 统计数据可能是任何能有效描述图像的特征。
       看一个例子,假设有一个矩阵包含一张图像的信息(灰度值):

                                                    

        如果我们按照某种方式去统计这些数字,会发生什么情况呢? 既然已知数字的范围包含 256 个值, 我们可以将这个范围分割成子区域(称作bins), 如:

                                                           

       然后再统计掉入每一个的像素数目。采用这一方法来统计上面的数字矩阵,我们可以得到下图(x轴表示bin,y轴表示各个bin中的像素个数)。

                                                     

      以上只是一个说明直方图如何工作以及它的用处的简单示例。直方图可以统计的不仅仅是颜色灰度, 它可以统计任何图像特征 (如 梯度, 方向等等)。
      直方图的一些具体细节:
     dims: 需要统计的特征的数目,在上例中,dims = 1因为我们仅仅统计了灰度值(灰度图像)。
     bins: 每个特征空间子区段的数目,在上例中,bins = 16
     range: 每个特征空间的取值范围,在上例中,range = [0,255]
     统计两个特征的直方图就是3维的了,x轴和y轴分别代表一个特征,z轴是掉入组合中的样本数目。同样的方法适用于更高维的情形(当然会变得很复杂)。

6.4.2 Opencv相关接口

void cv::calcHist(const Mat * images,
		int nimages,
		const int * channels,
		InputArray mask,
		OutputArray hist,
		int dims,
		const int* histSize,
		const float** ranges,
		bool uniform = true,
		bool accumulate = false 
	)		
参数
images	输入数组(或数组集)。它们都应该具有相同的深度,CV_8U, CV_16U或CV_32F,以及相同的大小。它们中的每一个都可以有任意数量的通道。
nimages	源图像数量。(一通道的则为1)
channels	用于计算直方图的dims通道列表。第一个数组通道的编号是从0到图像[0].channels()-1,第二个数组通道的编号是从图像[0].channels()到图像[0].channels() +图像[1].channels()-1,以此类推。只是统计了灰度时为0。
mask	掩码( 0 表示忽略该像素), 如果未定义,则不使用掩码
hist	储存直方图的矩阵
dims	直方图维数
histSize	每个维度的bin数目
ranges	每个维度的取值范围
uniform	是否要把bin范围设定成同样大小(均一)
accumulate	是否开始统计前先清除直方图中的痕迹
void ES::ImageProcessing::histImageOper(cv::Mat* dst)
{
	Mat src = imread("lena.jpg", IMREAD_COLOR);
	cv::resize(src, src, Size(src.rows / 4 * 3, src.cols / 4 * 3));
	/// 分割成3个单通道图像 ( R, G 和 B )
	std::vector<Mat> rgb_planes;
	split(src, rgb_planes);
	/// 设定bin数目
	int histSize = 255;
	/// 设定取值范围 ( R,G,B) )
	float range[] = { 0, 255 };
	const float* histRange = { range };
	//把bin范围设定成同样大小(均一)以及开始统计前先清除直方图中的痕迹
	bool uniform = true; bool accumulate = false;
	Mat r_hist, g_hist, b_hist;
	/// 计算直方图:
	calcHist(&rgb_planes[0], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate);
	calcHist(&rgb_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate);
	calcHist(&rgb_planes[2], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate);
	// 创建直方图画布
	int hist_w = src.cols; int hist_h = src.rows;
	int bin_w = cvRound((double)hist_w / histSize);
	Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));
	/// 将直方图归一化到范围 [ 0, histImage.rows ]
	normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
	normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
	normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
	int lineType = LINE_AA;
	/// 在直方图画布上画出直方图
	for (int i = 1; i < histSize; i++)
	{
		line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),
			Point(bin_w*(i), hist_h - cvRound(r_hist.at<float>(i))),
			Scalar(0, 0, 255), 2, lineType, 0);
		line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),
			Point(bin_w*(i), hist_h - cvRound(g_hist.at<float>(i))),
			Scalar(0, 255, 0), 2, lineType, 0);
		line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),
			Point(bin_w*(i), hist_h - cvRound(b_hist.at<float>(i))),
			Scalar(255, 0, 0), 2, lineType, 0);
	}
	Mat mergeMat(src.rows, src.cols + histImage.cols, src.type());
	Mat submat = mergeMat.colRange(0, src.cols);
	src.copyTo(submat);
	submat = mergeMat.colRange(src.cols, src.cols + histImage.cols);
	histImage.copyTo(submat);
	mergeMat.copyTo(*dst);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dylan55_you

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值