日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

不调用python函数实现直方图均衡化_直方图均衡化(HE)

發布時間:2024/10/12 python 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 不调用python函数实现直方图均衡化_直方图均衡化(HE) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前面我們已經講過圖像的直方圖,那圖像的直方圖均衡化又是干嘛的呢?

顧名思義:其實對直方圖進行均衡化,哈哈感覺自己說的就是廢話...

舉個例子:

import cv2 from matplotlib import pyplot as pltimg = cv2.imread("src.jpg", 0)plt.hist(img.ravel(), 256, [0, 256])plt.savefig("histogram.jpg", dpi = 300, bbox_inches = "tight", pad_inches = 0)# dpi : dot per inch # bbox_inches: if 'tight', try to figure out the tight bbox of the figure. # pad_inches: amount of padding[填充] around the figure when bbox_inches is 'tight'.plt.show()

圖1 原圖及對應的直方圖

觀察圖1:原圖的亮暗對比不明顯,感性上,感覺整幅圖像就是灰蒙蒙的.

通過繪制原圖的灰度直方圖,可以看到,像素基本集中在100~200之間,其它的幾乎沒有,因此可理性判斷,該圖像不能夠很好的突出細節信息.

Q1: 怎么才能讓圖像看起來層次比較分明呢?(包含細節信息)

A1: 需要對灰度值進行相關的處理(各種均衡化算法),使圖像的像素分布盡可能廣泛,改善圖像的對比度.

圖2 像素范圍拉伸

1.直方圖均衡化

首先需要明白一個概念:累積分布函數(CDF : Cumulative Distribution Function)

可參考:

0704:概率分布函數、概率密度函數?zhuanlan.zhihu.com

假設你明白了,累積分布函數的相關概念.

現在我們開始直接舉例:

下圖是一個8 x 8 的 灰度圖像的灰度值.

圖3 灰度值

對灰度值的出現次數進行統計:

表1 灰度值的頻率統計

更進一步:計算累積分布函數值,為簡化,累積分布函數值為0的灰度值被省略.

表2 累積分布函數值

直方圖均衡化的公式如下:

注:式(1) 中的round()是一個函數
a: 為整數,round(a)不變;
a: 為浮點數,round(a)圓整到離它最近的整數
a: 為浮點數,且距離兩個整數一樣近時,圓整到偶數.
比如:a = 1.5, 則round(a) = 2

本例中,

注:L為圖像的灰度級數,圖像為灰度圖,所以位深度為8,故灰度級數共有2^8 = 256 級數.

均衡化后的灰度是多少呢?

用灰度78進行實驗:

依次類推:可計算出原圖中每個灰度均衡化后的灰度,如圖4所示:

圖4 均衡化后的灰度注:最小值52變為了0,最大值154變為了255.

圖5 原始圖像與均衡化后圖像的對比圖

代碼實現:

① 原始圖像的直方圖及累積函數圖像:

from cv2 import cv2 import numpy as np from matplotlib import pyplot as pltimg = cv2.imread("src.jpg", 0)hist, bins = np.histogram(img.ravel(), 256, [0, 256])cdf = np.cumsum(hist) #計算累積函數值 cdf_normalized = cdf * max(hist) / max(cdf)plt.plot(cdf_normalized, color = "r") plt.hist(img.ravel(), 256, [0, 256])plt.legend(("cdf", "histogram"), loc = "upper left")plt.show()

圖6 原圖及對應的直方圖與累積分布圖

我們可以看出來直方圖大部分在灰度值較高的部分,而且分布很集中。而 我們希望直方圖的分布比較分散,能夠涵蓋整個 x 軸。所以,我們就需要一個 變換函數幫助我們把現在的直方圖映射到一個廣泛分布的直方圖中。這就是直方圖均衡化要做的事情。

② 原始圖像均衡化后的直方圖與累積函數分布圖

為便于與直方圖均衡化算法原理相結合,我們分為以下幾步來實驗.

第一步:看一下原圖像直方圖縱坐標值

我們用程序跑一下,顯示原圖像直方圖縱坐標值(也就是上面代碼中hist數組里的值),如下圖7所示:

圖7 原圖像的hist數組hist數組:序號表示的是灰度,數值表示灰度的個數.

同樣:我們可以看原圖像累積函數cdf的值,如下圖8所示:

圖8 原圖像的cdf函數值

Q1:cdf中含有大量的0值,我們上述的算法是要忽略0,那怎么辦呢?

A1:使用numpy

# 構建 Numpy 掩膜數組,cdf 為原數組,當數組元素為 0 時,掩蓋(計算時被忽略). cdf_m = np.ma.masked_equal(cdf,0)

使用這個函數,效果如何呢?如圖9所示:

圖9 Numpy掩膜數組

注:計算時,0會被忽略.

第二步:算法公式

其實比較容易實現,如下:

cdf_m = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min())

可以得到映射完后的灰度值,如圖10所示:

圖10 映射后的灰度值

第三步:對掩蓋的元素重新賦值0

圖10所顯示映射后的灰度值,需對被掩蓋的元素重新賦值0

Q1:該怎么做?

# 對被掩蓋的元素賦值,這里賦值為 0 cdf = np.ma.filled(cdf_m, 0).astype('uint8') # 數據類型為:uint8

