基礎版傳送門:
python3+opencv學習筆記彙總目錄(适合基礎入門學習)
進階版筆記目錄連結:
python+opencv進階版學習筆記目錄(适合有一定基礎)
直方圖基礎講解:
opencv學習筆記21:直方圖和掩膜 原理及其應用
圖像直方圖
numpy實作
函數:hist(資料源,像素級)
資料源:圖像,必須是一維數組
像素級:一般是256,指[0-255]
np.raval()可以實作多元數組轉一維。
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
def plot_demo(image):
plt.hist(image.ravel(),256,[0,256])
# plt.hist(image.ravel(),256)#兩種寫法都對
plt.show()
print("--------- Hello Python ---------")
src = cv.imread("fangye.jpg")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
plot_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()
OpenCV實作
hist=cv2.calcHist(images,channels,mask,histsize,ranges,accumulate)
hist:直方圖
images:原始圖像,格式[src],需要用中括号括起來
channels:通道,灰色直接[0],BGR對應[0],[1],[2]
mask:掩碼圖像。如果一個圖很大,需要計算部分圖的直方圖,需要掩碼。
histsize:BINS的數量,需要用中括号括起來。一般是[256]
ranges:像素值範圍,一般[0,255]
accumulate:累積辨別。可選參數、預設false,設為true為計算好幾幅圖的直方圖。
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
def image_hist(image):
color = ('blue', 'green', 'red')
for i, color in enumerate(color):
hist = cv.calcHist([image], [i], None, [256], [0, 256])
plt.plot(hist, color=color)
plt.xlim([0, 256])
plt.show()
print("--------- Hello Python ---------")
src = cv.imread("renwu.jpg")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
image_hist(src)
cv.waitKey(0)
cv.destroyAllWindows()
圖像來源于網圖。
圖像的主要特征來源于波峰。
圖像直方圖應用
1全局直方圖均衡化
直方圖均衡化都是基于灰色圖
原理見上面提到的基礎連結
效果:使對比圖增強
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
def equalHist_demo(image):
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
dst = cv.equalizeHist(gray)
cv.imshow("equalHist_demo", dst)
print("--------- Hello Python ---------")
src = cv.imread("renwu.jpg")
src=cv.resize(src,None,fx=0.5,fy=0.5)
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
equalHist_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()
2局部直方圖均衡化
局部自适應的圖像直方圖均衡化
自适應直方圖均衡化(AHE)是用來提升圖像的對比度的一種計算機圖像處理技術。和普通的直方圖均衡算法不同,AHE算法通過計算圖像的局部直方圖,然後重新分布亮度來改變圖像對比度。是以,該算法更适合于改進圖像的局部對比度以及獲得更多的圖像細節。
不過,AHE有過度放大圖像中相同區域的噪音的問題,另外一種自适應的直方圖均衡算法即限制對比度直方圖均衡(CLAHE)算法能有限的限制這種不利的放大。
cv2.createCLAHE(clipLimit=5.0, tileGridSize=(8, 8))
第一個參數的意義是那一小部分的直方圖大于clipLimit的部分将被剪裁掉平均配置設定 給整個圖像;第二個參數的意義是 所分小區域的大小。一般的clipLimit設定的值是40,自定義的話值越大均化的效果越顯著,值越接近零,就和原圖像沒什麼差別,
原理圖:
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
def clahe_demo(image):
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
clahe = cv.createCLAHE(clipLimit=3.0, tileGridSize=(5, 5))
dst = clahe.apply(gray)
cv.imshow("clahe_demo", dst)
print("--------- Hello Python ---------")
src = cv.imread("renwu1.jpg")
src=cv.resize(src,None,fx=0.6,fy=0.6)
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
clahe_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()
直方圖比較
對輸入的兩張圖像計算得到直方圖H1與H2,歸一化到相同的尺度空間,然後可以通過計算H1與H2的之間的距離得到兩個直方圖的相似程度進而比較圖像本身的相似程度。
直方圖比較函數
cv2.compareHist(H1, H2, method)
其中:
H1,H2 分别為要比較圖像的直方圖
method - 比較方式
比較方式(method)
相關性比較 (method=cv.HISTCMP_CORREL) 值越大,相關度越高,最大值 為1,最小值為0
卡方比較(method=cv.HISTCMP_CHISQR 值越小,相關度越高,最大值無上界,最小值0
巴氏距離比較(method=cv.HISTCMP_BHATTACHARYYA) 值越小,相關度越高,最大值為1,最小值為0
import cv2 as cv
import numpy as np
#rgb直方圖
def create_rgb_hist(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#出現了就加1
return rgbHist
#比較函數
def hist_compare(image1, image2):
hist1 = create_rgb_hist(image1)
hist2 = create_rgb_hist(image2)
match1 = cv.compareHist(hist1, hist2, cv.HISTCMP_BHATTACHARYYA)#比較方法1,越小越相似
match2 = cv.compareHist(hist1, hist2, cv.HISTCMP_CORREL)#相關性越大越相似
match3 = cv.compareHist(hist1, hist2, cv.HISTCMP_CHISQR)#卡方越大約不相似
print("巴氏距離: %s, 相關性: %s, 卡方: %s"%(match1, match2, match3))
print("--------- Hello Python ---------")
src1 = cv.imread("renwu1.jpg")
src2 = cv.imread("renwu.jpg")
src1=cv.resize(src1,None,fx=0.5,fy=0.5)
src2=cv.resize(src2,None,fx=0.5,fy=0.5)
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src1)
cv.imshow("image2", src2)
hist_compare(src1, src2)
cv.waitKey(0)
cv.destroyAllWindows()
輸入兩張完全一樣圖檔
結果
直方圖反向投影
直方圖反向投影式通過給定的直方圖資訊,在圖像找到相應的像素分布區域,opencv提供兩種算法,一個是基于像素的,一個是基于塊的。
2D直方圖建立
直方圖是基于2D的,首先先計算2D直方圖建立。
使用函數 cv2.calcHist() 來計算直方圖既簡單又友善。如果要繪制顔色直方圖的話,首先需要将圖像的顔色空間從 BGR 轉換到 HSV。(記住,計算二維直方圖,要從 BGR 轉換到 HSV)。計算 2D 直方圖,函數的參數要做如下修改:
• channels=[0, 1] 因為我們需要同時處理 H 和 S 兩個通道。
• bins=[180, 256]H 通道為 180, S 通道為 256。 如果寫其他數值(小于180,256)則表示是通道合并。
• range=[0, 180, 0, 256]H 的取值範圍在 0 到 180, S 的取值範圍在 0 到 256。
hist = cv2.calcHist([image], [0, 1], None, [32, 32], [0, 180, 0, 256])
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
def hist2d_demo(image):
hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV)
hist = cv.calcHist([image], [0, 1], None, [180, 256], [0, 180, 0, 256])
#cv.imshow("hist2d", hist)
plt.imshow(hist, interpolation='nearest')#nearest鄰近點插值
plt.title("2D Histogram")
plt.show()
print("--------- Hello Python ---------")
src = cv.imread("yangmi.jpg")
src=cv.resize(src,None,fx=0.5,fy=0.5)
#hist2d_demo(src)
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
hist2d_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()
直方圖反向投影
此段代碼有借鑒他人
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
def back_projection_demo():
# ROI區域
roi= cv.imread("head.png")
#roi=cv.resize(roi,None,fx=0.5,fy=0.5)
#目标搜尋區域
target = cv.imread("renwu.jpg")
target= cv.resize(target, None, fx=0.2, fy=0.2)
roi_hsv = cv.cvtColor(roi, cv.COLOR_BGR2HSV)
target_hsv = cv.cvtColor(target, cv.COLOR_BGR2HSV)
# show images
cv.imshow("roi", roi)
#cv.imshow("target", target)
roiHist = cv.calcHist([roi_hsv], [0, 1], None, [180,256], [0, 180, 0, 256])#2D直方圖
cv.normalize(roiHist, roiHist, 0, 255, cv.NORM_MINMAX)#歸一化到0-255
dst = cv.calcBackProject([target_hsv], [0, 1], roiHist, [0, 180, 0, 256], 1)
#cv.imshow("backProjectionDemo", dst)
# 此處卷積可以把分散的點連在一起
disc = cv.getStructuringElement(cv.MORPH_ELLIPSE, (5, 5))
dst = cv.filter2D(dst, -1, disc)
# threshold and binary AND
ret, thresh = cv.threshold(dst, 200, 255, 0)
# 别忘了是三通道圖像,是以這裡使用 merge 變成 3 通道
thresh = cv.merge((thresh, thresh, thresh))
# 按位操作
res = cv.bitwise_and(target, thresh)
res = np.hstack((target, thresh, res))
cv.imshow('res',res)
#cv.imwrite('res.jpg', res)
back_projection_demo()
cv.waitKey(0)
cv.destroyAllWindows()
原始模闆ROI
即從目标圖尋找和模闆相似的區域(直方圖相似)
結果:
要修改 ret, thresh = cv.threshold(dst, 200, 255, 0) 數值才能得到更好。
電氣專業的計算機萌新,寫博文不容易。如果你覺得本文對你有用,請點個贊再走。謝謝。