python-opencv对极几何 StereoRectify

news2025/4/6 17:18:47

OpenCV如何正确使用stereoRectify函数

函数介绍

    用于双目相机的立体校正环节中,这里只谈谈这个函数怎么使用,参数具体指哪些

函数参数

    随便去网上一搜或者看官方手册就能得到参数信息,但是!!相对关系非常容易出错!!

    这里详细解释一下这些参数究竟怎么用
void stereoRectify(InputArray cameraMatrix1, InputArray distCoeffs1, 
           InputArray cameraMatrix2,InputArray distCoeffs2, Size imageSize, 
           InputArray R, InputArray T,OutputArray R1, OutputArray R2, OutputArray P1, 
           OutputArray P2, OutputArray Q, int flags=CALIB_ZERO_DISPARITY, double alpha=-1, 
           Size newImageSize=Size(), Rect* validPixROI1=0, Rect* validPixROI2=0 )
cameraMatrix1-第一个摄像机的摄像机矩阵,即左相机相机内参矩阵,矩阵第三行格式应该为 0 0 1
distCoeffs1-第一个摄像机的畸变向量
cameraMatrix2-第一个摄像机的摄像机矩阵,即右相机相机内参矩阵,矩阵第三行格式应该为 0 0 1
distCoeffs2-第二个摄像机的畸变向量
imageSize-图像大小
R- 相机之间的旋转矩阵,这里R的意义是:相机1通过变换R到达相机2的位姿
T-  左相机到右相机的平移矩阵
R1-输出矩阵,第一个摄像机的校正变换矩阵(旋转变换)
R2-输出矩阵,第二个摄像机的校正变换矩阵(旋转矩阵)
P1-输出矩阵,第一个摄像机在新坐标系下的投影矩阵
P2-输出矩阵,第二个摄像机在想坐标系下的投影矩阵
Q-4*4的深度差异映射矩阵
flags-可选的标志有两种零或者 CV_CALIB_ZERO_DISPARITY ,如果设置 CV_CALIB_ZERO_DISPARITY 的话,该函数会让两幅校正后的图像的主点有相同的像素坐标。否则该函数会水平或垂直的移动图像,以使得其有用的范围最大
alpha-拉伸参数。如果设置为负或忽略,将不进行拉伸。如果设置为0,那么校正后图像只有有效的部分会被显示(没有黑色的部分),如果设置为1,那么就会显示整个图像。设置为0~1之间的某个值,其效果也居于两者之间。
newImageSize-校正后的图像分辨率,默认为原分辨率大小。
validPixROI1-可选的输出参数,Rect型数据。其内部的所有像素都有效
validPixROI2-可选的输出参数,Rect型数据。其内部的所有像素都有效

opencv进行双目标定以及极线校正 python代码

双目标定

参考博客 OpenCV相机标定全过程
[OpenCV实战]38 基于OpenCV的相机标定
opencv立体标定函数 stereoCalibrate()

主要使用的函数

findChessboardCorners() #棋盘格角点检测
cornerSubPix() #亚像素检测
calibrateCamera() #单目标定 求解摄像机的内在参数和外在参数
stereoCalibrate() #双目标定 求解两个摄像头的内外参数矩阵,以及两个摄像头的位置关系R,T

代码

import cv2
import os
import numpy as np

leftpath = 'images/left'
rightpath = 'images/right'
CHECKERBOARD = (11,12)  #棋盘格内角点数
square_size = (30,30)   #棋盘格大小,单位mm
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
imgpoints_l = []    #存放左图像坐标系下角点位置
imgpoints_r = []    #存放左图像坐标系下角点位置
objpoints = []   #存放世界坐标系下角点位置
objp = np.zeros((1, CHECKERBOARD[0]*CHECKERBOARD[1], 3), np.float32)
objp[0,:,:2] = np.mgrid[0:CHECKERBOARD[0], 0:CHECKERBOARD[1]].T.reshape(-1, 2)
objp[0,:,0] *= square_size[0]
objp[0,:,1] *= square_size[1]


for ii in os.listdir(leftpath):
    img_l = cv2.imread(os.path.join(leftpath,ii))
    gray_l = cv2.cvtColor(img_l,cv2.COLOR_BGR2GRAY)
    img_r = cv2.imread(os.path.join(rightpath,ii))
    gray_r = cv2.cvtColor(img_r,cv2.COLOR_BGR2GRAY)
    ret_l, corners_l = cv2.findChessboardCorners(gray_l, CHECKERBOARD)   #检测棋盘格内角点
    ret_r, corners_r = cv2.findChessboardCorners(gray_r, CHECKERBOARD)
    if ret_l and ret_r:
        objpoints.append(objp)
        corners2_l = cv2.cornerSubPix(gray_l,corners_l,(11,11),(-1,-1),criteria) 
        imgpoints_l.append(corners2_l)
        corners2_r = cv2.cornerSubPix(gray_r,corners_r,(11,11),(-1,-1),criteria)
        imgpoints_r.append(corners2_r)
        #img = cv2.drawChessboardCorners(img, CHECKERBOARD, corners2,ret)
        #cv2.imwrite('./ChessboardCornersimg.jpg', img)
ret, mtx_l, dist_l, rvecs_l, tvecs_l = cv2.calibrateCamera(objpoints, imgpoints_l, gray_l.shape[::-1],None,None)  #先分别做单目标定
ret, mtx_r, dist_r, rvecs_r, tvecs_r = cv2.calibrateCamera(objpoints, imgpoints_r, gray_r.shape[::-1],None,None)

retval, cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2, R, T, E, F = \
    cv2.stereoCalibrate(objpoints, imgpoints_l, imgpoints_r, mtx_l, dist_l, mtx_r, dist_r, gray_l.shape[::-1])   #再做双目标定

print("stereoCalibrate : \n")
print("Camera matrix left : \n")
print(cameraMatrix1)
print("distCoeffs left  : \n")
print(distCoeffs1)
print("cameraMatrix left : \n")
print(cameraMatrix2)
print("distCoeffs left : \n")
print(distCoeffs2)
print("R : \n")
print(R)
print("T : \n")
print(T)
print("E : \n")
print(E)
print("F : \n")
print(F)

将打印的结果保存到标定文件中即可

极线校正
参考博客 机器视觉学习笔记(8)——基于OpenCV的Bouguet立体校正
小白视角之Bouguet双目立体校正原理

主要使用的函数

stereoRectify() #计算旋转矩阵和投影矩阵
initUndistortRectifyMap() #计算校正查找映射表
remap() #重映射

代码

import cv2
import numpy as np

def cat2images(limg, rimg):
    HEIGHT = limg.shape[0]
    WIDTH = limg.shape[1]
    imgcat = np.zeros((HEIGHT, WIDTH*2+20,3))
    imgcat[:,:WIDTH,:] = limg
    imgcat[:,-WIDTH:,:] = rimg
    for i in range(int(HEIGHT / 32)):
        imgcat[i*32,:,:] = 255 
    return imgcat

left_image = cv2.imread("images/left/268.jpg")
right_image = cv2.imread("images/right/268.jpg")

imgcat_source = cat2images(left_image,right_image)
HEIGHT = left_image.shape[0]
WIDTH = left_image.shape[1]
cv2.imwrite('imgcat_source.jpg', imgcat_source )

camera_matrix0 = np.array([[1.30991855e+03, 0.00000000e+00, 5.90463086e+02],
                            [0.00000000e+00, 1.31136722e+03, 3.33464608e+02],
                            [0.00000000e+00, 0.00000000e+00, 1.00000000e+00]]
                        ) .reshape((3,3)) #即上文标定得到的 cameraMatrix1
                        
distortion0 = np.array([-4.88890701e-01,  3.27964225e-01, -2.72130825e-04,  1.28030208e-03, -1.85964828e-01]) #即上文标定得到的 distCoeffs1

camera_matrix1 = np.array([[1.30057467e+03, 0.00000000e+00, 6.28445749e+02],
                            [0.00000000e+00, 1.30026325e+03, 3.90475091e+02],
                            [0.00000000e+00, 0.00000000e+00, 1.00000000e+00]]
                        ) .reshape((3,3)) #即上文标定得到的 cameraMatrix2
distortion1 = np.array([-4.95938411e-01,  2.70207629e-01,  1.81014753e-04, -4.58891345e-04, 4.41327829e-01]) #即上文标定得到的 distCoeffs2

R = np.array([[ 0.99989348,  0.01340678, -0.00576869], 
              [-0.01338004,  0.99989967,  0.00465071], 
              [ 0.00583046, -0.00457303,  0.99997255]]
            ) #即上文标定得到的 R
T = np.array([-244.28272039, 3.84124178, 2.0963191]) #即上文标定得到的T


(R_l, R_r, P_l, P_r, Q, validPixROI1, validPixROI2) = \
    cv2.stereoRectify(camera_matrix0, distortion0, camera_matrix1, distortion1, np.array([WIDTH,HEIGHT]), R, T) #计算旋转矩阵和投影矩阵

(map1, map2) = \
    cv2.initUndistortRectifyMap(camera_matrix0, distortion0, R_l, P_l, np.array([WIDTH,HEIGHT]), cv2.CV_32FC1) #计算校正查找映射表

rect_left_image = cv2.remap(left_image, map1, map2, cv2.INTER_CUBIC) #重映射

#左右图需要分别计算校正查找映射表以及重映射
(map1, map2) = \
    cv2.initUndistortRectifyMap(camera_matrix1, distortion1, R_r, P_r, np.array([WIDTH,HEIGHT]), cv2.CV_32FC1)
    
rect_right_image = cv2.remap(right_image, map1, map2, cv2.INTER_CUBIC)

imgcat_out = cat2images(rect_left_image,rect_right_image)
cv2.imwrite('imgcat_out.jpg', imgcat_out)

效果图
校正前
左图
在这里插入图片描述
右图
在这里插入图片描述
校正后
在这里插入图片描述

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

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

相关文章

MySQL体系结构

连接层: 最上层是一些客户端和链接服务,主要完成一些类似于连接处理、授权认证、及相关的安全方案。服务器也会为安全接入的每个客户端验证它所具有的操作权限。服务层: 第二层架构主要完成大多数的核心服务功能,如…

【从零学习python 】02. 开发工具介绍

文章目录 编写Python代码一、常见的代码编辑工具二、运行Python程序三、Pycharm的下载和安装PyCharm的主要功能区域进阶案例 编写Python代码 根据我们之前介绍的知识,我们知道,所谓代码其实就是将一段普通文本按照一定的规范编写,然后交给电…

微信提示操作太频繁怎么办?

微信使用过程中,遇到“操作太频繁”的提示该怎么办? 而提示频繁最常见的两种情况:加好友频繁和发消息频繁。 微信为什么提示频繁?频繁是因为微信故意这样设置的,压根就不想你群发!!&#xff0…

《Zookeeper》从零开始学Zookeeper源码(三)之服务器的启动过程

目录 QuorumPeerMain QuorumPeerMain 在搭建本地的源码环境中,启动zookeeper服务端的入口为QuorumPeerMain,先看下它的类结构: 它本身只有一个属性quorumPeer,它代表了zookeeper集群中的一台机器,它会不断检测当前服…

营销文案流水线化生产——agent llm

背景: 做过工厂生产的朋友应该对生产流程:BOM、SOP这两个词不陌生,然而这两个词更厉害的地方在于标准化流程化作业。其实经过这么多轮迭代的内容生成,特别是和商业营销相关的数字化内容生成和其不是在追求标准化、流程化、定制化…

某大型医院门户网站性能分析案例

故障现象 门户网站近期出现少量的访问体验慢现象,主要是由于服务器响应时间慢。出现慢页面的页面簇为:http://www.xxx.ac.cn/。 分析过程 下面将分析异常原因:页面的URL信息?页面慢的原因? 性能问题分析,定位到慢访…

知识付费系统开发:构建高效智能的付费内容平台

随着数字化时代的来临,知识付费正迅速崭露头角,为知识创作者和求知者带来了全新的商机。在这个背景下,开发一款高效智能的知识付费系统成为了一项重要的任务。本文将深入探讨如何基于Python编程语言和相关技术构建一个智能的知识付费内容平台…

kconfig语法

前言 Kconfig文件:存放生成基于图形化界面内容 学习原因:Kconfig是各种配置界面的源文件,内核的配置工具读取各个Kconfig文件,生成配置界面供开发人员配置内核,最后生成配置文件.config 语法 1.概念:主…

【51单片机】晨启科技,7针OLED显示驱动程序,STC89C52RC

文章目录 原理图oled.coled.hmain.c 原理图 sbit OLED_SCLP4^3;//SCL-D0 sbit OLED_SDAP4^1;//SDA-D1 sbit OLED_RES P3^6;//RES sbit OLED_DC P3^7;//DC sbit OLED_CSP2^7; //CS oled.c #include "OLED.h"//******************************说明*******************…

【gavh39芯片用什么代替-AH8652】

问:gavh39芯片用什么代替? 答:gavh39是一颗用于交流220v转5v输出的芯片,它的拼对拼代替型号为AH8652 AH8652是一款非隔离电源管理芯片,它用于将交流电压转换为直流电压输出。可以将输入的220V交流电转换为输出的5V直流…

Harbor企业镜像仓库部署(本地)

简述: Docker 官方镜像仓库是用于管理公共镜像的地方,大家可以在上面找到想要的镜像,也可以把自己的镜像推送上去。但是有时候服务器无法访问互联网,或者不希望将自己的镜像放到互联网上,那么就需要用到 Docker Regis…

Docker desktop使用配置

1. 下载安装 https://www.docker.com/ 官网下载并安装doker desktop 2. 配置镜像 (1)首先去阿里云网站上进行注册:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors (2)注册完成后搜索:容…

用 docker 创建 jmeter 容器,能做性能测试?

我们都知道,jmeter 可以做接口测试,也可以用于性能测试,现在企业中性能测试也大多使用 jmeter。docker 是最近这些年流行起来的容器部署工具,可以创建一个容器,然后把项目放到容器中,就可以构建出一个独立的…

独立站私域怎么玩?浅浅了解一下吧!

当你是一个跨境电商独立站的卖家,你的工作有三个主要焦点:充分利用流量、提升用户转化率和降低用户的总体成本。 然而,除了利用广告以外,是否有更多的策略可以帮助你接触到用户,同时降低吸引新用户的成本呢&#xff1…

LeetCode150道面试经典题-合并两个有序数组(简单)

合并两个有序数组 题目: 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。 注意&a…

每天一道leetcode:剑指 Offer 11. 旋转数组的最小数字(适合初学者)

今日份题目: 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如&am…

前端页面性能优化,性能测试算法优化,MeterSphere开源持续测试平台v2.10.5 LTS版本发布

2023年8月7日,MeterSphere一站式开源持续测试平台正式发布v2.10.5 LTS版本。自2023年5月发布v2.10 LTS版本后,MeterSphere开源项目组坚持每两周发布小版本,持续进行问题的修复更新,并针对部分功能进行优化。 本次发布的MeterSphe…

【深度学习】采用自动编码器生成新图像

一、说明 你知道什么会很酷吗?如果我们不需要所有这些标记的数据来训练 我们的模型。我的意思是标记和分类数据需要太多的工作。 不幸的是,大多数现有模型从支持向量机到卷积神经网,没有它们,卷积神经网络就无法训练。无监督学习不…

7月27日上课内容 Firewalld防火墙

iptables 软件防火墙 包过滤防火墙firewalld 防火墙包过滤防火墙。网络层centos7自带的默认的防火墙。取代iptables firewalld两种配置模式 运行时配置 永久配置 iptables是静态防火墙 firewalld是动态防火墙。 firewalld安装区域来进行划分: 9个区域 moba里面要打开防火墙 fi…

智慧工厂解决方案[60页PPT]

导读:原文《》(获取来源见文尾),本文精选其中精华及架构部分,逻辑清晰、内容完整,为快速形成售前方案提供参考。 完整版领取方式 完整版领取方式: 如需获取完整的电子版内容参考学习 您可以关注…