【opencv】直方图均衡化
2014-04-14 11:26
211 查看
直方图的均衡化
我们先来看看原图的直方图
![](https://img-blog.csdn.net/20140414112056937?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZHJlYW1mbHlodWE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
我们发现高亮区域的像素点很少,主要像素点集中在中低亮度区域。
我们先设置一个阈值,也就是图中的那根粉色的线,当某一亮度值的像素点的个数低于这个值时,我们认为这些像素点是无关紧要的。
灰度图的亮度值范围是0-255,若亮度值为1的像素点的个数低于阈值,我们可简单的把亮度为1的像素点的亮度全设为0,同理,我们从高往低找,若亮度值为254的像素点的个数低于阈值,我们可以把这些像素点的亮度设为255这样我们可以从小到大,从大到小分别找到两个亮度,它们的像素点的个数恰大于阈值他们之间的区域,我们可以认为是有效区域,也就是蓝色框出来的区域。我们把这一区域扩展到0-255的区域去,可实现均衡化效果。
编程实现为:
cv::Mat Histogram::stretch1(const cv::Mat& image, int minValue) {
cv::MatND hist = getHistogram(image);
int imin =0;
for (; imin < histSize[0]; imin++) {
if (hist.at<float>(imin) > minValue) {
break;
}
}
int imax = histSize[0] -1;
for (; imax >=0; imax--) {
if (hist.at<float>(imax) > minValue) {
break;
}
}
cv::Mat lookup(cv::Size(1, 256), CV_8U);
for (int i =0; i <256; i++) {
if (i < imin) {
lookup.at<uchar>(i) =0;
} elseif (i > imax) {
lookup.at<uchar>(i) =255;
} else {
lookup.at<uchar>(i) = static_cast<uchar>(255.0* (i - imin)
/ (imax - imin) +0.5);}
}
cv::Mat result;
cv::LUT(image, lookup, result);
return result;
}
![](https://img-blog.csdn.net/20140414112228656?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZHJlYW1mbHlodWE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
可以看出拉伸后的直方图和原直方图形状是一致的
再来看看另一种直方图均衡化的思路
理想的直方图均衡化效果是希望每个亮度的像素点的个数都相同。我们设原亮度为 i 的点均衡化后亮度为S(i),原亮度为 i 的点的个数为N(i), 其占总像素点的概率为p(i) = N(i) / SUM; SUM为像素点的总和。可以得到公式:
S(0) = p(0)*255
S(1) = [p(0)+p(1)]*255
S(2) = [p(0)+p(1)+p(2)]*255
........
S(255) = [p(0)+p(1)+......+p(255)]*255 = 255
我们在原图中将亮度为 i 的像素点赋值为 S(i),就可以实现均衡化了。
cv::Mat Histogram::stretch2(const cv::Mat& image) {
cv::MatND hist = getHistogram(image);
float scale[256];
float lookupF[256];
cv::Mat lookup(cv::Size(1, 256), CV_8U);
int pixNum = image.cols * image.rows;
for (int i =0; i <256; i++) {
scale[i] = hist.at<float>(i) / pixNum *255;
if (i ==0) {
lookupF[i] = scale[i];
} else {
lookupF[i] = lookupF[i -1] + scale[i];
}
}
for (int i =0; i <256; i++) {
lookup.at<uchar>(i) = static_cast<uchar>(lookupF[i]);
}
cv::Mat result;
cv::LUT(image, lookup, result);
return result;
}
cv::Mat Histogram::stretch3(const cv::Mat& image) {
cv::Mat result;
cv::equalizeHist(image, result);
return result;
}
在这里,我们定义了两个函数,一个按照刚才的思路来实现,另一个是OpenCV2 提供的标准的均衡化函数。
我们来看看效果
![](https://img-blog.csdn.net/20140414112421390?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZHJlYW1mbHlodWE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
两种方法得到的效果和直方图的形状几乎一模一样。可见,标准的均衡化方法也是按此思路实现的,具体的源代码就不研究了。
我们先来看看原图的直方图
我们发现高亮区域的像素点很少,主要像素点集中在中低亮度区域。
我们先设置一个阈值,也就是图中的那根粉色的线,当某一亮度值的像素点的个数低于这个值时,我们认为这些像素点是无关紧要的。
灰度图的亮度值范围是0-255,若亮度值为1的像素点的个数低于阈值,我们可简单的把亮度为1的像素点的亮度全设为0,同理,我们从高往低找,若亮度值为254的像素点的个数低于阈值,我们可以把这些像素点的亮度设为255这样我们可以从小到大,从大到小分别找到两个亮度,它们的像素点的个数恰大于阈值他们之间的区域,我们可以认为是有效区域,也就是蓝色框出来的区域。我们把这一区域扩展到0-255的区域去,可实现均衡化效果。
编程实现为:
cv::Mat Histogram::stretch1(const cv::Mat& image, int minValue) {
cv::MatND hist = getHistogram(image);
int imin =0;
for (; imin < histSize[0]; imin++) {
if (hist.at<float>(imin) > minValue) {
break;
}
}
int imax = histSize[0] -1;
for (; imax >=0; imax--) {
if (hist.at<float>(imax) > minValue) {
break;
}
}
cv::Mat lookup(cv::Size(1, 256), CV_8U);
for (int i =0; i <256; i++) {
if (i < imin) {
lookup.at<uchar>(i) =0;
} elseif (i > imax) {
lookup.at<uchar>(i) =255;
} else {
lookup.at<uchar>(i) = static_cast<uchar>(255.0* (i - imin)
/ (imax - imin) +0.5);}
}
cv::Mat result;
cv::LUT(image, lookup, result);
return result;
}
可以看出拉伸后的直方图和原直方图形状是一致的
再来看看另一种直方图均衡化的思路
理想的直方图均衡化效果是希望每个亮度的像素点的个数都相同。我们设原亮度为 i 的点均衡化后亮度为S(i),原亮度为 i 的点的个数为N(i), 其占总像素点的概率为p(i) = N(i) / SUM; SUM为像素点的总和。可以得到公式:
S(0) = p(0)*255
S(1) = [p(0)+p(1)]*255
S(2) = [p(0)+p(1)+p(2)]*255
........
S(255) = [p(0)+p(1)+......+p(255)]*255 = 255
我们在原图中将亮度为 i 的像素点赋值为 S(i),就可以实现均衡化了。
cv::Mat Histogram::stretch2(const cv::Mat& image) {
cv::MatND hist = getHistogram(image);
float scale[256];
float lookupF[256];
cv::Mat lookup(cv::Size(1, 256), CV_8U);
int pixNum = image.cols * image.rows;
for (int i =0; i <256; i++) {
scale[i] = hist.at<float>(i) / pixNum *255;
if (i ==0) {
lookupF[i] = scale[i];
} else {
lookupF[i] = lookupF[i -1] + scale[i];
}
}
for (int i =0; i <256; i++) {
lookup.at<uchar>(i) = static_cast<uchar>(lookupF[i]);
}
cv::Mat result;
cv::LUT(image, lookup, result);
return result;
}
cv::Mat Histogram::stretch3(const cv::Mat& image) {
cv::Mat result;
cv::equalizeHist(image, result);
return result;
}
在这里,我们定义了两个函数,一个按照刚才的思路来实现,另一个是OpenCV2 提供的标准的均衡化函数。
我们来看看效果
两种方法得到的效果和直方图的形状几乎一模一样。可见,标准的均衡化方法也是按此思路实现的,具体的源代码就不研究了。
相关文章推荐
- opencv查找表值直方图均衡化
- OpenCV直方图均衡化
- OpenCV之imgproc 模块. 图像处理(4)直方图均衡化 直方图计算 直方图对比 反向投影 模板匹配
- opencv-直方图均衡化
- OpenCV图像增强:直方图拉伸和直方图均衡化
- OPENCV直方图均衡化
- opencv直方图均衡化图像
- 【OpenCV入门指南】第十篇 彩色直方图均衡化
- opencv2直方图均衡化
- 【OpenCV入门指南】第十篇 彩色直方图均衡化
- OpenCV2.4.4中利用直方图均衡化增强图像对比度(Mat结构实现)
- 【OpenCV入门指南】第十篇 彩色直方图均衡化
- (34)Air Band OpenCV2.4.13_直方图均衡化
- OPenCV直方图均衡化
- OpenCV 图像处理(直方图均衡化、拉普拉斯算子图像增强、Gamma校正)
- 彩色图像的直方图均衡化--基于OpenCV中EqualizeHist_Demo实现
- OpenCV图像增强算法实现(直方图均衡化、拉普拉斯、Log、Gamma)
- opencv 直方图均衡化
- OpenCV-Python教程(9)(10)(11): 使用霍夫变换检测直线 直方图均衡化 轮廓检测
- Opencv图像识别从零到精通(10)-----直方图均衡化与直方图拉伸