OpenCV Python 直方圖
直方圖
什么是直方圖
直方圖的作用
敲程序
下面為使用Python
的OpenCV
和matplotlib
來編寫幾個samples程序來實際感受一下圖像的直方圖:
使用matplotlib計算直方圖
代碼
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('~/Pictures/IMG_4137.JPG', 0)
plt.hist(img.ravel() , 256, [0, 256])
plt.show()
出現錯誤
上面的這段程序,你運行會出現這樣的error:
Traceback (most recent call last): File "/home/aobo/PycharmProjects/OpenCV2/Histograms/hist.py", line 6, in <module> plt.hist(img.ravel() , 256, [0, 256]) AttributeError: 'NoneType' object has no attribute 'ravel'
解決辦法
將代碼里的下面這行
img = cv2.imread('~/Pictures/IMG_4137.JPG', 0)
修改為:(圖片路徑使用完整的絕對路徑)
img = cv2.imread('/home/aobo/Pictures/IMG_4137.JPG', 0)
錯誤的原因是:img
變量沒有成功的載入圖片(cv2.imread()
),所以這個img
變量就是一個沒有任何變量類型的一個變量,在Python語言里img
現在就是一個NoneType
對象。因為只要Mat
對象才有ravel()
這個方法,而NoneType
對象沒有,所以才出現了上面的error
。
img.ravel() 將圖像轉成一維數組。
運行結果:
輸出一個彩色圖像的直方圖
代碼
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('/home/aobo/Pictures/IMG_4137.JPG')
color = ('b','g','r')
# enumerate():python里的一個新函數
# 它的作用:同時遍歷索引(i)和元素(col)
for i,col in enumerate(color):
histr = cv2.calcHist([img], [i], None, [256], [0, 256])
plt.plot(histr, color = col)
plt.xlim([0, 256])
plt.show()
運行效果
代碼講解
histr = cv2.calcHist([img], [i], None, [256], [0, 256])
cv2.calcHist()
是OpenCV里面求直方圖的函數。下面介紹這個函數需要傳入的形參:
cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])
實參 | 對應形參 | 解釋 |
---|---|---|
[img] |
images |
原始圖像,需要使用[] 修飾 |
[i] |
channels |
cv2.calcHist()函數一次只能得到一張圖片的其中一個通道的直方圖,所以,這里傳入的是本次需要處理的元素圖片的通道的索引號,同樣需要使用[] 修飾。如果輸入的元素圖像是灰度圖,它的值就是[0]; 如果輸入的元素圖像是彩色圖像的話,傳入的參數可以是[0], [1], [2],它們分別對應着通道B, G, R。 |
plt.plot(histr, color = col)
這句話中的col
的值是:’b’, ‘g ’ 或 ‘r’,賦給color
形參,函數會自動處理成形應的顏色值,用這個顏色值將histr
直方圖繪制到plt
畫板上。
plt.xlim([0, 256])
設置plt
畫板x軸的上下限,就是x軸所顯示的長度。我們將這段代碼修改出下面這個樣子,然后運行程序,會得到下面的結果:
plt.xlim([0, 100])
使用掩模
代碼
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('/home/aobo/Pictures/IMG_4137.JPG')
color = ('b','g','r')
mask = np.zeros(img.shape[:2], np.uint8)
mask[1000:2000, 1000:2000] = 255
masked_img = cv2.bitwise_and(img, img, mask = mask)
hist_full = cv2.calcHist([img], [0], None, [256], [0, 256])
hist_mask = cv2.calcHist([img], [0], mask, [256], [0, 256])
plt.subplot(221), plt.imshow(img, 'gray')
plt.subplot(222), plt.imshow(mask, 'gray')
plt.subplot(223), plt.imshow(masked_img, 'gray')
plt.subplot(224), plt.plot(hist_full), plt.plot(hist_mask)
plt.xlim([0, 256])
plt.show()
運行效果
<注>:當原始圖像使用較大圖像的時候,你會發現程序運行后需要好久才能得到下面的結果。
代碼解釋
mask = np.zeros(img.shape[:2], np.uint8)
mask[1000:2000, 1000:2000] = 255
制作一個掩模。首先使用np.zeros()
函數創建一個與原圖尺寸和深度都一樣,像素值全為0
(黑色)圖像mask
,然后指定mask
掩模的[1000:2000, 1000:2000]
區域的像素全為255
(白色)。上圖右上角的圖就是掩模圖像。
masked_img = cv2.bitwise_and(img, img, mask = mask)
現在掩模發揮了作用:掩模的黑色區域(像素值為0)用來遮蓋原圖img
,即不參與圖像處理,只保留像素值不為0的區域。masked_img
圖像就是上圖左下角的圖像。
cv2.bitwise_and()函數的功能是位與。下面是這個函數的聲明:
cv2.bitwise_and(src1, src2[, dst[, mask]])
當前代碼里,對應的src1
和src2
是同一種數據類型,所以此時cv2.bitwise_and()函數執行的是下面的操作:
hist_full = cv2.calcHist([img], [0], None, [256], [0, 256])
hist_mask = cv2.calcHist([img], [0], mask, [256], [0, 256])
分別計算出原圖img
的直方圖和img
掩模區域的直方圖。
plt.subplot(221), plt.imshow(img, 'gray')
plt.subplot(222), plt.imshow(mask, 'gray')
plt.subplot(223), plt.imshow(masked_img, 'gray')
plt.subplot(224), plt.plot(hist_full), plt.plot(hist_mask)
plt.xlim([0, 256])
subplot()
是matplotlib.pyplot
里的函數。它是:將多個圖畫到一個平面上的工具。
subplot(m, n, p)
或者subplot(mnp)
m 表示圖排成m行 n 表示圖排成n列 p 表示將圖畫到 Figure
(指的是上面截圖里的窗口)哪個圖上,順序是從左到右,從上到下