使用這個函數后,效果如圖11所示:

圖11 賦值0

現在就獲得了一個表(里面的值為映射后的灰度值),我們可以通過查表得知與輸入像素對應的輸出像素 的值。我們只需要把這種變換應用到圖像上就可以了。

img2 = cdf[img] # img為原圖像

這個不知道大家理不理解,其實img的灰度值 成了cdf的索引,然后重新生成一幅新的圖像(也就是均衡化后的圖像).

最后寫一個代碼:

import cv2 import numpy as np from matplotlib import pyplot as pltimg = cv2.imread("src.jpg", 0)hist, bins = np.histogram(img.ravel(), 256, [0, 256])cdf = np.cumsum(hist)# 構建 Numpy 掩模數組,cdf 為原數組,當數組元素為 0 時,掩蓋(計算時被忽略)。 cdf_m = np.ma.masked_equal(cdf,0)# 均衡化公式 cdf_m = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min())# 對被掩蓋的元素賦值,這里賦值為 0 cdf = np.ma.filled(cdf_m,0).astype('uint8')img2 = cdf[img]hist2, bins2 = np.histogram(img2.ravel(), 256, [0, 256])cdf2 = np.cumsum(hist2) cdf_equal_normalized = cdf2 * max(hist2) / max(cdf2)plt.hist(img2.ravel(), 256, [0, 256]) plt.plot(cdf_equal_normalized, "r")cv2.imwrite("equal.jpg", img2) plt.savefig("histogram.jpg", dpi = 300, bbox_inches = "tight")plt.show()

圖12 均衡化后的圖像與對應的直方圖

參考:

https://bk.tw.lvfukeji.com/wiki/%E7%9B%B4%E6%96%B9%E5%9B%BE%E5%9D%87%E8%A1%A1%E5%8C%96?bk.tw.lvfukeji.com

是不是感覺上面的直方圖均衡化算法有點難,其實OpenCV提供了直方圖均衡化算法.

equ = cv2.equalizeHist(img)

一個函數就搞定了,哈哈,說這么多,其實就是在說一個函數,相關的代碼如下:

import cv2 import numpy as npimg = cv2.imread("Origianl.jpg", 0)equ = cv2.equalizeHist(img) res = cv2.hstack((img, equ)) #stacking images side-by-sidecv2.imshow("demo", res)cv2.waitKey() cv2.destroyAllWindows()

效果如下:

圖13 OpenCV的直方圖均衡化

Q2: 大家有沒有想過,為什么變換函數是形如CDF的形式,難道是憑空想出來的 ?

A2: 顯然不是,下面我們一起來分析一下.

假設我們有一張圖像

,其直方圖分布 ,我們想利用一個函數映射: ,將圖像 變為圖像 ,即對圖像 每個像素點施加 變換,就會得到圖像 的直方圖分布為 .

整個過程可按下圖13的圖示說明:圖中右下方是

圖像的灰度直方圖分布,圖中右上方是單調非線性變換函數 ,左上方通過映射得到的圖像 的直方圖分布,其中有 , .

于是可以理解

的作用是將 圖像里面像素點灰度為 的全部變為 ,那么則有:

上面公式可以理解為對應的區間內像素點總數不變. 為實現直方圖均衡化,特殊地有:

其實在這里,我自己有一個疑問:區間 與區間 內的像素點總數是相等的,這點確實如此,但是,這跟積分求和,好像沒有多大的關系啊,在數學中,積分就是求面積(無窮個小矩形的面積相加,這是比較好理解的),在物理中,拿速度與時間進行舉例,積分就是路程(無窮個小區間的路程相加,就是整個區間的路程),而本題中, ,這個我不清楚它代表的是什么?好像沒有實際的意義.
不知道有沒有人清楚,這個該怎么解釋?
經查資料,其實這個積分可以理解為概率,我們可以把灰度與灰度出現的次數(要進行相應的歸一化處理),看成概率密度函數,某一灰度出現的次數越多,代表它的概率密度越大(注意并不是概率越大,連續型隨機變量,概率是要區間的,單說某一變量的概率并沒有意義).

因為我們的目標是直方圖均勻化,那么理想的有

,其中 :圖像的像素點個數, :灰度級數,灰度圖像的位深為 , . 那么可以得到:

便可以解得:

離散形式得:

圖13 直方圖均衡化示意圖

通過上面推導過程可以看出,映射函數

和CDF是密切存相關. 并且,推導過程在是連續上作的處理,而實際上圖像灰度級為256,故是一種以離散情況近似連續分布,如果灰度級別足夠高,產生的結果會是真正均勻分布的直方圖,然而實際得到的直方圖往往不是均勻分布的,而是近似均勻分布. 同時,假設A圖像的灰度直方圖變化劇烈,且某些灰度區間不存在像素點,這會造成CDF劇烈變化 ,從而導致最后產生的B圖像的直方圖也有較大的不均勻性. 但,實際運用過程中,得到的圖像能近似均勻分布已經能達到比較好的對比度增強效果.

參考:

李新春:直方圖均衡化?zhuanlan.zhihu.comybai62868:說說直方圖均衡化?zhuanlan.zhihu.com

總結

以上是生活随笔為你收集整理的不调用python函数实现直方图均衡化_直方图均衡化(HE)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。