Opencv绘制灰度/彩色图像的直方图及直方图的均衡化实例及源代码

1. Opencv中的坐标关系

在开始绘制直方图之前,需要明确Opencv中采用的坐标关系。下图非常清晰的标出了三种常用的坐标轴名称,及相互的关系。

Opencv绘制灰度/彩色图像的直方图及直方图的均衡化实例及源代码_第1张图片


2. 灰度图像的直方图及均衡化

利用opencv中的calcHist()函数计算直方图,利用equalizeHist()对直方图进行均衡化,然后利用rectangle()(通过绘制多个矩形/线条)绘制出直方图。

下面是对一张图像进行均衡化后的对比效果。需要注意的是这里绘制的是灰度图像的直方图。

Opencv绘制灰度/彩色图像的直方图及直方图的均衡化实例及源代码_第2张图片


Opencv绘制灰度/彩色图像的直方图及直方图的均衡化实例及源代码_第3张图片


3. 源代码

#include
#include

//绘制直方图,src为输入的图像,histImage为输出的直方图,name是输出直方图的窗口名称
void drawHistImg(cv::Mat &src, cv::Mat &histImage,std::string name)
{
	const int bins = 256;
	int hist_size[] = { bins };
	float range[] = { 0, 256 };
	const float* ranges[] = { range };
	cv::MatND hist;
	int channels[] = { 0 };

	cv::calcHist(&src, 1, channels, cv::Mat(), hist, 1, hist_size, ranges, true, false);

	double maxValue;
	cv::minMaxLoc(hist, 0, &maxValue, 0, 0);
	int scale = 1;
	int histHeight = 256;

	for (int i = 0; i < bins; i++)
	{
		float binValue = hist.at(i);
		int height = cvRound(binValue*histHeight / maxValue);
		cv::rectangle(histImage, cv::Point(i*scale, histHeight), cv::Point((i + 1)*scale, histHeight - height), cv::Scalar(255));

		cv::imshow(name, histImage);
	}
}

int main(void)
{
	cv::Mat src, dst;

	src=cv::imread("d:/Opencv Picture/hist.png", CV_LOAD_IMAGE_GRAYSCALE);
	if (!src.data)
		std::cout << "ERR";
	cv::equalizeHist(src, dst);

	cv::imshow("src", src);
	cv::imshow("equalizeHist", dst);

	cv::Mat srcHistImage = cv::Mat::zeros(256, 256, CV_8UC1);
	cv::Mat dstHistImage = cv::Mat::zeros(256, 256, CV_8UC1);
	drawHistImg(src, srcHistImage,"srcHistImage");
	drawHistImg(dst, dstHistImage,"dstHistImage");

	cvWaitKey(0);
	return 0;

}

4. 彩色图像的直方图及均衡化

由于opencv自带的函数是对灰度图像进行直方图均衡化的,所以不可直接调用函数。需要注意的是对于彩色图像(RGB),直接对三个通道单独进行直方图均衡化,然后合成是不可取的,原因是直方图均衡化并非线性操作,这样会引起彩色失真,可取的方式是将RGB转换到HSV,HSI,YUV 或者YCbCr,然后对亮度(即前面的V, I,Y通道)进度均衡化,这样不会对彩色的色调产生影响,然后转换回RGB空间即可。这里特别推荐最后一个YCbCr,因为它就是专门为数字图像所设计的。

先看效果图。下面分别是均衡前后的对比图,以及对Y通道均衡前后的直方图对比图。

Opencv绘制灰度/彩色图像的直方图及直方图的均衡化实例及源代码_第4张图片

Opencv绘制灰度/彩色图像的直方图及直方图的均衡化实例及源代码_第5张图片


代码如下

#include
#include

//绘制直方图,src为输入的图像,histImage为输出的直方图,name是输出直方图的窗口名称
void drawHistImg(cv::Mat &src, cv::Mat &histImage, std::string name)
{
	const int bins = 256;
	int hist_size[] = { bins };
	float range[] = { 0, 256 };
	const float* ranges[] = { range };
	cv::MatND hist;
	int channels[] = { 0 };

	cv::calcHist(&src, 1, channels, cv::Mat(), hist, 1, hist_size, ranges, true, false);

	double maxValue;
	cv::minMaxLoc(hist, 0, &maxValue, 0, 0);
	int scale = 1;
	int histHeight = 256;

	for (int i = 0; i < bins; i++)
	{
		float binValue = hist.at(i);
		int height = cvRound(binValue*histHeight / maxValue);
		cv::rectangle(histImage, cv::Point(i*scale, histHeight), cv::Point((i + 1)*scale, histHeight - height), cv::Scalar(255));

		cv::imshow(name, histImage);
	}
}

int main(void)
{
	cv::Mat src, dst;
	cv::Mat srcHistImage = cv::Mat::zeros(256, 256, CV_8UC1);
	cv::Mat dstHistImage = cv::Mat::zeros(256, 256, CV_8UC1);

	src = cv::imread("d:/Opencv Picture/Haze Removal/1.png",1);
	if (!src.data)
		std::cout << "ERR";

	cv::Mat YCC;
	cv::cvtColor(src,YCC,cv::COLOR_RGB2YCrCb);
	std::vector channels;
	cv::split(YCC, channels);

	drawHistImg(channels[0], srcHistImage, "srcHistImage");
	cv::equalizeHist(channels[0], channels[0]);//对Y通道进行均衡化
	
	cv::merge(channels, YCC);
	cv::cvtColor(YCC,dst,cv::COLOR_YCrCb2RGB);//重新转换到RGB颜色域

	cv::imshow("src", src);
	cv::imshow("dst", dst);

	drawHistImg(channels[0], dstHistImage, "dstHistImage");

	cvWaitKey(0);
	return 0;

}


你可能感兴趣的:(opencv,数字图像处理基础)