Python实现双目标定、畸变矫正、立体矫正

一,双目标定、畸变矫正、立体矫正的作用

  1. 双目目标定

    • 3D重建和测距:通过双目目标定,您可以确定两个摄像头之间的相对位置和朝向,从而能够根据视差信息计算物体的深度,进行三维重建和测距。
    • 姿态估计:双目摄像头可以用于估计物体或相机的姿态,这对于虚拟现实、增强现实和机器人导航等应用非常重要。
  2. 畸变矫正

    • 图像质量提高:镜头畸变会引入图像失真,畸变矫正可以改善图像质量,使物体的形状更准确。
    • 特征匹配:在图像特征匹配中,畸变矫正可以提高匹配的精度,有助于在不同视图之间正确匹配特征点。
  3. 立体矫正

    • 立体视觉:立体矫正是用于双目或多目视觉系统的关键步骤,可使两个摄像头的像素对应点在同一水平线上,从而简化了立体视觉中的视差计算。
    • 深度感知:立体矫正后,您可以使用视差图来估计物体的深度,这对于实现深度感知和3D重建非常重要。

二,双目拍照代码

#coding:utf-8
import cv2
import time
import timeleft_camera = cv2.VideoCapture(0)
left_camera.set(cv2.CAP_PROP_FRAME_WIDTH,640)
left_camera.set(cv2.CAP_PROP_FRAME_HEIGHT,480)right_camera = cv2.VideoCapture(1)
right_camera.set(cv2.CAP_PROP_FRAME_WIDTH,640)
right_camera.set(cv2.CAP_PROP_FRAME_HEIGHT,480)path="/home/song/pic/" #图片存储路径AUTO =False   # True自动拍照,False则手动按s键拍照
INTERVAL = 0.0000005 # 调整自动拍照间隔cv2.namedWindow("left")
cv2.namedWindow("right")
cv2.moveWindow("left", 0, 0)counter = 0
utc = time.time()
folder = "/home/song/pic/" # 照片存储路径def shot(pos, frame):global countertimestr = datetime.datetime.now()path = folder + pos + "_" + str(counter) +".jpg"cv2.imwrite(path, frame)print("snapshot saved into: " + path)while True:ret, left_frame = left_camera.read()ret, right_frame = right_camera.read()cv2.imshow("left", left_frame)cv2.imshow("right", right_frame)now = time.time()if AUTO and now - utc >= INTERVAL:shot("left", left_frame)shot("right", right_frame)counter += 1utc = nowkey = cv2.waitKey(1)if key == ord("q"):breakelif key == ord("s"):shot("left", left_frame)shot("right", right_frame)counter += 1left_camera.release()
right_camera.release()
cv2.destroyWindow("left")
cv2.destroyWindow("right")

三,分别对左右目进行标定

在进行双目相机的标定之前,需要先对左右目的单目摄像头进行单目标定。这是因为双目摄像头的标定需要知道每个摄像头的内部参数(如相机矩阵、畸变系数)以及相机之间的外部参数(相对位置和朝向)。这些参数是通过单目标定来获得的。

单目标定通常包括以下步骤:

  1. 相机内参标定:通过拍摄一个包含已知尺寸的标定板的图像,然后使用相机标定算法来估计相机内参,如焦距、主点坐标和畸变系数。

  2. 相机外参标定:通过将相机放置在不同位置或拍摄不同方向的图像,使用外参标定算法来估计相机的位置和朝向。这一步通常需要多幅图像,以确定相机在三维空间中的位置和姿态。

  3. 畸变矫正:使用内参标定得到的畸变系数来矫正图像,以去除镜头畸变。

  4. 生成标定文件:将内外参和畸变系数保存在标定文件中,以便后续的双目标定使用。

一旦单目摄像头的内部参数、外部参数和畸变系数都已知,就可以进行双目标定,以确定双目摄像头之间的相对位置和朝向,以及立体视觉中的标定参数。

