OpenCV入门10——特征点检测与匹配

文章目录

  • 特征检测的基本概念
  • Harris角点检测
  • Shi-Tomasi角点检测
  • SIFT关键点检测
  • SIFT计算描述子
  • SURF特征检测
  • OBR特征检测
  • 暴力特征匹配
  • FLANN特征匹配
  • 实战flann特征匹配
  • 图像查找
  • 图像拼接基础知识
  • 图像拼接实战

特征点检测与匹配是计算机视觉中非常重要的内容。不是所有图像操作都是对每个像素进行处理,有些只需使用4个顶点即可,如图像的拼接、二维码定位等

特征检测的基本概念

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Harris角点检测

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
详情见官方参考文档
在这里插入图片描述

# -*- 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角点检测
dst = cv2.cornerHarris(gray, blockSize, ksize, k)# Harris角点展示
img[dst > 0.01 * dst.max()] = [0, 255, 0]cv2.imshow('harris', img)
if cv2.waitKey(0) & 0xff == 27:cv2.destroyAllWindows()

在这里插入图片描述

Shi-Tomasi角点检测

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
距离越大检测到的角数越少,距离越小检测到的角数越多

# -*- 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角点检测
# dst = cv2.cornerHarris(gray, blockSize, ksize, k)# Harris角点展示
# 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关键点检测

详情见官方文档
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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)# 创建SIFT对象
sift = cv2.xfeatures2d.SIFT_create()
# 进行检测
kp = sift.detect(gray, None)# 绘制keypoints
cv2.drawKeypoints(gray, kp, img)cv2.imshow('img', img)
if cv2.waitKey(0) & 0xff == 27:cv2.destroyAllWindows()

在这里插入图片描述

  1. sift = cv2.xfeatures2d.SIFT_create() 实例化
    参数说明:sift为实例化的sift函数

  2. kp = sift.detect(gray, None) 找出图像中的关键点
    参数说明: kp表示生成的关键点,gray表示输入的灰度图,

  3. ret = cv2.drawKeypoints(gray, kp, img) 在图中画出关键点
    参数说明:gray表示输入图片, kp表示关键点,img表示输出的图片

  4. kp, dst = sift.compute(kp) 计算关键点对应的sift特征向量
    参数说明:kp表示输入的关键点,dst表示输出的sift特征向量,通常是128维的

SIFT计算描述子

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

# -*- coding: utf-8 -*-
import cv2
import numpy as npimg = cv2.imread('./chess.png')
# 灰度化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 创建SIFT对象
sift = cv2.xfeatures2d.SIFT_create()
# 进行检测
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特征检测

在这里插入图片描述
在这里插入图片描述

# -*- coding: utf-8 -*-
import cv2
import numpy as npimg = cv2.imread('./chess.png')
# 灰度化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 创建SIFT对象
# sift = cv2.xfeatures2d.SIFT_create()# 创建SURF对象
surf = cv2.xfeatures2d.SURF.create()# 进行检测
# 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付费了,不是开源的接口了,需要大家自己造轮子,写新的好算法!

OBR特征检测

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

# -*- coding: utf-8 -*-
import cv2
import numpy as npimg = cv2.imread('./chess.png')
# 灰度化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 创建SIFT对象
# sift = cv2.xfeatures2d.SIFT_create()# 创建SURF对象
# surf = cv2.xfeatures2d.SURF.create()# 创建ORB对象
orb = cv2.ORB_create()# 进行检测
# 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
# 创建SIFT对象
sift = cv2.xfeatures2d.SIFT_create()# 创建SURF对象
# surf = cv2.xfeatures2d.SURF.create()# 创建ORB对象
orb = cv2.ORB_create()# detect features from the image
# 进行检测
# 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)# 创建匹配器
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特征匹配

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实战flann特征匹配

参考的官网手册

# -*- 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)# 创建SIFT特征检测器
# Initiate SIFT detector
sift = cv2.xfeatures2d.SIFT_create()# 计算描述子与特征点
# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(g1, None)
kp2, des2 = sift.detectAndCompute(g2, None)# 创建匹配器
# FLANN parameters
index_params = dict(algorithm = 1, trees = 5)
search_params = dict(checks = 50)
flann = cv2.FlannBasedMatcher(index_params, search_params)# 对描述子进行匹配计算
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)# 创建SIFT特征检测器
sift = cv2.xfeatures2d.SIFT_create()# 计算描述子与特征点
kp1, des1 = sift.detectAndCompute(g1, None)
kp2, des2 = sift.detectAndCompute(g2, None)# 创建匹配器
index_params = dict(algorithm = 1, trees = 5)
search_params = dict(checks = 50)
flann = cv2.FlannBasedMatcher(index_params, search_params)# 对描述子进行匹配计算
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()

在这里插入图片描述

图像拼接基础知识

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
(0,0)是第二张图的左上角
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

图像拼接实战

