??????歡迎來到本博客??????
本次博客內(nèi)容將繼續(xù)講解關(guān)于OpenCV的相關(guān)知識
??作者簡介:??????目前計算機研究生在讀。主要研究方向是人工智能和群智能算法方向。目前熟悉深度學習(keras、pytorch、yolo),python網(wǎng)頁爬蟲、機器學習、計算機視覺(OpenCV)、群智能算法。然后正在學習深度學習的相關(guān)內(nèi)容。以后可能會涉及到網(wǎng)絡(luò)安全相關(guān)領(lǐng)域,畢竟這是每一個學習計算機的夢想嘛!
??目前更新:??????目前已經(jīng)更新了關(guān)于網(wǎng)絡(luò)爬蟲的相關(guān)知識、機器學習的相關(guān)知識、目前正在更新計算機視覺-OpenCV的相關(guān)內(nèi)容。
??????本文摘要??????
本文我們將繼續(xù)講解計算機視覺領(lǐng)域項目-基于特征點匹配的圖像拼接。 ![]()
??項目前言
之前我們介紹過基于OpenCv的特征匹配操作,我們通過特征匹配可以精確的找到目標。本節(jié)我們繼續(xù)探索基于特征匹配還可以做哪些事情。我們都在拍一個集體的過程中使用過蘋果手機的全圖效果進行拍照留念。那么蘋果手機這個效果它是基于什么技術(shù)來做的呢?沒錯其實就是特征匹配。他是實時拍取多個照片,然后使用特征匹配操作繼續(xù)兩個圖像之間特征點的匹配,然后生成轉(zhuǎn)換矩陣,最后轉(zhuǎn)換成效果圖,我們本次博客就是要介紹一下這個操作如何使用OpenCv進行實現(xiàn)。
??項目講解前期準備
??圖像特征檢測Harris原理
- 角點:在圖像的角度來看,無論是沿著水平方向還是豎直方向進行移動時候,灰度級會發(fā)生變化,而且這個變化是非常迅速的,我們稱這個圖像就是一個角點。
- 邊界:在圖像的角度上來看,指把圖像按照水平或者垂直方向移動的時候,只有一個一個方向變化的比較明顯,另一個方向變化就比較微弱,這樣的我們就稱之為邊界。
- 平面:平面就是說無論向垂直方向還是水平方向移動,圖像的灰度值都不會發(fā)生迅速的變化,這個就是平面。
原理圖,這里第一個圖表示的就是平面灰度值沒有明顯變化,第二個圖就是要給邊界灰度值水平方向變化明顯垂直方向灰度值變化并不明顯,第三個圖表示的就是一個角點,無論水平還是垂直方向都很明顯。主要看灰度級的變化結(jié)果:
邊界:一個特征值大,一個特征值小,自相關(guān)函數(shù)在某一個方向上大,在其他方向上小。
平面:兩個特征都小,且近似相等。
角點:兩個特征都大,且近似相等,自相關(guān)函數(shù)在所有方向都大。
在OpenCV當中我們使用,cv2.cornerHarris()
來進行角點檢測。
其中參數(shù)都有:
- img: 數(shù)據(jù)類型為 ?oat32 的入圖像
- blockSize: 角點檢測中指定區(qū)域的大小
- ksize: Sobel求導中使用的窗口大小
- k: 取值參數(shù)為 [0,04,0.06]
我們使用幾個小圖像去做一下角點檢測:
import cv2
import numpy as np
img = cv2.imread('white-black.webp')
print ('img.shape:',img.shape)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# gray = np.float32(gray)
dst = cv2.cornerHarris(gray, 2, 3, 0.04)
print ('dst.shape:',dst.shape)
img[dst>0.01*dst.max()]=[0,0,255]
cv2.imshow('dst',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
這里有一些點檢測的不是特別好,然后我們用黑白棋盤來看一下。
這個效果堪稱完美?。?!
??圖像特征檢測SIFT原理
SIFT是指尺度空間:是指在一定的范圍內(nèi),無論物體是大是小,人眼都可以進行一個識別,然后計算機要去識別卻很難,所以要讓計算機能夠?qū)ξ矬w進行一個在不同尺度下都存在一個統(tǒng)一的認知,就要考慮圖像在不同的尺度在都存在的特點,尺度空間的獲取一般使用高斯模糊來實現(xiàn)-高斯濾波。
我們再說說SIFT有什么優(yōu)點:
1、具有較好的穩(wěn)定性和不變性,能夠適應(yīng)旋轉(zhuǎn)、尺度縮放、亮度的變化,能在一定程度上不受視角變化、仿射變換、噪聲的干擾。
2、區(qū)分性好,能夠在海量特征數(shù)據(jù)庫中進行快速準確的區(qū)分信息進行匹配
3、多量性,就算只有單個物體,也能產(chǎn)生大量特征向量
4、高速性,能夠快速的進行特征向量匹配
5、可擴展性,能夠與其它形式的特征向量進行聯(lián)合
我們都知道如果圖片經(jīng)過高斯濾波操作之后呢,他會變模糊,那么為什么要這么做呢?因為當我們從很近的看一個人的時候,他是清晰的,那么從很遠看的時候他就是模糊的。所以我們?yōu)榱四M這個過程,就用高斯濾波來進行相同了一個模擬。
不同σ的高斯函數(shù)決定了對圖像的平滑程度,越大的σ值對應(yīng)的圖像越模糊。
因此我們要介紹一個金字塔,高斯差分金字塔。
我們需要做一個多分辨率的金字塔,對于金字塔的每一層都要做高斯濾波。
根據(jù)意思就是5個輸入的高斯圖像,相鄰的進行像素值相減,得到4張差分后的結(jié)果。那么我們想要找什么呢?找SIFT,就是特征點,那么什么樣的點被認為是特征點呢?通常關(guān)鍵點數(shù)值較大、差分結(jié)果較大的、極值里面較大的。是不是有點像之前講的圖像金字塔。
??圖像特征匹配實戰(zhàn)
??項目詳解
前面我們簡單的將特征匹配介紹了一下,然后我們開始講一下我們本次博客的內(nèi)容。
主函數(shù):
from Stitcher import Stitcher
import cv2
# 讀取拼接圖片
imageA = cv2.imread("left_02.jpg")
imageB = cv2.imread("right_02.jpg")
# 把圖片拼接成全景圖
stitcher = Stitcher()
(result, vis) = stitcher.stitch([imageA, imageB], showMatches=True)
# 顯示所有圖片
cv2.imshow("Image A", imageA)
cv2.imshow("Image B", imageB)
cv2.imshow("Keypoint Matches", vis)
cv2.imshow("Result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
在主函數(shù)這里我們把兩張圖像導入進來,注意這里的圖像寬度必須一致,因為后續(xù)要進行拼接。長度可以保持不一致。然后我們進入拼接全景圖的操作當中。Stitcher()
函數(shù)部分:
import numpy as np
import cv2
class Stitcher:
#拼接函數(shù)
def stitch(self, images, ratio=0.75, reprojThresh=4.0,showMatches=False):
#獲取輸入圖片
(imageB, imageA) = images
(kpsA, featuresA) = self.detectAndDescribe(imageA)
(kpsB, featuresB) = self.detectAndDescribe(imageB)
M = self.matchKeypoints(kpsA, kpsB, featuresA, featuresB, ratio, reprojThresh)
# 如果返回結(jié)果為空,沒有匹配成功的特征點,退出算法
if M is None:
return None
# 否則,提取匹配結(jié)果
# H是3x3視角變換矩陣
(matches, H, status) = M
# 將圖片A進行視角變換,result是變換后圖片
result = cv2.warpPerspective(imageA, H, (imageA.shape[1] + imageB.shape[1], imageA.shape[0]))
#self.cv_show('result', result)
# 將圖片B傳入result圖片最左端
result[0:imageB.shape[0], 0:imageB.shape[1]] = imageB
#self.cv_show('result', result)
# 檢測是否需要顯示圖片匹配
if showMatches:
# 生成匹配圖片
vis = self.drawMatches(imageA, imageB, kpsA, kpsB, matches, status)
# 返回結(jié)果
return (result, vis)
# 返回匹配結(jié)果
return result
首先我們將程序?qū)懗梢粋€類,然后在類中使用self.detectAndDescribe()
函數(shù)檢測A、B圖片的SIFT關(guān)鍵特征點,并計算特征描述子。
def detectAndDescribe(self, image):
# 將彩色圖片轉(zhuǎn)換成灰度圖
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
descriptor = cv2.SIFT_create()
(kps, features) = descriptor.detectAndCompute(image, None)
kps = np.float32([kp.pt for kp in kps])
return (kps, features)
首先我們將圖像轉(zhuǎn)換成了灰度圖,然后我們建立了使用SIFT檢測特征點的檢測器。然后對兩張圖片進行特征點檢測,然后將結(jié)果轉(zhuǎn)化成numpy數(shù)組并且返回。
然后在使用self.matchKeypoints()
對特征點進行匹配。
def matchKeypoints(self, kpsA, kpsB, featuresA, featuresB, ratio, reprojThresh):
# 建立暴力匹配器
matcher = cv2.BFMatcher()
# 使用KNN檢測來自A、B圖的SIFT特征匹配對,K=2
rawMatches = matcher.knnMatch(featuresA, featuresB, 2)
matches = []
for m in rawMatches:
# 當最近距離跟次近距離的比值小于ratio值時,保留此匹配對
if len(m) == 2 and m[0].distance < m[1].distance * ratio:
# 存儲兩個點在featuresA, featuresB中的索引值
matches.append((m[0].trainIdx, m[0].queryIdx))
# 當篩選后的匹配對大于4時,計算視角變換矩陣
if len(matches) > 4:
# 獲取匹配對的點坐標
ptsA = np.float32([kpsA[i] for (_, i) in matches])
ptsB = np.float32([kpsB[i] for (i, _) in matches])
# 計算視角變換矩陣
(H, status) = cv2.findHomography(ptsA, ptsB, cv2.RANSAC, reprojThresh)
# 返回結(jié)果
return (matches, H, status)
# 如果匹配對小于4時,返回None
return None
通過上述代碼我們可以計算出來兩張圖象的視角變換矩陣,然后返回結(jié)果。最后進行可視化操作。
def drawMatches(self, imageA, imageB, kpsA, kpsB, matches, status):
# 初始化可視化圖片,將A、B圖左右連接到一起
(hA, wA) = imageA.shape[:2]
(hB, wB) = imageB.shape[:2]
vis = np.zeros((max(hA, hB), wA + wB, 3), dtype="uint8")
vis[0:hA, 0:wA] = imageA
vis[0:hB, wA:] = imageB
# 聯(lián)合遍歷,畫出匹配對
for ((trainIdx, queryIdx), s) in zip(matches, status):
# 當點對匹配成功時,畫到可視化圖上
if s == 1:
# 畫出匹配對
ptA = (int(kpsA[queryIdx][0]), int(kpsA[queryIdx][1]))
ptB = (int(kpsB[trainIdx][0]) + wA, int(kpsB[trainIdx][1]))
cv2.line(vis, ptA, ptB, (0, 255, 0), 1)
# 返回可視化結(jié)果
return vis
我們來看一下效果圖:
左一圖:
右一圖:
最終效果圖:
在用一個經(jīng)典案例:文章來源:http://www.zghlxwxcb.cn/news/detail-787184.html
??支持:??????如果覺得博主的文章還不錯或者您用得到的話,可以免費的關(guān)注一下博主,如果三連收藏支持就更好啦!這就是給予我最大的支持!文章來源地址http://www.zghlxwxcb.cn/news/detail-787184.html
到了這里,關(guān)于計算機視覺項目實戰(zhàn)-基于特征點匹配的圖像拼接的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!