OpenCV solvePnP位姿估计

news2024/9/22 9:35:14

目录

一、概述

二、实现代码

2.1solvePnP函数

2.1.1输入参数

2.1.2输出参数

2.2完整代码

三、实现效果

3.1标定板位姿

3.2标定板到相机的变换矩阵


一、概述

        完成相机标定后,可以通过检测标定板在图像中的位置来计算标定板在相机坐标系下的位姿(外参)。通过cv2.solvePnP求出标定板在相机坐标系下的姿态矩阵后,保存下来可用于后续的手眼标定

具体步骤如下:

  1. 相机标定:获取相机的内参矩阵和畸变系数。
  2. 检测标定板:在图像中检测棋盘格角点。
  3. 计算外参:使用 cv2.solvePnP 计算标定板在相机坐标系下的位姿。

二、实现代码

2.1solvePnP函数

        cv2.solvePnP 是 OpenCV 中用于估计对象姿态的函数。它计算从 3D 点到 2D 图像点的变换,包括旋转和位移。

retval, rvec, tvec = cv2.solvePnP(objectPoints, imagePoints, cameraMatrix, distCoeffs[, rvec[, tvec[, useExtrinsicGuess[, flags]]]])

2.1.1输入参数

2.1.2输出参数

2.2完整代码

import cv2
import numpy as np
import glob

# 加载相机标定参数
with np.load('camera_calibration.npz') as data:
    mtx = data['mtx']
    dist = data['dist']

# 设置棋盘格参数
chessboard_size = (11, 8)  # 棋盘格的内角点个数
square_size = 1.0  # 棋盘格每个方格的实际大小,单位可以是毫米、厘米或米

# 准备棋盘格的世界坐标系坐标(假设z=0)
objp = np.zeros((chessboard_size[0] * chessboard_size[1], 3), np.float32)
objp[:, :2] = np.mgrid[0:chessboard_size[0], 0:chessboard_size[1]].T.reshape(-1, 2)
objp *= square_size

# 用于存储每张图像的位姿矩阵
pose_matrices = []

# 获取所有棋盘格图像的路径
images = glob.glob('board_image/*.png')

for image_path in images:
    # 读取图像
    img = cv2.imread(image_path)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # 检测棋盘格角点
    ret, corners = cv2.findChessboardCorners(gray, chessboard_size, None)

    if ret:
        # 优化角点位置到亚像素级精度
        criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
        corners = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)

        # 计算标定板在相机坐标系下的位姿(标定板在相机坐标系下的位姿)
        ret, rvec, tvec = cv2.solvePnP(objp, corners, mtx, dist)

        # 将旋转向量转换为旋转矩阵
        rmat, _ = cv2.Rodrigues(rvec)

        # 组合旋转矩阵和平移向量为位姿矩阵
        pose_matrix = np.hstack((rmat, tvec))
        pose_matrices.append(pose_matrix)

        # 在图像上绘制坐标轴用于可视化
        axis = np.float32([[3, 0, 0], [0, 3, 0], [0, 0, -3]]).reshape(-1, 3)
        imgpts, _ = cv2.projectPoints(axis, rvec, tvec, mtx, dist)

        img = cv2.drawChessboardCorners(img, chessboard_size, corners, ret)
        corner = tuple(corners[0].ravel().astype(int))

        # 确保坐标点是以正确的格式传递给 cv2.line 函数
        img = cv2.line(img, corner, tuple(imgpts[0].ravel().astype(int)), (255, 0, 0), 5)
        img = cv2.line(img, corner, tuple(imgpts[1].ravel().astype(int)), (0, 255, 0), 5)
        img = cv2.line(img, corner, tuple(imgpts[2].ravel().astype(int)), (0, 0, 255), 5)

        cv2.imshow('Pose Estimation', img)
        cv2.waitKey(0)

cv2.destroyAllWindows()

# # 保存所有位姿矩阵到文件
# np.save('pose_matrices.npy', np.array(pose_matrices))
#
# 输出所有位姿矩阵
for i, pose_matrix in enumerate(pose_matrices):
    print(f"Pose matrix for image {i+1}:\n", pose_matrix)

三、实现效果

3.1标定板位姿

3.2标定板到相机的变换矩阵

Pose matrix for image 1:
 [[ 9.54690321e-01  1.63896269e-01  2.48403711e-01 -9.17541763e+00]
 [-1.45600442e-01  9.85200423e-01 -9.04468778e-02 -1.04041170e+01]
 [-2.59551347e-01  5.01810686e-02  9.64424677e-01  8.94162448e+01]]