#-*- coding:utf-8 -*-
import numpy as np
import cv2
import glob# 设置迭代终止条件
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)# 设置 object points, 形式为 (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((6*7,3), np.float32) #我用的是6×7的棋盘格,可根据自己棋盘格自行修改相关参数
objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2)# 用arrays存储所有图片的object points 和 image points
objpoints = [] # 3d point in real world space
imgpoints = [] # 2d points in image plane.#用glob匹配文件夹/home/song/pic_1/right/下所有文件名含有“.jpg"的图片
images = glob.glob(r"/home/song/pic/right/*.jpg")for fname in images:img = cv2.imread(fname)gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 查找棋盘格角点ret, corners = cv2.findChessboardCorners(gray, (7,6), None)# 如果找到了就添加 object points, image pointsif ret == True:objpoints.append(objp)corners2=cv2.cornerSubPix(gray,corners, (11,11), (-1,-1), criteria)imgpoints.append(corners)# 对角点连接画线加以展示cv2.drawChessboardCorners(img, (7,6), corners2, ret)cv2.imshow('img', img)cv2.waitKey(500)
cv2.destroyAllWindows()# 标定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
print(mtx, dist)#对所有图片进行去畸变,有两种方法实现分别为: undistort()和remap()
images = glob.glob(r"/home/song/pic/right/*.jpg")
for fname in images:prefix=fname.split('/')[5]img = cv2.imread(fname)h,  w = img.shape[:2]newcameramtx, roi=cv2.getOptimalNewCameraMatrix(mtx, dist, (w,h), 1, (w,h))# # 使用 cv.undistort()进行畸变校正# dst = cv2.undistort(img, mtx, dist, None, newcameramtx)# # 对图片有效区域进行剪裁# # x, y, w, h = roi# # dst = dst[y:y+h, x:x+w]# cv2.imwrite('/home/song/pic_1/undistort/'+prefix, dst)#  使用 remap() 函数进行校正mapx, mapy = cv2.initUndistortRectifyMap(mtx, dist, None, newcameramtx, (w, h), 5)dst = cv2.remap(img, mapx, mapy, cv2.INTER_LINEAR)# 对图片有效区域进行剪裁x, y, w, h = roidst = dst[y:y + h, x:x + w]cv2.imwrite('/home/song/pic/undistort/'+prefix, dst)#重投影误差计算
mean_error = 0
for i in range(len(objpoints)):imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)error = cv2.norm(imgpoints[i],imgpoints2, cv2.NORM_L2)/len(imgpoints2)mean_error += errorprint("total error: ", mean_error/len(objpoints))

四,双目标定及其立体校正

