[Computer Vision]实验三:图像拼接

news2025/1/23 20:33:27

目录

一、实验内容

二、实验过程及结果

2.1 单应性变换

 2.2 RANSAC算法

三、实验小结


一、实验内容

  1. 理解单应性变换中各种变换的原理(自由度),并实现图像平移、旋转、仿射变换等操作,输出对应的单应性矩阵。
  2. 利用RANSAC算法优化关键点匹配,比较优化前后图像拼接和所生成全景图的差别,输出RANSAC前后匹配点数量、单应性矩阵。

二、实验过程及结果

2.1 单应性变换

(1)实验代码

import cv2
from networkx import center
import numpy as np
from scipy.fft import dst
import matplotlib.pyplot as plt
img=cv2.imread("D:/Computer vision/test1 picture/picture3.png")

x=100
y=50
M0=np.float32([[1,0,x],[0,1,y]])
translated=cv2.warpAffine(img,M0,(img.shape[1],img.shape[0]))
print("平移变换单应性矩阵:\n",M0)

img_center=(img.shape[1]/2,img.shape[0]/2)
M1=cv2.getRotationMatrix2D(img_center,45,1)
rotated=cv2.warpAffine(img,M1,(img.shape[1],img.shape[0]))
print("旋转变换单应性矩阵:\n",M1)

M2=cv2.getRotationMatrix2D(img_center,0,0.5)
scaled=cv2.warpAffine(img,M2,(img.shape[1],img.shape[0]))
print("缩放变换单应性矩阵:\n",M2)

rows,cols,ch=img.shape
src_points=np.float32([[0,0],[cols-1,0],[0,rows-1]])
dst_points=np.float32([[0,rows*0.33],[cols*0.85,rows*0.25],[cols*0.15,rows*0.7]])
M3=cv2.getAffineTransform(src_points,dst_points)
warped=cv2.warpAffine(img,M3,(cols,rows))
print("扭曲变换单应性矩阵:\n",M3)

rows,cols=img.shape[:2]
pts1=np.float32([[150,50],[400,50],[60,450],[310,450]])
pts2=np.float32([[50,50],[rows-50,50],[50,cols-50],[rows-50,cols-50]])
M4=cv2.getPerspectiveTransform(pts1,pts2)
img_dst=cv2.warpPerspective(img,M4,(cols,rows))
print("透视变换单应性矩阵:\n",M4)

plt.figure("Processed Images")
plt.subplot(2,3,1)
plt.imshow(img)
plt.title("Original Image")
plt.subplot(2,3,2)
plt.imshow(translated)
plt.title("Translated Image")
plt.subplot(2,3,3)
plt.imshow(rotated)
plt.title("Rotated Image")
plt.subplot(2,3,4)
plt.imshow(scaled)
plt.title("Scaled Image")
plt.subplot(2,3,5)
plt.imshow(warped)
plt.title("Warped Image")
plt.subplot(2,3,6)
plt.imshow(img_dst)
plt.title("Dst Image")
plt.show()
plt.savefig("D:/Computer vision/ransac_picture/processed_images.png")
plt.show()

(2)实验结果截图

图1为输出的单应性矩阵结果截图:

平移变换:两个自由度(两个平移参数),单应性矩阵为2*3的矩阵

旋转变换:一个自由度(一个旋转角度参数),单应性矩阵为2*3的矩阵

缩放变换:一个自由度(一个缩放因子),单应性矩阵为2*3的矩阵

扭曲变换有六个自由度(两个旋转参数 一个缩放因子),单应性矩阵为2*3的矩阵

透视变换有八个自由度(5个是仿射变换参数,3个是透视变换参数),单应性矩阵为3*3的矩阵

图1

图2为输出的单应性变换的结果图:

可以看到,平移变换的图像在x方向上平移100个像素,在y方向上平移50个像素。旋转变换的图像绕图像中心旋转45度。缩放变换的图像在x方向上缩小到原来的一半,在y方向上缩小到原来的一半。扭曲变换的图像进行仿射变换,包括旋转、缩放、平移和剪切。透视变换的图像进行了透视变换,包括旋转、缩放、平移和透视变形。

图2
 2.2 RANSAC算法

(1)实验代码

import cv2
import numpy as np

def detectAndCompute(image):
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    sift = cv2.SIFT_create()
    keypoints, descriptors = sift.detectAndCompute(gray, None)
    return keypoints, descriptors

def matchKeyPoints(kpsA, kpsB, featuresA, featuresB, ratio=0.75, reprojThresh=4.0):
    matcher = cv2.BFMatcher()
    rawMatches = matcher.knnMatch(featuresA, featuresB, 2)
    matches = []
    for m in rawMatches:
        if len(m) == 2 and m[0].distance < ratio * m[1].distance:
            matches.append((m[0].queryIdx, m[0].trainIdx))
    ptsA = np.float32([kpsA[i].pt for (i, _) in matches])
    ptsB = np.float32([kpsB[i].pt for (_, i) in matches])
    (M, status) = cv2.findHomography(ptsA, ptsB, cv2.RANSAC, reprojThresh)
    return (M, matches, status)

def drawMatches(imgA, imgB, kpsA, kpsB, matches, status):
    (hA, wA) = imgA.shape[:2]
    (hB, wB) = imgB.shape[:2]
    result = np.zeros((max(hA, hB), wA + wB, 3), dtype="uint8")
    result[0:hA, 0:wA] = imgA
    result[0:hB, wA:] = imgB
    for ((trainIdx, queryIdx), s) in zip(matches, status):
        if s == 1:
            ptA = (int(kpsA[queryIdx].pt[0]), int(kpsA[queryIdx].pt[1]))
            ptB = (int(kpsB[trainIdx].pt[0]) + wA, int(kpsB[trainIdx].pt[1]))
            cv2.line(result, ptA, ptB, (0, 255, 0), 1)
    return result

def stitchImages(imageA, imageB, M):
    (hA, wA) = imageA.shape[:2]
    (hB, wB) = imageB.shape[:2]
    result = cv2.warpPerspective(imageA, M, (wA + wB, hA))
    result[0:hB, 0:wB] = imageB
    return result

if __name__ == '__main__':
    imageA = cv2.imread("D:\Computer vision/ransac_picture/ransac1.jpg")
    imageB = cv2.imread("D:/Computer vision/ransac_picture/ransac2.jpg")
    
    kpsA, featuresA = detectAndCompute(imageA)
    kpsB, featuresB = detectAndCompute(imageB)
    
    M, matches, status = matchKeyPoints(kpsA, kpsB, featuresA, featuresB)
    
    initial_matches = sum(status)
    final_matches = len(matches)
    print(f"RANSAC前匹配点数量: {initial_matches}")
    print(f"RANSAC后匹配点数量: {final_matches}")
    print("单应性矩阵为:\n", M)
    
    drawImgBeforeRANSAC = drawMatches(imageA, imageB, kpsA, kpsB, matches, status)
    cv2.imshow("drawMatches Before RANSAC", drawImgBeforeRANSAC)
    cv2.waitKey()
    cv2.destroyAllWindows()

    stitchedImage = stitchImages(imageA, imageB, M)
    cv2.imshow("Stitched Image", stitchedImage)
    cv2.waitKey()
    cv2.destroyAllWindows()
    cv2.imwrite("D:/Computer vision/ransac_picture/stitched_image.jpg", stitchedImage)
cv2.imwrite("D:/Computer vision/ransac_picture/drawMatchesBeforeRANSAC.jpg", drawImgBeforeRANSAC)

(2)数据集(待拼接)

(3)实验结果截图

图3为输出的单应性矩阵结果截图:

如图所示,在运行SIFT特征检测和描述符提取后,通过BFMatcher进行特征匹配,初始匹配点的数量是198对。经过RANSAC算法去除错误匹配后,剩余的匹配点数量为1074对。这表明RANSAC算法有效地保留了正确的匹配点并去除了错误的匹配点。

图3

图4为在应用RANSAC算法之前绘制的匹配结果图像:

如图所示,绘制两幅图像的匹配结果并显示特征点之间的匹配关系。通过可视化匹配结果,可以直观地看到哪些特征点被成功匹配。

图4

图5为最终拼接后的图像:

