天天看点

OpenCV中直方图均衡化OpenCV中直方图均衡化

OpenCV中直方图均衡化

首先知道直方图是个什么鬼?在一幅图像中,直方图所体现的是每个像素值在所有的像素中所占的比例:例 值 为 127 的 像 素 点 的 个 数 / 图 像 总 的 像 素 点 的 个 数 \color{#f00}值为127的像素点的个数/图像总的像素点的个数 值为127的像素点的个数/图像总的像素点的个数

根据这个可以想到在比较 暗的图像中,直方图主要分布在0的附近,而在比较亮的图像中,直方图主要分布在255附近,为了使图像更加清晰,体现出更多的纹理等,需要将像素均匀的分布在0-255之间,这样图像看起来就不会太暗或者太亮,这就是直方图均衡化的思想。

具体的步骤:

OpenCV中直方图均衡化OpenCV中直方图均衡化

图片来自:https://blog.csdn.net/macunshi/article/details/79815870

根据这个图片上所说,我将均衡化分为以下几个步骤,并在最后根据这个步骤手写代码实现直方图的均衡化:

1、统计各个像素出现的频率。

2、计算每个像素频率的向前累积。

3、根据计算的频率,得到均衡化后的图像像素值。

4、根据像素值之间的映射将原图像进行相应的处理。

当然了,我们可以不用这麽麻烦,因为OpenCV再一次给我们了一个方便至极的API函数:

equalizeHist(
	输入图像,要求是但通道灰度图。
	输出图像。
);
           

下面看一下手动实现吧!效果没有使用API来的好,所以推荐使用API,但也要知道如何实现。在一个小白看来API确实开发方便,但如果只是会使用API,而对实现的原理一无所知,不仅API函数用不好,基础也没法得到锻炼。

int a[256][3];//定义一个256行3列的数组,第一列存贮0-255像素值,第二列存储出    现的次数,第三列存储均衡化后的像素值。这样第一列和第三列就构成了原像素到新像素的映射关系。
    for(int i = 0 ;i < 256;i++)
    {
        a[i][0] = i;
        a[i][1] = 0;
        a[i][2] = 0;
    }
    for(int row = 0;row < dst.rows;row++)
    {
        for(int col = 0;col < dst.cols;col++)
        {
            a[dst.at<uchar>(row,col)][1] += 1;
        }
    }
    double p[256];//定义一个数组用来存储每个像素出现的频率。
    for(int i  = 1;i < 256;i++)
    {
        p[0] = (float)a[0][1]/(dst.rows*dst.cols);
        p[i] = (float)a[i][1]/(dst.rows*dst.cols) + p[i-1];
        a[i][2] = int(p[i]*255+0.5);
    }

    for(int row = 0;row < dst.rows;row++)
    {
        for(int col = 0;col < dst.cols;col++)
        {
            dst.at<uchar>(row,col) = a[dst.at<uchar>(row,col)][2];//根据映射关系将原像素值由新像素值替代。
        }
    }
    
    imshow("dst",dst);
           

以下是完整的代码:

#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;


int main()
{
    Mat src = imread("/home/dynamicw/Project/C++_Project/opencvtest/src/lesson01/source/map.png");
    Mat dst;
    cvtColor(src,dst,CV_RGB2GRAY);
    imshow("yuan",dst);
    equalizeHist(dst,src);
    imshow("src",src);
    int a[256][3];
    for(int i = 0 ;i < 256;i++)
    {
        a[i][0] = i;
        a[i][1] = 0;
        a[i][2] = 0;
    }
    for(int row = 0;row < dst.rows;row++)
    {
        for(int col = 0;col < dst.cols;col++)
        {
            a[dst.at<uchar>(row,col)][1] += 1;
        }
    }
    double p[256];
    for(int i  = 1;i < 256;i++)
    {
        p[0] = (float)a[0][1]/(dst.rows*dst.cols);
        p[i] = (float)a[i][1]/(dst.rows*dst.cols) + p[i-1];
        a[i][2] = int(p[i]*255+0.5);
    }

    for(int row = 0;row < dst.rows;row++)
    {
        for(int col = 0;col < dst.cols;col++)
        {
            dst.at<uchar>(row,col) = a[dst.at<uchar>(row,col)][2];
        }
    }
    
    imshow("dst",dst);
    
    waitKey(0);
    return 0;
}