#coding:utf-8
import numpy as np
import cv2
import matplotlib.pyplot as plt
from PIL import Image# 设置迭代终止条件
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
criteria_stereo = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)# 设置 object points, 形式为 (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((6 * 7, 3), np.float32)  #我用的是6×7的棋盘格,可根据自己棋盘格自行修改相关参数
objp[:, :2] = np.mgrid[0:7, 0:6].T.reshape(-1, 2)# 用arrays存储所有图片的object points 和 image points
objpoints = []  # 3d points in real world space
imgpointsR = []  # 2d points in image plane
imgpointsL = []# 本次实验采集里共计30组待标定图片依次读入进行以下操作
for i in range(0,30):  t = str(i)ChessImaR = cv2.imread('/home/song/pic/right_' + t + '.jpg', 0)  # 右视图ChessImaL = cv2.imread('/home/song/pic/left_' + t + '.jpg', 0)  # 左视图retR, cornersR = cv2.findChessboardCorners(ChessImaR,(7, 6), None)  # 提取右图每一张图片的角点retL, cornersL = cv2.findChessboardCorners(ChessImaL,(7, 6), None)  # # 提取左图每一张图片的角点if (True == retR) & (True == retL):objpoints.append(objp)cv2.cornerSubPix(ChessImaR, cornersR, (11, 11), (-1, -1), criteria)  # 亚像素精确化,对粗提取的角点进行精确化cv2.cornerSubPix(ChessImaL, cornersL, (11, 11), (-1, -1), criteria)  # 亚像素精确化,对粗提取的角点进行精确化imgpointsR.append(cornersR)imgpointsL.append(cornersL)# 相机的单双目标定、及校正
#   右侧相机单独标定
retR, mtxR, distR, rvecsR, tvecsR = cv2.calibrateCamera(objpoints,imgpointsR,ChessImaR.shape[::-1], None, None)#   获取新的相机矩阵后续传递给initUndistortRectifyMap,以用remap生成映射关系
hR, wR = ChessImaR.shape[:2]
OmtxR, roiR = cv2.getOptimalNewCameraMatrix(mtxR, distR,(wR, hR), 1, (wR, hR))#   左侧相机单独标定
retL, mtxL, distL, rvecsL, tvecsL = cv2.calibrateCamera(objpoints,imgpointsL,ChessImaL.shape[::-1], None, None)#   获取新的相机矩阵后续传递给initUndistortRectifyMap,以用remap生成映射关系
hL, wL = ChessImaL.shape[:2]
OmtxL, roiL = cv2.getOptimalNewCameraMatrix(mtxL, distL, (wL, hL), 1, (wL, hL))# 双目相机的标定
# 设置标志位为cv2.CALIB_FIX_INTRINSIC,这样就会固定输入的cameraMatrix和distCoeffs不变,只求解𝑅,𝑇,𝐸,𝐹
flags = 0
flags |= cv2.CALIB_FIX_INTRINSICretS, MLS, dLS, MRS, dRS, R, T, E, F = cv2.stereoCalibrate(objpoints,imgpointsL,imgpointsR,OmtxL,distL,OmtxR,distR,ChessImaR.shape[::-1], criteria_stereo,flags)# 利用stereoRectify()计算立体校正的映射矩阵
rectify_scale= 1 # 设置为0的话,对图片进行剪裁,设置为1则保留所有原图像像素
RL, RR, PL, PR, Q, roiL, roiR= cv2.stereoRectify(MLS, dLS, MRS, dRS,ChessImaR.shape[::-1], R, T,rectify_scale,(0,0))  
# 利用initUndistortRectifyMap函数计算畸变矫正和立体校正的映射变换,实现极线对齐。
Left_Stereo_Map= cv2.initUndistortRectifyMap(MLS, dLS, RL, PL,ChessImaR.shape[::-1], cv2.CV_16SC2)   Right_Stereo_Map= cv2.initUndistortRectifyMap(MRS, dRS, RR, PR,ChessImaR.shape[::-1], cv2.CV_16SC2)#立体校正效果显示
for i in range(0,1):  # 以第一对图片为例t = str(i)frameR = cv2.imread('/home/song/pic/right_' + t + '.jpg', 0)  frameL = cv2.imread('/home/song/pic/left_' + t + '.jpg', 0) Left_rectified= cv2.remap(frameL,Left_Stereo_Map[0],Left_Stereo_Map[1], cv2.INTER_LANCZOS4, cv2.BORDER_CONSTANT, 0)  # 使用remap函数完成映射im_L=Image.fromarray(Left_rectified) # numpy 转 image类Right_rectified= cv2.remap(frameR,Right_Stereo_Map[0],Right_Stereo_Map[1], cv2.INTER_LANCZOS4, cv2.BORDER_CONSTANT, 0)im_R=Image.fromarray(Right_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.show()

五,双目的具体应用

双目视觉是指通过两个摄像头(或相机)捕获的图像来模拟人类双眼视觉系统。它可以提供更多的深度信息和立体感,因此在许多领域都有具体的应用。

以下是一些双目视觉的具体应用:

  1. 三维重建:通过双目摄像头捕获的图像,可以使用立体视觉算法来重建场景的三维结构。这对于计算机辅助设计、虚拟现实、增强现实等领域非常有用。

  2. 物体检测与跟踪:双目视觉可以提供更多的深度信息,从而使得物体检测和跟踪更加准确和稳定。例如,在自动驾驶中,双目视觉可以用于检测和跟踪其他车辆、行人等。

  3. 深度感知:通过双目视觉可以获取场景中物体的深度信息,从而可以进行深度感知和距离测量。这在机器人导航、室内定位、无人机避障等领域非常有用。

  4. 姿态估计:双目视觉可以用于估计物体或人体的姿态和运动。例如,在人机交互中,双目视觉可以用于手势识别和追踪。

  5. 立体匹配:通过双目视觉可以进行立体匹配,即将两个图像中对应的像素点进行匹配。这在计算机视觉中是一个重要的问题,可以用于图像配准、目标识别等。

  6. 视觉SLAM:双目视觉可以与同步定位与地图构建(SLAM)算法结合使用,实现同时定位和地图构建。这在无人车、无人机等领域中非常重要。

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

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

