目錄
一.圖像拼接案例
1.圖像拼接項目介紹
2.核心步驟
①計算圖片特征點及描述符
②匹配特征點,使用暴力匹配器
③篩選有效匹配
④計算透視變換矩陣
⑤應用變換和拼接
二.摳圖案例
1.縮放旋轉處理
2.轉化為灰度圖并二值化
3.找出所有輪廓,并在img的副本上畫出
4.排序輪廓找到最大的扇子輪廓
5.創建掩膜
6.’與‘操作,完成摳圖
一.圖像拼接案例
1.圖像拼接項目介紹
- 目標:將兩張視角不同、角度傾斜的圖片(如包含A/B/C物的圖片)如下通過算法融合,使其在同一平面視角下呈現。
- 技術路徑:
- 使用SIFT特征提取兩個圖片中的關鍵點和描述符。
- 采用暴力匹配器(bf_match)進行特征匹配,因其適用于特征點數量較少的場景。
- 基于匹配結果計算并應用透視變換,最終完成兩圖拼接。
2.核心步驟
讀取拼接圖片????????
def cv_show(name,img):cv2.imshow(name,img)cv2.waitKey(0)
#讀取拼接圖片
imageA=cv2.imread('1.jpg')
cv_show('imageA',imageA)
imageB=cv2.imread('2.jpg')
cv_show('imageB',imageB)
①計算圖片特征點及描述符
使用SIFT算法從兩張圖片中提取關鍵點和描述符,利用BFMatcher進行暴力匹配,獲得初步的點對匹配結果。
特征提取我們直接定義一個方法來實現
def detectAndDescribe(image):gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)sift=cv2.SIFT_create()(kps,des)=sift.detectAndCompute(gray,None)kps_float=np.float32([kp.pt for kp in kps])return (kps,kps_float,des)
kps_float是特征點的坐標x和y的ndarray類型的數組
#計算圖片特征點及描述符
(kpsA,kps_floatA,desA)=detectAndDescribe(imageA)
(kpsB,kps_floatB,desB)=detectAndDescribe(imageB)
②匹配特征點,使用暴力匹配器
#建立暴力匹配器
matcher=cv2.BFMatcher()
rawMatches=matcher.knnMatch(desB,desA,k=2)
③篩選有效匹配
通過設定距離閾值(如近點距離小于遠點距離的65%)篩選出可靠的匹配點。
good=[]
matches=[]
for m in rawMatches:if len(m)==2 and m[0].distance<0.65*m[1].distance:good.append(m)matches.append((m[0].queryIdx,m[0].trainIdx))
print(len(good))
print(matches)31
[(14, 76), (36, 105), (39, 105), (63, 118), (65, 121), (66, 122), (74, 130), (83, 128), (87, 136), (93, 140), (105, 147), (118, 172), (138, 176), (154, 191), (155, 192), (158, 198), (164, 213), (165, 206), (176, 217), (185, 227), (201, 242), (202, 243), (204, 246), (207, 250), (209, 255), (212, 257), (217, 7), (228, 275), (229, 276), (231, 275), (233, 276)]
good存放匹配成功的最近點和次近點相關信息
matches用來存放desA特征圖片的匹配成功特征點索引和desB特征圖片的匹配成功特征點索引的元組
畫出兩幅圖之間的特征點對應聯系
vis=cv2.drawMatchesKnn(imageB,kpsB,imageA,kpsA,good,None,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv_show('Keypoint Matches',vis)
④計算透視變換矩陣
利用篩選出的核心特征點,計算出變換矩陣H,使得一張圖片能精確地“變形”到與另一張圖片相同的視角平面上。
#透視變換
if len(matches)>4:#當篩選后的匹配對大于4時,計算視角變換矩陣#獲取匹配對的點坐標ptsB=np.float32([kps_floatB[i] for (i,_) in matches])ptsA=np.float32([kps_floatA[i] for (_,i) in matches])(H,mask)=cv2.findHomography(ptsB,ptsA,cv2.RANSAC,10)
else:print('圖片未找到四個以上的匹配點')sys.exit()
注意點數范圍(至少4個)
mask數組用于標識內點與外點。
⑤應用變換和拼接
變換,這里圖片的寬度我們使用土圖片A和圖片B的寬度和方便后面直接將A圖片拼接上來
result=cv2.warpPerspective(imageB,H,(imageB.shape[1]+imageA.shape[1],imageB.shape[0]))
cv_show('resultB',result)
拼接,將圖片A傳入result圖片最左端
#將圖片A傳入result圖片最左端
result[0:imageA.shape[0],0:imageA.shape[1]]=imageA
cv_show('result',result)
cv2.imwrite('pingjie.jpg',result)
二.摳圖案例
實現只將圖中的扇子摳圖出來,核心技術用到掩膜
1.縮放旋轉處理
import cv2
import numpy as npimg=cv2.imread('img.jpg')
img=cv2.resize(img,(640,480))
img=np.rot90(img,1)
cv2.imshow('img',img)
2.轉化為灰度圖并二值化
這里我們沒有使用閾值的方法來二值化而是使用Canny()邊緣檢測實現二值化
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edged=cv2.Canny(gray,75,200)
cv2.imshow('edged',edged)
cv2.waitKey(0)
3.找出所有輪廓,并在img的副本上畫出
cnts=cv2.findContours(edged.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]
cv2.drawContours(img_cnts,cnts,-1,(0,0,255),2)
cv2.imshow('img_cnts',img_cnts)
cv2.waitKey(0)
4.排序輪廓找到最大的扇子輪廓
cnt=sorted(cnts,key=cv2.contourArea,reverse=True)[0]
5.創建掩膜
先創建和eddged圖片等大的全黑掩膜,再根據扇子的輪廓把掩膜中該部分變成白色
mask = np.zeros(edged.shape, dtype='uint8')
cv2.drawContours(mask, [cnt], -1, 255, -1) # -1表示填充
cv2.imshow('mask',mask)
cv2.waitKey(0)
6.’與‘操作,完成摳圖
img_mask_and=cv2.bitwise_and(img,img,mask=mask)
cv2.imshow('img_mask_and',img_mask_and)
cv2.waitKey(0)
cv2.bitwise_and(img,img,mask=mask)會指將掩膜中白色的部分顯示出來