OpenCV下的无标定校正(stereoRectifyUncalibrated)

OpenCV下的无标定校正(stereoRectifyUncalibrated)

文章目录

  • 1. 杂话
  • 2. 无标定校正
    • 2.1 先看代码
    • 2.2 一点解释
    • 2.3 findFundamentalMat参数
    • 2.4 stereoRectifyUncalibrated参数
  • 3. 矫正结果

1. 杂话

 咱们在之前的帖子里面讲了一些比较常规的标定和校正OpenCV下的单目标定,双目标定与立体校正(calibrateCamera, stereoCalibrate and stereoRectify),但是,如果说两个相机之间的转角比较大,那么可能并不适合用双目标定+立体校正的步骤来做,参考这个贴子立体校正失效的情况,所以为了解决这个问题,今天咱们就来说说如何使用非标定的校正函数:

 对了,我使用的数据和完整的代码在这里:Repo : Calibrate-and-Rectify

2. 无标定校正

2.1 先看代码

import cv2
import numpy as np
import glob
import matplotlib.pyplot as plt
from PIL import Imagec1_images_names = sorted(glob.glob('demo/left*.jpg'))
c2_images_names = sorted(glob.glob('demo/right*.jpg'))c1_images = []
c2_images = []
for im1, im2 in zip(c1_images_names, c2_images_names):_im = cv2.imread(im1, 1)c1_images.append(_im)_im = cv2.imread(im2, 1)c2_images.append(_im)def find_corners(image_names):images = []for imname in image_names:im = cv2.imread(imname, 1)images.append(im)criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)rows = 6 #number of checkerboard rows.columns = 9 #number of checkerboard columns.#coordinates of squares in the checkerboard world spaceobjp = np.zeros((rows*columns,3), np.float32)objp[:,:2] = np.mgrid[0:rows,0:columns].T.reshape(-1,2)#frame dimensions. Frames should be the same size.width = images[0].shape[1]height = images[0].shape[0]#Pixel coordinates of checkerboardsimgpoints = [] # 2d points in image plane.for frame in images:gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)gray = cv2.rotate(gray, cv2.ROTATE_90_CLOCKWISE)#find the checkerboardret, corners = cv2.findChessboardCorners(gray, (rows, columns), None)if ret == True:#Convolution size used to improve corner detection. Don't make this too large.conv_size = (11, 11)#opencv can attempt to improve the checkerboard coordinatescorners = cv2.cornerSubPix(gray, corners, conv_size, (-1, -1), criteria)imgpoints.append(corners)return imgpointsimgpoints1 = find_corners(c1_images_names)
imgpoints2 = find_corners(c2_images_names)# 将角点坐标转换为float32格式
points1all = np.array([pt.ravel() for pts in imgpoints1 for pt in pts], dtype=np.float32)
points2all = np.array([pt.ravel() for pts in imgpoints2 for pt in pts], dtype=np.float32)# 计算基础矩阵
F, mask = cv2.findFundamentalMat(points1all, points2all, cv2.FM_RANSAC)# 图像大小
img_size = (640, 480)img1 = cv2.imread('demo/left03.jpg', 1)
img2 = cv2.imread('demo/right03.jpg', 1)img1 = cv2.rotate(img1, cv2.ROTATE_90_CLOCKWISE)
img2 = cv2.rotate(img2, cv2.ROTATE_90_CLOCKWISE)gray_left = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
gray_right = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)# 找到棋盘格角点
ret_left, corners_left = cv2.findChessboardCorners(gray_left, (6, 9), None)
ret_right, corners_right = cv2.findChessboardCorners(gray_right, (6, 9), None)criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)print(ret_left, ret_right)if ret_left and ret_right:# 提高角点的精度corners_left = cv2.cornerSubPix(gray_left, corners_left, (11, 11), (-1, -1), criteria)corners_right = cv2.cornerSubPix(gray_right, corners_right, (11, 11), (-1, -1), criteria)# 将角点坐标转换为float32格式
points1 = np.array([pt[0] for pt in corners_left], dtype=np.float32).reshape(-1, 2)
points2 = np.array([pt[0] for pt in corners_right], dtype=np.float32).reshape(-1, 2)# 进行立体校正
retval, H1, H2 = cv2.stereoRectifyUncalibrated(points1, points2, F, img_size)# 裁剪图像去除黑边
def crop_image(image):gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)_, thresh = cv2.threshold(gray, 1, 255, cv2.THRESH_BINARY)contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)x, y, w, h = cv2.boundingRect(contours[0])cropped_image = image[y:y+h, x:x+w]return cropped_imageif retval:# 计算校正映射img1_rectified = cv2.warpPerspective(img1, H1, img_size)img2_rectified = cv2.warpPerspective(img2, H2, img_size)# 显示校正后的图像cv2.imwrite('Rectified Image 1.png', img1_rectified)cv2.imwrite('Rectified Image 2.png', img2_rectified)
else:print("立体校正失败")plt.figure(figsize=(20, 20))for i in range(0,1):  # 以第一对图片为例im_L=Image.fromarray(img1_rectified) # numpy 转 image类im_R=Image.fromarray(img2_rectified) # numpy 转 image 类width = im_L.size[0]*2height = im_L.size[1]img_compare = Image.new('RGBA',(width, height))img_compare.paste(im_L,box=(0,0))img_compare.paste(im_R,box=(640,0))#在已经极线对齐的图片上均匀画线for i in range(1,20):len=480/20plt.axhline(y=i*len, color='r', linestyle='-')plt.imshow(img_compare)plt.savefig('epipolar_lines_ro.png', bbox_inches='tight', pad_inches=0)plt.show()