# -*- coding: utf-8 -*-
import cv2
import numpy as np#第一步,读取文件,将图片设置成一样大小640x480
#第二步,找特征点,描述子,计算单应性矩阵
#第三步,根据单应性矩阵对图像进行变换,然后平移
#第四步,拼接并输出最终结果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#第一步,读取文件,将图片设置成一样大小640x480
#第二步,找特征点,描述子,计算单应性矩阵
#第三步,根据单应性矩阵对图像进行变换,然后平移
#第四步,拼接并输出最终结果MIN_MATCH_COUNT = 8def stitch_image(img1, img2, H):# 1. 获得每张图片的四个角点# 2. 对图片进行变换(单应性矩阵使图进行旋转,平移)# 3. 创建一张大图,将两张图拼接到一起# 4. 将结果输出#获得原始图的高/宽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. 创建特征转换对象#2. 通过特征转换对象获得特征点和描述子#3. 创建特征匹配器#4. 进行特征匹配#5. 过滤特征,找出有效的特征匹配点# 创建SIFT特征检测器sift = cv2.xfeatures2d.SIFT_create()# 计算描述子与特征点kp1, des1 = sift.detectAndCompute(img1, None)kp2, des2 = sift.detectAndCompute(img2, None)# 创建特征匹配器bf = cv2.BFMatcher()# 对描述子进行匹配计算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)# 获取单应性矩阵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))#获得单应性矩阵
H = get_homo(img1, img2)#进行图像拼接
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#第一步,读取文件,将图片设置成一样大小640x480
#第二步,找特征点,描述子,计算单应性矩阵
#第三步,根据单应性矩阵对图像进行变换,然后平移
#第四步,拼接并输出最终结果MIN_MATCH_COUNT = 8def stitch_image(img1, img2, H):# 1. 获得每张图片的四个角点# 2. 对图片进行变换(单应性矩阵使图进行旋转,平移)# 3. 创建一张大图,将两张图拼接到一起# 4. 将结果输出#获得原始图的高/宽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. 创建特征转换对象#2. 通过特征转换对象获得特征点和描述子#3. 创建特征匹配器#4. 进行特征匹配#5. 过滤特征,找出有效的特征匹配点# 创建SIFT特征检测器sift = cv2.xfeatures2d.SIFT_create()# 计算描述子与特征点kp1, des1 = sift.detectAndCompute(img1, None)kp2, des2 = sift.detectAndCompute(img2, None)# 创建特征匹配器bf = cv2.BFMatcher()# 对描述子进行匹配计算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)# 获取单应性矩阵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))#获得单应性矩阵
H = get_homo(img1, img2)#进行图像拼接
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#第一步,读取文件,将图片设置成一样大小640x480
#第二步,找特征点,描述子,计算单应性矩阵
#第三步,根据单应性矩阵对图像进行变换,然后平移
#第四步,拼接并输出最终结果MIN_MATCH_COUNT = 8def stitch_image(img1, img2, H):# 1. 获得每张图片的四个角点# 2. 对图片进行变换(单应性矩阵使图进行旋转,平移)# 3. 创建一张大图,将两张图拼接到一起# 4. 将结果输出#获得原始图的高/宽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. 创建特征转换对象#2. 通过特征转换对象获得特征点和描述子#3. 创建特征匹配器#4. 进行特征匹配#5. 过滤特征,找出有效的特征匹配点# 创建SIFT特征检测器sift = cv2.xfeatures2d.SIFT_create()# 计算描述子与特征点kp1, des1 = sift.detectAndCompute(img1, None)kp2, des2 = sift.detectAndCompute(img2, None)# 创建特征匹配器bf = cv2.BFMatcher()# 对描述子进行匹配计算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)# 获取单应性矩阵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))#获得单应性矩阵
H = get_homo(img1, img2)#进行图像拼接
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#第一步,读取文件,将图片设置成一样大小640x480
#第二步,找特征点,描述子,计算单应性矩阵
#第三步,根据单应性矩阵对图像进行变换,然后平移
#第四步,拼接并输出最终结果MIN_MATCH_COUNT = 8def stitch_image(img1, img2, H):# 1. 获得每张图片的四个角点# 2. 对图片进行变换(单应性矩阵使图进行旋转,平移)# 3. 创建一张大图,将两张图拼接到一起# 4. 将结果输出#获得原始图的高/宽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))result_img[transform_dist[1]:transform_dist[1]+h2, transform_dist[0]:transform_dist[0]+w2] = img2return result_imgdef get_homo(img1, img2):#1. 创建特征转换对象#2. 通过特征转换对象获得特征点和描述子#3. 创建特征匹配器#4. 进行特征匹配#5. 过滤特征,找出有效的特征匹配点# 创建SIFT特征检测器sift = cv2.xfeatures2d.SIFT_create()# 计算描述子与特征点kp1, des1 = sift.detectAndCompute(img1, None)kp2, des2 = sift.detectAndCompute(img2, None)# 创建特征匹配器bf = cv2.BFMatcher()# 对描述子进行匹配计算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)# 获取单应性矩阵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))#获得单应性矩阵
H = get_homo(img1, img2)#进行图像拼接
result_image = stitch_image(img1, img2, H)cv2.imshow('input_img', result_image)
if cv2.waitKey(0) & 0xff == 27:cv2.destroyAllWindows()