Pose matrix for image 2:
 [[ 9.68117431e-01 -2.30857543e-02  2.49430728e-01 -4.40319806e+00]
 [ 5.02887074e-02  9.93383921e-01 -1.03244525e-01 -8.17764301e+00]
 [-2.45396997e-01  1.12496373e-01  9.62873242e-01  8.84715217e+01]]
Pose matrix for image 3:
 [[  0.77862222  -0.56844737   0.26573487  -4.22080186]
 [  0.61191435   0.78162231  -0.12094374 -12.23688825]
 [ -0.13895415   0.25677646   0.95642961  87.62645824]]
Pose matrix for image 4:
 [[ 3.65280489e-01 -8.84489869e-01  2.90254777e-01 -4.59486253e-01]
 [ 9.30890782e-01  3.45882851e-01 -1.17504915e-01 -1.47317632e+01]
 [ 3.53775679e-03  3.13117749e-01  9.49707723e-01  8.60033729e+01]]
Pose matrix for image 5:
 [[ 2.10536679e-02 -9.53945915e-01  2.99238925e-01  2.39861926e+00]
 [ 9.94637523e-01 -1.03281967e-02 -1.02905426e-01 -1.39552702e+01]
 [ 1.01256809e-01  2.99800800e-01  9.48612955e-01  8.52141515e+01]]
Pose matrix for image 6:
 [[-8.08420711e-01 -5.24826800e-01  2.66482240e-01  5.53844533e+00]
 [ 5.25127881e-01 -8.47600539e-01 -7.62498222e-02 -8.15940333e+00]
 [ 2.65888440e-01  7.82953186e-02  9.60819015e-01  8.55355115e+01]]
Pose matrix for image 7:
 [[-0.90930726  0.32912313  0.25463362  0.90404698]
 [-0.3662639  -0.92345944 -0.11433903 -3.69221782]
 [ 0.1975122  -0.19723241  0.96025429 87.56252021]]

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

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

相关文章

Python基础知识——(004)

文章目录 P16——15. 布尔类型 P17——16. 类型转换函数 P18——17. eval函数 P19——18. 算数运算符 P20——19. 赋值运算符 P16——15. 布尔类型 布尔类型 用来表示 “真” 值或 “假” 值的数据类型在Python中使用标识符 True 或 False 表示布尔类型的值True表示整数1&…

python的集合

定义 集合(是一个无序的、不包含重复元素的集合。集合对象支持数学上的标准集合操作,如并集、交集、差集等。) 创建集合 添加元素 删除元素 遍历 其他 union() 或 |:返回两个集合的 并集intersection() 或 &:返回…

关于共享盘(文件夹)

1、创建共享文件夹或共享盘 对应文件或盘-》右键-》属性-》共享或高级共享 2、设置权限来针对不同的用户进行访问 2.1 关于用户的添加 电脑->计算机管理->添加用户和组 2.2 本地用户 在属性的安全之中,可针对不同的用户和组进行权限设置,例如某…

MYSQL--第七次作业

MYSQL–第七次作业 在product表上创建三个触发器。每次激活触发器后,都会更新operate表。product表和表的内容如下 Product表内容 字段名 字段描述 数据类型 主键 外键 非空 唯一 自增 Id 产品编号 Int(10) 是 否 是 是 否 Name …

iPad锁屏密码忘记怎么办?有什么方法可以解锁?

当我们在日常使用iPad时,偶尔可能会遇到忘记锁屏密码的尴尬情况。这时,不必过于担心,因为有多种方法可以帮助您解锁iPad。接下来,小编将为您详细介绍这些解决方案。 一、使用iCloud的“查找我的iPhone”功能 如果你曾经启用了“查…

Nginx:关于实现跨域代理

运维专题 Nginx:关于实现跨域代理 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite:http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.ne…

openWrt(3) - ubus (下)

参考自: [OpenWrt Wiki] ubus(OpenWrt微总线架构) --- [OpenWrt Wiki] ubus (OpenWrt micro bus architecture) ubus补充 查看注册到 ubusd 的所有服务的所有方法: ubus -v list system 调用远程方法并接收回复。回复可以是简单的整数返回…

超声波清洗机哪个牌子好?耐用的超声波眼镜清洗机推荐

超声波清洗机大家也一定不陌生了,提起超声波清洗机啊,大家对他的印象一定是清洗眼镜,这话没毛病,但是,这仅仅只是清洗机的基本功,清洗机的功能远远比咱们想象中的强大,但是目前市面上的小型超声…

