OpenCV--图像拼接

server/2024/12/22 0:09:59/

OpenCV--图像拼接

  • 代码和笔记

代码和笔记

import cv2
import numpy as np"""
图像拼接:
1. 读取图片,灰度化
2. 计算各自的特征点和描述子
3. 匹配特征
4. 计算单应性矩阵
5. 透视变换
6. 创建一个大图,放图两张图
"""img1 = cv2.imread('./img/ca2.jpeg')
img2 = cv2.imread('./img/cat.jpeg')# 把两张图的尺寸变为同样大小
img1 = cv2.resize(img1, (640, 480))
img2 = cv2.resize(img2, (640, 480))# 灰度化处理
gary1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
gary2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)# 创建特征检测器
sift = cv2.SIFT_create()# 计算描述子
kp1, des1 = sift.detectAndCompute(gary1, None)
kp2, des2 = sift.detectAndCompute(gary2, None)# 创建特征匹配器 为了更准确,这里使用KNN算法匹配器进行相应的筛选,k是KNN的参数
bf = cv2.BFMatcher()
match = bf.knnMatch(des1, des2, k=2)# 筛选后的集合
goods = []
# 开始筛选
# match返回两个index
for m, n in match:# 这个阈值一般为0.7-0.8# distance为描述子之间的距离,越小越好if m.distance < 0.75 * n.distance:goods.append(m)# 计算单应性矩阵至少需要四个点
if len(goods) >= 4:# src_points:源平面中点的坐标矩阵。 dst_points:目标平面中点的坐标矩阵src_points = np.float32([kp1[m.queryIdx].pt for m in goods]).reshape(-1, 1, 2)dst_points = np.float32([kp2[m.trainIdx].pt for m in goods]).reshape(-1, 1, 2)# 根据匹配的点计算单应性矩阵H, _ = cv2.findHomography(src_points, dst_points, cv2.RANSAC, 5)
else:exit()# 获取原始图的高和宽
h1, w1 = img1.shape[:2]
h2, w2 = img2.shape[:2]
img1_pts = np.float32([[0, 0], [0, h1-1], [w1-1, h1-1], [w1-1, 0]]).reshape(-1, 1, 2)
img2_pts = np.float32([[0, 0], [0, h2-1], [w2-1, h2-1], [w2-1, 0]]).reshape(-1, 1, 2)# 计算img1的四个角变换之后的坐标
# 变换后img1_transform可能有负数,要平移回正,OpenCV中,x向左或者y向上为负
img1_transform = cv2.perspectiveTransform(img1_pts, H)# 要把两幅图放在一个大图上,先把坐标聚合,也就是数组上下放在一起,对齐
results_pts = np.concatenate((img2_pts, img1_transform))# 对齐后,找到每一列的最小值(应该为负数),平移这个最小值为正数,才能显示图像
# results_pts.min(axis=0)是二维的,用ravel直接取到一维的数据
# 因为原来有小数,可以-+1
[x_min, y_min] = np.int32(results_pts.min(axis=0).ravel() - 1)# 大图需要的大小为两张图最大的宽和高与最小的宽和高的绝对值的和,这里求出最大的值
[x_max, y_max] = np.int32(results_pts.max(axis=0).ravel() + 1)# 构造平移矩阵(格式固定),平移即仿射变换,原图点乘平移矩阵
move_matrix = np.array([[1, 0, -x_min], [0, 1, -y_min], [0, 0, 1]])# 将img1平移并透视变换到大图中,如果不平移,我们看不全图片
# 大图的大小:(x_max - x_min, y_max - y_min)
results_img = cv2.warpPerspective(img1, move_matrix.dot(H), (x_max - x_min, y_max - y_min))# 把第二张图放进来,直接用切片放进来 ndarray和OpenCV的wh是反的
results_img[-y_min: -y_min + h2, -x_min: -x_min + w2] = img2
# 如果中间有线,可以对img2进行透视变换,把图片拉正,大图片也可以拉正cv2.imshow('results_img', results_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

http://www.ppmy.cn/server/152084.html

相关文章

SSM 寝室管理系统:为住宿生活保驾护航

摘 要 寝室管理设计是高校为学生提供第二课堂&#xff0c;而我们所在学院多采用半手工管理学生寝室的方式&#xff0c;所以有必要开发寝室管理系统来对进行数字化管理。既可减轻学院宿舍长工作压力&#xff0c;比较系统地对宿舍通告、卫生上的各项服务和信息进行管理&#xff…

解锁大数据治理的“密码”与应用奥秘

一、大数据治理的基本认知 (一)定义与内涵 在当今数字化飞速发展的时代,数据量呈现出爆炸式增长,大数据已然成为了一种极具价值的资源。而大数据治理,就是针对大数据的产生、存储、处理、分析以及应用等全生命周期所开展的一系列规划、组织、协调、控制和监督活动。 从产…

define ATL_NO_VTABLE __declspec(novtable)

#define ATL_NO_VTABLE __declspec(novtable) 以下是对 #define ATL_NO_VTABLE __declspec(novtable) 这行代码的详细解释&#xff1a; 整体功能概述 这行代码是一个宏定义&#xff0c;在使用 ATL&#xff08;Active Template Library&#xff0c;活动模板库&#xff0c;常用…

java全栈day17--Web后端实战(java操作数据库)

前言&#xff1a;本章应该是针对数据库基础讲解&#xff0c;数据的增删改查但是本人忘记对知识进行归纳总结就直接跳过&#xff0c;基本的内容都很简单&#xff0c;都是套式子使用。现在开始学习本章&#xff0c;很重要需要好好掌握。 一、使用的工具 二、JDBC 2.1概述 JDBC …

OB删除1.5亿数据耗费2小时

目录 回顾&#xff1a;mysql是怎么删除数据的&#xff1f; 删除方案 代码实现 执行结果 结论 本篇是实际操作 批量处理数据以及线程池线程数设置 记录学习 背景&#xff1a;有一张用户标签表&#xff0c;存储数据量达4个亿&#xff0c;使用OceanBase存储&#xff0c;由于…

卷积神经网络-填充+步长

Padding nn的图像 * ff的图像 &#xff08;n-f1&#xff09;&#xff08;n-f1&#xff09; f通常为奇数(会有中心点 好填充) 缺点&#xff1a; 1.多次卷积图像会变小 2.边缘的像素点 在ff的卷积中覆盖的比较少&#xff0c;而中间的像素点会被多次覆盖到-》会丢失图像的边缘位…

[数据结构#2] 图(1) | 概念 | 邻接矩阵 | 邻接表 | 模拟

图是由顶点集合及顶点间的关系&#xff08;边&#xff09;组成的数据结构&#xff0c;可用 G ( V , E ) G(V,E) G(V,E)表示&#xff0c;其中&#xff1a; 顶点集合 V V V: V { x ∣ x ∈ 某数据对象集 } V\{x|x\in\text{某数据对象集}\} V{x∣x∈某数据对象集}&#xff0c;…

Linux 忘记密码解决方法

Linux 忘记密码解决方法 在Linux操作系统中,忘记root密码或普通用户密码是一个常见的问题。幸运的是,有多种方法可以解决这个问题。本文将详细介绍如何在不同的Linux发行版中重置或恢复忘记的密码。 1. 使用单用户模式(Single User Mode) 单用户模式是一种安全模式,允许…