2.2 一点解释

 其实也没啥好解释的吧,一些基础的参数都在上面说的另外一篇帖子里面写好了。主要就是说一下思路,因为是标定图片,所以还是用角点做关键点,之后通过匹配的关键点和findFundamentalMat去计算基础矩阵,描述两个图片的映射关系。然后针对示例图片,应用这个映射,也就是stereoRectifyUncalibrated函数。

2.3 findFundamentalMat参数

 findFundamentalMat 是 OpenCV 中用于计算基础矩阵的函数。基础矩阵描述了两个图像之间的点对应关系,是立体视觉计算中的一个重要概念。以下是该函数的详细解释:

cv2.findFundamentalMat(points1, points2[, method[, ransacReprojThreshold[, confidence[, maxIters]]]]) -> fundamentalMatrix, mask输入参数
points1:
描述:在第一幅图像中检测到的特征点列表或数组。应该是 Nx2 的二维点坐标列表,其中 N 是特征点的数量。points2:
描述:在第二幅图像中检测到的特征点列表或数组。应该与 points1 中的点一一对应,且格式相同。method (可选):
描述:用于估算基础矩阵的方法。可以是以下之一:
cv2.FM_7POINT: 七点算法。要求点数量为 7。
cv2.FM_8POINT: 八点算法。要求点数量大于或等于 8。
cv2.FM_RANSAC: 使用 RANSAC 方法。推荐用于处理带有噪声的点。
cv2.FM_LMEDS: 使用最小中值平方算法。也用于处理带有噪声的点。ransacReprojThreshold (可选):
描述:RANSAC 算法中的最大重投影误差阈值,仅在使用 RANSAC 方法时有效。默认值为 3。confidence (可选):
描述:RANSAC 算法中的置信度,仅在使用 RANSAC 方法时有效。默认值为 0.99。maxIters (可选):
描述:RANSAC 算法的最大迭代次数,仅在使用 RANSAC 方法时有效。默认值为 1000。输出参数
fundamentalMatrix:
描述:计算得到的基础矩阵,大小为 3x3。mask:
描述:输出参数,用于标识内点(inliers)。大小为 Nx1 的二值数组,其中 N 是输入特征点的数量。值为 1 的元素表示对应的特征点是内点,值为 0 的元素表示对应的特征点是外点(outliers)。

2.4 stereoRectifyUncalibrated参数

