当前位置: 首页 > news >正文

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()

在这里插入图片描述

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

相关文章:

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

文章目录 特征检测的基本概念Harris角点检测Shi-Tomasi角点检测SIFT关键点检测SIFT计算描述子SURF特征检测OBR特征检测暴力特征匹配FLANN特征匹配实战flann特征匹配图像查找图像拼接基础知识图像拼接实战 特征点检测与匹配是计算机视觉中非常重要的内容。不是所有图像操作都是对…...

教育机构拒绝“数据陷阱”,群硕将英孚新一代教学管理系统搬上桌

为什么小机构年年担心招生不够&#xff0c;英孚却令学生家长趋之若鹜&#xff1f; 区别就在教学管理方式。为了更好地管理分布全球的校区、学生和老师&#xff0c;英孚应用了一套教学管理系统&#xff0c;帮助学校管理学员&#xff0c;帮老师智慧排课&#xff0c;帮助家长记录…...

小辰的智慧树(差分+前缀和)

登录—专业IT笔试面试备考平台_牛客网 1.考虑总长度之和不能超过m&#xff0c;2考虑限制每棵树高度不能低于ci&#xff0c;如果用二分最短输能截到的高度&#xff0c;还要另外去判断&#xff0c;是否每棵树mid都能严格大于ci &#xff0c;这样容易超时&#xff0c;换个角度&…...

Windows如何使用key登录Linux服务器

场景&#xff1a;因为需要回收root管理员权限&#xff0c;禁止root用户远程登录&#xff0c;办公环境只允许普通用户远程登录&#xff0c;且不允许使用密码登录。 一、生成与配置ssh-key 1.使用root管理员权限登录到目标系统。 2.创建一个新的普通用户&#xff0c;和设置密码用…...

k8s无法删除pv,pvc问题

问题&#xff1a; 在k8s里面创建了pv&#xff0c;pvc删除时报错&#xff1a;error: resource(s) were provided, but no name was specified 解决&#xff1a; 正确的删除顺序&#xff1a;1.先删除pod2.再删除pv 3.在删除pvc 删除pv&#xff0c;pvc命令&#xff1a; kubect…...

基于框架的线性回归

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

万宾科技智能井盖传感器使用方式,具有什么效果?

有问题的井盖可能导致人们在行走或驾驶时不经意地踩中或碰到&#xff0c;从而导致摔倒、扭伤或交通事故等安全事故。有问题的井盖可能会破坏井盖和下方污水管道之间的密封性&#xff0c;导致污水泄漏。这不仅会对环境造成污染&#xff0c;还可能对公共卫生和健康构成威胁。 将智…...

13.什么是Spring beans?

什么是Spring beans&#xff1f; Spring 官方文档对 bean 的解释是&#xff1a; In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assem…...

算法通关村第十二关|白银|字符串经典基础面试题

1.反转问题 1.1 反转字符串 原题&#xff1a;力扣344. 要求原地修改。 public void reverseString(char[] s) {if (s null || s.length() 0) {return;}int n s.length;for (int left 0, right n - 1; left < right; left, right--) {char temp s[left];s[left] s…...

Spring框架学习 -- 读取和存储Bean对象

目录 &#x1f680;&#x1f680; 回顾 getBean()方法的使用 根据name来获取对象 再谈getBean() (1) 配置扫描路径 (2) 添加注解 ① spring注解简介 ② 对类注解的使用 ③ 注解Bean对象的命名问题 ④ 方法加Bean注解 (3) Bean 注解的重命名 (4) 获取Bean对象 -- …...

APM工具skywalking部署

一 整体架构 整个架构&#xff0c;分成上、下、左、右四部分&#xff1a; 上部分 Agent &#xff1a;负责从应用中&#xff0c;收集链路信息&#xff0c;发送给 SkyWalking OAP 服务器。目前支持 SkyWalking、Zikpin、Jaeger 等提供的 Tracing 数据信息。而我们目前采用的是&…...

MFC打开可执行文件exe

CString exeName, propathdir;//propath _T("D:\\vs2017\\Project\\work\\mySqlselect\\release64\\mySqlselect.exe");//propathdir _T("D:\\vs2017\\Project\\work\\mySqlselect\\elease64\\");//路径太深的时候要指明文件所在路径&#xff0c;奇葩//p…...

css实现原生form表单label必填选项红色*样式,以及js控制必填校验

文章目录 一、css实现原生form表单label必填选项红色*样式&#xff0c;以及js控制必填校验&#xff1f;二、实现方案参考原文 一、css实现原生form表单label必填选项红色*样式&#xff0c;以及js控制必填校验&#xff1f; 二、实现方案 1.css实现原生form表单label必填选项红色…...

10_6 input输入子系统,流程解析

