網(wǎng)站設(shè)計(jì)導(dǎo)航欄高度中國(guó)萬(wàn)網(wǎng)域名注冊(cè)
文章目錄
- 特征檢測(cè)的基本概念
- Harris角點(diǎn)檢測(cè)
- Shi-Tomasi角點(diǎn)檢測(cè)
- SIFT關(guān)鍵點(diǎn)檢測(cè)
- SIFT計(jì)算描述子
- SURF特征檢測(cè)
- OBR特征檢測(cè)
- 暴力特征匹配
- FLANN特征匹配
- 實(shí)戰(zhàn)flann特征匹配
- 圖像查找
- 圖像拼接基礎(chǔ)知識(shí)
- 圖像拼接實(shí)戰(zhàn)
特征點(diǎn)檢測(cè)與匹配是計(jì)算機(jī)視覺(jué)中非常重要的內(nèi)容。不是所有圖像操作都是對(duì)每個(gè)像素進(jìn)行處理,有些只需使用4個(gè)頂點(diǎn)即可,如圖像的拼接、二維碼定位等
特征檢測(cè)的基本概念
Harris角點(diǎn)檢測(cè)
詳情見(jiàn)官方參考文檔
# -*- coding: utf-8 -*-
import cv2
import numpy as npblockSize = 2
ksize = 3
k = 0.04img = cv2.imread('./chess.png')# 灰度化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# Harris角點(diǎn)檢測(cè)
dst = cv2.cornerHarris(gray, blockSize, ksize, k)# Harris角點(diǎn)展示
img[dst > 0.01 * dst.max()] = [0, 255, 0]cv2.imshow('harris', img)
if cv2.waitKey(0) & 0xff == 27:cv2.destroyAllWindows()
Shi-Tomasi角點(diǎn)檢測(cè)
距離越大檢測(cè)到的角數(shù)越少,距離越小檢測(cè)到的角數(shù)越多
# -*- coding: utf-8 -*-
import cv2
import numpy as np# Harris
# blockSize = 2
# ksize = 3
# k = 0.04# Shi-Tomasi
maxCorners = 1000
ql = 0.01
minDistance = 10img = cv2.imread('./chess.png')# 灰度化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# Harris角點(diǎn)檢測(cè)
# dst = cv2.cornerHarris(gray, blockSize, ksize, k)# Harris角點(diǎn)展示
# img[dst > 0.01 * dst.max()] = [0, 255, 0]corners = cv2.goodFeaturesToTrack(gray, maxCorners, ql, minDistance)corners = np.int0(corners)for i in corners:x, y = i.ravel()cv2.circle(img, (x, y), 3, (0, 255, 0), -1)cv2.imshow('Tomasi', img)
if cv2.waitKey(0) & 0xff == 27:cv2.destroyAllWindows()
SIFT關(guān)鍵點(diǎn)檢測(cè)
詳情見(jiàn)官方文檔
The distinguishing qualities of an image that make it stand out are referred to as key points in an image. The key points of a particular image let us recognize objects and compare images. Detecting critical spots in a picture may be done using a variety of techniques and algorithms. We utilize the drawKeypoints() method in OpenCV to be able to draw the identified key points on a given picture. The input picture, keypoints, color, and flag are sent to the drawKeypoints() method. key points are the most important aspects of the detection. Even after the image is modified the key points remain the same. As of now, we can only use the SIRF_create() function as the surf function is patented.
# -*- coding: utf-8 -*-
import cv2
import numpy as npimg = cv2.imread('./chess.png')
# 灰度化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 創(chuàng)建SIFT對(duì)象
sift = cv2.xfeatures2d.SIFT_create()
# 進(jìn)行檢測(cè)
kp = sift.detect(gray, None)# 繪制keypoints
cv2.drawKeypoints(gray, kp, img)cv2.imshow('img', img)
if cv2.waitKey(0) & 0xff == 27:cv2.destroyAllWindows()
-
sift = cv2.xfeatures2d.SIFT_create() 實(shí)例化
參數(shù)說(shuō)明:sift為實(shí)例化的sift函數(shù) -
kp = sift.detect(gray, None) 找出圖像中的關(guān)鍵點(diǎn)
參數(shù)說(shuō)明: kp表示生成的關(guān)鍵點(diǎn),gray表示輸入的灰度圖, -
ret = cv2.drawKeypoints(gray, kp, img) 在圖中畫出關(guān)鍵點(diǎn)
參數(shù)說(shuō)明:gray表示輸入圖片, kp表示關(guān)鍵點(diǎn),img表示輸出的圖片 -
kp, dst = sift.compute(kp) 計(jì)算關(guān)鍵點(diǎn)對(duì)應(yīng)的sift特征向量
參數(shù)說(shuō)明:kp表示輸入的關(guān)鍵點(diǎn),dst表示輸出的sift特征向量,通常是128維的
SIFT計(jì)算描述子
# -*- coding: utf-8 -*-
import cv2
import numpy as npimg = cv2.imread('./chess.png')
# 灰度化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 創(chuàng)建SIFT對(duì)象
sift = cv2.xfeatures2d.SIFT_create()
# 進(jìn)行檢測(cè)
kp, des = sift.detectAndCompute(gray, None)print(des)# 繪制keypoints
cv2.drawKeypoints(gray, kp, img)cv2.imshow('img', img)
if cv2.waitKey(0) & 0xff == 27:cv2.destroyAllWindows()
SURF特征檢測(cè)
# -*- coding: utf-8 -*-
import cv2
import numpy as npimg = cv2.imread('./chess.png')
# 灰度化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 創(chuàng)建SIFT對(duì)象
# sift = cv2.xfeatures2d.SIFT_create()# 創(chuàng)建SURF對(duì)象
surf = cv2.xfeatures2d.SURF.create()# 進(jìn)行檢測(cè)
# kp, des = sift.detectAndCompute(gray, None)
kp, des = surf.detectAndCompute(gray, None)# print(des[0])# 繪制keypoints
cv2.drawKeypoints(gray, kp, img)cv2.imshow('img', img)
if cv2.waitKey(0) & 0xff == 27:cv2.destroyAllWindows()
好消息,SURF付費(fèi)了,不是開(kāi)源的接口了,需要大家自己造輪子,寫新的好算法!
OBR特征檢測(cè)
# -*- coding: utf-8 -*-
import cv2
import numpy as npimg = cv2.imread('./chess.png')
# 灰度化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 創(chuàng)建SIFT對(duì)象
# sift = cv2.xfeatures2d.SIFT_create()# 創(chuàng)建SURF對(duì)象
# surf = cv2.xfeatures2d.SURF.create()# 創(chuàng)建ORB對(duì)象
orb = cv2.ORB_create()# 進(jìn)行檢測(cè)
# kp, des = sift.detectAndCompute(gray, None)
# kp, des = surf.detectAndCompute(gray, None)
kp, des = orb.detectAndCompute(gray, None)# print(des[0])# 繪制keypoints
cv2.drawKeypoints(gray, kp, img)cv2.imshow('img', img)
if cv2.waitKey(0) & 0xff == 27:cv2.destroyAllWindows()
暴力特征匹配
# -*- coding: utf-8 -*-
import cv2
import numpy as np# img = cv2.imread('./chess.png')
img1 = cv2.imread('./opencv_search.png')
img2 = cv2.imread('./opencv_orig.png')# 灰度化
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)# create SIFT feature extractor
# 創(chuàng)建SIFT對(duì)象
sift = cv2.xfeatures2d.SIFT_create()# 創(chuàng)建SURF對(duì)象
# surf = cv2.xfeatures2d.SURF.create()# 創(chuàng)建ORB對(duì)象
orb = cv2.ORB_create()# detect features from the image
# 進(jìn)行檢測(cè)
# kp, des = sift.detectAndCompute(gray, None)
# kp, des = surf.detectAndCompute(gray, None)
# kp, des = orb.detectAndCompute(gray, None)# draw the detected key points
kp1, des1 = sift.detectAndCompute(gray1, None)
kp2, des2 = sift.detectAndCompute(gray2, None)# print(des[0])# 繪制keypoints
# cv2.drawKeypoints(gray, kp, img)# 創(chuàng)建匹配器
bf = cv2.BFMatcher(cv2.NORM_L1)
match = bf.match(des1, des2)img3 = cv2.drawMatches(img1, kp1, img2, kp2, match, None)cv2.imshow('img', img3)
if cv2.waitKey(0) & 0xff == 27:cv2.destroyAllWindows()
FLANN特征匹配
實(shí)戰(zhàn)flann特征匹配
參考的官網(wǎng)手冊(cè)
# -*- coding: utf-8 -*-
import cv2
import numpy as np# queryImage
img1 = cv2.imread('./opencv_search.png')
# trainImage
img2 = cv2.imread('./opencv_orig.png')# 灰度化
g1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
g2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)# 創(chuàng)建SIFT特征檢測(cè)器
# Initiate SIFT detector
sift = cv2.xfeatures2d.SIFT_create()# 計(jì)算描述子與特征點(diǎn)
# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(g1, None)
kp2, des2 = sift.detectAndCompute(g2, None)# 創(chuàng)建匹配器
# FLANN parameters
index_params = dict(algorithm = 1, trees = 5)
search_params = dict(checks = 50)
flann = cv2.FlannBasedMatcher(index_params, search_params)# 對(duì)描述子進(jìn)行匹配計(jì)算
matchs = flann.knnMatch(des1, des2, k = 2)good = []
# ratio test as per Lowe's paper
for i, (m, n) in enumerate(matchs):if m.distance < 0.7 * n.distance:good.append(m)ret = cv2.drawMatchesKnn(img1, kp1, img2, kp2, [good], None)cv2.imshow('res', ret)
if cv2.waitKey(0) & 0xff == 27:cv2.destroyAllWindows()
圖像查找
# -*- coding: utf-8 -*-
import cv2
import numpy as npimg1 = cv2.imread('./opencv_search.png')
img2 = cv2.imread('./opencv_orig.png')MIN_MATCH_COUNT = 4# 灰度化
g1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
g2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)# 創(chuàng)建SIFT特征檢測(cè)器
sift = cv2.xfeatures2d.SIFT_create()# 計(jì)算描述子與特征點(diǎn)
kp1, des1 = sift.detectAndCompute(g1, None)
kp2, des2 = sift.detectAndCompute(g2, None)# 創(chuàng)建匹配器
index_params = dict(algorithm = 1, trees = 5)
search_params = dict(checks = 50)
flann = cv2.FlannBasedMatcher(index_params, search_params)# 對(duì)描述子進(jìn)行匹配計(jì)算
matchs = flann.knnMatch(des1, des2, k = 2)good = []
for i, (m, n) in enumerate(matchs):if m.distance < 0.7 * n.distance:good.append(m)if len(good) >= MIN_MATCH_COUNT:src_pts = np.float32([ kp1[m.queryIdx].pt for m in good ]).reshape(-1,1,2)dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good ]).reshape(-1,1,2)M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)h,w = img1.shape[:2]pts = np.float32([ [0, 0], [0, h-1], [w-1, h-1], [w-1, 0]]).reshape(-1,1,2)dst = cv2.perspectiveTransform(pts, M)cv2.polylines(img2, [np.int32(dst)], True, (0, 255, 0))
else:print('the number of good is less than 4.')exit()ret = cv2.drawMatchesKnn(img1, kp1, img2, kp2, [good], None)cv2.imshow('res', ret)
if cv2.waitKey(0) & 0xff == 27:cv2.destroyAllWindows()
圖像拼接基礎(chǔ)知識(shí)
(0,0)是第二張圖的左上角
圖像拼接實(shí)戰(zhàn)
# -*- coding: utf-8 -*-
import cv2
import numpy as np#第一步,讀取文件,將圖片設(shè)置成一樣大小640x480
#第二步,找特征點(diǎn),描述子,計(jì)算單應(yīng)性矩陣
#第三步,根據(jù)單應(yīng)性矩陣對(duì)圖像進(jìn)行變換,然后平移
#第四步,拼接并輸出最終結(jié)果img1 = cv2.imread('map1.png')
img2 = cv2.imread('map2.png')img1 = cv2.resize(img1, (640, 480))
img2 = cv2.resize(img2, (640, 480))inputs = np.hstack((img1, img2))
cv2.imshow('input_img', inputs)
if cv2.waitKey(0) & 0xff == 27:cv2.destroyAllWindows()
# -*- coding: utf-8 -*-
import cv2
import numpy as np#第一步,讀取文件,將圖片設(shè)置成一樣大小640x480
#第二步,找特征點(diǎn),描述子,計(jì)算單應(yīng)性矩陣
#第三步,根據(jù)單應(yīng)性矩陣對(duì)圖像進(jìn)行變換,然后平移
#第四步,拼接并輸出最終結(jié)果MIN_MATCH_COUNT = 8def stitch_image(img1, img2, H):# 1. 獲得每張圖片的四個(gè)角點(diǎn)# 2. 對(duì)圖片進(jìn)行變換(單應(yīng)性矩陣使圖進(jìn)行旋轉(zhuǎn),平移)# 3. 創(chuàng)建一張大圖,將兩張圖拼接到一起# 4. 將結(jié)果輸出#獲得原始圖的高/寬h1, w1 = img1.shape[:2]h2, w2 = img2.shape[:2]img1_dims = np.float32([[0,0], [0, h1], [w1, h1], [w1, 0]]).reshape(-1, 1, 2)img2_dims = np.float32([[0,0], [0, h2], [w2, h2], [w2, 0]]).reshape(-1, 1, 2)img1_transform = cv2.perspectiveTransform(img1_dims, H)print(img1_dims)print(img2_dims)print(img1_transform)def get_homo(img1, img2):#1. 創(chuàng)建特征轉(zhuǎn)換對(duì)象#2. 通過(guò)特征轉(zhuǎn)換對(duì)象獲得特征點(diǎn)和描述子#3. 創(chuàng)建特征匹配器#4. 進(jìn)行特征匹配#5. 過(guò)濾特征,找出有效的特征匹配點(diǎn)# 創(chuàng)建SIFT特征檢測(cè)器sift = cv2.xfeatures2d.SIFT_create()# 計(jì)算描述子與特征點(diǎn)kp1, des1 = sift.detectAndCompute(img1, None)kp2, des2 = sift.detectAndCompute(img2, None)# 創(chuàng)建特征匹配器bf = cv2.BFMatcher()# 對(duì)描述子進(jìn)行匹配計(jì)算matchs = bf.knnMatch(des1, des2, k = 2)verify_matches = []for i, (m, n) in enumerate(matchs):if m.distance < 0.8 * n.distance:verify_matches.append(m)if len(verify_matches) > MIN_MATCH_COUNT:img1_pts = []img2_pts = []for m in verify_matches:img1_pts.append(kp1[m.queryIdx].pt)img2_pts.append(kp2[m.trainIdx].pt)#[(x1, y1), (x2, y2), ...]#[[x1, y1], [x2, y2], ...] img1_pts = np.float32(img1_pts).reshape(-1, 1, 2)img2_pts = np.float32(img2_pts).reshape(-1, 1, 2)# 獲取單應(yīng)性矩陣H, mask = cv2.findHomography(img1_pts, img2_pts, cv2.RANSAC, 5.0)return Helse:print('err: Not enough matches!')exit()img1 = cv2.imread('map1.png')
img2 = cv2.imread('map2.png')img1 = cv2.resize(img1, (640, 480))
img2 = cv2.resize(img2, (640, 480))inputs = np.hstack((img1, img2))#獲得單應(yīng)性矩陣
H = get_homo(img1, img2)#進(jìn)行圖像拼接
result_image = stitch_image(img1, img2, H)cv2.imshow('input_img', inputs)
if cv2.waitKey(0) & 0xff == 27:cv2.destroyAllWindows()
# -*- coding: utf-8 -*-
import cv2
import numpy as np#第一步,讀取文件,將圖片設(shè)置成一樣大小640x480
#第二步,找特征點(diǎn),描述子,計(jì)算單應(yīng)性矩陣
#第三步,根據(jù)單應(yīng)性矩陣對(duì)圖像進(jìn)行變換,然后平移
#第四步,拼接并輸出最終結(jié)果MIN_MATCH_COUNT = 8def stitch_image(img1, img2, H):# 1. 獲得每張圖片的四個(gè)角點(diǎn)# 2. 對(duì)圖片進(jìn)行變換(單應(yīng)性矩陣使圖進(jìn)行旋轉(zhuǎn),平移)# 3. 創(chuàng)建一張大圖,將兩張圖拼接到一起# 4. 將結(jié)果輸出#獲得原始圖的高/寬h1, w1 = img1.shape[:2]h2, w2 = img2.shape[:2]img1_dims = np.float32([[0,0], [0, h1], [w1, h1], [w1, 0]]).reshape(-1, 1, 2)img2_dims = np.float32([[0,0], [0, h2], [w2, h2], [w2, 0]]).reshape(-1, 1, 2)img1_transform = cv2.perspectiveTransform(img1_dims, H)# print(img1_dims)# print(img2_dims)# print(img1_transform)result_dims = np.concatenate((img2_dims, img1_transform), axis=0)# print(result_dims)[x_min, y_min] = np.int32(result_dims.min(axis=0).ravel()-0.5)[x_max, y_max ] = np.int32(result_dims.max(axis=0).ravel()+0.5)#平移的距離transform_dist = [-x_min, -y_min]result_img = cv2.warpPerspective(img1, H, (x_max-x_min, y_max-y_min))return result_imgdef get_homo(img1, img2):#1. 創(chuàng)建特征轉(zhuǎn)換對(duì)象#2. 通過(guò)特征轉(zhuǎn)換對(duì)象獲得特征點(diǎn)和描述子#3. 創(chuàng)建特征匹配器#4. 進(jìn)行特征匹配#5. 過(guò)濾特征,找出有效的特征匹配點(diǎn)# 創(chuàng)建SIFT特征檢測(cè)器sift = cv2.xfeatures2d.SIFT_create()# 計(jì)算描述子與特征點(diǎn)kp1, des1 = sift.detectAndCompute(img1, None)kp2, des2 = sift.detectAndCompute(img2, None)# 創(chuàng)建特征匹配器bf = cv2.BFMatcher()# 對(duì)描述子進(jìn)行匹配計(jì)算matchs = bf.knnMatch(des1, des2, k = 2)verify_matches = []for i, (m, n) in enumerate(matchs):if m.distance < 0.8 * n.distance:verify_matches.append(m)if len(verify_matches) > MIN_MATCH_COUNT:img1_pts = []img2_pts = []for m in verify_matches:img1_pts.append(kp1[m.queryIdx].pt)img2_pts.append(kp2[m.trainIdx].pt)#[(x1, y1), (x2, y2), ...]#[[x1, y1], [x2, y2], ...] img1_pts = np.float32(img1_pts).reshape(-1, 1, 2)img2_pts = np.float32(img2_pts).reshape(-1, 1, 2)# 獲取單應(yīng)性矩陣H, mask = cv2.findHomography(img1_pts, img2_pts, cv2.RANSAC, 5.0)return Helse:print('err: Not enough matches!')exit()img1 = cv2.imread('map1.png')
img2 = cv2.imread('map2.png')img1 = cv2.resize(img1, (640, 480))
img2 = cv2.resize(img2, (640, 480))inputs = np.hstack((img1, img2))#獲得單應(yīng)性矩陣
H = get_homo(img1, img2)#進(jìn)行圖像拼接
result_image = stitch_image(img1, img2, H)cv2.imshow('input_img', result_image)
if cv2.waitKey(0) & 0xff == 27:cv2.destroyAllWindows()
# -*- coding: utf-8 -*-
import cv2
import numpy as np#第一步,讀取文件,將圖片設(shè)置成一樣大小640x480
#第二步,找特征點(diǎn),描述子,計(jì)算單應(yīng)性矩陣
#第三步,根據(jù)單應(yīng)性矩陣對(duì)圖像進(jìn)行變換,然后平移
#第四步,拼接并輸出最終結(jié)果MIN_MATCH_COUNT = 8def stitch_image(img1, img2, H):# 1. 獲得每張圖片的四個(gè)角點(diǎn)# 2. 對(duì)圖片進(jìn)行變換(單應(yīng)性矩陣使圖進(jìn)行旋轉(zhuǎn),平移)# 3. 創(chuàng)建一張大圖,將兩張圖拼接到一起# 4. 將結(jié)果輸出#獲得原始圖的高/寬h1, w1 = img1.shape[:2]h2, w2 = img2.shape[:2]img1_dims = np.float32([[0,0], [0, h1], [w1, h1], [w1, 0]]).reshape(-1, 1, 2)img2_dims = np.float32([[0,0], [0, h2], [w2, h2], [w2, 0]]).reshape(-1, 1, 2)img1_transform = cv2.perspectiveTransform(img1_dims, H)# print(img1_dims)# print(img2_dims)# print(img1_transform)result_dims = np.concatenate((img2_dims, img1_transform), axis=0)# print(result_dims)[x_min, y_min] = np.int32(result_dims.min(axis=0).ravel()-0.5)[x_max, y_max ] = np.int32(result_dims.max(axis=0).ravel()+0.5)#平移的距離transform_dist = [-x_min, -y_min]#[1, 0, dx]#[0, 1, dy] #[0, 0, 1 ]transform_array = np.array([[1, 0, transform_dist[0]],[0, 1, transform_dist[1]],[0, 0, 1]])result_img = cv2.warpPerspective(img1, transform_array.dot(H), (x_max-x_min, y_max-y_min))return result_imgdef get_homo(img1, img2):#1. 創(chuàng)建特征轉(zhuǎn)換對(duì)象#2. 通過(guò)特征轉(zhuǎn)換對(duì)象獲得特征點(diǎn)和描述子#3. 創(chuàng)建特征匹配器#4. 進(jìn)行特征匹配#5. 過(guò)濾特征,找出有效的特征匹配點(diǎn)# 創(chuàng)建SIFT特征檢測(cè)器sift = cv2.xfeatures2d.SIFT_create()# 計(jì)算描述子與特征點(diǎn)kp1, des1 = sift.detectAndCompute(img1, None)kp2, des2 = sift.detectAndCompute(img2, None)# 創(chuàng)建特征匹配器bf = cv2.BFMatcher()# 對(duì)描述子進(jìn)行匹配計(jì)算matchs = bf.knnMatch(des1, des2, k = 2)verify_matches = []for i, (m, n) in enumerate(matchs):if m.distance < 0.8 * n.distance:verify_matches.append(m)if len(verify_matches) > MIN_MATCH_COUNT:img1_pts = []img2_pts = []for m in verify_matches:img1_pts.append(kp1[m.queryIdx].pt)img2_pts.append(kp2[m.trainIdx].pt)#[(x1, y1), (x2, y2), ...]#[[x1, y1], [x2, y2], ...] img1_pts = np.float32(img1_pts).reshape(-1, 1, 2)img2_pts = np.float32(img2_pts).reshape(-1, 1, 2)# 獲取單應(yīng)性矩陣H, mask = cv2.findHomography(img1_pts, img2_pts, cv2.RANSAC, 5.0)return Helse:print('err: Not enough matches!')exit()img1 = cv2.imread('map1.png')
img2 = cv2.imread('map2.png')img1 = cv2.resize(img1, (640, 480))
img2 = cv2.resize(img2, (640, 480))inputs = np.hstack((img1, img2))#獲得單應(yīng)性矩陣
H = get_homo(img1, img2)#進(jìn)行圖像拼接
result_image = stitch_image(img1, img2, H)cv2.imshow('input_img', result_image)
if cv2.waitKey(0) & 0xff == 27:cv2.destroyAllWindows()
# -*- coding: utf-8 -*-
import cv2
import numpy as np#第一步,讀取文件,將圖片設(shè)置成一樣大小640x480
#第二步,找特征點(diǎn),描述子,計(jì)算單應(yīng)性矩陣
#第三步,根據(jù)單應(yīng)性矩陣對(duì)圖像進(jìn)行變換,然后平移
#第四步,拼接并輸出最終結(jié)果MIN_MATCH_COUNT = 8def stitch_image(img1, img2, H):# 1. 獲得每張圖片的四個(gè)角點(diǎn)# 2. 對(duì)圖片進(jìn)行變換(單應(yīng)性矩陣使圖進(jìn)行旋轉(zhuǎn),平移)# 3. 創(chuàng)建一張大圖,將兩張圖拼接到一起# 4. 將結(jié)果輸出#獲得原始圖的高/寬h1, w1 = img1.shape[:2]h2, w2 = img2.shape[:2]img1_dims = np.float32([[0,0], [0, h1], [w1, h1], [w1, 0]]).reshape(-1, 1, 2)img2_dims = np.float32([[0,0], [0, h2], [w2, h2], [w2, 0]]).reshape(-1, 1, 2)img1_transform = cv2.perspectiveTransform(img1_dims, H)# print(img1_dims)# print(img2_dims)# print(img1_transform)result_dims = np.concatenate((img2_dims, img1_transform), axis=0)# print(result_dims)[x_min, y_min] = np.int32(result_dims.min(axis=0).ravel()-0.5)[x_max, y_max ] = np.int32(result_dims.max(axis=0).ravel()+0.5)#平移的距離transform_dist = [-x_min, -y_min]# 齊次坐標(biāo)#[1, 0, dx]#[0, 1, dy] #[0, 0, 1 ]transform_array = np.array([[1, 0, transform_dist[0]],[0, 1, transform_dist[1]],[0, 0, 1]])result_img = cv2.warpPerspective(img1, transform_array.dot(H), (x_max-x_min, y_max-y_min))result_img[transform_dist[1]:transform_dist[1]+h2, transform_dist[0]:transform_dist[0]+w2] = img2return result_imgdef get_homo(img1, img2):#1. 創(chuàng)建特征轉(zhuǎn)換對(duì)象#2. 通過(guò)特征轉(zhuǎn)換對(duì)象獲得特征點(diǎn)和描述子#3. 創(chuàng)建特征匹配器#4. 進(jìn)行特征匹配#5. 過(guò)濾特征,找出有效的特征匹配點(diǎn)# 創(chuàng)建SIFT特征檢測(cè)器sift = cv2.xfeatures2d.SIFT_create()# 計(jì)算描述子與特征點(diǎn)kp1, des1 = sift.detectAndCompute(img1, None)kp2, des2 = sift.detectAndCompute(img2, None)# 創(chuàng)建特征匹配器bf = cv2.BFMatcher()# 對(duì)描述子進(jìn)行匹配計(jì)算matchs = bf.knnMatch(des1, des2, k = 2)verify_matches = []for i, (m, n) in enumerate(matchs):if m.distance < 0.8 * n.distance:verify_matches.append(m)if len(verify_matches) > MIN_MATCH_COUNT:img1_pts = []img2_pts = []for m in verify_matches:img1_pts.append(kp1[m.queryIdx].pt)img2_pts.append(kp2[m.trainIdx].pt)#[(x1, y1), (x2, y2), ...]#[[x1, y1], [x2, y2], ...] img1_pts = np.float32(img1_pts).reshape(-1, 1, 2)img2_pts = np.float32(img2_pts).reshape(-1, 1, 2)# 獲取單應(yīng)性矩陣H, mask = cv2.findHomography(img1_pts, img2_pts, cv2.RANSAC, 5.0)return Helse:print('err: Not enough matches!')exit()img1 = cv2.imread('map1.png')
img2 = cv2.imread('map2.png')img1 = cv2.resize(img1, (640, 480))
img2 = cv2.resize(img2, (640, 480))inputs = np.hstack((img1, img2))#獲得單應(yīng)性矩陣
H = get_homo(img1, img2)#進(jìn)行圖像拼接
result_image = stitch_image(img1, img2, H)cv2.imshow('input_img', result_image)
if cv2.waitKey(0) & 0xff == 27:cv2.destroyAllWindows()
之后我會(huì)持續(xù)更新,如果喜歡我的文章,請(qǐng)記得一鍵三連哦,點(diǎn)贊關(guān)注收藏,你的每一個(gè)贊每一份關(guān)注每一次收藏都將是我前進(jìn)路上的無(wú)限動(dòng)力 !!!↖(▔▽▔)↗感謝支持!