直接用matplotlib畫出直方圖
def plot_demo(image):
plt.hist(image.ravel(), 256, [0, 256]) # image.ravel()將圖像展開,256為bins數量,[0, 256]為范圍
plt.show()
圖像直方圖
def image_hist(image):
color = ('blue', 'green', 'red')
for i, color in enumerate(color):
# 計算出直方圖,calcHist(images, channels, mask, histSize(有多少個bin), ranges[, hist[, accumulate]]) -> hist
# hist 是一個 256x1 的數組,每一個值代表了與該灰度值對應的像素點數目。
hist = cv.calcHist(image, [i], None, [256], [0, 256])
print(hist.shape)
plt.plot(hist, color=color)
plt.xlim([0, 256])
plt.show()
直方圖均值化
是圖像增強的一個手段
def equalHist_demo(image):
gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY)
# 全局直方圖均衡化,用於增強圖像對比度,即黑的更黑,白的更白
dst = cv.equalizeHist(gray)
cv.imshow("equalHist_demo", dst)
# 局部直方圖均衡化
clahe = cv.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
clahe_dst = clahe.apply(gray)
cv.imshow("clahe", clahe_dst)
直方圖比較
# 創建直方圖
def create_rgb_demo(image):
h, w, c = image.shape
rgbHist = np.zeros([16*16*16, 1], np.float32)
bsize = 256 / 16
for row in range(h):
for col in range(w):
b = image[row, col, 0]
g = image[row, col, 1]
r = image[row, col, 2]
index = np.int(b/bsize)*16*16 + np.int(g/bsize)*16 + np.int(r/bsize)
rgbHist[np.int(index), 0] = rgbHist[np.int(index), 0] + 1
return rgbHist
# 利用直方圖比較相似性,用巴氏和相關性比較好
def hist_compare(image1, image2):
hist1 = create_rgb_demo(image1)
hist2 = create_rgb_demo(image2)
match1 = cv.compareHist(hist1, hist2, method=cv.HISTCMP_BHATTACHARYYA)
match2 = cv.compareHist(hist1, hist2, method=cv.HISTCMP_CORREL)
match3 = cv.compareHist(hist1, hist2, method=cv.HISTCMP_CHISQR)
print("巴式距離:%s, 相關性:%s, 卡方:%s"%(match1, match2, match3))
直方圖反向投影
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
def hist2d_demo(image):
hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV)
hist = cv.calcHist([image], [0, 1], None, [180, 360], [0, 180, 0, 256]) # 計算直方圖
print(hist.shape)
# cv.imshow("hist2d_demo", hist)
plt.imshow(hist, interpolation="nearest") # 直方圖顯示
plt.title("2D Histogram")
plt.show()
# OpenCV 提供的函數 cv2.calcBackProject() 可以用來做直方圖反向 投影。
# 它的參數與函數 cv2.calcHist 的參數基本相同。其中的一個參數是我 們要查找目標的直方圖。
# 同樣再使用目標的直方圖做反向投影之前我們應該先對其做歸一化處理。
# 返回的結果是一個概率圖像
def back_projection_demo():
"""
反向投影可以用來做圖像分割,或者在圖像中找尋我們感興趣的部分。
它會輸出與輸入圖像(待搜索)同樣大小的圖像,其中的每一個像素值代表了輸入圖像上對應點屬於目標對象的概率。
輸出圖像中像素值越高(越白)的點就越可能代表我們要搜索的目標 (在輸入圖像所在的位置)。
直方圖投影經常與camshift 算法等一起使用。
步驟:
1. 為一張包含我們要查找目標的圖像創建直方圖,我們要查找的對象要盡量占滿這張圖像。
最好使用顏色直方圖,因為一個物體的顏色要比它的灰 度能更好的被用來進行圖像分割與對象識別。
2. 們再把這個顏色直方圖投 影到輸入圖像中尋找我們的目標,
也就是找到輸入圖像中的每一個像素點的像素值在直方圖中對應的概率,這樣我們就得到一個概率圖像。
3. 設置適當的閾值對概率圖像進行二值化
"""
sample = cv.imread("../images/roi.png")
target = cv.imread("../images/CrystalLiu3.jpg")
roi_hsv = cv.cvtColor(sample, cv.COLOR_BGR2HSV)
target_hsv = cv.cvtColor(target, cv.COLOR_BGR2HSV)
cv.imshow("sample", sample)
cv.imshow("target", target)
roiHist = cv.calcHist([roi_hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
# 歸一化:原始圖像,結果圖像,映射到結果圖像中的最小值,最大值,歸一化類型
# cv.NORM_MINMAX對數組的所有值進行轉化,使它們線性映射到最小值和最大值之間
# 歸一化后的圖像便於顯示,歸一化后到0,255之間了
cv.normalize(roiHist, roiHist, 0, 255, cv.NORM_MINMAX)
dst = cv.calcBackProject([target_hsv], [0, 1], roiHist, [0, 180, 0, 256], 1)
cv.imshow("backProjectionDemo", dst)
if __name__ == '__main__':
src = cv.imread("../images/CrystalLiu1.jpg") # 讀入圖片放進src中
cv.namedWindow("Crystal Liu") # 創建窗口
cv.imshow("Crystal Liu", src) # 將src圖片放入該創建的窗口中
hist2d_demo(src)
# back_projection_demo()
cv.waitKey(0) # 等有鍵輸入或者1000ms后自動將窗口消除,0表示只用鍵輸入結束窗口
cv.destroyAllWindows() # 關閉所有窗口