cv::solvePnP使用方法及注意点详解(OpenCV/C++)

这篇具有很好参考价值的文章主要介绍了cv::solvePnP使用方法及注意点详解(OpenCV/C++)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

cv::solvePnP(objectPoints, imagePoints, cameraMatrix, distCoeffs, rvec, tvec, useExtrinsicGuess, flags);

1、参数说明:

  • objectPoints:一个 vector<cv::Point3f>,包含了在世界坐标系中的三维点的坐标,至少需要4个点。
  • imagePoints:一个 vector<cv::Point2f>,包含了对应的图像上的二维点的坐标,与 objectPoints 中的点一一对应。
  • cameraMatrix:相机的内参数矩阵,类型为 cv::Mat,一般为 3x3 的浮点数矩阵。
  • distCoeffs:相机的畸变系数,类型为 cv::Mat,一般为 4x1 或 5x1 的浮点数矩阵。
  • rvec:输出的旋转向量,类型为 cv::Mat,是大小为 3x1 的浮点数矩阵。
  • tvec:输出的平移向量,类型为 cv::Mat,是大小为 3x1 的浮点数矩阵。
  • useExtrinsicGuess:一个布尔值,表示是否使用可选的旋转和平移向量的初始猜测。默认为 false。
  • flags:一个用于控制函数行为的选项标志,默认为 0。

        函数返回:

  • 成功返回 true,失败返回 false。

2、使用说明:

objectPoints, imagePoints, cameraMatrix, distCoeffs  四个参数作为输入参数

rvec, tvec 作为输出参数

objectPoints是世界坐标系的三维坐标

imagePoints是图像上的二维点坐标

例如 使用标定好的单目相机拍摄一个矩形物体(已知相机内参&畸变系数),

objectPoints:使用量尺测量物体的左上角、右上角、左下角、右下角之间的距离,以任意一个点作为0点,建立世界坐标系,z值设为0,得到所有点的坐标则为objectPoints,保存在vector中。

imagePoints:在图像中找到物体的左上角、右上角、左下角、右下角四个点,其所有点的像素坐标为imagePoints,保存在vector中。

使用示例:

#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>

