4.2 直方图均衡化

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


前言

上一章我们简单介绍了一下什么是直方图,并且举例说明了一下不同特点的图像的直方图有什么不同,这一章我们讨论直方图均衡化。


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,...L1=MNh(k)=MNnk:像素值为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=1010=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=0kNni=[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 L1再四舍五入,以使得均衡化后图像的灰度级与归一化前的原始图像一致。

  • s 0 = 7 100 ∗ ( L − 1 ) = 7 100 ∗ 9 = 1 s_0=\frac{7}{100}*(L-1)=\frac{7}{100}*9=1 s0=1007(L1)=10079=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(L1)=100169=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(L1)=100249=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(L1)=100349=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(L1)=100499=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(L1)=100569=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(L1)=100659=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(L1)=100839=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(L1)=100909=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(L1)=1001009=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 示例效果说明

在这里插入图片描述
从上述图像中可以看出:

  • 图像经过均衡化后,不论是亮度还是对比度,都有明显增强
  • 经过均衡化之后的图像的直方图分布更加均衡化
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值