在这里插入图片描述

之后我会持续更新,如果喜欢我的文章,请记得一键三连哦,点赞关注收藏,你的每一个赞每一份关注每一次收藏都将是我前进路上的无限动力 !!!↖(▔▽▔)↗感谢支持!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/210822.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

无人智能货柜:提升购物体验

无人智能货柜&#xff1a;提升购物体验 随着移动支付的普及&#xff0c;人们日常生活中的主要场景已经渗透了这一支付方式。同时&#xff0c;无人智能货柜作为购物的重要渠道&#xff0c;正在崭露头角。通过人工智能、图像识别和物联网技术的应用&#xff0c;无人智能货柜将使购…

软件开发及交付的项目管理角色

在软件开发及交付过程中&#xff0c;通常会涉及不同的角色和职责&#xff0c;包括业务角色、技术角色和管理角色。这些角色在项目管理中发挥着不同的作用&#xff0c;以确保项目的成功和交付高质量的产品。 业务角色&#xff1a;包括产品经理、业务分析师和业务运营人员等职位…

基于框架的线性回归

线性回归是机器学习中最简单和最常用的回归方法之一。它建立了自变量和因变量之间的线性关系&#xff0c;并通过拟合一条直线或超平面来预测和分析数据。 基于框架的线性回归是构建线性回归模型的一种常见方法&#xff0c;它利用现有的机器学习框架来实现线性回归模型的建立、…

【史上最细教程】服务器MySQL数据库完成主从复制

文章目录 MySQL完成主从复制教程准备&#xff1a;原理&#xff1a;步骤&#xff1a; 推荐文章 MySQL完成主从复制教程 主从复制&#xff08;也称 AB 复制&#xff09;就是将一个服务器&#xff08;主服务器&#xff09;的数据复制到一个或多个MySQL数据库服务器&#xff08;从…

将所有图片居中对齐

Ctrl h 调出替换框 ^g表示所有图片 格式里面选择段落 全部替换

Halcon学习笔记

目录 一.简介 一.简介 Halcon和OpenCV在工业应用中的区别&#xff1a; OpenCV的精度没Halcon高&#xff1b;OpenCV没有模板匹配&#xff0c;Halcon有&#xff0c;而且Halcon匹配的精度更高。

OpenCV滑块验证码图像缺口位置识别

OpenCV图像缺口位置识别 1、背景2、图像缺口位置识别原理3、图像缺口位置识别实现4、滑块验证码HTTP图像需要保存到本地吗1、背景 在使用Selenium完成自动化爬虫时,许多网站为了防止机器人爬取数据会使用验证码(例如滑块验证码)。通过Selenium动作操作,爬虫可以模拟用户输入…

CS2的到来会对csgo产生什么影响?

从左手持枪到教练观战位&#xff0c;周四更新的CS新版本缺乏CSGO里很多关键功能。社区服务器和创意工坊地图&#xff0c;目前最重要的功能缺失是创意工坊地图和社区服务器。这些社区制作的地图长期以来一直是玩家磨练技能的首选场所&#xff0c;从死斗服务器到用来练习瞄准、跑…

sql调优

慢查询 SQL 治理方案 一、SQL 性能下降的原因 在对 SQL 进行分析之前&#xff0c;需要明确可能导致 SQL 执行性能下降的原因进行分析&#xff0c;执行性能下降可以体现在很多方面&#xff1a; 查询语句写的烂索引没加好表数据过大数据库连接数不够查询的数据量过大被其他慢s…

XC3320 离线式、无电感交流输入线性稳压器 可替代KP3310 固定5V输出电压

XC3320 是一款紧凑型无电感设计的离线式线性稳压器。XC3320 可获得 5V输出电压。XC3320 是一种简单可靠的获得偏置供电的离线式电源解决方案。XC3320 集成了 650V 功率 MOSFET&#xff0c;启动控制电路,VDD 电压控制电路,AC 交流信号同步检测电路&#xff0c;低压差稳压器等。该…

构建个性化预约服务:预约上门服务系统源码解读与实战

随着社会的发展&#xff0c;预约上门服务系统在满足用户需求、提升服务效率方面发挥着越来越重要的作用。在本文中&#xff0c;我们将深入研究预约上门服务系统的源码&#xff0c;通过实际的技术代码示例&#xff0c;揭示系统内部的关键机制&#xff0c;以及如何在实际项目中应…

地埋式积水监测仪厂家批发,实时监测路面积水

地埋式积水监测仪是针对城市内涝推出的积水信息监测采集设备&#xff0c;采用超声波传感技术和超声波抗干扰功能&#xff0c;对路面的积水进行实时精准的监测。该设备能够在零下-5℃至高温70℃的严寒酷暑环境下可靠运行。它对城市道路积水进行实时监测并上报到监测系统之中&…