相关文章

CVE-2022-22963 Spring Cloud Function SpEL命令注入

一、简介 Spring Cloud Function 是基于 Spring Boot的函数计算框架。该项目致力于促进函数为主的开发单元,它抽象出所有传输细节和基础架构,并提供一个通用的模型,用于在各种平台上部署基于函数的软件。在Spring Cloud Function相关版本&am…

京东平台数据分析:2023年9月京东空气净化器行业品牌销售排行榜

鲸参谋监测的京东平台9月份空气净化器市场销售数据已出炉! 9月份,空气净化器的销售同比上年增长。根据鲸参谋平台的数据显示,今年9月,京东平台空气净化器的销量将近15万,同比增长约1%;销售额将近2亿元&…

Mac版好用的Git客户端 Fork 免激活

Fork是一款强大的Git客户端软件,在Mac和Windows操作系统上都可以使用。汇集了众多先进的功能和工具,可以帮助用户更方便地管理和控制Git仓库。 Fork的界面简洁直观,易于使用。它提供了许多高级的Git功能,如分支管理、合并、提交、…

NTRU 加密方案

参考文献: [Rivest97] Rivest R L. All-or-nothing encryption and the package transform[C]//Fast Software Encryption: 4th International Workshop, FSE’97 Haifa, Israel, January 20–22 1997 Proceedings 4. Springer Berlin Heidelberg, 1997: 210-218.[…

每日一题 2558. 从数量最多的堆取走礼物(简单,heapq)

怎么这么多天都是简单题,不多说了 class Solution:def pickGifts(self, gifts: List[int], k: int) -> int:gifts [-gift for gift in gifts]heapify(gifts)for i in range(k):heappush(gifts, -int(sqrt(-heappop(gifts))))return -sum(gifts)

多线程---线程安全问题及解决

文章目录 一个线程不安全的案例造成线程不安全的原因抢占式执行多个线程修改同一个变量修改操作不是原子的内存可见性问题指令重排序问题 如何让线程变得安全?加锁synchronized volatile 一个线程不安全的案例 题目:有较短时间让变量count从0加到10_000…

行业追踪,2023-10-26

自动复盘 2023-10-26 凡所有相,皆是虚妄。若见诸相非相,即见如来。 k 线图是最好的老师,每天持续发布板块的rps排名,追踪板块,板块来开仓,板块去清仓,丢弃自以为是的想法,板块去留让…

分享一波操作系统、谢希仁版本计算机网络学习笔记【思维导图】

操作系统复习笔记 - 幕布第一章引论第二章处理器管理进程同步与通信https://www.mubu.com/doc/58qrnf20ndg 大纲 - 幕布物理层数据链路层网络层https://www.mubu.com/doc/1eo9_8TyUdg计算机网络-语雀https://www.yuque.com/yuqueyonghu6nc56e/dgg1dl/wx34gx72xpgmt598?singleD…

HackTheBox-Starting Point--Tier 1---Crocodile

文章目录 一 题目二 实验过程 一 题目 Tags Web、Network、Custom Applications、Protocols、Apache、FTP、Reconnaissance、Web Site Structure Discovery、Clear Text Credentials、Anonymous/Guest Access译文:Web、网络、定制应用程序、协议、Apache、FTP、侦…

华为eNSP配置专题-策略路由的配置

文章目录 华为eNSP配置专题-策略路由的配置0、概要介绍1、前置环境1.1、宿主机1.2、eNSP模拟器 2、基本环境搭建2.1、终端构成和连接2.2、终端的基本配置 3、配置接入交换机上的VLAN4、配置核心交换机为网关和DHCP服务器5、配置核心交换机和出口路由器互通6、配置PC和出口路由器…

