OpenCV(十九)直方图(直方图计算、掩膜、均衡化、自适应均衡化)
目錄
一、基礎理論
1、原理及作用
2、專業術語
二、直方圖計算
函數介紹:
1、灰度圖
代碼:
?效果:
2、彩色圖
代碼:
?三、直方圖掩膜的應用(mask)
1、基礎理論
2、代碼
3、效果
?四、直方圖均衡化
1、基礎理論
2、代碼
3、效果?
五、自適應的直方圖均衡化
1、基礎理論
2、代碼
3、效果
總代碼
參考資料
一、基礎理論
1、原理及作用
作用:
獲取圖像的強度(灰度)分布。
????????直方圖是數據統計的一種方法,并且將統計值組織到一系列實現定義好的 bin當中。其中, bin為直方圖中經常用到的一個概念,可以譯為“直條”或“組距”,其數值是從數據中計算出的特征統計量,這些數據可以是諸如梯度、方向、色彩或任何其他特征。
????????圖像直方圖(Image Histogram)是用以表示數字圖像中亮度分布的直方圖,標繪了圖像中每個亮度值的像素個數。這種直方圖中,橫坐標的左側為較暗的區域,而右側為較亮的區域。因此—張較暗圖片的直方圖中的數據多集中于左側和中間部分,而整體明亮、只有少量陰影的圖像則相反。?(如圖,左側較暗,右側較亮)?????????灰度直方圖是一幅圖像中個像素灰度值出現次數或頻數的統計結果,它只反映該圖像中灰度值出現的頻率,而未反映某一灰度值像素所在的位置。
直方圖統計的是每一個灰度值所具有的像素個數。(不同圖像直方圖可能相同)
?
??
注意:直方圖是根據灰度圖進行繪制的,而不是彩色圖像。?
2、專業術語
BINS:上面的直方圖顯示每個像素值的像素數,即從0到255。(只需要16個值即可表示直方圖,例如:找到介于0到15之間的像素數,然后找到16到31之間,…,240到255之間的像素數。)(因此,您要做的就是將整個直方圖分成16個子部分)
DIMS:這是我們為其收集數據的參數的數量。在這種情況下,我們僅收集關于強度值的一件事的數據,所以這里是1。
RANGE:這是您要測量的強度值的范圍。通常,它是[0,256],即所有強度值。
二、直方圖計算
函數介紹:
注:這部分實現的是python代碼
cv.calcHist(images,channels,mask,histSize,ranges [,hist [,accumulate]])
- images:它是uint8或float32類型的源圖像。它應該放在方括號中,即“ [img]”。
- channels:也以方括號給出。它是我們計算直方圖的通道的索引。例如,如果輸入為灰度圖像,則其值為[0]。對于彩色圖像,您可以傳遞[0],[1]或[2]分別計算藍色,綠色或紅色通道的直方圖。
- mask:圖像掩碼。為了找到完整圖像的直方圖,將其指定為“無”。但是,如果要查找圖像特定區域的直方圖,則必須為此創建一個掩碼圖像并將其作為掩碼。(我將在后面顯示一個示例。)
- histSize:這表示我們的BIN計數。需要放在方括號中。對于全尺寸,我們通過[256]。
- ranges:這是我們的RANGE。通常為[0,256]。
hist = cv2.calcHist([img], [0], None, [256], [0, 256]) # 圖像 通道索引 掩碼(完整/局部) bin計數 范圍
1、灰度圖
代碼:
#計算直方圖(灰度)
def Calculate_Hist():# 1、讀取圖片, 并轉換成灰度圖img = cv2.imread("Resource/test11.jpg", 0) # 0即灰度圖,1彩圖cv2.imshow("img", img)# 2、獲取并繪制直方圖hist = cv2.calcHist([img], [0], None, [256], [0, 256]) #獲取# 圖像 通道索引 掩碼(完整/局部) bin計數 范圍plt.plot(hist) # 繪圖(基于一點或多點)# 3、直方圖展示plt.show() # 顯示
?效果:
打印直方圖獲取的像素(hist)結果:
前者較亮(直方圖偏右),后者較暗(直方圖偏左):
?純黑白:
2、彩色圖
代碼:
#計算直方圖(彩圖)
def Calculate_Hist_RGB():# 1、讀取圖片img = cv2.imread("Resource/test11.jpg") #彩圖cv2.imshow("img", img)# 設置顏色通道color = ["b", "g", "r"]# 2、獲取直方圖for i, c in enumerate(color): #i是索引,c是內容hist = cv2.calcHist([img], [i], None, [256], [0, 256])plt.plot(hist, color=c)# 3、直方圖展示plt.legend(["B Channel", "G Channel", "R Channel"]) #批注plt.show()
?三、直方圖掩膜的應用(mask)
1、基礎理論
1、作用
(1)提取感興趣區域:用預先制作的感興趣區掩模與待處理圖像進行"與“操作,得到感興趣區圖像,感興趣區內圖像值保持不變,而區外圖像值都為0。
(2)屏蔽∶用掩模對圖像上某些區域作屏蔽,使其不參加處理或不參加處理參數的計算,或僅對屏蔽區作處理或統計。
(3)結構特征提取∶用相似性變量或方圖像匹配法檢測和提取圖像中與掩模相似的結構特征?!ぬ厥庑螤顖D像制作。
掩膜在遙感影像處理中使用較多,當提取道路或者河流,或者房屋時,通過一個掩膜矩陣來對圖像進行像素過濾,然后將我們需要的地物或者標志突出顯示出來。(提取感興趣區域)
2、原理
在數字圖像處理中,通常使用二維矩陣數組進行掩膜。掩膜是由0和1組成一個二進制圖像,利用該掩膜圖像要處理的圖像進行掩膜,其中1值的區域被處理,0值區域被屏蔽,不會處理。
?
2、代碼
#掩膜
def Mask():# 1、讀取圖片, 并轉換成灰度圖img = cv2.imread("Resource/test11.jpg", 0)cv2.imshow("img", img)# 2、創建maskmask = np.zeros(img.shape, np.uint8)mask[100:400, 20:200] = 255 #白色掩膜# 橫坐標范圍 縱坐標范圍cv2.imshow("mask", mask)# 3、獲取mask后的圖像masked_img = cv2.bitwise_and(img, img, mask=mask) #把掩膜用于圖像cv2.imshow("masked_img", masked_img)# 4、獲取并繪制直方圖hist_full = cv2.calcHist([img], [0], None, [256], [0, 256]) #全部直方圖plt.plot(hist_full)hist_mask = cv2.calcHist([img], [0], mask, [256], [0, 256]) #掩膜直方圖plt.plot(hist_mask)# 5、顯示直方圖plt.show()
3、效果
?四、直方圖均衡化
1、基礎理論
作用:通常用于提高圖像的對比度。(強化細節)
????????想象一下,如果一副圖像中的大多數像素點的像素值都集中在某一個小的灰度值值范圍之內會怎樣呢?如果一幅圖像整體亮,那所有的像素值的取值個數應該都會很高。所以應該把它的直方圖做一個橫向拉伸(如下圖),就可以擴大圖像像素值的分布范圍,提高圖像的對比度,這就是直方圖均衡化要做的事情。
圖像均衡化:“直方圖均衡化"是把原始圖像的灰度直方圖從比較集中的某個灰度區間變成在更廣泛灰度范圍內的分布。直方圖均衡化就是對圖像進行非線性拉伸,重新分配圖像像素值,使一定灰度范圍內的像素數量大致相同。直方圖被拉伸(均衡化)之后,細節自然能夠強化。
函數:?
cv2.equalizeHist(img) #直方圖均衡化
2、代碼
#直方圖均衡化
def Equalize_Hist():# 1、讀取圖片, 并轉換成灰度圖img = cv2.imread("Resource/test11.jpg", 0) #灰度圖# 2、直方圖均衡化img_equal = cv2.equalizeHist(img) #直方圖均衡化# 3、顯示直方圖f, ax = plt.subplots(2, 2, figsize=(16, 16))#顯示圖像ax[0, 0].imshow(img, "gray")ax[0, 1].imshow(img_equal, "gray") #注:"gray"是有效名,不能亂寫#顯示直方圖ax[1, 0].hist(img.ravel(), 256) #ravel():多維數組轉一維數組ax[1, 1].hist(img_equal.ravel(), 256)#顯示plt畫板plt.show()
3、效果?
直方圖均衡化的缺陷:由于太暗,損失了許多信息。?所以引入:自適應的直方圖均衡化。
五、自適應的直方圖均衡化
1、基礎理論
直方圖均衡化的缺陷:由于太暗,損失了許多信息。?所以引入:自適應的直方圖均衡化。
作用:
在直方圖均衡化的基礎上,盡可能保留細節信息。(把直方圖分成多個小塊,防止細節信息由于過暗而損失掉)
為了解決這個問題,需要使用自適應的直方圖均衡化。此時,整幅圖像會被分成很多小塊,這些小塊被稱為"tiles”(在OpenCV中tiles的大小默認是8x8),然后再對每一個小塊分別進行直方圖均衡化。所以在每一個的區域中,直方圖會集中在某一個小的區域中)。如果有噪聲的話,噪聲會被放大。為了避免這種情況的出現要使用對比度限制。對于每個小塊來說,如果直方圖中的bin 超過對比度的上限的話,就把其中的像素點均勻分散到其他 bins 中,然后在進行直方圖均衡化。
如下圖,把直方圖像素點分散:
為了去除每一個小塊之間的邊界,再使用雙線性差值,對每個小塊進行拼接。
函數:
cv.createCLAHE(clipLimit, titleGridSize)參數1 clipLimit:????????對比度限值(默認40)。(閾值)
參數2 titleGridSize: 分塊的大小(默認8*8)。(分成幾塊)
2、代碼
#自適應直方圖均衡化
def Clahe_Hist():# 1、讀取圖片, 并轉換成灰度圖img = cv2.imread("Resource/test11.jpg", 0) #灰度圖# 2、自適應直方圖均衡化cl = cv2.createCLAHE(2.0, (8,8))# 對比度限制 分塊大小clahe = cl.apply(img) #自適應直方圖均衡化# 3、顯示直方圖f, ax = plt.subplots(2, 2, figsize=(16, 16))#顯示圖像ax[0, 0].set_title("origin")ax[0, 0].imshow(img, "gray")ax[0, 1].set_title("Equalized")ax[0, 1].imshow(clahe, "gray") #注:"gray"是有效名,不能亂寫#顯示直方圖ax[1, 0].hist(img.ravel(), 256) #ravel():多維數組轉一維數組ax[1, 1].hist(clahe.ravel(), 256)#顯示plt畫板plt.show()
3、效果
尤其是最后一張,可以明顯感覺到普通均衡化和自適應均衡化的差距。
總代碼
#直方圖計算、掩膜及均衡化
import cv2
import numpy as np
from matplotlib import pyplot as plt
#plt:本庫函數主要是一些plt常見的畫圖操作,如設置圖的顏色,線條,字體,坐標軸,標題,legend,在畫好的圖上寫文字等。#計算直方圖(灰度)
def Calculate_Hist():# 1、讀取圖片, 并轉換成灰度圖img = cv2.imread("Resource/test11.jpg", 0) # 0即灰度圖,1彩圖cv2.imshow("img", img)# 2、獲取并繪制直方圖hist = cv2.calcHist([img], [0], None, [256], [0, 256]) #獲取# 圖像 通道索引 掩碼(完整/局部) bin計數 范圍plt.plot(hist) # 繪圖(基于一點或多點)# 3、直方圖展示plt.show() # 顯示#計算直方圖(彩圖)
def Calculate_Hist_RGB():# 1、讀取圖片img = cv2.imread("Resource/test11.jpg") #彩圖cv2.imshow("img", img)# 設置顏色通道color = ["b", "g", "r"]# 2、獲取直方圖for i, c in enumerate(color): #i是索引,c是內容hist = cv2.calcHist([img], [i], None, [256], [0, 256])plt.plot(hist, color=c)# 3、直方圖展示plt.legend(["B Channel", "G Channel", "R Channel"]) #批注plt.show()#掩膜
def Mask():# 1、讀取圖片, 并轉換成灰度圖img = cv2.imread("Resource/test11.jpg", 0)cv2.imshow("img", img)# 2、創建maskmask = np.zeros(img.shape, np.uint8)mask[100:400, 20:200] = 255 #白色掩膜# 高 寬cv2.imshow("mask", mask)# 3、獲取mask后的圖像masked_img = cv2.bitwise_and(img, img, mask=mask) #把掩膜用于圖像cv2.imshow("masked_img", masked_img)# 4、獲取并繪制直方圖hist_full = cv2.calcHist([img], [0], None, [256], [0, 256]) #全部直方圖plt.plot(hist_full)hist_mask = cv2.calcHist([img], [0], mask, [256], [0, 256]) #掩膜直方圖plt.plot(hist_mask)# 5、顯示直方圖plt.show()#直方圖均衡化
def Equalize_Hist():# 1、讀取圖片, 并轉換成灰度圖img = cv2.imread("Resource/test11.jpg", 0) #灰度圖# 2、直方圖均衡化img_equal = cv2.equalizeHist(img) #直方圖均衡化# 3、顯示直方圖f, ax = plt.subplots(2, 2, figsize=(16, 16))#顯示圖像ax[0, 0].set_title("origin")ax[0, 0].imshow(img, "gray")ax[0, 1].set_title("Equalized")ax[0, 1].imshow(img_equal, "gray") #注:"gray"是有效名,不能亂寫#顯示直方圖ax[1, 0].hist(img.ravel(), 256) #ravel():多維數組轉一維數組ax[1, 1].hist(img_equal.ravel(), 256)#顯示plt畫板plt.show()#自適應直方圖均衡化
def Clahe_Hist():# 1、讀取圖片, 并轉換成灰度圖img = cv2.imread("Resource/vague1.jpg", 0) #灰度圖# 2、自適應直方圖均衡化cl = cv2.createCLAHE(2.0, (8,8))# 對比度限制 分塊大小clahe = cl.apply(img) #自適應直方圖均衡化# 3、顯示直方圖f, ax = plt.subplots(2, 2, figsize=(16, 16))#顯示圖像ax[0, 0].set_title("origin")ax[0, 0].imshow(img, "gray")ax[0, 1].set_title("Equalized")ax[0, 1].imshow(clahe, "gray") #注:"gray"是有效名,不能亂寫#顯示直方圖ax[1, 0].hist(img.ravel(), 256) #ravel():多維數組轉一維數組ax[1, 1].hist(clahe.ravel(), 256)#顯示plt畫板plt.show()if __name__ == '__main__':plt.style.use("fivethirtyeight") #直方圖樣式設計plt.figure(figsize=(6, 4)) #直方圖大小Calculate_Hist() #計算直方圖(灰度)Calculate_Hist_RGB() #計算直方圖(彩圖)Mask() #掩膜直方圖Equalize_Hist() #直方圖均衡化Clahe_Hist() #自適應直方圖均衡化
參考資料
https://www.bilibili.com/video/BV1Fo4y1d7JL?p=29
https://iamarookie.blog.csdn.net/article/details/119092739
http://woshicver.com/FifthSection/4_10_2_%E7%9B%B4%E6%96%B9%E5%9B%BE-2%EF%BC%9A%E7%9B%B4%E6%96%B9%E5%9B%BE%E5%9D%87%E8%A1%A1/
總結
以上是生活随笔為你收集整理的OpenCV(十九)直方图(直方图计算、掩膜、均衡化、自适应均衡化)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OpenCV(十七)边缘检测3 -- C
- 下一篇: 奇葩错误:灰度图也想转彩图???(凭空增