基于RHCE基础搭建简单服务

目录 项目标题与需求一 配置IP地址server机node02机 二 配置web服务三 搭建dns服务器四 开启防火墙server firewalld 五 配置nfs服务器node02 nfsserver autofs 六 开启SELinux七 验证是否能访问www.rhce.com 项目标题与需求 项目标题: 项目需求: 现有…

眼镜清洗机哪款好用?眼镜党必备四款高性价比热门清洗机

戴眼镜的朋友应该深有体会,每次去眼镜店给眼镜“洗个澡”,重新戴上眼镜那一刻是不是觉得眼前的事物特别清晰,镜片也变得清澈透明。但是每次都得跑眼镜店,不仅耗时还费精力。这个时候,家用眼镜清洗机就显得特别有用了。…

MongoDB教程(四):mongoDB索引

💝💝💝首先,欢迎各位来到我的博客,很高兴能够在这里和您见面!希望您在这里不仅可以有所收获,同时也能感受到一份轻松欢乐的氛围,祝你生活愉快! 文章目录 引言一、MongoD…

软文推广小白进阶高手之路,这几招让你事半功倍

在数字营销的大潮中,软文推广作为一种润物细无声的营销手段,越来越受到企业和个人的青睐。对于初入此道的小白而言,想要从懵懂探索到游刃有余,其实并不遥远。今日投媒网就来与您分享掌握以下几招,让你的软文推广之路便…

Vxe UI vxe-table column 根据内容的长度来自适应列的宽度

Vxe UI vue vxe-table 根据内容的长度来自适应列的宽度 列的 width 宽度支持多种格式&#xff08;默认情况下是等比例分配&#xff09;&#xff1a; 固定像素&#xff1a;100 或者 ‘100px’ 百分比&#xff1a;‘20%’ 自适应内容&#xff1a;‘auto’ 代码 <template&g…

如何检测代理IP是否有效?检查因素与方法全解

代理IP是一种网络代理技术&#xff0c;它是通过中间服务器来转发网络请求的IP地址。当我们使用代理IP时&#xff0c;我们的真实IP地址会被隐藏起来&#xff0c;而代理服务器的IP地址会被用作我们的身份标识。使用代理IP的步骤如下&#xff1a; 1.选择合适的代理服务器 考虑服务…

2024年最新PyCharm保姆级安装教程

PyCharm是一款专为Python开发者设计的集成开发环境&#xff08;IDE&#xff09;&#xff0c;旨在帮助用户在使用Python语言开发时提高效率。 PyCharm作为一款强大的Python IDE&#xff0c;其主要作用在于提供了一整套可以帮助Python开发者提高开发效率的工具。这些工具包括但不…

Python转换PDF为PowerPoint演示文件

PDF文件以其跨平台兼容性和版面固定性成为了分享和存储文档资料的首选格式。然而&#xff0c;在需要进行生动、互动性强的演示时&#xff0c;PDF的静态特性便难以满足个性化演示需求。将PDF文件转换为PowerPoint演示文稿可以解决这一问题。PowerPoint不仅提供了丰富的动画和过渡…

时间管理的6张清单:做个时间清单控,提高时间颗粒度!

时间管理管理的到底是什么&#xff1f;我觉得其根本就是时间的颗粒度。这与大多数行业精英的时间管理不谋而合&#xff0c;也就是身段越高&#xff0c;时间管理的颗粒度越高。比尔盖茨的颗粒度是5分钟&#xff0c;精确到与人握手&#xff0c;按秒来安排&#xff01;接下来&…

Vue3打包发布,刷新出现的空白页面和错误

Vue3打包发布出现的错误&#xff1a;Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of text/html. Strict MIME type checking is enforced for module scripts per HTML spec. 第一次点击访问到这个路径&…

如何选择一款适合自己的鼠标?

在今天的数字时代&#xff0c;鼠标已经成为人们日常办公和娱乐的不可或缺的工具之一。然而&#xff0c;市面上各式各样的鼠标琳琅满目&#xff0c;如何选择一款适合自己的鼠标成为了一个令人困惑的问题。 鼠标的类型 在选择鼠标时&#xff0c;首先需要了解鼠标的类型。常见的…

前端遇见复杂的数据结构怎么办?

对象包含一个属性名会变的数组 for (let [name, value] of Object.entries(res.data)) {console.log(name,value)} 即可解决 语法&#xff1a;Object.entries(obj) 返回值&#xff1a;给定对象自身可枚举属性的键值对数组。 const obj { name: xiaoming, age: seven,sex: man,…