提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
上一章我们简单介绍了一下什么是直方图,并且举例说明了一下不同特点的图像的直方图有什么不同,这一章我们讨论直方图均衡化。
1. 直方图均衡化原理
直方图均衡化依旧属于图像变换,也就是输入一个图像,经过变换,输出另一个图像,既然是图像变换,那么实际作用到的依旧是图像的像素,那么图像变换的函数公式依旧可以表示如下: g ( x , y ) = F ( f ( x , y ) ) f ( x , y ) 是位于图像点 ( x , y ) 处的像素的值 g(x,y)=F(f(x,y))\quad f(x,y)是位于图像点(x,y)处的像素的值 g(x,y)=F(f(x,y))f(x,y)是位于图像点(x,y)处的像素的值那么问题的重点就来到了如何确定 F F F
1.1 直方图均衡化理论基础
上一章我们介绍了下面两个公式
h
(
k
)
=
n
k
k
=
0
,
1
,
2
,
3
,
.
.
.
L
−
1
p
(
k
)
=
h
(
k
)
M
∗
N
=
n
k
M
∗
N
n
k
:像素值为
k
的像素的个数
p
(
k
)
:像素值为
k
的像素的频率
(
概率
)
\begin{aligned} h(k)&=n_k \quad k=0,1,2,3,...L-1 \\ p(k)&=\frac{h(k)}{M*N}=\frac{n_k}{M*N} \\ \\ n_k&:像素值为k的像素的个数 \\ p(k)&:像素值为k的像素的频率(概率) \\ \end{aligned}
h(k)p(k)nkp(k)=nkk=0,1,2,3,...L−1=M∗Nh(k)=M∗Nnk:像素值为k的像素的个数:像素值为k的像素的频率(概率)
那么直方图均衡化究竟要做什么呢?将一个图像(输入图像)变换成另一个图像,我们先假设已经变换成功,也就是说已经输出了一个图像,那么输出图像有什么特点呢?输出图像的特点就是图像的概率密度比较均衡,也就是输出图像的直方图比较均衡。
上图中,左边是输入图像概率密度,右边是我们期望的输出图像的概率密度。
理论公式推导
- 假设 r r r为归一化之后的输入图像灰度, s s s 为输出图像的灰度,即: r , s ∈ [ 0 , 1 ] r,s\in[0,1] r,s∈[0,1]
- 由概率论的知识可知,某随机变量的概率分布函数等于其概率密度的函数的积分,即: F ( x ) = ∫ ∞ x f ( t ) d t F(x)=\int_\infty^x {f(t)} \,{\rm d}t F(x)=∫∞xf(t)dt
- 若随机变量 r r r 的概率密度函数为 p ( r ) p(r) p(r),且随机变量 s s s 为 r r r的函数,则必有: ∫ 0 b p ( s ) d s = ∫ 0 a p ( r ) d r \int_0^b {p(s)} \,{\rm d}s=\int_0^a {p(r)} \,{\rm d}r ∫0bp(s)ds=∫0ap(r)dr对两边求导可得: p ( s ) = p ( r ) d r d s p(s)=\frac{p(r)dr}{ds} p(s)=dsp(r)dr
- 有上面得知,我们要的输出图像的概率密度需要均衡,因此我们令
p
(
s
)
p(s)
p(s),则可以得:
p
(
r
)
=
d
s
d
r
,即
d
s
=
p
(
r
)
d
r
p(r)=\frac{ds}{dr},即\quad ds=p(r)dr
p(r)=drds,即ds=p(r)dr两边对
r
r
r 积分,上式可变为:
s
=
∫
0
x
p
(
r
)
d
r
,其中
x
为输入灰度级,
x
∈
[
0
,
1
]
s=\int_0^x {p(r)} \,{\rm d}r,其中x为输入灰度级,x\in[0,1]
s=∫0xp(r)dr,其中x为输入灰度级,x∈[0,1]
上式就是图像均衡化的变换公式。
1.2 直方图均衡化手工实现
了解直方图均衡化理论基础之后,我们以一个简单的例子来手工计算均衡化后的图像。图像如下图所示,灰度级是
(
0
,
9
)
(0,9)
(0,9):
计算过程如下:
第一步:统计原图像的
n
k
n_k
nk,可以得到 :
n
k
=
[
7
,
9
,
8
,
10
,
15
,
7
,
9
,
18
,
7
,
10
]
,
k
=
0
,
1
,
2
,
3
,
.
.
.
,
9
n_k=[7, 9, 8, 10, 15, 7, 9, 18, 7, 10],k = 0,1,2,3,...,9
nk=[7,9,8,10,15,7,9,18,7,10],k=0,1,2,3,...,9
第二步:原图像的个数
N
=
10
∗
10
=
100
N = 10*10 = 100
N=10∗10=100
第三步:计算原始图像的频率 :
p
r
(
k
)
=
n
k
N
=
[
7
100
,
9
100
,
8
100
,
10
100
,
15
100
,
7
100
,
9
100
,
18
100
,
7
100
,
10
100
]
,
k
=
0
,
1
,
2
,
3
,
.
.
.
,
9
p_r(k)=\frac{n_k}{N}=[\frac{7}{100},\frac{9}{100},\frac{8}{100},\frac{10}{100},\frac{15}{100},\frac{7}{100},\frac{9}{100},\frac{18}{100},\frac{7}{100},\frac{10}{100}],k = 0,1,2,3,...,9
pr(k)=Nnk=[1007,1009,1008,10010,10015,1007,1009,10018,1007,10010],k=0,1,2,3,...,9
第四步:计算原始图像的累计分布频率 :
s
(
k
)
=
∑
i
=
0
k
n
i
N
=
[
7
100
,
16
100
,
24
100
,
34
100
,
49
100
,
56
100
,
65
100
,
83
100
,
90
100
,
100
100
]
,
k
=
0
,
1
,
2
,
3
,
.
.
.
,
9
s(k)=\sum_{i=0}^k\frac{n_i}{N}=[\frac{7}{100},\frac{16}{100},\frac{24}{100},\frac{34}{100},\frac{49}{100},\frac{56}{100},\frac{65}{100},\frac{83}{100},\frac{90}{100},\frac{100}{100}],k = 0,1,2,3,...,9
s(k)=i=0∑kNni=[1007,10016,10024,10034,10049,10056,10065,10083,10090,100100],k=0,1,2,3,...,9
第五步:将归一化的
s
k
s_k
sk 乘以
L
−
1
L-1
L−1再四舍五入,以使得均衡化后图像的灰度级与归一化前的原始图像一致。
- s 0 = 7 100 ∗ ( L − 1 ) = 7 100 ∗ 9 = 1 s_0=\frac{7}{100}*(L-1)=\frac{7}{100}*9=1 s0=1007∗(L−1)=1007∗9=1
- s 1 = 16 100 ∗ ( L − 1 ) = 16 100 ∗ 9 = 1 s_1=\frac{16}{100}*(L-1)=\frac{16}{100}*9=1 s1=10016∗(L−1)=10016∗9=1
- s 2 = 24 100 ∗ ( L − 1 ) = 24 100 ∗ 9 = 2 s_2=\frac{24}{100}*(L-1)=\frac{24}{100}*9=2 s2=10024∗(L−1)=10024∗9=2
- s 3 = 34 100 ∗ ( L − 1 ) = 34 100 ∗ 9 = 3 s_3=\frac{34}{100}*(L-1)=\frac{34}{100}*9=3 s3=10034∗(L−1)=10034∗9=3
- s 4 = 49 100 ∗ ( L − 1 ) = 49 100 ∗ 9 = 4 s_4=\frac{49}{100}*(L-1)=\frac{49}{100}*9=4 s4=10049∗(L−1)=10049∗9=4
- s 5 = 56 100 ∗ ( L − 1 ) = 56 100 ∗ 9 = 5 s_5=\frac{56}{100}*(L-1)=\frac{56}{100}*9=5 s5=10056∗(L−1)=10056∗9=5
- s 6 = 65 100 ∗ ( L − 1 ) = 65 100 ∗ 9 = 6 s_6=\frac{65}{100}*(L-1)=\frac{65}{100}*9=6 s6=10065∗(L−1)=10065∗9=6
- s 7 = 83 100 ∗ ( L − 1 ) = 83 100 ∗ 9 = 7 s_7=\frac{83}{100}*(L-1)=\frac{83}{100}*9=7 s7=10083∗(L−1)=10083∗9=7
- s 8 = 90 100 ∗ ( L − 1 ) = 90 100 ∗ 9 = 8 s_8=\frac{90}{100}*(L-1)=\frac{90}{100}*9=8 s8=10090∗(L−1)=10090∗9=8
- s 9 = 100 100 ∗ ( L − 1 ) = 100 100 ∗ 9 = 9 s_9=\frac{100}{100}*(L-1)=\frac{100}{100}*9=9 s9=100100∗(L−1)=100100∗9=9
根据以上映射关系,映射后的图像如下
有点尴尬,变换前后区别不大(只是将0变换为1),但是计算过程没有问题
2. 示例
2.1 示例一(自己计算)
2.1.1 示例代码
import numpy as np
import matplotlib.pyplot as plt
import cv2 as cv
def getImagePdf(img):
"""
获取图像的概率密度
:param img: 输入图像
:return: 返回图像的概率密度
"""
# 计算图像的直方图
hist = cv.calcHist([img], [0], None, [256], [0, 256])
# 将直方图归一化为概率密度
pdf = hist / np.sum(hist)
# 将pdf转化为一维数组
pdf = pdf.flatten()
return pdf
def getHETrans(pdf):
"""
计算直方图均衡化的映射方式(即变换函数),也就是输入图像的像素值会被映射到哪个像素值
:param pdf:输入图像的概率密度
:return:
"""
dst = np.zeros(256)
cdf = 0 # 累计概率密度(也就是概率分布)
for i in range(256):
cdf += pdf[i]
dst[i] = round(cdf * 255, 0)
def equalizeHistogram(img):
"""
直方图均衡化
:param img:
:return:
"""
dst = np.copy(img)
# 计算图像的概率密度
pdf = getImagePdf(img)
cdf = 0 # 累计概率密度(也就是概率分布)
trans = np.zeros(256) # 用来绘制映射表
for i in range(256):
cdf += pdf[i]
dst[img == i] = round(cdf * 255, 0)
trans[i] = round(cdf * 255, 0)
return dst, trans
def calculateHE(img):
# 原图像直方图
hist = cv.calcHist([img], [0], None, [256], [0, 256])
# 均衡化后的图像
# heImg = cv.equalizeHist(img)
heImg, heTrans = equalizeHistogram(img)
# 均衡化后的图像的直方图
heHist = cv.calcHist([heImg], [0], None, [256], [0, 256])
return hist, heImg, heHist, heTrans
if __name__ == '__main__':
# 读取灰度图像
# 读取灰度图像
imgGray1 = cv.imread('Image/Fig0401.tif', 0)
imgHist1, heImg1, heHist1, heTrans1 = calculateHE(imgGray1)
imgGray2 = cv.imread('Image/Fig0402.tif', 0)
imgHist2, heImg2, heHist2, heTrans2 = calculateHE(imgGray2)
imgGray3 = cv.imread('Image/Fig0403.tif', 0)
imgHist3, heImg3, heHist3, heTrans3 = calculateHE(imgGray3)
imgGray4 = cv.imread('Image/Fig0404.tif', 0)
imgHist4, heImg4, heHist4, heTrans4 = calculateHE(imgGray4)
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.figure(figsize=(10, 13))
titleList = ["暗图像", "亮图像", "低对比度图像", "高对比度", "直方图", "直方图", "直方图", "直方图"
, "均衡化后", "均衡化后", "均衡化后", "均衡化后", "直方图", "直方图", "直方图", "直方图", "映射图", "映射图", "映射图", "映射图"]
imageList = [imgGray1, imgGray2, imgGray3, imgGray4, imgHist1, imgHist2, imgHist3, imgHist4
, heImg1, heImg2, heImg3, heImg4, heHist1, heHist2, heHist3, heHist4, heTrans1, heTrans2, heTrans3, heTrans4]
for i in range(4):
plt.subplot(5, 4, i + 1), plt.title(titleList[i]), plt.axis('off')
plt.imshow(imageList[i], vmin=0, vmax=255, cmap='gray')
for i in range(4, 8):
plt.subplot(5, 4, i + 1), plt.title(titleList[i])
plt.plot(imageList[i], color='r')
for i in range(8, 12):
plt.subplot(5, 4, i + 1), plt.title(titleList[i]), plt.axis('off')
plt.imshow(imageList[i], vmin=0, vmax=255, cmap='gray')
for i in range(12, 16):
plt.subplot(5, 4, i + 1), plt.title(titleList[i])
plt.plot(imageList[i], color='r')
for i in range(16, 20):
plt.subplot(5, 4, i + 1), plt.title(titleList[i])
plt.plot(imageList[i], color='r')
plt.tight_layout()
plt.savefig("Image/tmp.png")
plt.show()
2.1.2 示例效果
2.2 示例二(直接使用opencv接口)
2.2.1 示例代码
我这里直接用的opencv的接口,没有直接实现算法。
import numpy as np
import matplotlib.pyplot as plt
import cv2 as cv
def calculateHE(img):
# 原图像直方图
hist = cv.calcHist([img], [0], None, [256], [0, 256])
# 均衡化后的图像
heImg = cv.equalizeHist(img)
# 均衡化后的图像的直方图
heHist = cv.calcHist([heImg], [0], None, [256], [0, 256])
return hist, heImg, heHist
if __name__ == '__main__':
# 读取灰度图像
imgGray1 = cv.imread('Image/Fig0401.tif', 0)
imgHist1, heImg1, heHist1 = calculateHE(imgGray1)
imgGray2 = cv.imread('Image/Fig0402.tif', 0)
imgHist2, heImg2, heHist2 = calculateHE(imgGray2)
imgGray3 = cv.imread('Image/Fig0403.tif', 0)
imgHist3, heImg3, heHist3 = calculateHE(imgGray3)
imgGray4 = cv.imread('Image/Fig0404.tif', 0)
imgHist4, heImg4, heHist4 = calculateHE(imgGray4)
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.figure(figsize=(10, 10))
titleList = ["暗图像", "亮图像", "低对比度图像", "高对比度", "直方图", "直方图", "直方图", "直方图"
, "均衡化后", "均衡化后", "均衡化后", "均衡化后", "直方图", "直方图", "直方图", "直方图"]
imageList = [imgGray1, imgGray2, imgGray3, imgGray4, imgHist1, imgHist2, imgHist3, imgHist4
, heImg1, heImg2, heImg3, heImg4, heHist1, heHist2, heHist3, heHist4]
for i in range(4):
plt.subplot(4, 4, i + 1), plt.title(titleList[i]), plt.axis('off')
plt.imshow(imageList[i], vmin=0, vmax=255, cmap='gray')
for i in range(4, 8):
plt.subplot(4, 4, i + 1), plt.title(titleList[i])
plt.plot(imageList[i], color='r')
for i in range(8, 12):
plt.subplot(4, 4, i + 1), plt.title(titleList[i]), plt.axis('off')
plt.imshow(imageList[i], vmin=0, vmax=255, cmap='gray')
for i in range(12, 16):
plt.subplot(4, 4, i + 1), plt.title(titleList[i])
plt.plot(imageList[i], color='r')
plt.tight_layout()
plt.savefig("Image/tmp.png")
plt.show()
2.2.2 示例效果说明
从上述图像中可以看出:
图像经过均衡化后,不论是亮度还是对比度,都有明显增强
经过均衡化之后的图像的直方图分布更加均衡化