[OpenCV] 直方图均衡化

直方图是图像处理中最最最最基本的操作之一,这个基本操作是在太太太太常见了,同时也是很容易理解的操作,对于一些对比度稍微较低的图像,这是一个还挺不错的预处理操作。

1、直方图

先说直方图,直方图就是图像像素的统计表,这个表里记录着一幅图像中每个像素值在图像中出现的个数,一幅图只有一个灰度直方图,但是多幅图可能有相同的直方图,这是N对1的关系。所以在制作直方图的时候就很容易啦,创建一个包含所有像素灰阶的数组(比如,0到255),然后遍历图像,对应像素的在数组中的值加一即可。

2、直方图均衡化

最普通最常见最简单也是比较有效的直方图均衡化,就是在得到直方图后,将直方图的值逐个累加得到一个累计直方图,累计直方图的每个值除以图像总的像素个数,这样就得到了每阶像素在这个图像中的占比,以这个占比乘以255就得到均衡化处理过后的像素值。

在代码实现上也比较简单,先申请一块大小为256的内存,然后遍历原图像,统计并记录像素:

cv::Mat histMat = cv::Mat::zeros(1, 256, CV_32FC1);
float *ptrHis = histMat.ptr<float>(0);
for (int i = 0; i < src.rows; i++)
{
    uchar *ptrSrc = src.ptr<uchar>(i);
    for (int j = 0; j < src.cols; j++)
    {
        int pix = (int)*(ptrSrc + j);
        *(ptrHis + pix) = *(ptrHis + pix) +  1;
    }
}

然后计算累计直方图:

cv::Mat cHistMat = cv::Mat::zeros(1, 256, CV_32FC1);
*(cHistMat.ptr<float>(0)) = *(histMat.ptr<float>(0));
for (int i = 1; i < 256; i++)
{
    *(cHistMat.ptr<float>(0) + i) = *(cHistMat.ptr<float>(0) + i - 1) + *(histMat.ptr<float>(0) + i);
}
for (int i = 0; i < 256; i++)
{
    *(cHistMat.ptr<float>(0) + i) = *(cHistMat.ptr<float>(0) + i) / src.rows / src.cols * 255;
}

然后重新遍历图像,将新的像素值代替原来的像素值:

cv::Mat dst;
src.copyTo(dst);
for (int i = 0; i < src.rows; i++)
{
    uchar *ptrDst = dst.ptr<uchar>(i);
    for (int j = 0; j < src.cols; j++)
    {
        int pix = (int)*(ptrDst + j);
        *(ptrDst + j) = (uchar)(*(cHistMat.ptr<float>(0) + pix));
    }
}

完成,测试结果:

洛阳城里见秋风,

欲作家书意万重。

复恐匆匆说不尽,

行人临发又开封。

上善若水,为而不争。
原文地址:https://www.cnblogs.com/Bearoom/p/11721740.html