图5

三、实验小结

图像拼接是计算机视觉领域的一个重要研究方向,通过将多张重叠的图像拼接在一起,实现更大、更全面的图像展示。实验中通过使用opencv中的相关函数实现图像的单应性变换,并使用BFMatcher和RANSAC算法进行了特征点匹配以及图像拼接。使用RANSAC算法后拼接效果良好,没有出现明显的错位或重叠问题。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微信小程序使用picker根据接口给的省市区的数据实现省市区三级联动或者省市区街道等多级联动

接口数据如上图 省市区多级联动&#xff0c;都是使用的一个接口通过传参父类的code。返回我们想要的数据 比如获取省就直接不要参数。市就把省得code传给接口&#xff0c;区就把市的code作为参数。 <picker mode"multiSelector" :range"mulSelect1" …

自动化01

测试用例的万能公式&#xff1a;功能测试界面测试性能测试易用性测试安全性测试兼容性测试 自动化的主要目的就是用来进行回归测试 新产品--第一个版本 (具备丰富的功能)&#xff0c;将产品的整体进行测试&#xff0c;人工创造一个自动化测试用例&#xff0c;在n个版本的时候…

JS宏进阶:正则表达式的使用

正则表达式&#xff0c;对于任何一门编程语言来说&#xff0c;都是一种非常强大的工具&#xff0c;主要用于搜索、编辑或操作文本和数据。因此&#xff0c;在JS中&#xff0c;也存在相应的对象new RegExp( )&#xff0c;在本章中&#xff0c;将详细介绍正则表达式在JS宏中的运用…

深度学习笔记——循环神经网络RNN

大家好&#xff0c;这里是好评笔记&#xff0c;公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细介绍面试过程中可能遇到的循环神经网络RNN知识点。 文章目录 文本特征提取的方法1. 基础方法1.1 词袋模型&#xff08;Bag of Words, BOW&#xff09;工作原…

Git进阶笔记系列(01)Git核心架构原理 | 常用命令实战集合

读书笔记&#xff1a;卓越强迫症强大恐惧症&#xff0c;在亲子家庭、职场关系里尤其是纵向关系模型里&#xff0c;这两种状态很容易无缝衔接。尤其父母对子女、领导对下属&#xff0c;都有望子成龙、强将无弱兵的期望&#xff0c;然而在你的面前&#xff0c;他们才是永远强大的…

SpringBoot读取yml配置文件一组对象数据初始化

1. yml的短横杠语法2. yml数组元素读取并初始化3. 测试结果 1. yml的短横杠语法 - 短横杠加空格&#xff0c;可以表示数组元素&#xff0c;如下配置 表示有名为apps的一组数据&#xff0c;数组的元素对象包含有corpId、corpSecret、appCode三个字段像server.port没有 - 表示的…

基于JAVA的校园二手商品交易平台的设计与开发

摘 要&#xff1a;政府政策引导与社会观念的转变使得国内大学生的创业意识逐渐提高&#xff0c;很多高校大学生开始自主创业。目前我国各大高校暂且还没有较为成型的针对校内学生创业者的校园网络服务平台。本文首先主要是介绍了关于java语言以及web开发的相关技术&#xff0c;…

深度学习核函数

一、核函数的基本概念 核函数在机器学习中具有重要应用价值&#xff0c;常用于支持向量机&#xff08;SVM&#xff09;等算法中。 核函数是面试中经常被考到的知识点&#xff0c;对于找工作和实际数据转换都有重要作用。 二、数据建模与核函数的作用 数据越多&#xff0c;可…

数据结构(三) 排序/并查集/图

目录 1. 排序 2.并查集 3.图 1.排序: 1.1 概念: 排序就是将数据按照某种规则进行排列, 具有某种顺序. 分为内排序和外排序. 内排序就是: 将数据放在内存中的排序; 外排序是: 数据太多无法在内存中排序的. 1.2 插入排序: 插入排序包含: 直接插入排序和希尔排序. (1) 直接插入…

ECCV 2024,全新激活函数!