int main() {
    std::vector<cv::Point3f> objectPoints;  // 世界坐标系中的三维点
    std::vector<cv::Point2f> imagePoints;   // 图像上的二维点
    
    // 添加 objectPoints 和 imagePoints 的数据
    
    // 创建相机内参数矩阵
    cv::Mat cameraMatrix = (cv::Mat_<double>(3,3) << fx, 0, cx, 0, fy, cy, 0, 0, 1);  
    // 创建相机畸变系数矩阵
    cv::Mat distCoeffs = (cv::Mat_<double>(1,5) << k1, k2, p1, p2, k3;
    
    //完善内参参数&畸变系数参数  
    
    cv::Mat rvec;  // 输出的旋转向量
    cv::Mat tvec;  // 输出的平移向量
    
    bool success = cv::solvePnP(objectPoints, imagePoints, cameraMatrix, distCoeffs, rvec, tvec);
    
    if (success) {
        // 获取旋转向量和平移向量的结果
        cv::Mat rotationMatrix;
        cv::Rodrigues(rvec, rotationMatrix);

        std::cout << "Rotation Vector:" << std::endl << rvec << std::endl;
        std::cout << "Translation Vector:" << std::endl << tvec << std::endl;
        std::cout << "Rotation Matrix:" << std::endl << rotationMatrix << std::endl;
    }
    
    return 0;
}

3、注意事项:

在使用solvePnP时,需注意objectPoints和imagePoints容器中的点坐标必须一一对应,例如只有四个点时,全部按左上角、右上角、左下角、右下角的顺序存放在容器中;如果顺序不相同,则最终输出值有误。

在笔者使用solvePnP时,拍摄物是四个定位圆,圆的像素坐标是通过opencv的SimpleBlobDetector识别的,识别以后的圆像素坐标是无序的,无法和objectPoints对应上,因此有了下述算法,

用于为四个二维坐标做冒泡排序得到左上角、右上角、左下角、右下角分别对应的点

(如果没有该需求,可以忽略此段)

int main() {
    std::vector<cv::Point2f> imagePoints; // 存放四个点的 vector

    // 假设已经将四个点的坐标存入 imagePoints 中

    // 寻找左上角、右上角、右下角和左下角对应的点
    cv::Point2f topLeft, topRight, bottomRight, bottomLeft;
    float minX = FLT_MAX, minY = FLT_MAX;
    float maxX = FLT_MIN, maxY = FLT_MIN;

    for (const auto& point : imagePoints) {
        if (point.x <= minX && point.y <= minY) {
            topLeft = point;
            minX = point.x;
            minY = point.y;
        }
        if (point.x >= maxX && point.y <= minY) {
            topRight = point;
            maxX = point.x;
            minY = point.y;
        }
        if (point.x >= maxX && point.y >= maxY) {
            bottomRight = point;
            maxX = point.x;
            maxY = point.y;
        }
        if (point.x <= minX && point.y >= maxY) {
            bottomLeft = point;
            minX = point.x;
            maxY = point.y;
        }
    }

    // 输出左上角、右上角、右下角和左下角对应的点的坐标
    std::cout << "左上角坐标: (" << topLeft.x << ", " << topLeft.y << ")" << std::endl;
    std::cout << "右上角坐标: (" << topRight.x << ", " << topRight.y << ")" << std::endl;
    std::cout << "右下角坐标: (" << bottomRight.x << ", " << bottomRight.y << ")" << std::endl;
    std::cout << "左下角坐标: (" << bottomLeft.x << ", " << bottomLeft.y << ")" << std::endl;

    // 新建一个vector存放四个点坐标,按照objectPoints的存放顺序进行存放
    std::vector<cv::Point2f> imagePoints2; 
    imagePoints2.push_back(topLeft);
    imagePoints2.push_back(topRight);
    imagePoints2.push_back(bottomRight);
    imagePoints2.push_back(bottomLeft);

    return 0;
}

4、补充

通过solvePnP得到旋转向量rvec和平移向量tvec后,可以计算相机到被测物中心的实际距离文章来源地址https://www.toymoban.com/news/detail-752665.html

#include <cmath>
#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>

int main() {
    std::vector<cv::Point3f> objectPoints;  // 世界坐标系中的三维点
    std::vector<cv::Point2f> imagePoints;   // 图像上的二维点
    
    // 添加 objectPoints 和 imagePoints 的数据
    
    // 创建相机内参数矩阵
    cv::Mat cameraMatrix = (cv::Mat_<double>(3,3) << fx, 0, cx, 0, fy, cy, 0, 0, 1);  
    // 创建相机畸变系数矩阵
    cv::Mat distCoeffs = (cv::Mat_<double>(1,5) << k1, k2, p1, p2, k3;
    
    //完善内参参数&畸变系数参数  
    
    cv::Mat rvec;  // 输出的旋转向量
    cv::Mat tvec;  // 输出的平移向量
    
    bool success = cv::solvePnP(objectPoints, imagePoints, cameraMatrix, distCoeffs, rvec, tvec);
    
    if (success) {
        //计算相机距离被测物的实际距离
        float distance = sqrt(tvec.at<double>(0,0) * tvec.at<double>(0,0) + tvec.at<double>(1,0) * tvec.at<double>(1,0) + tvec.at<double>(2,0) * tvec.at<double>(2,0)) / 10; 
        std::cout << "distance = "<< distance << std::endl;
    }
    
    return 0;
}

到了这里,关于cv::solvePnP使用方法及注意点详解(OpenCV/C++)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 使用Map.clear()、List.clear()方法,清空时注意!

    对 Map、List 对象进行清空操作时,常常会使用 clear() 方法。 例如,清空 Map 换做 List 也是同样的用法 本文想要说的是,需要注意,如果使用clear()方法, Map被清空的同时,原本对Map的引用会一起被清空!!! 代码举例: 这段代码也很简单,两层循环。 最里层向 listTemp 中添加

    2024年01月20日
    浏览(47)
  • Copilot使用的关卡——GitHub教育认证方法和注意事项

    问题描述: 想试一试copilot写代码功能,但是付费。好在github学生包里面可以免费用。但要Github Education认证,学生包认证,但认证过程中会有诸多问题,比如说拍照上传被多次打回。对于认证,可以不拍照,选择上传文件认证。试试下面的方法,亲测可以。 上传一个png文件的

    2024年02月11日
    浏览(56)
  • 一篇文章带你了解抖音来客功能的使用方法和注意事项

    抖音是近年来备受欢迎的社交媒体平台之一,其中的“来客”功能更是让许多人喜爱。那么什么是抖音来客呢?抖音来客是指在直播过程中,可以邀请其他抖音用户进行互动和参与,从而增加直播的热度和粉丝数量。下面不若与众科技就来介绍一下抖音来客的具体使用方法和

    2024年02月08日
    浏览(56)
  • element-plus el-form 表单、表单验证 使用方法、注意事项

    element-plus@2.0.6 及之后的版本,表单验证不再是同步执行的了 另外, element-plus@2.1.4 及之后的版本,才可按照官方文档示例正常使用(使用的是两者的中间版本的话,最好先自行确认下正确的 上例中: 如果在“ 位置1 ”执行表单验证通过后的业务代码,可以去掉 async...await 如

    2024年02月05日
    浏览(63)
  • Java中TreeSet的基本介绍,细节讨论,使用注意事项,常用方法,底层源码分析

    TreeSet 是 Java 中的一个有序集合实现,它基于红黑树数据结构来存储元素, 可以保持元素的自然顺序(默认情况下升序)或者根据自定义比较器来进行排序 。下面是关于 TreeSet 的基本介绍、细节讨论、使用注意事项、常用方法以及一些底层实现细节。 基本介绍: TreeSet 是

    2024年02月11日
    浏览(42)
  • OpenCV VideoWriter使用方法

    在opencv中提供很好用的录制视频的句柄,也可称之为类videowriter。 1、打开视频输出 cv::VideoWriter有两个构造函数,一个是默认构造函数,仅仅创建一个未初始化的VideoWriter对象用于之后的打开操作;另一个是拥有所需要的参数,并初始化VideoWriter对象,如下: 写视频时需要设置

    2024年02月06日
    浏览(33)
  • 随手笔记——OpenCV 的基础使用方法

    演示了如下几个操作:图像读取、显示、像素遍历、复制、赋值等。大部分的注解已写在代码里面。编译该程序时,需要在 CMakeLists.txt 中添加 OpenCV 的头文件,然后把程序链接到库文件上。同时,由于使用了 C++ 11 标准(如 nullptr 和 chrono),还需要设置一下编译器。

    2024年02月16日
    浏览(38)
  • 详解cv2.addWeighted函数【使用 OpenCV 添加(混合)两个图像-Python版本】

    有的时候我们需要将两张图片在alpha通道进行混合,比如深度学习数据集增强方式MixUp。OpenCV的 addWeighted 提供了相关操作,此篇博客将详细介绍这个函数,并给出代码示例。🚀🚀 o u t p u t I m g = s a t u r a t e ( α ∗ i n p u t I m g 1 + β ∗ i n p u t I m g 2 + γ ) rm outputImg=saturate( al

    2024年02月06日
    浏览(98)
  • opencv如何使用GPU的三种方法

    我在工作实验涉及到图像和视频处理时,通常使用opencv提供的库来做处理,虽然OpenCV是一个广泛使用的库,它提供了丰富的功能和工具。然而,有时候在处理大量图片或视频时,我们可能会面临速度受限的问题。 opencv执行图像处理,就跟我们电脑一样,打游戏CPU是来加载处理

    2024年02月11日
    浏览(46)
  • 【CV大模型SAM(Segment-Anything)】真是太强大了,分割一切的SAM大模型使用方法:可通过不同的提示得到想要的分割目标

    本文主要介绍SAM模型的使用方法:如何使用不同的提示进行目标分割。而且该模型在CPU的环境下就可以快速运行,真心不错~,赶紧来试试吧 关于Segment-Anything模型的 相关代码、论文PDF、预训练模型、使用方法 等,我都已打包好,供需要的小伙伴交流研究, 获取方式如下 : 关

    2023年04月18日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包