Python與機器視覺(x) 顏色直方圖
本系列部落格主要分享Python在機器視覺/計算機視覺下的程式設計應用
cv2包是著名的視覺庫OpenCV的Python實現
顏色直方圖一般用於統計圖片不同通道畫素強度的分佈,並可以基於此來實現對比度提升、以及簡單的目標識別、跟蹤以及分割等任務。在openCV中集成了函式cv2.calcHist()
來實現直方圖的計算。
函式定義如下:
cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]]) → hist
其中images
可為單張或多張影象的array
channels
mask
為影象掩膜histSize
為直方圖的柱子數量,即將資料分佈在多少個區間上計數range
為直方圖取值範圍hist
為返回值,不用填accumulate
多張圖的時候是否疊加所以一般呼叫的時候只需要填上面四個引數,掩膜為None,範圍0.0-255.0,數量255個:
hist = cv2.calcHist(img, [0], None,[256], [0.0,255.0])
1. 看一個例子
import cv2
import numpy as np
import matplotlib.pyplot as plt
#讀入灰度影象並顯示(imread用0引數)
img = cv2.imread('img.jpeg',0)
cv2.imshow('img',img)
cv2.waitKey()
cv2.destroyAllWindows()
接下來計算其畫素亮度分佈的直方圖,在0~255範圍內分為255級來計算
hist_255 = cv2.calcHist([img],[0], None, [256], [0.0,255.0]) #灰度圖只有一個通道,通道0
#注意,img一定要加[],使其變成三維,否則則會使用第一維進行計算,即不加中括號會計算img[0,:]的直方分佈
print('histrogram shape is' ,hist_255.shape)
plt.plot(hist_255,'gray')
plt.title('Histrogram of gray image')
plt.show()
Output: ‘histrogram shape is’, (256L, 1L)
可以看到這幅灰度圖,其亮度集中在250附近,這是由於有大片的天空呈現白色,而暗區的峰值則來源於較暗的山體。
2.看第二個例子
我們讀入彩色圖,並將rgb通道的顏色直方圖分別畫出來:
img = cv2.imread('img.jpeg')
cv2.imshow('img',img)
cv2.waitKey()
cv2.destroyAllWindows()
我們對三個通道分別遍歷求直方圖,注意opencv中的顏色是按照b,g,r順序的。
color = ['blue','springgreen','red'] #稍微調整顯示顏色,提高視覺化效果
for i in [0,1,2]:
hist = cv2.calcHist([img],[0], None, [256], [0.0,255.0]) #彩色圖有三個通道,通道b:0,g:1,r:2
plt.plot(hist, color[i])
plt.title('Histrogram of Color image')
plt.show()
可以看到在低亮度區域紅色比較多,對應了圖中上體的反光和雲彩的顏色。
可以改變區間分割的數量來得到更為平滑或者稠密的分佈曲線:
color = ['blue','springgreen','red'] #稍微調整顯示顏色,提高視覺化效果
for i in [0,1,2]:
hist = cv2.calcHist([img],[i], None, [64], [0.0,256.0]) #用64端區間來統計0~256的灰度分佈
plt.plot(hist, color[i])
plt.title('Histrogram of Color image')
plt.show()
為了直觀的檢視每個通道的質量,我們畫出各個通道的影象來與直方圖對比:
#畫出各個通道檢視,opencv中為bgr順序
img_b = img.copy();img_b[:,:,2] = 0;img_b[:,:,1] = 0
img_g = img.copy();img_g[:,:,2] = 0;img_g[:,:,0] = 0
img_r = img.copy();img_r[:,:,0] = 0;img_r[:,:,1] = 0
#轉為rgb顯示
plt.figure(figsize=(10,30))
plt.subplot(1,3,1)
plt.imshow(cv2.cvtColor(img_r,cv2.COLOR_BGR2RGB)) #r
plt.title('red')
plt.subplot(1,3,2)
plt.imshow(cv2.cvtColor(img_g,cv2.COLOR_BGR2RGB)) #g
plt.title('green')
plt.subplot(1,3,3)
plt.imshow(cv2.cvtColor(img_b,cv2.COLOR_BGR2RGB)) #b
plt.title('blue')
plt.show()
可以與上圖的直方圖相比較。
3.直方圖均衡
有的時候我們需要調整影象的對比度,讓整幅圖在各個取值區間的畫素數變得更加均衡,就需要利用上面計算出的直方圖進行直方圖均衡。OpenCV中主要利用cv2.equalizeHist()
來實現。
import cv2
import numpy as np
import matplotlib.pyplot as plt
img2= cv2.imread('img2.jpeg')
# img from:https://www.pexels.com/photo/white-yacht-on-body-of-water-under-bridge-1529625/
cv2.imshow('img',img2)
cv2.waitKey()
cv2.destroyAllWindows()
可以看到這幅圖的暗部和亮部分對比度不夠好,每一部分畫素分佈過於集中了,在直方圖中更為明顯:
equal_hist_255 = cv2.calcHist([img2],[0], None, [256], [0.0,256.0]) #灰度圖只有一個通道,通道0
print('histrogram shape is',hist_255.shape)
plt.plot(hist_255,'gray')
plt.title('Histrogram of gray image')
plt.show()
下面我們進行直方圖均衡化,然後檢視對比度修正的結果:
img_equal = cv2.equalizeHist(img2)
hist_255_equal = cv2.calcHist([img_equal],[0], None, [256], [0.0,256.0]) #灰度圖只有一個通道,通道0
print('histrogram shape is',hist_255.shape)
plt.figure(figsize=(20,20))
plt.subplot(2,2,1)
plt.imshow(img2,'gray')
plt.title('source')
plt.subplot(2,2,2)
plt.imshow(img_equal,'gray')
plt.title('histrogram equilized')
plt.subplot(2,2,3)
plt.plot(hist_255,'gray')
plt.title('Histrogram of gray image')
plt.subplot(2,2,4)
plt.plot(hist_255_equal,'gray')
plt.title('Histrogram of equalized image')
plt.show()
可以看到修正後的直方圖分佈更均勻,對比度也比原來好了很多,更能看清暗處的部分了。
讓我們再來看看彩色圖:
img2_color = cv2.imread('img2.jpeg') #讀入彩色圖
img2_color_equl = img2_color.copy()
#需要按通道分別均衡化
img2_color_equl[:,:,0] = cv2.equalizeHist(img2_color[:,:,0])
img2_color_equl[:,:,1] = cv2.equalizeHist(img2_color[:,:,1])
img2_color_equl[:,:,2] = cv2.equalizeHist(img2_color[:,:,2])
plt.figure(figsize=(20,10))
plt.subplot(2,2,1)
plt.imshow(cv2.cvtColor(img2_color,cv2.COLOR_BGR2RGB))
plt.title('source')
plt.subplot(2,2,2)
plt.imshow(cv2.cvtColor(img2_color_equl,cv2.COLOR_BGR2RGB))
plt.title('Histrogram of equalized image')
plt.subplot(2,2,3)
for i in [0,1,2]:
hist = cv2.calcHist([img2_color],[i], None, [255], [0.0,256.0]) #彩色圖三通道
plt.plot(hist, color[i])
plt.title('Histrogram of Color image')
plt.subplot(2,2,4)
for i in [0,1,2]:
hist = cv2.calcHist([img2_color_equl],[i], None, [255], [0.0,256.0]) #彩色圖
plt.plot(hist, color[i])
plt.title('Histrogram of equalized Color image')
plt.show()
對比度有很大改觀,但是顏色產生了一定的失真。
ref:
Doc:https://docs.opencv.org/2.4/modules/imgproc/doc/histograms.html?highlight=hist
Tutorial:http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/table_of_content_imgproc/table_of_content_imgproc.html
blog1
blog2