數字圖像處理:直方圖均衡推導及實現

推導

岡薩雷斯的書裏給了幾個公式,書中的式3.3-3一直不明白是如何得出的。
ps(s)ds=pr(r)dr p_s(s)ds=p_r(r)dr

下面參考一些文章加上自己理解進行的推導:
s=T(r)s = T(r)

rr爲歸一化後的顏色值,ss爲經過TT變換的值,且T(r)T(r)在區間上爲單調遞增函數,即變換後的s,也是從黑到白,反函數:
r=T1(s)r = T^{-1}(s)


FS(s)FR(r)F_S(s)、F_R(r)分別爲SSRR的分佈函數,則有:
FS(s)=p{Ss}=p{T(R)s}=p{RT1(s)}=FR(T1(s))F_S(s) = p\{S \leq s\} = p\{T(R) \leq s\} = p\{ R \leq T^{-1}(s)\} = F_R(T^{-1}(s))

FS(s)=FR(T1(s))=FR(r)r=T1(s)F_S(s) = F_R(T^{-1}(s)) = F_R(r)|_{r = T^{-1}(s)}左右求導,ps(s)pr(r)p_s(s)、p_r(r)爲概率密度函數:
ps(s)=pr(r)drdsr=T1(s)p_s(s) = p_r(r) \frac{dr}{ds}|_{r = T^{-1}(s)}

dsdr=pr(r)ps(s)\frac{ds}{dr} = \frac{p_r(r)}{p_s(s)}

即爲所求。
均衡化後可知ps(s)=1L1p_s(s) = \frac{1}{L-1},對dsdr=pr(r)ps(s)\frac{ds}{dr} = \frac{p_r(r)}{p_s(s)}進行積分,則:
s=(L1)0rpr(w)dw=T(r) s = (L-1 ) \int_{0}^rp_r(w)dw=T(r)

岡薩雷斯是先給出此公式,說這是圖像處理中特別重要的變換函數,然後求得用這公式可以得到ps(s)=1L1p_s(s) = \frac{1}{L-1}。 可是我不知道怎麼來的,所以這裏我先用結果ps(s)=1L1p_s(s) = \frac{1}{L-1},帶入求得此公式。
此公式也就解釋了爲什麼累計概率(L1)0rpr(w)dw(L-1)\int_{0}^rp_r(w)dw就是T(r)T(r),即ss。離散化比較好理解,這裏不再解釋。

說明

輸入

假設有一幅4*4 大小8灰度級的圖:
在這裏插入圖片描述
在這裏插入圖片描述

0 1 2 3
4 4 4 4
5 5 5 5
6 7 5 6

運算過程

*取整: sk1=int(sk+0.5)s_{k1} = int(s_k + 0.5)

rkr_{_k} nn pr(rk)p_r(r_{_k}) pr(r)\sum p_r(r) sk1s_{k1} ps(rk)p_s(r_{_k})
0 1 1/16 1/16 = 0.06 0 1/16
1 1 1/16 2/16 = 0.12 1 2/16
2 1 1/16 3/16 = 0.19 1 1/16
3 1 1/16 4/16 = 0.25 2 0
4 5 5/16 9/16 = 0.56 4 5/16
5 5 5/16 14/16 = 0.88 6 0
6 1 1/16 15/16 = 0.93 7 5/16
7 1 1/16 1 7 2/16

結果

在這裏插入圖片描述
在這裏插入圖片描述

代碼實現

用python實現

# -*- coding: utf-8 -*-

"""
    @Date: 2019-10-07
    @Written By: jiangzhigang
    @Description:
"""
import cv2
import numpy as np
import matplotlib.pyplot as plt
 

def equalize_hist(img, level):
    img = cv2.copyTo(img, None)
    height = img.shape[0]
    width = img.shape[1]

    color_gray = np.zeros(level, np.float)
    # n
    for i in range(height):
        for j in range(width):
            color_gray[img[i, j]] += 1
    # pr
    are = height * width
    for i in range(level):
        color_gray[i] /= are
    # sum(pr)
    for i in range(1, level):
        color_gray[i] += color_gray[i - 1]
    # sk
    for i in range(level):
        color_gray[i] = color_gray[i] * (level - 1) + 0.5
    # r -> s
    for i in range(height):
        for j in range(width):
            img[i, j] = color_gray[img[i, j]]
    return img


def show_hist(img, level, title="hist"):
    height = img.shape[0]
    width = img.shape[1]

    color_gray = np.zeros(level, np.float)
    # n
    for i in range(height):
        for j in range(width):
            color_gray[img[i, j]] += 1

    # pr
    are = height * width
    for i in range(level):
        color_gray[i] /= are

    x = np.linspace(0, level-1, level)
    y = color_gray
    plt.bar(x, y, 1, alpha=1, color='b')
    plt.title(title)
    plt.show()


img0 = cv2.imread("images/leaf.jpg", 0)
gray = cv2.resize(img0, (400, 400))
# test use
# gray = cv2.resize(img0, (4, 4))
# gray[0][0] = 0
# gray[0][1] = 1
# gray[0][2] = 2
# gray[0][3] = 3
# gray[1][0] = 4
# gray[1][1] = 4
# gray[1][2] = 4
# gray[1][3] = 4
# gray[2][0] = 5
# gray[2][1] = 5
# gray[2][2] = 5
# gray[2][3] = 5
# gray[3][0] = 6
# gray[3][1] = 7
# gray[3][2] = 5
# gray[3][3] = 4

plt.imshow(gray, cmap='gray')
plt.title('resource')
plt.show()
show_hist(gray, 256, "rec_hist")

destination = equalize_hist(gray, 256)
plt.imshow(destination, cmap='gray')
plt.title('destination')
plt.show()
show_hist(destination, 256, 'dst_hist')

# opencv 
destination_ = cv2.equalizeHist(gray)
plt.imshow(destination_, cmap='gray')
plt.title('destination_')
plt.show()
show_hist(destination_, 256, 'op_cv_hist')

結果

原圖

在這裏插入圖片描述
在這裏插入圖片描述

實現均衡化

在這裏插入圖片描述
在這裏插入圖片描述

opencv實現

在這裏插入圖片描述
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章