提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
上一章我们介绍了直方图均衡化,用一句话总结直方图均衡化,就是我们需要找到一种变换方式,使变换后的图像的直方图跟价均衡,这一章我们介绍直方图匹配(即:直方图规定化)。
1. 直方图规定原理
1.1 理论基础
直方图规定化,顾名思义,就是规定输出图像的直方图,理论推导如下。
假设有一张原始图像
A
A
A,已知其概率密度为
p
(
r
)
p(r)
p(r),若对其做直方图均衡化得到图像
A
′
A'
A′,对应的变换函数为
T
(
i
)
T(i)
T(i),则有:
T
(
i
)
=
∫
0
i
p
(
r
)
d
r
T(i)=\int_0^i {p(r)} \,{\rm d}r
T(i)=∫0ip(r)dr假设有一张目标图像
B
B
B,已知其概率密度为
p
(
u
)
p(u)
p(u),若对其做直方图均衡化得到图像
B
′
B'
B′,对应的变换函数为
G
(
j
)
G(j)
G(j),则有:
G
(
j
)
=
∫
0
j
p
(
u
)
d
u
G(j)=\int_0^j {p(u)} \,{\rm d}u
G(j)=∫0jp(u)du由上面两个公式可以证明
G
(
j
)
=
s
=
T
(
i
)
G(j)=s=T(i)
G(j)=s=T(i),因此
A
′
=
B
′
A'=B'
A′=B′,即:
B
=
G
−
1
(
B
′
)
=
G
−
1
(
A
′
)
B=G^{-1}(B')=G^{-1}(A')
B=G−1(B′)=G−1(A′)
B
=
G
−
1
[
T
(
i
)
]
B=G^{-1}[T(i)]
B=G−1[T(i)]
1.2 手工实现
后续实现
2. 直方图规定化示例
2.1. 示例代码
import numpy as np
import matplotlib.pyplot as plt
import cv2 as cv
from matplotlib.ticker import MultipleLocator, AutoMinorLocator
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 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 generateMappingTable(pdf):
"""
根据概率密度函数生成映射表
:param pdf: 概率密度函数
:return: 返回映射表
"""
table = np.zeros(256)
cdf = 0 # 累计概率密度(也就是概率分布)
for i in range(256):
cdf += pdf[i]
table[i] = round(cdf * 255, 0)
return table
def generateMulNormalPdf(means, stds, weights, shift):
"""
生成多峰正态分布概率密度
:param means: 每个峰的均值
:param stds: 每个峰的标准值
:param weights: 每个峰所占的权重(和为1)
:param shift: 整体向上偏移量
:return: 返回概率密度
"""
# 生成变量
x = np.arange(0, 256)
PDF = np.zeros([256, ], dtype=float)
for i in range(len(means)):
# 每个正态分布的均值和方差和所占权重
mean = means[i]
std = stds[i]
weight = weights[i]
pdf = weight * np.exp(-(x - mean) ** 2 / (2 * std ** 2)) / (std * np.sqrt(2 * np.pi))
PDF += pdf
# 整体向上移动
PDF += shift
# 归一化处理
return PDF / np.sum(PDF)
# 映射表(均衡化后的图像的像素 映射到了 哪个像素值)
def histogramMatching(img, pdf):
"""
进行直方图匹配(即直方图规定化)
:param img: 灰度图像
:param pdf: 指定的概率密度
:return: 返回规定化图像
"""
# 第一步:根据双峰概率密度生成映射表
table = generateMappingTable(pdf)
# 第二步:对灰度图像进行均衡化
imgHE, transHE = equalizeHistogram(img)
# 第三步:执行匹配操作
dst = np.copy(imgHE)
for v in range(256):
if v in imgHE:
if v in table:
dst[imgHE[:, :] == v] = np.where(table == v)[0][-1]
return imgHE, table, dst, transHE
if __name__ == '__main__':
img = cv.imread('Image/Fig0405.tif')
# 生成双峰概率密度
means = (38, 191)
stds = (13, 13)
weights = (0.93, 0.07)
shift = 0.002
pdf = generateMulNormalPdf(means, stds, weights, shift)
# 根据上面的概率密度,进行直方图匹配
imgHE, table, imgMatch, transHE = histogramMatching(img, pdf)
# 计算三个图像的直方图
hist = cv.calcHist([img], [0], None, [256], [0, 256])
hist = hist / np.sum(hist)
histHE = cv.calcHist([imgHE], [0], None, [256], [0, 256])
histHE = histHE / np.sum(histHE)
histMatch = cv.calcHist([imgMatch], [0], None, [256], [0, 256])
histMatch = histMatch / np.sum(histMatch)
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams["font.size"] = 16
plt.figure(figsize=(11, 15))
titleList = ["原图像", "均衡化后", "正规化后", "原图像直方图", "均衡化后直方图", "正规化后直方图", "双峰正态",
"均衡化灰度级变换", "正规化灰度级变换"]
imageList = [img, imgHE, imgMatch, hist, histHE, histMatch, pdf, transHE, table]
for i in range(3):
plt.subplot(3, 3, i + 1), plt.title(titleList[i]), plt.axis('off')
plt.imshow(imageList[i], vmin=0, vmax=255, cmap='gray')
for i in range(3, 6):
plt.subplot(3, 3, i + 1), plt.title(titleList[i])
plt.plot(imageList[i], color='r')
plt.grid(True)
plt.gca().xaxis.set_major_locator(MultipleLocator(50))
plt.gca().yaxis.set_major_locator(MultipleLocator(0.1))
x = np.arange(0, 256)
for i in range(6, 9):
plt.subplot(3, 3, i + 1), plt.title(titleList[i])
plt.plot(x, imageList[i], color='r')
plt.grid(True)
plt.gca().xaxis.set_major_locator(MultipleLocator(50))
# plt.gca().yaxis.set_major_locator(MultipleLocator(0.1))
plt.tight_layout()
plt.savefig("Image/tmp.png")
plt.show()
plt.show()
2.2. 示例效果
从上图分析可知:
对原图像进行直方图均衡化,会导致原图像过亮,变换效果不好,而从均衡化直方图可以看出,变换后的直方图150之后,明显的矫正过度,从均衡化变换图像可以看出 0 直接变换成了 160,因此效果较差
对原图像进行直方图规定话,指定目标直方图为双峰直方图(因为原图像也是有两个峰的),可以看出效果更好,而且正规化后的直方图分布也更加均匀