循序渐进之(二)空间域图像增强之直方图处理直方图均衡化(HE)
冈萨雷斯第二版《数字图像处理》,直方图均衡化是3.3.1章节的内容。
(拓展:
HE算法:直方图均衡化。。
AHE算法:自适应直方图均衡化。。
CLHE算法:限制对比度直方图均衡化。。
CLAHE算法:限制对比度自适应直方图均衡化。。)
第一个问题。均衡化过程中,必须要保证两个条件:①像素无论怎么映射,一定要保证原来的大小关系不变,较亮的区域,依旧是较亮的,较暗依旧暗,只是对比度增大,绝对不能明暗颠倒;②如果是八位图像,那么像素映射函数的值域应在0和255之间的,不能越界。综合以上两个条件,累积分布函数是个好的选择,因为累积分布函数是单调增函数(控制大小关系),并且值域是0到1(控制越界问题),所以直方图均衡化中使用的是累积分布函数。
第二个问题。累积分布函数具有一些好的性质,那么如何运用累积分布函数使得直方图均衡化?比较概率分布函数和累积分布函数,前者的二维图像是参差不齐的,后者是单调递增的。
1.具体原理请参考:
2.opencv中equalizeHist()源码学习请参考:
3.代码主要参考:
#include<iostream>
#include<opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat originImage = imread("E://duibi.jpg",0);
Mat equalizeImage(originImage.size(), originImage.type());
Mat src(originImage.size(), originImage.type());
vector<vector<int>> pixelNumber(256);//这里的双重vector主要是为了存储对应各个级别像素的个数,每次找到一个
//一个灰度为x的像素,对应的将pixelNumber[x] push_back一个数进去,我们不关心实际的vector的数值,只关心pixelNumber[x]的size()即对应灰度像素的数量,
for (int i = 0; i < (originImage.rows - 1); i++)
for (int j = 0; j < (originImage.cols - 1); j++)
{
int x = originImage.at<uchar>(i, j);
pixelNumber[x].push_back(0);
}
//下面这个数组的方法貌似更简洁点
/* for (int j = 0; j < nHeight; j++)
{
for (int i = 0; i < nWidth; i++)
{
arrayDstNum[matDst.at<uchar>(j, i)]++;
}
}*/
for (int i = 0; i < (originImage.rows - 1); i++)
for (int j = 0; j < (originImage.cols - 1); j++)
{
int pixelNumberTotal = 0;
int x = originImage.at<uchar>(i, j);
for (int k = 0; k < x+1; k++)//这里主要计算累计分布,即像素灰度为x的pixelNumberTotal为灰度≤x的所有像素数量的总和
pixelNumberTotal += pixelNumber[k].size();
equalizeImage.at<uchar>(i, j) = pixelNumberTotal * 255 / (equalizeImage.rows*equalizeImage.cols);//利用公式计算均衡化后的灰度值
}
equalizeHist(originImage, src);
imshow("原图", originImage);
imshow("均衡化图", equalizeImage);
imshow("opencv默认均衡化图", src);
waitKey(0);
return 0;
}
结果: