图像的空间域增强——直方图均衡化算法的原理和实现

摘要

   本文记录机器视觉学习中常用的图像空间域增强的原理和实现,作为自己后续参考的文献,也给看到本文的同学参考。

直方图均衡化原理

1)基础知识

对于图像,我们可将其看成带有像素值的数字图像,而每一个像素值为一个灰度级,且数字图像的灰度级范围为[0,L-1](L最大为256),同时其为一个离散的图像,我们可以将离散的数值从整体角度看成一个离散函数,故有
h ( r k ) = n k ( r k ) h\begin{pmatrix} r_k\end{pmatrix} = n_k\begin{pmatrix} r_k\end{pmatrix} h(rk)=nk(rk)
其中 r k r_k rk为第k级灰度值, n k n_k nk为图像中灰度级为 r k r_k rk的像素个数,进行归一化处理,求 r k r_k rk的发生概率:
p ( r k ) = n k / n p\begin{pmatrix} r_k\end{pmatrix} = n_k/n p(rk)=nk/n
其中,n为图像中像素的总数,而 p ( r k ) p\begin{pmatrix} r_k\end{pmatrix} p(rk)为灰度级 r k r_k rk发生的概率估计值,进一步推理出,图像中所有灰度级的概率估计值就可以构成灰度级的概率密度函数 p r ( r k ) p_r\begin{pmatrix} r_k\end{pmatrix} pr(rk)

2)直方图均衡化原理

   在真正说直方图原理之前,要先明白直方图均衡化的目的是什么?直方图均衡化本质上就是将图像中的灰度级数目进行均衡化的分布,即为灰度级数目不集中在部分的灰度级之上,当图像直方图完全的均匀分布后,此时的图像的熵是最大的(即每个灰度级的概率分布都是均衡的),图像的对比度也是最大的,进而增强了图像的可观察度。
那我们又如何实现图像的灰度级均匀的分布呢? 答案是变换函数,通过对灰度级的变换实现对原直方图的变换。
在这里我们假设找到一个变换函数 T ( r ) T\begin{pmatrix} r\end{pmatrix} T(r),实现: S = T ( r ) S=T\begin{pmatrix}r\end{pmatrix} S=T(r),但需要满足如下的条件:
(1)灰度级范围为: 0 ≤ r ≤ 1 0\leq r \leq1 0r1
(2)变换函数 T ( r ) T\begin{pmatrix}r\end{pmatrix} T(r)在区间 0 ≤ r ≤ 1 0\leq r \leq1 0r1上单调递增
(3)当 0 ≤ r ≤ 1 0\leq r \leq1 0r1时, T ( r ) T\begin{pmatrix}r\end{pmatrix} T(r)范围为 0 ≤ r ≤ 1 0\leq r \leq1 0r1
注意:
(1)可能看到这里的小伙伴会有一个疑问?为啥灰度级的范围不是最大为255呢?大家可以把这理解成理论知识或者理解成灰度级的取值都在1范围内,实际应用时灰度级的范围还应该是 [ 0 , 255 ] \begin{bmatrix}0,255\end{bmatrix} [0,255]
(2)关于 T ( r ) T\begin{pmatrix}r\end{pmatrix} T(r)范围是因为初始变换为灰度级概率密度累加计算,因此最大值不会超过1。

2)直方图均衡化推理求解

   在原理中,已经介绍初始的变换为灰度级概率密度函数的累加过程(即为求解累加分布函数 T ( r ) T\begin{pmatrix}r\end{pmatrix} T(r)):
S = T ( r ) = ∫ 1 r p r ( x ) d x S=T\begin{pmatrix}r\end{pmatrix}=\int_1^rp_r\begin{pmatrix} x\end{pmatrix}dx S=T(r)=1rpr(x)dx
其中, p r ( x ) p_r\begin{pmatrix} x\end{pmatrix} pr(x)表示灰度级概率密度函数,该累加分布函数(CDF)需要满足如下条件:
(1)灰度级范围为: 0 ≤ r ≤ L − 1 0\leq r \leq L-1 0rL1
(2)变换函数 T ( r ) T\begin{pmatrix}r\end{pmatrix} T(r)在区间 0 ≤ r ≤ L − 1 0\leq r \leq L-1 0rL1上单调递增
(3)当 0 ≤ r ≤ L − 1 0\leq r \leq L-1 0rL1时, T ( r ) T\begin{pmatrix}r\end{pmatrix} T(r)范围为 0 ≤ r ≤ L − 1 0\leq r \leq L-1 0rL1
在此基础上再进一步进行函数变换,寻找变换函数实现图像的直方图均衡分布,在这里我就直接给出如下公式:
S = T ( r ) = ( L − 1 ) ∫ 0 r p r ( x ) d x ( 1 ) S=T\begin{pmatrix}r\end{pmatrix}=\begin{pmatrix}L-1\end{pmatrix}\int_0^rp_r\begin{pmatrix} x\end{pmatrix}dx \begin{pmatrix} 1\end{pmatrix} S=T(r)=(L1)0rpr(x)dx(1)
对于该公式是如何得到的?我只能说是之前的研究员经过大量实验获得的,大家也可以尝试如下一个公式,个人观点均可以:
S = T ( r ) = ( ( L − 1 ) ∫ 0 r p r ( x ) d x + 0.5 ) ( 2 ) S=T\begin{pmatrix}r\end{pmatrix}=\begin{pmatrix} \begin{pmatrix}L-1\end{pmatrix}\int_0^rp_r\begin{pmatrix} x\end{pmatrix}dx+0.5\end{pmatrix} \begin{pmatrix} 2\end{pmatrix} S=T(r)=((L1)0rpr(x)dx+0.5)(2)
注意:该公式没有附贴代码,大家可自己修改
接下来,对上述的 公式 ( 1 ) \begin{pmatrix} 1\end{pmatrix} (1)进行离散形式变换,因为是对灰度级概率密度函数进行积分,而积分的本质可看成为累加,故可变换如下形式:
S = T ( r ) = ( L − 1 ) ∑ 0 r p r ( x ) S=T\begin{pmatrix}r\end{pmatrix}=\begin{pmatrix}L-1\end{pmatrix}\sum_0^rp_r\begin{pmatrix} x\end{pmatrix} S=T(r)=(L1)0rpr(x)
其中, r r r的范围为 0 ≤ r ≤ L − 1 0\leq r \leq L-1 0rL1

直方图均衡化实现

(1)统计图像中灰度级的数目
(2)计算灰度级的累加分布概率
(3)通过变换函数,获变换后的灰度级的概率密度
(4)遍布原图,修改原图像

直方图均衡化代码

# include <iostream>
#include <opencv.hpp>

using namespace cv;
using namespace std;
void GetHistogram(const Mat& srcImage, int* histogram);

int main() {
	Mat srcImage; //存放读取的原图
	Mat dstImage; //直方均衡的图像
	srcImage = imread("d://1.jpg", 0); //1RGB 0灰色

	if (!srcImage.data) 
		cout << "图片加载失败,请检查文件是否存在!" << endl;
	else
		cout << "图片加载成功!" << endl;
	CV_Assert(srcImage.type() == CV_8UC1); //判断图像是否为灰度图片,非灰色报错
	dstImage.create(srcImage.size(), srcImage.type()); //设置目标图与原图大小和类型相同

	// 计算直方图,即为每个灰度级在图像中的数目
	int histogram[256]; //存放为每一个灰度级在图像中的数目
	GetHistogram(srcImage, histogram);

	//计算累积分布函数,变换函数
	int pixelSrcImage = srcImage.cols * srcImage.rows;
	int Lut[256]; //分布函数
	Lut[0] = (1.0 * histogram[0] / pixelSrcImage) * 255;
	int sum = histogram[0];
	for (int i = 1; i < 256; ++i) {
		sum += histogram[i];
		Lut[i] = (1.0 * sum / pixelSrcImage) * 255;
	}

	//灰度变换
	uchar* srcImageDate = srcImage.data;
	uchar* dstImageDate = dstImage.data;
	for (int i = 0; i < pixelSrcImage; ++i) {
		dstImageDate[i] = Lut[srcImageDate[i]];
	}
	imshow("原始图像", srcImage);
	imshow("直方图均衡后图像", dstImage);
	//保持等待状态
	waitKey(0);//括号里可以填任意正整数,意味着,图像显示的毫秒时间

	return 0;
}
void GetHistogram(const Mat& srcImage, int* histogram) {
	memset(histogram, 0, 256 * sizeof(int)); //设置histogram数组初始全为0

	//建立直方图, 统计图像中每一灰度级数
	int pixelCount = srcImage.cols * srcImage.rows;
	uchar *srcImageDate = srcImage.data;
	for (int i = 0; i < pixelCount; ++i) {
		int grayDate = srcImageDate[i];
		histogram[grayDate]++;
	}
}

实验结果

在这里插入图片描述

如有错误!敬请大家批评指责!

      一起学习!一起进步!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Chuckie今天也要学习!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值