您現在的位置是:首頁 > 攝影首頁攝影
OpenCV影象處理—模版匹配和霍夫變換
怎麼求兩組資料的相關係數
學習目標
掌握模板匹配的原理,能完成模板匹配的應用
理解霍夫線變換的原理,瞭解霍夫圓檢測
知道使用OpenCV如何進行線和圓的檢測
1 模板匹配
1。1 原理
所謂的模板匹配,就是在給定的圖片中查詢和模板最相似的區域,該演算法的輸入包括模板和圖片,整個任務的思路就是按照滑窗的思路不斷的移動模板圖片,計算其與影象中對應區域的匹配度,最終將匹配度最高的區域選擇為最終的結果。
實現流程:
準備兩幅影象:
1。原影象(I):在這幅圖中,找到與模板相匹配的區域2。模板(T):與原影象進行比對的影象塊
滑動模板影象和原影象進行比對:
將模板塊每次移動一個畫素 (從左往右,從上往下),在每一個位置,都計算與模板影象的相似程度。
對於每一個位置將計算的相似結果儲存在結果矩陣(R)中。如果輸入影象的大小(WxH)且模板影象的大小(wxh),則輸出矩陣R的大小為(W-w + 1,H-h + 1)將R顯示為影象,如下圖所示:
獲得上述影象後,查詢最大值所在的位置,那麼該位置對應的區域就被認為是最匹配的。對應的區域就是以該點為頂點,長寬和模板影象一樣大小的矩陣。
1。2 實現
我們使用OpenCV中的方法實現模板匹配。
API:
res = cv。matchTemplate(img,template,method)
引數:
img: 要進行模板匹配的影象
Template :模板
method:實現模板匹配的演算法,主要有:
平方差匹配(CV_TM_SQDIFF):利用模板與影象之間的平方差進行匹配,最好的匹配是0,匹配越差,匹配的值越大。
相關匹配(CV_TM_CCORR):利用模板與影象間的乘法進行匹配,數值越大表示匹配程度較高,越小表示匹配效果差。
利用相關係數匹配(CV_TM_CCOEFF):利用模板與影象間的相關係數匹配,1表示完美的匹配,-1表示最差的匹配。
完成匹配後,使用cv。minMaxLoc()方法查詢最大值所在的位置即可。如果使用平方差作為比較方法,則最小值位置是最佳匹配位置。
示例:
在該案例中,載入要搜尋的影象和模板,影象如下所示:
模板如下所示:
透過matchTemplate實現模板匹配,使用minMaxLoc定位最匹配的區域,並用矩形標註最匹配的區域。
import cv2 as cvimport numpy as npfrom matplotlib import pyplot as plt# 1 影象和模板讀取img = cv。imread(‘。/image/wulin2。jpeg’)template = cv。imread(‘。/image/wulin。jpeg’)h,w,l = template。shape# 2 模板匹配# 2。1 模板匹配res = cv。matchTemplate(img, template, cv。TM_CCORR)# 2。2 返回影象中最匹配的位置,確定左上角的座標,並將匹配位置繪製在影象上min_val, max_val, min_loc, max_loc = cv。minMaxLoc(res)# 使用平方差時最小值為最佳匹配位置# top_left = min_loctop_left = max_locbottom_right = (top_left[0] + w, top_left[1] + h)cv。rectangle(img, top_left, bottom_right, (0,255,0), 2)# 3 影象顯示plt。imshow(img[:,:,::-1])plt。title(‘匹配結果’), plt。xticks([]), plt。yticks([])plt。show()
拓展:模板匹配不適用於尺度變換,視角變換後的影象,這時我們就要使用關鍵點匹配演算法,比較經典的關鍵點檢測演算法包括SIFT和SURF等,主要的思路是首先透過關鍵點檢測演算法獲取模板和測試圖片中的關鍵點;然後使用關鍵點匹配演算法處理即可,這些關鍵點可以很好的處理尺度變化、視角變換、旋轉變化、光照變化等,具有很好的不變性。
2 霍夫變換
霍夫變換常用來提取影象中的直線和圓等幾何形狀,如下圖所示:
2。1 原理
原理
在笛卡爾座標系中,一條直線由兩個點A=(x_1,y_1)
A
=(
x
1,
y
1)和B=(x_2,y_2)
B
=(
x
2,
y
2)確定,如下圖所示:
將直線y=kx+q可寫成關於(k,q)(
k
,
q
)的函式表示式:
對應的變換透過圖形直觀的表示下:
變換後的空間我們叫做霍夫空間。即:
笛卡爾座標系中的一條直線,對應於霍夫空間中的一個點
。反過來,同樣成立,霍夫空間中的一條線,對應於笛卡爾座標系中一個點,如下所示:
我們再來看下A、B兩個點,對應於霍夫空間的情形:
在看下三點共線的情況:
可以看出如果
在笛卡爾座標系的點共線,那麼這些點在霍夫空間中對應的直線交於一點
。
如果不止存在一條直線時,如下所示:
我們選擇儘可能多的直線匯成的點,上圖中三條直線匯成的A、B兩點,將其對應回笛卡爾座標系中的直線:
到這裡我們似乎已經完成了霍夫變換的求解。但如果像下圖這種情況時:
上圖中的直線是x=2
x
=2,那(k,q)(
k
,
q
)怎麼確定呢?
為了解決這個問題,我們考慮將笛卡爾座標系轉換為極座標。
在極座標下是一樣的,極座標中的點對應於霍夫空間的線,這時的霍夫空間是不在是引數(k,q)(
k
,
q
)的空間,而是(\rho,\theta)(
ρ
,
θ
)的空間,\rho
ρ
是原點到直線的垂直距離,\theta
θ
表示直線的垂線與橫軸順時針方向的夾角,垂直線的角度為0度,水平線的角度是180度。
我們只要求得霍夫空間中的交點的位置,即可得到原座標系下的直線。
實現流程
假設有一個大小為100*∗100的圖片,使用霍夫變換檢測圖片中的直線,則步驟如下所示:
直線都可以使用(\rho,\theta)(
ρ
,
θ
) 表示,首先建立一個2D陣列,我們叫做
累加器
,初始化所有值為0,行表示\rho
ρ
,列表示\theta
θ
。
該陣列的大小決定了結果的準確性,若希望角度的精度為1度,那就需要180列。對於\rho
ρ
,最大值為圖片對角線的距離,如果希望精度達到畫素級別,行數應該與影象的對角線的距離相等。
取直線上的第一個點(x,y)(
x
,
y
),將其帶入直線在極座標中的公式中,然後遍歷\theta
θ
的取值:0,1,2,。。。,180,分別求出對應的\rho
ρ
值,如果這個數值在上述累加器中存在相應的位置,則在該位置上加1。
取直線上的第二個點,重複上述步驟,更新累加器中的值。對影象中的直線上的每個點都直線以上步驟,每次更新累加器中的值。
搜尋累加器中的最大值,並找到其對應的(\rho,\theta)(
ρ
,
θ
),就可將影象中的直線表示出來。
2。2 霍夫線檢測
在OpenCV中做霍夫線檢測是使用的API是:
cv。HoughLines(img, rho, theta, threshold)
引數:
img: 檢測的影象,要求是二值化的影象,所以在呼叫霍夫變換之前首先要進行二值化,或者進行Canny邊緣檢測
rho、theta: \rho
ρ
和\theta
θ
的精確度
threshold: 閾值,只有累加器中的值高於該閾值時才被認為是直線。
霍夫線檢測的整個流程如下圖所示,這是在stackflow上一個關於霍夫線變換的解釋:
示例:
檢測下述影象中的直線:
import numpy as npimport randomimport cv2 as cvimport matplotlib。pyplot as plt# 1。載入圖片,轉為二值圖img = cv。imread(‘。/image/rili。jpg’)gray = cv。cvtColor(img, cv。COLOR_BGR2GRAY)edges = cv。Canny(gray, 50, 150)# 2。霍夫直線變換lines = cv。HoughLines(edges, 0。8, np。pi / 180, 150)# 3。將檢測的線繪製在影象上(注意是極座標噢)for line in lines: rho, theta = line[0] a = np。cos(theta) b = np。sin(theta) x0 = a * rho y0 = b * rho x1 = int(x0 + 1000 * (-b)) y1 = int(y0 + 1000 * (a)) x2 = int(x0 - 1000 * (-b)) y2 = int(y0 - 1000 * (a)) cv。line(img, (x1, y1), (x2, y2), (0, 255, 0))# 4。 影象顯示plt。figure(figsize=(10,8),dpi=100)plt。imshow(img[:,:,::-1]),plt。title(‘霍夫變換線檢測’)plt。xticks([]), plt。yticks([])plt。show()
2。3 霍夫圓檢測[瞭解]
原理
圓的表示式是:
其中a
a
和b
b
表示圓心座標,r
r
表示圓半徑,因此標準的霍夫圓檢測就是在這三個引數組成的三維空間累加器上進行圓形檢測,此時效率就會很低,所以OpenCV中使用
霍夫梯度法
進行圓形的檢測。
霍夫梯度法將霍夫圓檢測範圍兩個階段,第一階段檢測圓心,第二階段利用圓心推匯出圓半徑。
圓心檢測的原理:圓心是圓周法線的交匯處,設定一個閾值,在某點的相交的直線的條數大於這個閾值就認為該交匯點為圓心。
圓半徑確定原理:圓心到圓周上的距離(半徑)是相同的,確定一個閾值,只要相同距離的數量大於該閾值,就認為該距離是該圓心的半徑。
原則上霍夫變換可以檢測任何形狀,但複雜的形狀需要的引數就多,霍夫空間的維數就多,因此在程式實現上所需的記憶體空間以及執行效率上都不利於把標準霍夫變換應用於實際複雜圖形的檢測中。霍夫梯度法是霍夫變換的改進,它的目的是減小霍夫空間的維度,提高效率。
API
在OpenCV中檢測影象中的圓環使用的是API是:
circles = cv。HoughCircles(image, method, dp, minDist, param1=100, param2=100, minRadius=0,maxRadius=0 )
引數:
image:輸入影象,應輸入灰度影象
method:使用霍夫變換圓檢測的演算法,它的引數是CV_HOUGH_GRADIENT
dp:霍夫空間的解析度,dp=1時表示霍夫空間與輸入影象空間的大小一致,dp=2時霍夫空間是輸入影象空間的一半,以此類推
minDist為圓心之間的最小距離,如果檢測到的兩個圓心之間距離小於該值,則認為它們是同一個圓心
param1:邊緣檢測時使用Canny運算元的高閾值,低閾值是高閾值的一半。
param2:檢測圓心和確定半徑時所共有的閾值
minRadius和maxRadius為所檢測到的圓半徑的最小值和最大值
返回:
circles:輸出圓向量,包括三個浮點型的元素——圓心橫座標,圓心縱座標和圓半徑
實現
由於霍夫圓檢測對噪聲比較敏感,所以首先對影象進行中值濾波。
import cv2 as cvimport numpy as npimport matplotlib。pyplot as plt# 1 讀取影象,並轉換為灰度圖planets = cv。imread(“。/image/star。jpeg”)gay_img = cv。cvtColor(planets, cv。COLOR_BGRA2GRAY)# 2 進行中值模糊,去噪點img = cv。medianBlur(gay_img, 7) # 3 霍夫圓檢測circles = cv。HoughCircles(img, cv。HOUGH_GRADIENT, 1, 200, param1=100, param2=30, minRadius=0, maxRadius=100)# 4 將檢測結果繪製在影象上for i in circles[0, :]: # 遍歷矩陣每一行的資料 # 繪製圓形 cv。circle(planets, (i[0], i[1]), i[2], (0, 255, 0), 2) # 繪製圓心 cv。circle(planets, (i[0], i[1]), 2, (0, 0, 255), 3)# 5 影象顯示plt。figure(figsize=(10,8),dpi=100)plt。imshow(planets[:,:,::-1]),plt。title(‘霍夫變換圓檢測’)plt。xticks([]), plt。yticks([])plt。show()
總結:
模板匹配
原理:在給定的圖片中查詢和模板最相似的區域API:利用cv。matchTemplate()進行模板匹配,然後使用cv。minMaxLoc()搜尋最匹配的位置。
霍夫線檢測
原理:將要檢測的內容轉換到霍夫空間中,利用累加器統計最優解,將檢測結果表示處理API:cv2。HoughLines()注意:該方法輸入是的二值化影象,在進行檢測前要將影象進行二值化處理
霍夫圓檢測
方法:霍夫梯度法API:cv。HoughCircles()