简单分层 应用层 内核层 --------------------------- input handler 数据处理层 driver/input/evdev.c1.和用户空间交互,实现fops2.不知道数据怎么得到的,但是可以把数据上传给用户--------------------------- input core层1.维护上面和下面的两个链表2.为上下两层提供接口--…...

竞赛选题 题目:垃圾邮件(短信)分类 算法实现 机器学习 深度学习 开题

文章目录 1 前言2 垃圾短信/邮件 分类算法 原理2.1 常用的分类器 - 贝叶斯分类器 3 数据集介绍4 数据预处理5 特征提取6 训练分类器7 综合测试结果8 其他模型方法9 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于机器学习的垃圾邮件分类 该项目…...

Web前端—移动Web第三天(移动Web基础、rem、less、综合案例—极速问诊)

版本说明 当前版本号[20231120]。 版本修改说明20231120初版 本课程的笔记已经更新完毕&#xff0c;各位可以通过点击《黑马程序员2023新版前端Web开发HTML5CSS3移动web视频教程&#xff0c;前端web入门首选》学习笔记总目录查看所有知识点&#xff0c;同时也能免费下载学习…...

MySQL--慢查询(一)

1. 查看慢查询日志是否开启 show variables like slow_query%; show variables like slow_query_log; 参数说明&#xff1a; 1、slow_query_log&#xff1a;这个参数设置为ON&#xff0c;可以捕获执行时间超过一定数值的SQL语句。 2、long_query_time&#xff1a;当SQL语句执行…...

【大神支招】3步,打造一张BI报表

随着BI报表的高效直观、灵活分析的特点越来越被大家所熟知&#xff0c;很多BI零基础的用户可积极尝试制作BI报表&#xff0c;以达到灵活自助分析、高效智能分析的效果。那么BI报表零基础的小白们该怎么做BI报表&#xff0c;才能又快又好地做出来&#xff1f; 大神支招&#xf…...

【Linux】文件操作

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;那个传说中的man的主页 &#x1f3e0;个人专栏&#xff1a;题目解析 &#x1f30e;推荐文章&#xff1a;题目大解析&#xff08;3&#xff09; 目录 &#x1f449;&#x1f3fb;文件是什么&#xff1f;&am…...

(动手学习深度学习)第13章 实战kaggle竞赛:狗的品种识别

文章目录 1. 导入相关库2. 加载数据集3. 整理数据集4. 图像增广5. 读取数据6. 微调预训练模型7. 定义损失函数和评价损失函数9. 训练模型 1. 导入相关库 import os import torch import torchvision from torch import nn from d2l import torch as d2l2. 加载数据集 - 该数据…...

Docker 运行 Kafka 带 SASL 认证教程

Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明&#xff1a;server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storms…...

在 Spring Boot 中使用 JSP

jsp&#xff1f; 好多年没用了。重新整一下 还费了点时间&#xff0c;记录一下。 项目结构&#xff1a; pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...

图解JavaScript原型:原型链及其分析 | JavaScript图解

​​ 忽略该图的细节&#xff08;如内存地址值没有用二进制&#xff09; 以下是对该图进一步的理解和总结 1. JS 对象概念的辨析 对象是什么&#xff1a;保存在堆中一块区域&#xff0c;同时在栈中有一块区域保存其在堆中的地址&#xff08;也就是我们通常说的该变量指向谁&…...

python基础语法Ⅰ

python基础语法Ⅰ 常量和表达式变量是什么变量的语法1.定义变量使用变量 变量的类型1.整数2.浮点数(小数)3.字符串4.布尔5.其他 动态类型特征注释注释是什么注释的语法1.行注释2.文档字符串 注释的规范 常量和表达式 我们可以把python当作一个计算器&#xff0c;来进行一些算术…...

CentOS 7.9安装Nginx1.24.0时报 checking for LuaJIT 2.x ... not found

Nginx1.24编译时&#xff0c;报LuaJIT2.x错误&#xff0c; configuring additional modules adding module in /www/server/nginx/src/ngx_devel_kit ngx_devel_kit was configured adding module in /www/server/nginx/src/lua_nginx_module checking for LuaJIT 2.x ... not…...

在MobaXterm 打开图形工具firefox

目录 1.安装 X 服务器软件 2.服务器端配置 3.客户端配置 4.安装并打开 Firefox 1.安装 X 服务器软件 Centos系统 # CentOS/RHEL 7 及之前&#xff08;YUM&#xff09; sudo yum install xorg-x11-server-Xorg xorg-x11-xinit xorg-x11-utils mesa-libEGL mesa-libGL mesa-…...

SpringSecurity+vue通用权限系统

SpringSecurityvue通用权限系统 采用主流的技术栈实现&#xff0c;Mysql数据库&#xff0c;SpringBoot2Mybatis Plus后端&#xff0c;redis缓存&#xff0c;安全框架 SpringSecurity &#xff0c;Vue3.2Element Plus实现后台管理。基于JWT技术实现前后端分离。项目开发同时采 …...