在線做熱圖的網(wǎng)站站長工具seo綜合查詢5g
文章目錄
- 圖像拼接
- 1. 讀取圖片
- 2. 計(jì)算圖片特征點(diǎn)及描述符
- 3. 建立暴力匹配器
- 4. 特征匹配
- 5. 透視變換
- 6. 圖像拼接
- 總結(jié)
圖像拼接
圖像拼接是一項(xiàng)將多張有重疊部分的圖像(這些圖像可能是不同時(shí)間、不同視角或者不同傳感器獲得的)拼成一幅無縫的全景圖或高分辨率圖像的技術(shù)。
主要過程:找到特征匹配點(diǎn),然后進(jìn)行透視變換操作,模擬了人眼或相機(jī)鏡頭觀看三維空間物體時(shí)的透視效果,從而能夠改變圖像的視角和形狀,使得兩個(gè)圖片可以完全拼接在一起。
1. 讀取圖片
def cv_show(name,img):cv2.imshow(name,img)cv2.waitKey(0)
"""-----讀取拼接圖片-----"""
imageA = cv2.imread("t1.jpg")
cv_show('imageA',imageA)
imageB = cv2.imread("t2.jpg")
cv_show('imageB',imageB)
2. 計(jì)算圖片特征點(diǎn)及描述符
def detectAndDescribe(image):gray = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY) # 將彩色圖片轉(zhuǎn)化為灰度圖descriptor = cv2.SIFT_create() # 建立SIFT生成器# 檢測SIFT特征點(diǎn),并計(jì)算描述符,第二個(gè)參數(shù)為掩膜(kps,des) = descriptor.detectAndCompute(gray,None)# 將結(jié)果轉(zhuǎn)化成Numoy數(shù)組kps_float = np.float32([kp.pt for kp in kps])# kp.pt包含兩個(gè)值,分別是關(guān)鍵點(diǎn)在圖像中的x和y坐標(biāo),這些坐標(biāo)通常時(shí)浮點(diǎn)數(shù),可以精確地描述關(guān)鍵點(diǎn)在圖像中的位置return (kps,kps_float,des) # 返回特征點(diǎn)集,及對(duì)應(yīng)的描述特征"""-----計(jì)算圖片特征點(diǎn)及描述符-----"""
(kpsA,kps_floatA,desA) = detectAndDescribe(imageA)
(kpsB,kps_floatB,desB) = detectAndDescribe(imageB)
3. 建立暴力匹配器
"""-----建立暴力匹配器BFMatcher,在匹配大型訓(xùn)練集合時(shí)使用FlannBasedMatcher速度更快-----"""
matcher = cv2.BFMatcher()
4. 特征匹配
方法:關(guān)鍵點(diǎn)A與找到的兩個(gè)關(guān)鍵點(diǎn) X、Y的歐氏距離分別 d1、d2,且d1<d2。
歐氏距離(關(guān)鍵點(diǎn)A,關(guān)鍵點(diǎn)X)=d1。歐氏距離(關(guān)鍵點(diǎn)A,關(guān)鍵點(diǎn)Y)=d2。
(1)d1<d2,比值較大:可能不是匹配點(diǎn),通常是由噪聲引起的。
(2)d1<d2,比值較小:是匹配點(diǎn)。
- 函數(shù):
--knnMatch(queryDescriptors,trainDescriptors,k,mask=None,compactResult = None)
使用KNN檢測來自A、B圖的SIFT特征匹配對(duì),參數(shù)說明:
queryDescriptors:匹配圖像A的描述符
trainDescriptors:匹配圖像B的描述符
k:最佳匹配的描述符個(gè)數(shù),一般k=2
- 返回值:
--返回的數(shù)據(jù)結(jié)構(gòu)描述:
distance:匹配的特征點(diǎn)描述符的歐氏距離,數(shù)值越小也就說明兩個(gè)特征點(diǎn)越相近。
queryIdx:測試圖像的特征點(diǎn)描述符的下標(biāo)(第幾個(gè)特征點(diǎn)描述符),同時(shí)也是描述符對(duì)應(yīng)特征點(diǎn)的下表
trainIdx:樣本圖像的特征點(diǎn)描述符下標(biāo),同時(shí)也是描述符對(duì)應(yīng)特征點(diǎn)的下標(biāo)。
- 代碼應(yīng)用:
rawMatches = matcher.knnMatch(desB,desA,2)
good = []
matches = []
for m in rawMatches:# 當(dāng)最近距離跟次近距離的比值小于0.65時(shí),保留此對(duì)匹配if len(m) == 2 and m[0].distance < 0.65 * m[1].distance:good.append(m)# 存儲(chǔ)兩個(gè)點(diǎn)在featureA,featureB中的索引值matches.append((m[0].trainIdx,m[0].queryIdx))
print(len(good))
print(matches)vis = cv2.drawMatchesKnn(imageB,kpsB,imageA,kpsA,good,None,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv_show("keypoint Matchs",vis)
5. 透視變換
透視變換是指利用透視中心、像點(diǎn)、目標(biāo)點(diǎn)三點(diǎn)共線的條件,按透視旋轉(zhuǎn)定律使承影面(透視面)繞跡線(透視軸)旋轉(zhuǎn)某一角度,破壞原有的投影光線束,但仍能保持承影面上投影幾何圖形不變的變換。它是中心投影的射影變換,在用非齊次射影坐標(biāo)表達(dá)時(shí)是平面的分式線性變換。
- 函數(shù):
-- 計(jì)算透視變換矩陣
findHomography(srcPoints,disPoints,method=None,ransacReprojThreshold=None,mask=None,maxIters=None,confidence=None)
計(jì)算視角變換矩陣,透視變換函數(shù),與cv2.getPerspectiveTransform()的區(qū)別在于可多個(gè)數(shù)據(jù)點(diǎn)變換
參數(shù):
-- srcPoints:圖片A的匹配點(diǎn)坐標(biāo)
-- disPoints:圖片B的匹配點(diǎn)坐標(biāo)
-- method:計(jì)算變換矩陣的方法0 - 使用所有的點(diǎn),最小二乘RANSAC - 基于隨機(jī)樣本一致性LMEDS - 最小中值RHO - 基于漸進(jìn)樣本一致性
-- ransacReprojThreshold:最大允許重投影錯(cuò)誤閾值,該參數(shù)只有在method參數(shù)為RANSAC與RHO的時(shí)候啟用,默認(rèn)為3
返回值:H為變換矩陣,mask時(shí)掩膜標(biāo)志,指示哪些點(diǎn)對(duì)時(shí)內(nèi)點(diǎn),哪些是外點(diǎn).內(nèi)點(diǎn):指那些與估計(jì)的模型非常接近的數(shù)據(jù)點(diǎn),通常是正確匹配或真實(shí)數(shù)據(jù)
- 代碼應(yīng)用:
if len(matches) > 4: # 當(dāng)篩選后的匹配對(duì)大于4時(shí),計(jì)算視角變換矩陣# 獲取匹配對(duì)的點(diǎn)坐標(biāo)ptsA = np.float32([kps_floatA[i] for (i, _) in matches]) # matches是通過閾值篩選之后的特征點(diǎn)對(duì)象ptsB = np.float32([kps_floatB[i] for (_, i) in matches]) # kps_floatA是圖片A中的全部特征點(diǎn)坐標(biāo)(H,mask) = cv2.findHomography(ptsB,ptsA,cv2.RANSAC,10)
else:print("圖片未找到4個(gè)以上的匹配點(diǎn)")sys.exit()
result = cv2.warpPerspective(imageB,H,(imageB.shape[1] + imageA.shape[1],imageB.shape[0]))
cv_show('resultB',result)
6. 圖像拼接
# 將圖片A傳入result圖片最左端
result[0:imageA.shape[0],0:imageA.shape[1]] = imageA
cv_show("result",result)
總結(jié)
本篇介紹了:
如何通過計(jì)算關(guān)鍵點(diǎn)以及透視變換的矩陣將兩個(gè)不同視角的圖片進(jìn)行拼接,使得它們能夠完整協(xié)和的展示出來。