OpenCV-Python : 直方圖


啥叫直方圖

直方圖簡單來說就是圖像中每個像素值的個數統計,比如一副灰度圖中像素值為0的有多少個,1的有多少個...

在計算直方圖之前,先了解幾個術語:

  • dims:要計算的通道數,對於灰度圖dims=1,普通彩色圖dims=3
  • range:要計算的像素值范圍,一般為[0,255]
  • bins:子區段數目,如果我們統計0~255每個像素值,bins=256;如果划分區間,比如0~15,16~31...240~255這樣16個區間,bins=16

計算直方圖

OpenCV和Numpy中提供了計算直方圖的函數,我們對比一下他們的性能

OpenCV中直方圖計算

在OpenCV中使用 cv2.calcHist(images,channels,mask,histSize,ranges) 計算,其中:

  • 參數1:要計算的原圖,以方括號的傳入,如:[img]
  • 參數2:類似前面提到的dims,灰度圖寫[0]就行,彩色圖B、G、R分別傳入[0]、[1]、[2]
  • 參數3:要計算的區域,計算整幅圖的話,寫None
  • 參數4:前面提到的bins
  • 參數5:前面提到的range
import cv2
import numpy as np
import matplotlib.pyplot as plt
start = cv2.getTickCount()

img = cv2.imread('hist.jpg', 0)
hist = cv2.calcHist([img], [0], None, [256], [0, 256])

end = cv2.getTickCount()

print((end - start) / cv2.getTickFrequency())

這里我使用到了評估代碼運行時間,且並沒有給出最初最后print()函數輸出的結果,其實這個結果一直在變化。這里簡單的介紹一下獲取代碼運行時間的兩種方式

第一種:

import cv2
start = cv2.getTickCount()
# 這里寫測試代碼...
end = cv2.getTickCount()
print((end - start) / cv2.getTickFrequency())

這段代碼就是用來測量程序運行時間(單位:s),其中cv2.getTickCount()函數得到電腦啟動以來的時鍾周期數,cv2.getTickFrequency()返回你電腦的主頻,前后相減再除以主頻就是你代碼的運行時間。我這里就是使用的第一種

第二種:使用Python中的time模塊計時:

import time
start = time.clock()
# 這里寫測試代碼...
end = time.clock()
print(end - start)

 

Numpy中直方圖計算

也可用Numpy的函數計算,使用 ravel() 函數 將二維矩陣展平變成一維數組,

hist, bins = np.histogram(img.ravel(), 256, [0, 256])

還有一種更高效的的方式:

hist = np.bincount(img.ravel(), minlength=256)

繪制直方圖

其實Matplotlib自帶了一個計算並繪制直方圖的功能,不需要用到上面的函數

plt.hist(img.ravel(), 256, [0, 256])
plt.show()

     

從直方圖上可以看出圖片的像素點集中子150附近,圖片偏灰白,效果不好。接下來我們來看看如何來改善它。

當然,我們也可以用前面計算出來的結果繪制:

plt.plot(hist)
plt.show()

 

直方圖的均衡化

一幅效果好的圖像通常在直方圖上的分布比較均勻,直方圖均衡化就是用來改善圖像的全局亮度和對比度的。

OpenCV中用cv2.equalizeHist()實現均衡化,我們把兩張圖片並排顯示一下,對比一下:

equ = cv2.equalizeHist(img)
cv2.imshow('equalization', np.hstack((img, equ)))  # 並排顯示
cv2.waitKey(0)

均衡后的直方圖:

plt.hist(equ.ravel(), 256, [0, 256])
plt.show()

可以看出均衡后的直方圖明顯好於原圖。均衡后的圖片的亮度和對比度效果明顯好於原圖

自適應均衡化

直方圖均衡化是應用於整幅圖片的,那是不是所有圖片都適合?會不會出現什么問題?看下圖:

很明顯,因為全局調整亮度和對比度的原因,臉部太亮,大部分細節都丟失了。

 

自適應均衡化就是解決這一問題的:它在每一個小區域內(默認8x8)進行直方圖均衡化。當然,如果有噪點的話,噪點會被放大,需要對小區域的對比度進行了限制,所以這個算法全稱叫:對比度受限的自適應直方圖均衡化 CLAHEContrast Limited Adaptive Histogram Equalization

# 自適應均衡化,參數可選
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
cl1 = clahe.apply(img)
cv2.imshow('equalization', np.hstack((equ, cl1)))  # 並排顯示
cv2.waitKey(0)

效果比均衡化效果要好,至少臉部的細節保留了

 

使用掩膜

要統計圖像某個局部區域的直方圖只需要構建一副掩膜圖像。將要統計的部分設置為白色,其余部分為黑色,就構成了一副掩膜圖像。然后把這個掩膜圖像傳給函數就可以了。

img = cv2.imread('home.jpg', 0)

# 創建一個掩膜
mask = np.zeros(img.shape[:2], np.uint8) # 取彩色通道的長寬
mask[0 : 200, 0 : 200] = 255
masked_img = cv2.bitwise_and(img, img, mask = mask)

Original_Hist = cv2.calcHist([img], [0], None, [256], [0, 256])
masked_img_Hist = cv2.calcHist([img], [0], mask, [256], [0, 256])

plt.subplot(231), plt.imshow(img, 'gray')
plt.subplot(232), plt.imshow(mask, 'gray')
plt.subplot(233), plt.imshow(masked_img, 'gray')
plt.subplot(234), plt.plot(Original_Hist)
plt.subplot(235), plt.plot(masked_img_Hist)
plt.subplot(236), plt.plot(Original_Hist), plt.plot(masked_img_Hist)
plt.show()

其中在混合的那副直方圖中,藍色為原圖的直方圖,橙色為進行掩膜之后的直方圖。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM