第13章:直方图处理
第13章:直方圖處理
- 一、直方圖的含義:
- 1. 普通直方圖:
- 2. 歸一化直方圖:
- 二、繪制直方圖:
- 1. 使用Numpy繪制直方圖:
- 2. 使用OpenCV繪制直方圖:
- 3. 使用掩碼繪制直方圖:
- 三、直方圖均衡化:
- 1. 直方圖均衡化的原理:
- (1) 在原有范圍內實現均衡化:
- (2) 在更廣泛的范圍內實現均衡化:
- 2. 直方圖均衡化處理:
- 直方圖是圖像處理過程中一種重要的分析工具。
- 直方圖是從圖像內部灰度級的角度對圖像進行表述,包含豐富重要的信息。
- 從直方圖的角度對圖像進行處理,可以達到增強圖像顯示效果的目的。
一、直方圖的含義:
1. 普通直方圖:
從統計的角度講,直方圖統計的是圖像內各個灰度級出現的次數。從直方圖的圖形上觀察,橫坐標是圖像中各像素點的灰度級,縱坐標是具有該灰度級(像素值)的像素個數。
例如,有一幅圖像。該圖中只有9個像素點,存在1、2、3、4、5,共5個灰度級。
統計各個灰度級出現的次數:
在繪制直方圖時,將灰度級作為x軸處理,該灰度級出現的次數作為y軸處理,則可知:
- x軸的數據為x=[1 2 3 4 5]。
- y軸的數據為y=[3 1 2 1 2]。
根據上述關系,可以繪制出如圖所示的折線圖(左圖)和直方圖(右圖)。一般情況下,我們把左側的直線圖和右側直方圖都稱為直方圖。
在實際處理中,圖像直方圖的x軸區間一般是[0,255],對應的是8位位圖的256個灰度級;y軸對應的是具有相應灰度級的像素點的個數。
2. 歸一化直方圖:
歸一化直方圖中,x軸仍然表示灰度級;y軸不再表示灰度級出現的次數,而是灰度級出現的頻率。
- 灰度級出現的頻率 = 灰度級出現的次數/總像素數
例如,統計各個灰度級出現的頻率:
在歸一化直方圖中,各個灰度級出現的頻率之和為1。例如,本例中:
在繪制直方圖時,將灰度級作為x軸數據處理,將其出現的頻率作為y軸數據處理,則可知:
- x軸的數據為x=[1 2 3 4 5]
- y軸的數據為y=[3/9 1/9 2/9 1/9 2/9]
注意:在OpenCV的官網上,特別提出了要注意三個概念:DIMS、BINS、RANGE。
- DIMS:表示在繪制直方圖時,收集的參數的數量。一般情況下,直方圖中收集的數據只有一種,就是灰度級。因此,該值為1。
- RANGE:表示要統計的灰度級范圍,一般為[0,255]。0對應的是黑色,255對應的是白色。
- BINS:參數子集的數目,即參數分的組的數量。在處理數據的過程中,有時需要將眾多的數據劃分為若干個組,再進行分析。
例如,在灰度圖像中,將[0,255]區間內的256個灰度級,按照每16個像素一組劃分為子集:
[0,255]=[0,15]∪[16,31]∪…∪[240,255]
按照上述方式,整個灰度級范圍可以劃分為16個子集,具體為:
整個灰度級范圍=bin1 ∪ bin2 ∪…∪ bin16
子集劃分完以后,某灰度圖像生成的直方圖如圖所示
討論BINS的值:
- 在原始圖像中,如果,共有5個灰度級,其BINS值為5。在以2個灰度級為一個小組劃分子集后,得到3個子集,其BINS值為3。
- 針對灰度圖像,灰度級區間為[0,255],共有256個灰度級,其BINS值為256;在以16個灰度級為一個小組劃分子集后,其BINS值為16。
二、繪制直方圖:
繪制直方圖的方式有兩種:
1. 使用Numpy繪制直方圖:
Python模塊matplotlib.pyplot 提供了一個類似于 MATLAB 繪圖方式的框架,可以使用其中的matplotlib.pyplot.hist() 函數(以下簡稱為hist()函數)來繪制直方圖。
此函數的作用是根據數據源和灰度級分組繪制直方圖。其基本語法格式為:
- matplotlib.pyplot.hist(X,BINS)
- X:數據源,必須是一維的。圖像通常是二維的,需要使用ravel()函數將圖像處理為一維數據源以后,再作為參數使用。
- BINS:BINS的具體值,表示灰度級的分組情況。
示例:
import cv2 import matplotlib.pyplot as pltimg = cv2.imread('../boat.512.tiff', 0) # 將二維數組轉換為一維的 data = img.ravel() print(data) plt.hist(data, 256) plt.show() cv2.imshow('img', img)cv2.waitKey() cv2.destroyAllWindows()# 輸出結果 [127 123 125 ... 102 95 97]2. 使用OpenCV繪制直方圖:
在OpenCV提供了函數cv2.calcHist()用來計算圖像的統計直方圖,該函數能夠統計圖像內各個灰度級的像素點個數。然后,利用matplotlib.pyplot模塊中的plot()函數,可以將函數cv2.calcHist()的統計結果繪制成直方圖。
- hist=cv2.calcHist(images,channels,mask,histSize,ranges,accumulate)
- hist:返回的統計直方圖,是一個一維數組,數組內的元素是各個灰度級的像素個數。
- images:原始圖像,該圖像需要使用“[]”括起來。
- channels:指定通道編號。通道編號需要用“[]”括起來,如果輸入圖像是單通道灰度圖像,該參數的值就是[0]。對于彩色圖像,它的值可以是[0]、[1]、[2],分別對應通道B、G、R。
- mask:掩模圖像。當統計整幅圖像的直方圖時,將這個值設為None。當統計圖像某一部分的直方圖時,需要用到掩模圖像。
- histSize:BINS的值,該值需要用“[]”括起來。例如,BINS的值是256,需要使用“[256]”作為此參數值。
- ranges:即像素值范圍。例如,8位灰度圖像的像素值范圍是[0,255]。
- accumulate:累計(累積、疊加)標識,默認值為False。如果被設置為True,則直方圖在開始計算時不會被清零,計算的是多個直方圖的累積結果,用于對一組圖像計算直方圖。該參數允許從多個對象中計算單個直方圖,或者實時更新直方圖。該參數是可選的,一般情況下不需要設置。
使用matplotlib.pyplot模塊內的plot()函數,將函數cv2.calcHist()的返回值繪制為圖像直方圖
import cv2 import matplotlib.pyplot as pltimg = cv2.imread('../boat.512.tiff', 0) hist = cv2.calcHist([img], [0], None, [256],[0, 255])plt.plot(hist,color='b') plt.show() cv2.imshow('img', img) cv2.waitKey() cv2.destroyAllWindows()補充: 學習plot()函數的其他用法:
示例1: 將給定的x=[0,1,2,3,4,5,6],y=[0.3,0.4,2,5,3,4.5,4],使用plot()函數繪制出來。
import matplotlib.pyplot as pltx = [0, 1, 2, 3, 4, 5, 6] y = [0.3, 0.4, 2, 5, 3, 4.5, 4] plt.plot(x, y) plt.show()圖中x軸由x=[0,1,2,3,4,5,6]指定,y軸由y=[0.3,0.4,2,5,3,4.5,4]指定。
示例2: 給定y=[0.3,0.4,2,5,3,4.5,4],使用plot()函數將其繪制出來,觀察繪制結果。
import matplotlib.pyplot as plty = [0.3, 0.4, 2, 5, 3, 4.5, 4] plt.plot(y) plt.show()從圖中可以看出,在使用plot()函數時,如果僅僅指定一個參數,則其對應x軸的值默認是一個自然數序列x=[0,1,… ,n?1,n]。自然序列x的長度與y的長度保持一致。
示例3: 使用plot()函數將兩組不同的值a=[0.3,0.4,2,5,3,4.5,4], b=[3,5,1,2,1,5,3]以不同的顏色繪制出來。
import matplotlib.pyplot as plta = [0.3, 0.4, 2, 5, 3, 4.5, 4] b = [3, 5, 1, 2, 1, 5, 3] plt.plot(a, color='b') plt.plot(b, color='g')plt.show()示例4: 使用函數plot()和函數cv2.calcHist(),將彩色圖像各個通道的直方圖繪制在一個窗口內。
import cv2 import matplotlib.pyplot as pltimg = cv2.imread('../lena512color.tiff') hist_b = cv2.calcHist([img], [0], None, [256], [0, 255]) hist_g = cv2.calcHist([img], [1], None, [256], [0, 255]) hist_r = cv2.calcHist([img], [2], None, [256], [0, 255])plt.plot(hist_b, 'b') plt.plot(hist_g, 'g') plt.plot(hist_r, 'r') plt.show()cv2.imshow('img', img) cv2.waitKey() cv2.destroyAllWindows()3. 使用掩碼繪制直方圖:
import cv2 import matplotlib.pyplot as plt import numpy as npimg = cv2.imread('../lena512color.tiff')mask = np.zeros(img.shape[:2], np.uint8) mask[200: 400, 200: 400] = 255hist_b = cv2.calcHist([img], [0], mask, [256], [0, 255]) hist_g = cv2.calcHist([img], [1], mask, [256], [0, 255]) hist_r = cv2.calcHist([img], [2], mask, [256], [0, 255])plt.plot(hist_b, 'b') plt.plot(hist_g, 'g') plt.plot(hist_r, 'r') plt.show()rst = cv2.bitwise_and(img, img, mask=mask) cv2.imshow('img', img) cv2.imshow('rst', rst) cv2.waitKey() cv2.destroyAllWindows()三、直方圖均衡化:
為什么要直方圖均衡化?
如果一幅圖像擁有全部可能的灰度級,并且像素值的灰度均勻分布,那么這幅圖像就具有高對比度和多變的灰度色調,灰度級豐富且覆蓋范圍較大。在外觀上,這樣的圖像具有更豐富的色彩,不會過暗或過亮。
如上圖直方圖均衡化前后的對比
? 在OpenCV的官網上,對圖像均衡化前后的直方圖進行了對比,如圖所示。其中,左圖是原始圖像的直方圖,可以看到灰度級集中在中間,圖像中沒有較暗和較亮的像素點;右圖是對原圖均衡化后的直方圖,像素分布更均衡。
什么是直方圖均衡化?
? 直方圖均衡化的主要目的是將原始圖像的灰度級均勻地映射到整個灰度級范圍內,得到一個灰度級分布均勻的圖像。這種均衡化,既實現了灰度值統計上的概率均衡,也實現了人類視覺系統(Human Visual System,HVS)上的視覺均衡。
例如:在某幅圖像內僅僅出現了1、2、3、101、102、103等6個像素值,其分布分別如表中的情況A和情況B所示。
下面分別討論這兩種情況下像素值均衡的情況。
- 情況A:每一個灰度級在圖像內出現的次數都是1,灰度級均勻地映射到當前的灰度級范圍內,所以可以理解為其直方圖是均衡的。
- 情況B:灰度級1、2、3出現的次數都是1次,灰度級103出現的次數是3次,灰度級101、102出現的次數是0次。從表面上看,灰度級是不均衡的。但是,從HVS的角度來說,人眼的敏感度不足以區分1個像素值的差異,即人眼會將灰度級1、2和3看作是相同的,會將灰度級101、102和103看作是相同的。也就是說,HVS會自動地將灰度級劃分為兩組,灰度級[1,3]為一組,灰度級[101,103]為另一組。在整幅圖像內,這兩組的灰度級出現的次數都是3次,概率是相等的。在均衡化處理中,綜合考慮了統計概率和HVS的均衡。
1. 直方圖均衡化的原理:
直方圖均衡化的算法主要包括兩個步驟:
(1)計算累計直方圖。
(2)對累計直方圖進行區間轉換
在此基礎上,再利用人眼視覺達到直方圖均衡化的目的。
下面我們通過一個例子進行講解。例如,圖像A,它是一幅3位的位圖,即共有8(23)個灰度級,有49個像素。
圖像A共有8個灰度級,范圍為[0,7],計算其統計直方圖如表所示:
在此基礎上,計算歸一化統計直方圖,計算方式是計算每個像素在圖像內出現的概率。出現概率=出現次數/像素總數,用每個灰度級的像素個數除以總的像素個數(49),就得到歸一化統計直方圖。
接下來,計算累計統計直方圖,即計算所有灰度級的累計概率。
在累計直方圖的基礎上,對原有灰度級空間進行轉換。可以在原有范圍內對灰度級實現均衡化,也可以在更廣泛的灰度空間范圍內對灰度級實現均衡化。下面分別介紹這兩種形式。
(1) 在原有范圍內實現均衡化:
在原有范圍內實現直方圖均衡化時,用當前灰度級的累計概率乘以當前灰度級的最大值7,得到新的灰度級,并作為均衡化的結果。
- 原始圖像A中的灰度級0,經直方圖均衡化后調整為新的灰度級1(即均衡化值1)。在原始圖像A中,灰度級0共有9個像素點,所以在均衡化后的圖像中,灰度級1共有9個像素點。
- 原始圖像A中的灰度級1和2經直方圖均衡化后調整為灰度級3。在原始圖像A中,灰度級1共有9個像素點,灰度級2共有6個像素點,所以在均衡化后的圖像中,灰度級3共有9+6=15個像素點。
- 原始圖像A中的灰度級3經直方圖均衡化后調整為灰度級4。在原始圖像A中,灰度級3共有5個像素點,所以在均衡化后的圖像中,灰度級4共有5個像素點。
- 原始圖像A中的灰度級4和5經直方圖均衡化后調整為灰度級5。在原始圖像A中,灰度級4共有6個像素點,灰度級5共有3個像素點,所以在均衡化后的圖像中,灰度級5共有6+3=9個像素點。
- 原始圖像A中的灰度級6經直方圖均衡化后調整為灰度級6。在原始圖像A中,灰度級6共有3個像素點,所以在均衡化后的圖像中,灰度級6共有3個像素點。
- 原始圖像A中的灰度級7經直方圖均衡化后調整為灰度級7。在原始圖像A中,灰度級7共有8個像素點,所以在均衡化后的圖像中,灰度級7共有8個像素點。
經過均衡化處理后,灰度級在整個灰度空間內的分布會更均衡。
直方圖均衡化前后的對比圖。其中,左圖是均衡化之前的直方圖,右圖是均衡化之后的直方圖。
這里的均衡化是綜合考慮了統計概率和HVS的結果。
- 在圖像A中,未進行直方圖均衡化之前:灰度級0 ~ 3之間的像素個數為29個,灰度級4 ~ 7之間的像素個數為20個。
- 對圖像A進行直方圖均衡化之后:灰度級0 ~ 3之間的像素個數為24個,灰度級4 ~ 7之間的像素個數為25個。
通過上述比較,可以看出,直方圖均衡化之后圖像的灰度級分布更均衡了。
(2) 在更廣泛的范圍內實現均衡化:
? 在更廣泛的范圍內實現直方圖均衡化時,用當前灰度級的累計概率乘以更廣泛范圍灰度級的最大值,得到新的灰度級,并作為均衡化的結果。
? 例如,要將灰度級空間擴展為[0,255]共256個灰度級,就必須將原灰度級的累計概率乘以255,得到新的灰度級。如表所示的是圖像A在新的灰度級空間[0,255]內的新的灰度級。
經過均衡化處理后,圖像A的灰度級在新灰度空間[0,255]內保持均衡。
通過上述分析可知,通過如下兩個步驟, 可以讓直方圖達到均衡化的效果。
-
計算累計直方圖。
-
將累計直方圖進行區間轉換。
下面我們用數學表達式描述以上的直方圖均衡化過程。假設圖像中像素的總數是N,圖像的灰度級數是L,灰度級空間是[0,L-1],用nkn_knk?表示第k級灰度(第k個灰度級,灰度值為k)在圖像內的像素點個數,那么該圖像中灰度級為rkr_krk?(第k個灰度級)出現的概率為:
根據灰度級概率,對其進行均衡化處理的計算公式為:
式中,表示累計概率,將該值與灰度級的最大值L-1相乘即得到均衡化后的新灰度級(像素值)。
? 直方圖均衡化使圖像色彩更均衡、外觀更清晰,也使圖像更便于處理,它被廣泛地應用在醫學圖像處理、車牌識別、人臉識別等領域。
2. 直方圖均衡化處理:
在OpenCV中通過函數cv2.equalizeHist()來實現直方圖均衡化。該函數的具體語法格式為:
- dst = cv2.equalizeHist(src)
- src:8位單通道原始圖像
- dst:直方圖均衡化處理的結果。
在直方圖均衡化之前,圖像整體比較亮;均衡化以后,圖像的亮度變得比較均衡。而兩幅圖像的直方圖的對比,則不太明顯。這實際上體現了,均衡化是指綜合考慮了統計概率和HVS的結果。
總結
以上是生活随笔為你收集整理的第13章:直方图处理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 字节和字符串
- 下一篇: Debian安装metasploit