4.3 直方图匹配(规定化)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

上一章我们介绍了直方图均衡化,用一句话总结直方图均衡化,就是我们需要找到一种变换方式,使变换后的图像的直方图跟价均衡,这一章我们介绍直方图匹配(即:直方图规定化)。


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=G1(B)=G1(A) B = G − 1 [ T ( i ) ] B=G^{-1}[T(i)] B=G1[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,因此效果较差
  • 对原图像进行直方图规定话,指定目标直方图为双峰直方图(因为原图像也是有两个峰的),可以看出效果更好,而且正规化后的直方图分布也更加均匀
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值