(1)模板匹配: cv2.matchTemplate();(2)圖像直方圖: cv2.calcHist();(3)圖像均衡化: cv2.equalizeHist();(4)自適應(yīng)均衡化: cv2.createCLAHE()
模板匹配和卷積的原理很像,模板在原圖像上從原點開始滑動(從左到右, 從上到下),計算模板與(圖像被模板覆蓋的地方)的差別程度,在opencv中計算差別程度有6種計算方法。然后將每次計算結(jié)果放入一個矩陣里,作為輸出結(jié)果。假如原圖形是A*B大小,而模板是a*b大小,則輸出結(jié)果的矩陣大小是(A-a+1)*(B-b+1)
匹配方法:
cv2.matchTemplate(img, templ, method)
參數(shù):
在開始前我們先導(dǎo)入需要用的庫函和圖像,定義一個圖像顯示函數(shù),方便后續(xù)操作
import cv2import numpy as npimport matplotlib.pyplot as plt# 獲取圖片所在文件夾filepath = 'C:\\...\\opencv\\img'# 獲取文件夾中的某一張圖片,0代表轉(zhuǎn)化灰度圖img = cv2.imread(filepath+'\\team.jpg',0)# 原圖上的一塊模板template = cv2.imread(filepath+'\\face.jpg',0)# 定義繪圖函數(shù)def cv_show(name,img): cv2.imshow(name,img) # 傳入自定義圖像名,和圖像變量 cv2.waitKey(0) # 圖片不會自動消失 cv2.destroyWindow() # 手動關(guān)閉窗口# 顯示圖像cv_show('img',img)cv_show('face',template)
我們需要在第一張圖img中找到模板face的位置,并把它框出來
1.1 匹配單個對象
模板在原圖像上移動時,返回匹配度最高的一塊區(qū)域。這里使用v2.TM_SQDIFF平方差計算方法,值越小代表匹配度越高。res中保存所有的計算結(jié)果,使用cv2.minMaxLoc()函數(shù),獲取res中的最值及最值最在的坐標位置,最值坐標是指左上角坐標(x, y),根據(jù)坐標位置和模板的寬和高,可以在原圖像中畫出目標所在位置。x軸向右為正,y軸向下為正,獲得目標右下角坐標(x+w, y+h)。注意在template.shape中提取模板尺寸的時候,shape[0]保存的是高,shape[1]保存的是寬。
#(1)匹配單個對象# img代表原始圖像,template代表模板窗口,1默認為cv2.TM_SQDIFF方法res = cv2.matchTemplate(img, template, 1) # 獲取結(jié)果的最值和最值位置min_val,max_val,min_loc,max_loc = cv2.minMaxLoc(res)# 最值位置是左上角的坐標位置,通過模板的寬和高可以在原圖上把模板位置畫出來h,w = template.shape # shape值是(高,寬)# 找出右下位置bottom_loc = (min_loc[0]+w,min_loc[1]+h)# 復(fù)制一份圖像,不然畫框的時候原圖像會變draw = img.copy()# 輸入圖像畫板draw,左上坐標,右下坐標cv2.rectangle(draw,min_loc,bottom_loc,(0,0,255),2)# 繪圖plt.subplot(121)plt.imshow(res,cmap='gray') # 計算出的每一個窗口的結(jié)果值plt.subplot(122)plt.imshow(draw,cmap='gray') # 在畫板上把目標值框出來plt.tight_layout() #自動排版
左側(cè)是res的圖像是模板和整個圖像運算后的結(jié)果,右側(cè)框出來的是匹配度最高的圖像,匹配正確
1.2 多目標匹配
設(shè)定一個閾值,只要模板和圖像運算后的結(jié)果大于這個閾值,就將這個區(qū)域框出來,不單單識別匹配度最高的,只要滿足給定的條件就行。
在這里使用cv2.TM_SQDIFF_NORMED歸一化平方差來表明匹配度,只要匹配度小于0.2,就將這個區(qū)域選出來。使用np.where()函數(shù)來獲取所有滿足閾值條件的區(qū)域的左上角坐標點,需要注意的是,獲取的坐標點loc中依次保存的是高和寬,即(y, x),而我們在畫矩形框的時候需要的坐標pt是(x, y),因此需要把loc的坐標順序翻轉(zhuǎn)一下。得到左上角坐標(x, y),右下角坐標(x+w, y+h)
# 導(dǎo)入灰度圖img = cv2.imread(filepath+'\\team.jpg',0) # 原圖template = cv2.imread(filepath+'\\face.jpg',0) # 從原圖上取下的一塊h,w = template.shape # 獲取模板的高和寬# 圖像匹配,使用歸一化相關(guān)系數(shù)res = cv2.matchTemplate(img,template,cv2.TM_SQDIFF_NORMED)# 設(shè)置閾值,只要計算出的歸一化平方差小于0.2就把那一塊位置找出來threshold = 0.2loc = np.where(res<threshold) #輸出滿足條件的坐標# 繪制所有的滿足匹配度的窗口# zip(*) 可理解為解壓,返回二維矩陣式。loc中l(wèi)oc[0]是高,loc[1]是寬,[::-1]表示倒序。p[0]代表寬,p[1]代表高for pt in zip(*loc[::-1]): bottom_loc = (pt[0]+w,pt[1]+h) cv2.rectangle(img,pt,bottom_loc,(0,0,255),1) # 參數(shù):圖像,左上坐標,右下坐標,線條顏色,線條粗細# 繪圖cv2.imshow('img',img)cv2.waitKey(0)
線條粗細代表匹配度,中間的可能性最大,(都是同一個人...)
2. 圖像直方圖
同樣,我們先導(dǎo)入需要的庫,和圖像文件,再定義一個圖像顯示函數(shù)
import cv2import numpy as npimport matplotlib.pyplot as plt# 獲取圖片所在文件夾filepath = 'C:\\...\\opencv\\img'# 定義繪圖函數(shù)def cv_show(name,img): # 傳入自定義圖像名,即圖像變量 cv2.imshow(name,img) # 圖片不會自動消失 cv2.waitKey(0) # 手動關(guān)閉窗口 cv2.destroyWindow()
2.1 直方圖繪制
用于統(tǒng)計圖像上每個像素值出現(xiàn)的次數(shù)。
(1)方法1:使用matplot繪制直方圖
# 導(dǎo)入圖像img = cv2.imread(filepath+'\\mh.jpg',0) #0代表灰度圖 # 直方圖展示plt.hist(img.ravel(),256) #ravel將二維拉長成一維,統(tǒng)計0-255每個像素值出現(xiàn)的個數(shù)plt.show()
讀入的img是灰度圖,只有兩個維度,將它變成一維統(tǒng)計像素值出現(xiàn)個數(shù),設(shè)置range=[0,256]顧頭不顧尾,對0-255每一個像素值計數(shù)。
(2)方法2:使用cv2.calcHist()函數(shù)
cv2.calcHist(img, channels, mask, histsize, ranges)
下面對彩圖img進行直方圖統(tǒng)計,不使用掩模,分別統(tǒng)計圖像BGR三通道上的各個像素值出現(xiàn)了多少次,使用折線圖繪制曲線。hist中保存的是每個通道每個像素值出現(xiàn)的次數(shù)。
img = cv2.imread(filepath+'\\mh.jpg') # 以彩色圖為例color = ['b','g','r'] #分別研究三顏色通道的直方圖,用顏色區(qū)分for i,col in enumerate(color): #enumerate遍歷數(shù)據(jù)對象,返回數(shù)據(jù)和對應(yīng)下標 # i存放color下標,col存放具體值 hist = cv2.calcHist([img], [i], None, [256], [0,256]) plt.plot(hist, color=col, label=f'{col}--channel') # 繪制三通道上每個通道像素點出現(xiàn)的個數(shù)的折線圖 plt.xlim([0,256])plt.legend()
2.2 掩模mask操作
掩模mask的大小和原圖像大小一致。掩模中只有兩部分,0和255,一部分為白色一部分為黑色。掩模中白色部分覆蓋到的區(qū)域保留原圖,黑色部分覆蓋到的區(qū)域置為0。
如果我們讀入的圖像時一張彩圖,在構(gòu)建np數(shù)組時,需要舍棄第三個維度,即通道。保留前兩個維度img.shape[:2],掩模的size和原圖像相同。由于mask是一個數(shù)組,可以使用切片的方法將需要保留的位置變成白色255。
使用圖像按位操作方法:cv2.bitwise_and(src1, src2, mask)
src: 輸入圖像
mask:掩膜,用一副二值化圖片對另外一幅圖片進行局部的遮
分別統(tǒng)計加了掩模和沒加掩模的圖像的像素點個數(shù)來對比。
img = cv2.imread(filepath+'\\shandi.jpg',0)# 創(chuàng)建mask,由于如果img是彩圖就是三維,舍棄通道取長和寬,創(chuàng)建一個和img相同大小的maskmask = np.zeros(img.shape[:2],np.uint8) # 8位無符號整型,0-255# 使用切片方法,將maks中的一部分變成255白色mask[200:700,200:700] = 255# 在圖像上覆蓋一層掩模masked_img = cv2.bitwise_and(img,img,mask=mask)# 直方圖統(tǒng)計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,label='non-mask'),plt.plot(hist_mask,label='masked') #像素值統(tǒng)計plt.legend()plt.tight_layout()plt.show()
圖像的直方圖是對圖像對比度效果上的一種處理,旨在使得圖像整體效果均勻。原始圖像由于其灰度分布可能集中在較窄的區(qū)間,造成圖像不夠清晰。通過改變圖像的直方圖,來改變圖像中各像素的灰度,用于增強局部的對比度而不影響整體的對比度。這種方法對于背景和前景都太亮或者太暗的圖像非常有用。
直方圖均衡化的基本原理:對在圖像中像素個數(shù)多的灰度值(即對畫面起主要作用的灰度值)進行展寬,而對像素個數(shù)少的灰度值(即對畫面不起主要作用的灰度值)進行歸并,從而增大對比度,使圖像清晰,達到增強的目的。
均衡化函數(shù): cv2.equalizeHist(img)
img:指需要均衡化的原圖像,灰度圖像。返回值為均衡化后的圖像。
3.1 對圖像整體進行均衡化
# 原圖像有些位置的像素值特別多,有的位置很少img = cv2.imread(filepath+'\\mh1.jpg',0) #0灰度圖plt.hist(img.ravel(),256) #0-255每一個值出現(xiàn)了多少次plt.show()# ==2== 均衡化equ = cv2.equalizeHist(img)plt.hist(equ.ravel(),256) # 將均衡化后的圖像使用ravel()拉長成一維,計算0-255每個值出現(xiàn)的次數(shù)plt.show# ==3== 圖像展示,整體做均衡化會丟失一些細節(jié)res = np.hstack((img,equ)) # 將兩張圖組合在一起cv_show('res',res)
左圖時原始圖像的像素直方圖,右圖是均衡化后的像素直方圖
左圖為原始圖像,右圖為均衡化之后的圖像。我們看出,對整體均衡化之后會大致一下細節(jié)的丟失
3.2 自適應(yīng)均衡化
整幅圖像會被分成很多小塊,然后再對每一個小塊分別進行直方圖均衡化。缺點是:如果有噪聲的話,噪聲會被放大。為了避免這種情況的出現(xiàn)要使用對比度限制。對于每個小塊來說,如果直方圖中的bin超過對比度的上限的話,就把 其中的像素點均勻分散到其他 bins中,然后在進行直方圖均衡化。
cv.createCLAHE(clipLimit, tileGridSize)
clipLimit: 顏色對比度限制,默認是40
tileGridSize: 進行像素均衡化的網(wǎng)格大小,默認為8*8
img = cv2.imread(filepath+'\\mh1.jpg',0)# 設(shè)置均衡化參數(shù),對比度閾值為2,網(wǎng)格為3*3clahe = cv2.createCLAHE(clipLimit=2,tileGridSize=(3,3))# 生成自適應(yīng)均衡化后的圖像res_clahe = clahe.apply(img)# 將三張圖象組合在一起看一下區(qū)別res = np.hstack((img,equ,res_clahe))cv_show('res',res)
第一張是原圖,第二張是整體均衡化之后的圖像,第三張是自適應(yīng)均衡化之后的圖像
聯(lián)系客服