cv2.stereoRectifyUncalibrated(points1, points2, F, imgSize[, H1[, H2[, threshold]]]) -> retval, H1, H2
输入参数points1:
描述:在左图中检测到的特征点列表或数组。应该是 Nx2 的二维点坐标列表,其中 N 是特征点的数量。points2:
描述:在右图中检测到的特征点列表或数组。应该与 points1 中的点一一对应,且格式相同。F:
描述:基础矩阵(3x3),它是在立体图像对之间通过特征点匹配估算得到的。imgSize:
描述:图像的尺寸,格式为 (width, height),即图像的宽度和高度。H1 (可选):
描述:输出参数,用于存储左图的 3x3 变换矩阵。如果提供了此参数,函数会将结果写入其中。H2 (可选):
描述:输出参数,用于存储右图的 3x3 变换矩阵。如果提供了此参数,函数会将结果写入其中。threshold (可选):
描述:用于 RANSAC 算法的阈值。RANSAC 算法用于估算变换矩阵时的容错范围。如果不提供,则使用默认值。输出参数
retval:
描述:函数执行成功与否的标志。返回 True 表示成功,返回 False 表示失败。H1:
描述:左图的 3x3 变换矩阵。只有在调用时提供了相应的参数,且函数执行成功时才会返回。H2:
描述:右图的 3x3 变换矩阵。只有在调用时提供了相应的参数,且函数执行成功时才会返回。

3. 矫正结果

在这里插入图片描述
 OK,基本符合预期哦~

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

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

相关文章

紫外测熔融实验结果温度和abs作折线图和求一阶导最大值

import numpy as np import pandas as pd from pyecharts.charts import Line from pyecharts import options as opts from matplotlib import pyplot as plt import xlrd # 读取 csv 文件 data pd.read_excel(F:/LJX/lc8.xls)# 假设 csv 文件中有两列数据:x 和 y…

iOS——编译链接

编译连接的过程 预处理编译汇编链接 预处理 clang -E main.m -o main.i“#define"删除并展开对应宏定义。处理所有的条件预编译指令。如#if/#ifdef/#else/#endif。”#include/#import"包含的文件递归插入到此处。删除所有的注释"//或/**/"。添加行号和文…

SpringCloud网关的实现原理与使用指南

Spring Cloud网关是一个基于Spring Cloud的微服务网关,它是一个独立的项目,可以对外提供API接口服务,负责请求的转发和路由。本文将介绍Spring Cloud网关的实现原理和使用指南。 一、Spring Cloud网关的实现原理 Spring Cloud网关基于Spring…

在 Windows 上开发.NET MAUI 应用_2.生成你的第一个应用

先决条件 Visual Studio 2022 17.8 或更高版本,并安装了 .NET Multi-platform App UI 工作负载。 可参考上一篇文章:http://t.csdnimg.cn/n38Yy 创建应用 1.启动 Visual Studio 2022。 在开始窗口中,单击“创建新项目”以创建新项目&#…

时间管理计划表怎么做 待办计划时间管理工具

每当夜深人静,我总会坐在书桌前,思考着如何更好地规划明天的时间。那一张张密密麻麻的时间管理计划表,就像是我生活的地图,指引着我前行。我知道,对于每一个在都市丛林中奔波的打工人来说,时间都是最宝贵的…

Java面试(持续更新)

Redis使用场景 缓存穿透 当有该数据的时候,redis中的数据已经是原来数据的null值了,可能会出现不一致的问题。 缓存击穿 跟钱相关的强一致用互斥锁。 用户高体验用逻辑过期。 缓存雪崩 ttl随机值

AI 绘画|Midjourney设计Logo提示词

你是否已经看过许多别人分享的 MJ 咒语,却仍无法按照自己的想法画图?通过学习 MJ 的提示词逻辑后,你将能够更好地理解并创作自己的“咒语”。本文将详细拆解使用 MJ 设计 Logo 的逻辑,让你在阅读后即可轻松上手,制作出…

2.I/O口

文章目录 I/O输出(点灯)分析电路代码编写 I/O输入(电平检测)代码编写 I/O内部电路分析51单片机STM32单片机输入输出 I/O输出(点灯) 分析电路 看电路图,元器件形成电压差,即可点亮LED灯 代码编写 使用不同操作进行LED控制 #include "reg52.h&quo…

怎么查看一个网站的ip地址?

