资讯专栏INFORMATION COLUMN

OpenCV-实现直方图均衡化(对比cv::equalizeHist)

YancyYe / 1979人阅读

摘要:而直方图均衡化就是通过图像变换使得直方图均匀分布,起到对比度增强的效果。基于上述原理,我自定义了一个简单的直方图均衡化函数,并定义了直方图简易绘制函数,用来作直观对比。

作者:Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

实现原理

       通过图像数据的直方图,可以快速判断图像的亮度和质量。而直方图均衡化就是通过图像变换使得直方图均匀分布,起到对比度增强的效果。在图像处理的课本中,针对离散形式的图像数据,最常用的一种方法就是累计概率分布。首先统计0-255灰度值所占像素个数;再计算出像素个数与总像素的比,表示为出现的概率;从0开始进行累计概率分布,即从0慢慢累加各层概率值直到1;则均衡化图像的灰度值=原灰度值所对应的累计概率*255。

       基于上述原理,我自定义了一个简单的直方图均衡化函数EqualizeHist,并定义了直方图简易绘制函数drawHistImg,用来作直观对比。

功能函数代码

// 直方图均衡化cv::Mat EqualizeHist(cv::Mat src){	cv::Mat h = cv::Mat::zeros(1, 256, CV_32FC1);	cv::Mat hs = cv::Mat::zeros(1, 256, CV_32FC1);	cv::Mat hp = cv::Mat::zeros(1, 256, CV_32FC1);	cv::Mat result = cv::Mat::zeros(src.size(), src.type());	int sum = 0;	for (int i = 0; i < src.rows; ++i)	{		for (int j = 0; j < src.cols; ++j)		{			h.at(0, src.at (i, j))++;			sum++;		}	}	for (int i = 0; i < 256; ++i)	{		hs.at(0, i) = h.at(0, i) / sum;		if (i == 0)		{			hp.at(0, i) = hs.at(0, i);		}		else {			hp.at(0, i) = hp.at(0, i - 1) + hs.at(0, i);		}	}	for (int i = 0; i < src.rows; ++i)	{		for (int j = 0; j < src.cols; ++j)		{			result.at (i, j) = uchar(round(255 * hp.at(0, src.at(i, j))));		}	}	return result;}// 绘制简易直方图cv::Mat drawHistImg(cv::Mat &src){	cv::Mat hist = cv::Mat::zeros(1, 256, CV_32FC1);	for (int i = 0; i < src.rows; ++i)	{		for (int j = 0; j < src.cols; ++j)		{			hist.at(0, src.at (i, j))++;		}	}	cv::Mat histImage = cv::Mat::zeros(540, 1020, CV_8UC1);	const int bins = 255;	double maxValue;	cv::Point2i maxLoc;	cv::minMaxLoc(hist, 0, &maxValue, 0, &maxLoc);	int scale = 4;	int histHeight = 540;	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-1, histHeight - height), cv::Scalar(255), -1);	}	return histImage;}

 函数原型

       官方OpenCV库中也有自带的直方图均衡化函数:

void equalizeHist( InputArray src, OutputArray dst );

参数说明

  1. InputArray类型的src,输入图像,如Mat类型。
  2. OutputArray类型的dst,输出图像。

C++测试代码

