OpenCV中直方图均衡化
首先知道直方图是个什么鬼?在一幅图像中,直方图所体现的是每个像素值在所有的像素中所占的比例:例 值 为 127 的 像 素 点 的 个 数 / 图 像 总 的 像 素 点 的 个 数 \color{#f00}值为127的像素点的个数/图像总的像素点的个数 值为127的像素点的个数/图像总的像素点的个数
根据这个可以想到在比较 暗的图像中,直方图主要分布在0的附近,而在比较亮的图像中,直方图主要分布在255附近,为了使图像更加清晰,体现出更多的纹理等,需要将像素均匀的分布在0-255之间,这样图像看起来就不会太暗或者太亮,这就是直方图均衡化的思想。
具体的步骤:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL4lFRNFTQU1UMJpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLxgjNyAjMxkDMyIDMxkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
图片来自: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;
}