1、使用nslookup nslookup 是一个网络诊断工具,用于查询域名系统(DNS)记录,将域名解析为IP地址,或者查询其他DNS记录类型,如MX(邮件交换记录)、CNAME(别名记录&#xff…

QT--控件篇四

一、对话框 在软件开发中,对话框(Dialog)是一种常见的用户界面元素,用于与用户进行交互和获取信息。它通常以模态或非模态的形式出现,模态对话框会阻止用户与应用程序的其他部分交互,直到对话框关闭为止&a…

8月贵阳学术会议:第二届机器人与软件工程前沿国际会议(FRSE 2024)

随着科技的飞速发展,机器人与软件工程作为两大前沿领域,正在不断地推动着人类社会的进步。在这样的背景下,第二届机器人与软件工程前沿国际会议(FRSE 2024)的召开,无疑为专家学者们提供了一个交流与合作的宝…

C4D各版本软件下载+自学C4D 从入门到精通【学习视频教程全集】+【素材笔记】

下载链接: 迅雷网盘https://pan.xunlei.com/s/VO1tydOxEo-Az_QCM-Jz2R4RA1?pwdvxg4# 夸克网盘https://pan.quark.cn/s/fe7450b02d80 百度网盘https://pan.baidu.com/s/1Omj4WL93F1DNdA2iP4SiMQ?pwdwmb8

Linux 下 redis 集群部署

目录 1. redis下载 2. 环境准备 3. redis部署 3.1 修改系统配置文件 3.2 开放端口 3.3 安装 redis 3.4 验证 本文将以三台服务器为例,介绍在 linux 系统下redis的部署方式。 1. redis下载 下载地址:Index of /releases/ 选择需要的介质下载&am…

【UDS刷写章节】

目录 一、UDS刷写的两种方式: 1.1普通刷写原理: 1.2强制刷写: 二、刷写流程图 2.1 刷写前(设置刷写网络) 2.1.1 切换到扩展模式(10 03) 2.1.2 检查刷写前提条件(31 01 XX XX) 2.1.3 停用故障码存储功能(85 02) 2.1.4 停止发送一般通…

3.Kafka生产者api实践

目录 概述实践代码命令行消费端代码 效果代码优化 概述 生产者API使用实践 官网:producerapi 实践 代码 命令行消费端 代码 public class KafkaProducerApp {public static void main(String[] args) {Properties props new Properties();props.put("boot…

【数据结构】探索排序的奥秘

若有不懂地方,可查阅我之前文章哦! 个人主页:小八哥向前冲~_csdn博客 所属专栏:数据结构_专栏 目录 排序的概念 几种排序方法介绍 冒泡排序 选择排序 插入排序 堆排序 向上调整建堆排序 向下调整建堆排序 希尔排序 快速…

CPU指令仿真模拟器设计

整体设计 模拟器软件可被细分为多个关键模块,包括但不限于:程序指令序列执行器模块,内存模拟模块,寄存器模拟模块,反汇编模块,以及一套详尽的调试模块(包含单步执行、连续运行、暂停以及断点设置…

如何通过网络快速搜寻到自己的STM32设备

目录 一、问题概述 二、解决思路 三、代码实现 1.创建任务 2.UDP广播接收 一、问题概述 以前一直用RS232串口修改设备配置信息,但是现场施工人员的232线太细,经常容易断掉,这次准备用网口去修改,遇到了一个问题,…

深入理解PostgreSql域类型(Domain),灵活定义数据约束,让表结构设计更加严谨

在PostgreSQL中,域(Domain)是一种用户定义的数据类型,它基于系统内已存在的数据类型,并可以附加约束条件。使用域可以增强数据的完整性和一致性,因为它允许开发者对特定列设定更为具体的规则,比…

Java爬虫安全策略:防止TikTok音频抓取过程中的请求被拦截

摘要 在当今互联网时代,数据采集已成为获取信息的重要手段。然而,随着反爬虫技术的不断进步,爬虫开发者面临着越来越多的挑战。本文将探讨Java爬虫在抓取TikTok音频时的安全策略,包括如何防止请求被拦截,以及如何提高…