#include #include #include using namespace std;using namespace cv;cv::Mat EqualizeHist(cv::Mat src);cv::Mat drawHistImg(cv::Mat &hist);int main(){	cv::Mat src = imread("test.jpg",0);	cv::Mat src1 = imread("test.jpg");	clock_t start1, start2, end1,end2;	// 绘制原图直方图	cv::Mat hI = drawHistImg(src);	// 自定义直方图均衡化	start1 = clock();	cv::Mat result1 = EqualizeHist(src);	end1 = clock();	double dif1 = (end1 - start1) / CLOCKS_PER_SEC;	cout << "time1:" << dif1 << endl;	// 绘制均衡化后直方图	cv::Mat hrI = drawHistImg(result1);	// 官方直方图均衡化函数	start2 = clock();	cv::Mat result2;	equalizeHist(src, result2);	end2 = clock();	double dif2 = (end2 - start2) / CLOCKS_PER_SEC;	cout << "time2:" << dif2 << endl;	// 绘制均衡化后直方图	cv::Mat hr2I = drawHistImg(result2);	// 彩色直方图均衡化,三通道分别作均衡再合并	vector rgb,rgb_;	cv::Mat r, g, b;	cv::split(src1, rgb);	equalizeHist(rgb[0], b);	equalizeHist(rgb[1], g);	equalizeHist(rgb[2], r);	rgb_.push_back(b);	rgb_.push_back(g);	rgb_.push_back(r);	cv::Mat src1_;	cv::merge(rgb_, src1_);	imshow("original", src1);	imshow("result", src1_);	waitKey(0);	return 0;}// 直方图均衡化cv::Mat EqualizeHist(cv::Mat src){	cv::Mat h = cv::Mat::zeros(1, 256, CV_32FC1);	cv::Mat hs = cv::Mat::zeros(1, 256, CV_32FC1);	cv::Mat hp = cv::Mat::zeros(1, 256, CV_32FC1);	cv::Mat result = cv::Mat::zeros(src.size(), src.type());	int sum = 0;	for (int i = 0; i < src.rows; ++i)	{		for (int j = 0; j < src.cols; ++j)		{			h.at(0, src.at (i, j))++;			sum++;		}	}	for (int i = 0; i < 256; ++i)	{		hs.at(0, i) = h.at(0, i) / sum;		if (i == 0)		{			hp.at(0, i) = hs.at(0, i);		}		else {			hp.at(0, i) = hp.at(0, i - 1) + hs.at(0, i);		}	}	for (int i = 0; i < src.rows; ++i)	{		for (int j = 0; j < src.cols; ++j)		{			result.at (i, j) = uchar(round(255 * hp.at(0, src.at(i, j))));		}	}	return result;}// 绘制简易直方图cv::Mat drawHistImg(cv::Mat &src){	cv::Mat hist = cv::Mat::zeros(1, 256, CV_32FC1);	for (int i = 0; i < src.rows; ++i)	{		for (int j = 0; j < src.cols; ++j)		{			hist.at(0, src.at (i, j))++;		}	}	cv::Mat histImage = cv::Mat::zeros(540, 1020, CV_8UC1);	const int bins = 255;	double maxValue;	cv::Point2i maxLoc;	cv::minMaxLoc(hist, 0, &maxValue, 0, &maxLoc);	int scale = 4;	int histHeight = 540;	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-1, histHeight - height), cv::Scalar(255), -1);	}	return histImage;}

测试效果

图1 灰度原图

       其直方图如下: 

图2 直方图
图3 均衡化后灰度图

       两个函数运行时间都在0.001s以下,其均衡化后直方图略有差异,但都实现了均衡效果。

       自定义函数:

图4 自定义函数均衡化后直方图

        官方函数:

图5 官方函数均衡化后直方图

         对彩色图的三通道分别进行直方图均衡化,实现彩色均衡效果:

图6 彩色原图
图7 彩色均衡化效果

       如果函数有什么可以改进完善的地方,非常欢迎大家指出,一同进步何乐而不为呢~

       如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/119653.html

相关文章

  • 数字图像处理:OpenCV-Python中的直方均衡知识介绍及函数equalizeHist详解

    摘要:对于图像整体比较暗的情况,直方图均衡能得到类似的效果。这些内容老猿在数字图像处理直方图均衡算法研究及模拟实现中进行介绍,本部分主要详细介绍提供的直方图均衡函数。更多图像直方图处理的内容请参考数字图像处理第三章学习总结感悟直方图处理的介绍。 ...

    ityouknow 评论0 收藏0
  • opencv python 直方均衡

    摘要:如果噪音在那里,它就会被放大为了避免这种情况,会应用对比限制如果任何直方图超出指定的对比度限制默认情况下是,在应用直方图均衡之前,这些像素被裁剪并均匀地分布到其他均衡后,删除边界中的工件,采用双线性插值代码 Histograms - 2: Histogram Equalization 直方图均衡化是图像处理领域中利用图像直方图对对比度进行调整的方法.通过这种方法,亮度可以更好地在直方...

    Airmusic 评论0 收藏0
  • OpenCV-Python计算机视觉函数

    摘要:如果不设置这个,图片只会一瞬间显示,就消失了。括号里面也可以设置显示时长。 目录 1、概述 2、OpenCV基础 读取图片 imread 调整显示窗口大小 resizeWindow 调整图像尺寸大小 resize 色彩空间进行转换 cvtColor 绘制线段 line 绘制矩形框 recta...

    levius 评论0 收藏0
  • OpenCV(项目)车牌识别4 -- 总结篇

    摘要:后期进军深度学习机器学习,可能会对这些进行优化。有什么好的建议大家可以提出来,共同进步,谢谢 目录 一、效果 1、成功案例 2、经典失败案例(单字符识别成类似字符) 3、其他失败案例 二、总结 三、车牌识别总代码 一、效果 1、成功案例   2、经典失败案例(单字符识别成类似字符)  ...

    YacaToy 评论0 收藏0
  • OpenCV(项目)车牌识别2 -- 车牌字符分割

    目录 试错 1、没有膨胀/膨胀过小:无法连接上单个字符。  2、膨胀过大:错误连接相邻字符。 一、直方图处理原理 1、横向分割 2、纵向分割 过程: 一、中值滤波、灰度化 二、二值化(统一黑底白字) 三、膨胀处理 四、统计各行各列白色像素个数(为绘制直方图做准备) 五、绘制直方图(横、纵) 六、分割车牌图像 1、横向分割:分割上下边框 1-1、下半图波谷  1-2、上半图波谷 代码 及效果 2、...

    lufficc 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<