【软件安装环境配置】vscode 安装界面没有出现安装路径的选择 的解决,以及vscode的删除的问题

由于vscode 没有删除干净,就会出现vscode 安装的时候,没有出现安装路径的界面,所以可以来到vscode的安装路径,点击 unins000.exe 文件就可以 实现将vscode 相关的文件删除, 如果是删除了整个vscode 安装下的文件&…

Win11 安装wsl遇到的问题解决

Win11 安装wsl遇到的问题解决 Win11 安装wsl遇到的问题解决WslRegisterDistribution failed:0x8007019eWslRegisterDistribution failed:0x800701bcUbuntu换源WSL通过网络访问Windows Win11 安装wsl遇到的问题解决 WslRegisterDistribution failed:0x8007019e 参考Link WslR…

软考高项-计算题(3)

题10 问题一 EV50*0.525 问题二 EACBAC/CPI CPIEV/AC25/28 EAC50*28/2556 问题三 因为CPI<1&#xff0c;所以项目实际费用超支 题11 PV2000500010000750006500020000177000 AC2100450012000860006000015000179600 EV200050001000075000*0.965000*0.720000*0.351370…

网络协议--TCP的成块数据流

20.1 引言 在第15章我们看到TFTP使用了停止等待协议。数据发送方在发送下一个数据块之前需要等待接收对已发送数据的确认。本章我们将介绍TCP所使用的被称为滑动窗口协议的另一种形式的流量控制方法。该协议允许发送方在停止并等待确认前可以连续发送多个分组。由于发送方不必…

SpringMVC Day02 : 请求方式

前言 欢迎阅读 Spring MVC 系列教程的第二篇文章&#xff01;在上一篇文章中&#xff0c;我们介绍了 Spring MVC 的基本概念和使用方法。今天&#xff0c;我们将深入探讨 Spring MVC 中不同的请求方式&#xff0c;以及如何在你的应用程序中正确地处理它们。 在 Web 开发中&am…

day01:数据库DDL

一:基础概念 数据库:存储数据的仓库&#xff0c;数据是有组织的进行存储 数据库管理系统:操纵和管理数据库的大型软件 SQL&#xff1a;操作关系型数据库的编程语言&#xff0c;定义了一套操作关系型数据库统一标准 关系图 二:数据模型 关系型数据库:建…

vue的双向绑定的原理,和angular的对比

目录 前言 Vue的双向绑定用法 代码 Vue的双向绑定原理 Angular的双向绑定用法 代码 Angular的双向绑定原理 理解 图片 关于Vue的双向绑定原理和与Angular的对比&#xff0c;我们可以从以下几个方面进行深入探讨&#xff1a; 前言 双向绑定是现代前端框架的核心特性之…

经典卷积神经网络 - ResNet

ResNet是一种残差网络&#xff0c;咱们可以把它理解为一个子网络&#xff0c;这个子网络经过堆叠可以构成一个很深的网络。 我们一直在加深神经网络&#xff0c;但是加深不一定只会带来好处。 残差块 串联一个层改变函数类&#xff0c;我们希望能扩大函数类残差块加入快速通…

计算机网络【CN】子网划分与子网掩码

一个子网定义(X.X.X.X/n) 子网掩码为 n 个 1&#xff0c;32-n 个 0包含的 IP 地址数&#xff1a;232−n 主机号全 0 表示本网段主机号全 1 表示网段的广播地址可分配的 IP 地址数 :232−&#x1d45b;−2 子网划分原则 满足子网定义子网&#x1d434;1…&#x1d434;&#x…

Three.js 基础纹理贴图

本文简介 带尬猴&#xff0c;我嗨德育处主任 尽管 Three.js 文档已经比较详细了&#xff0c;但对于刚接触 Three.js 的工友来说&#xff0c;最麻烦的还是不懂如何组合。Three.js 的功能实在太多了&#xff0c;初学者很容易被大量的新概念冲晕。 本文主要讲解入门 Three.js 必…