激活函数对深度神经网络的成功可太重要了&#xff0c;它可以提升学习复杂关系的能力&#xff0c;减少过拟合&#xff0c;增强模型性能&#xff0c;与它相关的研究一直是重中之重。最近&#xff0c;这方向有了不少新突破。 ECCV 2024上的这篇&#xff0c;提出了一种可训练的高表…

小米Vela操作系统开源:AIoT时代的全新引擎

小米近日正式开源了其物联网嵌入式软件平台——Vela操作系统&#xff0c;并将其命名为OpenVela。这一举动在AIoT&#xff08;人工智能物联网&#xff09;领域掀起了不小的波澜&#xff0c;也为开发者们提供了一个强大的AI代码生成器和开发平台。OpenVela项目源代码已托管至GitH…

ComfyUI实现老照片修复——AI修复老照片(ComfyUI-ReActor / ReSwapper)尚待完善

AI修复老照片&#xff0c;试试吧&#xff0c;不一定好~~哈哈 2023年4月曾用过ComfyUI&#xff0c;当时就感慨这个工具和虚幻的蓝图很像&#xff0c;以后肯定是专业人玩的。 2024年我写代码去了&#xff0c;AI做图没太关注&#xff0c;没想到&#xff0c;现在ComfyUI真的变成了工…

YOLOv5训练自己的数据及rknn部署

YOLOv5训练自己的数据及rknn部署 一、下载源码二、准备自己的数据集2.1 标注图像2.2 数据集结构 三、配置YOLOv5训练3.1 修改配置文件3.2 模型选择 四、训练五、测试六、部署6.1 pt转onnx6.2 onnx转rknn 七、常见错误7.1 训练过程中的错误7.1.1 cuda: out of memory7.1.2 train…

C# OpenCvSharp 部署文档矫正,包括文档扭曲/模糊/阴影等情况

目录 说明 效果 模型 项目 代码 下载 参考 C# OpenCvSharp 部署文档矫正&#xff0c;包括文档扭曲/模糊/阴影等情况 说明 地址&#xff1a;https://github.com/RapidAI/RapidUnDistort 修正文档扭曲/模糊/阴影等情况&#xff0c;使用onnx模型简单轻量部署&#xff0c…

贪心算法(题1)区间选点

输出 2 #include <iostream> #include<algorithm>using namespace std;const int N 100010 ;int n; struct Range {int l,r;bool operator <(const Range &W)const{return r<W.r;} }range[N];int main() {scanf("%d",&n);for(int i0;i&l…

煤矿场景下安全帽检测数据集VOC+YOLO格式179张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;170 标注数量(xml文件个数)&#xff1a;170 标注数量(txt文件个数)&#xff1a;170 标注…

RTX 5090原型据称有24576个CUDA核心和800 W TDP -两个16针连接器

英伟达今年早些时候发布、将于1月30日上市的GeForce RTX 5090&#xff0c;有望成为最出色的显卡之一。然而&#xff0c;硬件侦探HXL发掘出了一款疑似早期原型产品。不过&#xff0c;考虑到传闻中的规格参数&#xff0c;它很有可能会成为GeForce RTX 5090 Ti或者RTX Titan Black…

哪个控制面板适合您?

如今&#xff0c;VPS云主机的控制面板在网站托管中变得越来越重要。对于网站管理者和普通用户来说&#xff0c;这类控制面板提供了一站式的管理工具&#xff0c;可以在同一个界面中处理所有网站的管理任务&#xff0c;极大地减少了多系统间重复操作的麻烦。 但随着越来越多的公…

Redis - 通用命令

目录 了解Redis客户端set 和 getRedis全局命令keys命令exists命令del命令expire命令ttl命令Redis中key的过期策略type 了解Redis客户端 想要输入Redis命令,必须先进入Redis客户端 使用redis-cli连接本机的命令行客户端 redis-cli如果想连接其他的ip和端口的客户端&#xff0…

重学SpringBoot3-WebClient配置与使用详解

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞??收藏评论 重学SpringBoot3-WebClient配置与使用详解 1. 简介2. 环境准备 2.1 依赖配置 3. WebClient配置 3.1 基础配置3.2 高级配置3.3 retrieve()和exchange()区别 4. 使用示例 4.1 基本请求操…