首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >OpenCV: solvePnP检测问题

OpenCV: solvePnP检测问题
EN

Stack Overflow用户
提问于 2013-11-08 00:49:21
回答 3查看 7.7K关注 0票数 20

我在使用OpenCV精确检测标记时遇到了问题。

我录制了关于这个问题的视频:http://youtu.be/IeSSW4MdyfU

如你所见,我检测到的标记在某些相机角度上有轻微的移动。我在网上读到这可能是摄像机校准问题,所以我会告诉你们我是如何校准摄像机的,也许你们能告诉我我做错了什么?

一开始,我从各种图像中收集数据,并将校准角点存储在_imagePoints矢量中,如下所示

代码语言:javascript
运行
AI代码解释
复制
std::vector<cv::Point2f> corners;
_imageSize = cvSize(image->size().width, image->size().height);

bool found = cv::findChessboardCorners(*image, _patternSize, corners);

if (found) {
    cv::Mat *gray_image = new cv::Mat(image->size().height, image->size().width, CV_8UC1);
    cv::cvtColor(*image, *gray_image, CV_RGB2GRAY);

    cv::cornerSubPix(*gray_image, corners, cvSize(11, 11), cvSize(-1, -1), cvTermCriteria(CV_TERMCRIT_EPS+ CV_TERMCRIT_ITER, 30, 0.1));

    cv::drawChessboardCorners(*image, _patternSize, corners, found);
}

_imagePoints->push_back(_corners);

然后,在收集了足够的数据后,我用下面的代码计算相机矩阵和系数:

代码语言:javascript
运行
AI代码解释
复制
std::vector< std::vector<cv::Point3f> > *objectPoints = new std::vector< std::vector< cv::Point3f> >();

for (unsigned long i = 0; i < _imagePoints->size(); i++) {
    std::vector<cv::Point2f> currentImagePoints = _imagePoints->at(i);
    std::vector<cv::Point3f> currentObjectPoints;

    for (int j = 0; j < currentImagePoints.size(); j++) {
        cv::Point3f newPoint = cv::Point3f(j % _patternSize.width, j / _patternSize.width, 0);

        currentObjectPoints.push_back(newPoint);
    }

    objectPoints->push_back(currentObjectPoints);
}

std::vector<cv::Mat> rvecs, tvecs;

static CGSize size = CGSizeMake(_imageSize.width, _imageSize.height);
cv::Mat cameraMatrix = [_userDefaultsManager cameraMatrixwithCurrentResolution:size]; // previously detected matrix
cv::Mat coeffs = _userDefaultsManager.distCoeffs; // previously detected coeffs
cv::calibrateCamera(*objectPoints, *_imagePoints, _imageSize, cameraMatrix, coeffs, rvecs, tvecs);

结果就像你在视频中看到的一样。

我做错了什么?这是代码中的一个问题吗?我应该使用多少图像来执行校准(目前我正在尝试在校准结束前获取20-30张图像)。

我应该使用包含错误检测到的棋盘角点的图像,如下所示:

或者我应该只使用正确检测的棋盘,如下所示:

我一直在尝试圆圈网格而不是棋盘,但结果比现在差得多。

如果有人问我是如何检测标记的:我正在使用solvepnp函数:

代码语言:javascript
运行
AI代码解释
复制
solvePnP(modelPoints, imagePoints, [_arEngine currentCameraMatrix], _userDefaultsManager.distCoeffs, rvec, tvec);

通过如下方式指定modelPoints:

代码语言:javascript
运行
AI代码解释
复制
    markerPoints3D.push_back(cv::Point3d(-kMarkerRealSize / 2.0f, -kMarkerRealSize / 2.0f, 0));
    markerPoints3D.push_back(cv::Point3d(kMarkerRealSize / 2.0f, -kMarkerRealSize / 2.0f, 0));
    markerPoints3D.push_back(cv::Point3d(kMarkerRealSize / 2.0f, kMarkerRealSize / 2.0f, 0));
    markerPoints3D.push_back(cv::Point3d(-kMarkerRealSize / 2.0f, kMarkerRealSize / 2.0f, 0));

imagePoints是处理图像时标记角点的坐标(我正在使用自定义算法来实现)

EN

回答 3

Stack Overflow用户

发布于 2013-11-24 10:57:08

为了正确调试你的问题,我需要所有的代码:-)

我假设您正在遵循@kobejohn在他的comment中引用的教程(calibrationpose)中建议的方法,因此您的代码遵循以下步骤:

  1. 收集棋盘目标的各种图像
  2. 在点1)的图像中查找棋盘角1)
  3. 校准相机(使用cv::calibrateCamera),因此获得内部相机参数(让我们称它们为intrinsic)和镜头失真参数(让我们称它们为您自己自定义目标的图像(目标可在0:57 in your video上看到),如下图<代码>H216<代码>G217所示

并在其中找到一些相关点(让我们将您在图像image_custom_target_vertices中找到的点命名为world_custom_target_vertices,并将相应的3D点命名为该点)。

  1. 估计相机的旋转矩阵(我们称其为R)和平移向量(我们称其为t)来自您在点4中获得的自定义目标的图像),通过像这样的cv::solvePnP调用cv::solvePnP(world_custom_target_vertices,image_custom_target_vertices,intrinsic,distortion,R,t)
  2. 在3D中给出8个角的立方体(让我们称它们为world_cube_vertices),您可以通过像这样的cv2::projectPoints调用获得8个2D图像点(让我们称它们为draw )。

现在,绘制过程的最终结果取决于所有以前计算的数据,我们必须找出问题所在:

Calibration:正如您在answer中观察到的,在3)中,您应该丢弃未正确检测到角点的图像。你需要一个重新投影误差的阈值,以便丢弃“坏的”棋盘目标图像。引用自calibration tutorial

重新投影错误

重新投影误差很好地估计了找到的参数的精确度。这应该尽可能接近于零。给定固有矩阵、失真矩阵、旋转矩阵和平移矩阵,我们首先使用cv2.projectPoints()将对象点转换为图像点。然后,我们计算我们通过变换得到的结果和角点查找算法之间的绝对范数。为了找到平均误差,我们计算所有校准图像的误差的算术平均值。

通常你会通过一些实验找到一个合适的阈值。有了这个额外的步骤,您将获得更好的intrinsicdistortion值。

查找您自己的自定义目标:在我标记为第4点的步骤中,您似乎没有解释如何查找您自己的自定义目标。你得到预期的image_custom_target_vertices了吗?你会丢弃那些结果“不好”的图像吗?

相机的姿势:我想你在5)中使用了3)中的intrinsic,你确定在此期间相机没有任何变化吗?参考Callari's Second Rule of Camera Calibration

摄像机校准第二条规则:“校准后不得触摸镜头”。特别是,您不能重新调焦或更改f光圈,因为调焦和光圈都会影响非线性镜头失真和(尽管影响较小,取决于镜头)视野。当然,您可以完全自由地更改曝光时间,因为它根本不会影响镜头的几何形状。

然后在draw函数中可能会有一些问题。

票数 5
EN

Stack Overflow用户

发布于 2013-11-20 00:36:44

所以,我已经用我的代码做了很多实验,我仍然没有修复主要的问题(移动对象),但我已经设法回答了我提出的一些校准问题。

首先-为了获得良好的校准结果,你必须使用正确检测到网格元素/圆位置的图像!。在校准过程中使用所有捕获的图像(即使是那些没有正确检测的图像)将导致糟糕的校准。

我尝试过各种校准模式:

  • Asymmetric circles (CALIB_CB_ASYMMETRIC_GRID),得到的结果比其他任何模式都差得多。说到更糟糕的结果,我的意思是它会产生很多像这样的错误检测到的角落:

我已经用CALIB_CB_CLUSTERING做了实验,但效果不是很好--在某些情况下(不同的光环境),它变得更好了,但效果不是很好。

  • Symmetric circles (CALIB_CB_SYMMETRIC_GRID) -比非对称网格更好的结果,但我得到的结果仍然比标准网格(棋盘)差得多。它通常会产生这样的错误:

  • Chessboard (使用findChessboardCorners函数找到)-此方法可以产生最佳结果-它不会经常产生未对齐的角点,并且几乎每个校准都会产生与对称圆grid

的最佳结果相似的结果

对于每一次校准,我都使用了20-30张来自不同角度的图像。我甚至尝试过100+图像,但与较小数量的图像相比,它在校准结果上并没有产生明显的变化。值得注意的是,更多的测试图像增加了以非线性方式计算相机参数所需的时间( 480x360分辨率的100张测试图像在iPad4中计算25分钟,而约50张图像计算4分钟)

我也尝试过solvePNP参数,但也没有给我任何可接受的结果:我尝试了所有3种检测方法(ITERATIVEEPNPP3P),但我没有看到明显的变化。

此外,我还尝试了将useExtrinsicGuess设置为true,并使用了之前检测到的rvectvec,但这次检测到的立方体完全消失了。

我的想法已经用完了--还有什么会影响这些转移问题呢?

票数 2
EN

Stack Overflow用户

发布于 2015-07-24 15:51:44

对于那些仍然感兴趣的人:这是一个老问题,但我认为你的问题不是糟糕的校准。我使用OpenCV和SceneKit为iOS开发了一个AR应用程序,我也遇到过同样的问题。

我认为你的问题是立方体的渲染位置错误:OpenCV的solvePnP返回标记中心的X,Y,Z坐标,但你想在标记上渲染立方体,沿着标记的Z轴的特定距离,恰好是立方体侧面大小的一半。因此,您需要改进此距离的标记平移向量的Z坐标。

实际上,当你从顶部看到你的立方体时,这个立方体被正确地渲染了。我已经做了一张图片来解释这个问题,但是我的名声阻止了我把它贴出来。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19849683

复制
相关文章
GTX/GTH/GTY/GTP/GTZ/GTM有什么区别?
  不同芯片上使用的高速收发器也不同,而且同样是GTX,不同系列芯片上的速率也可能不同。
猫叔Rex
2022/01/24
1.8K0
GTX/GTH/GTY/GTP/GTZ/GTM有什么区别?
都是net,有什么区别
pin与pin之间都是通过net相连的,可以看到net举足轻重的地位。通过net可以找到与之相连的pin或cell,而net本身也有一些重要的属性。
Lauren的FPGA
2020/02/17
1.6K0
都是net,有什么区别
都是pin,有什么区别
打开任何阶段的DCP,选中一个cell,按F4,都会显示其Schematic视图。在这个视图中,可以清楚地看到每个cell的pin。小到一个触发器、查找表,大到用户的RTL模块甚至整个顶层设计,都有相应的pin。这里,我们重点了解一下pin的特征,借助这些特征可以帮助我们高效地搜到到目标pin。
Lauren的FPGA
2020/02/17
3.8K0
都是pin,有什么区别
网站https证书种类有哪些?有什么区别
  网站https证书可分为2大类,一类按照验证方式进行分类,即:DV SSL证书、OV SSL证书、EV SSL证书。另一类按照域名数量进行分类,即:单域名SSL证书、多域名SSL证书、通配符证书。
安信SSL证书
2019/07/31
5.5K0
网站https证书种类有哪些?有什么区别
蓝牙和WiFi有什么区别?
如果您拥有手机、笔记本电脑、计算机或任何其他现代电子设备,知道蓝牙和 WiFi 。
网络技术联盟站
2021/11/05
2.2K0
蓝牙和WiFi有什么区别?
OracleJDK和OpenJDK有什么区别?
Oracle JDK与OpenJDK里的JVM都是HotSpot VM。从源码层面说,两者基本上是同一个东西。
码农架构
2021/09/18
2K0
OracleJDK和OpenJDK有什么区别?
Closeable和AutoCloseable有什么区别?
导读:我们知道,在java中jvm虚拟机会自动去调用gc(垃圾回收器)去回收堆中没有被引用的对象,至于什么时候回收,是不确定的,同时有些是用到其他资源,jvm也不会进行回收,类似Io流中的FileInputStream使用到了硬盘资源,垃圾回收器是不会去回收的,因此,必须手动关闭掉。我们进行手动的编写close()方法进行关闭,然而,每次这些写会造成代码冗余不优雅,JDK中对于释放资源有Closeable和AutoCloseable可以使用,以下为详解。
码农架构
2021/04/22
3.2K0
Closeable和AutoCloseable有什么区别?
String、StringBuffer、StringBuilder有什么区别?
String 是 Java 语言非常基础和重要的类, 提供了构造和管理字符串的各种基本逻辑。它是典型的 Immutable 类,被声明成为 final class,所有属性也都是 final 的。也由于它的不可变性,类似拼接、裁剪字符串等动作,都会产生新的 String 对象。由于字符串操作的普遍性,所以相关操作的效率往往对应用性能有明显影响。
葆宁
2019/04/18
4660
Exception和Error有什么区别?
世界上存在永远不会出错的程序吗?也许这只会出现在程序员的梦中。随着编程语言和软件的诞生,异常情况就如影随形地纠缠着我们,只有正确处理好意外情况,才能保证程序的
灬沙师弟
2022/09/06
1.5K0
int和Integer有什么区别?
Java虽然号称是面向对象的语言,但是原始数据类型仍然是重要的组成元素,所以在面试中,经常考察原始数据类型和包装类等Java语言特性。
灬沙师弟
2022/10/07
4.1K1
kubernetes和docker有什么区别
本教程操作环境:linux5.9.8系统、docker-1.13.1版、Dell G3电脑。
码农编程进阶笔记
2023/03/23
2.1K0
kubernetes和docker有什么区别
声明和定义有什么区别
问题 C/C++ 中,声明和定义有什么区别? 回答 1. 声明不分配存储空间,定义会分配。 定义会实实在在地创造这个东西,而声明只是告诉编译器有这么个东西,它的创造在别处。 extern int bar; // 声明 extern int g(int, int); // 声明 double f(int, double); // 声明 class foo; // 声明 int bar; // 定义 int g(int lhs, int rhs) {return lhs*rhs;} // 定义 double
ClearSeve
2022/02/11
1.6K0
沪市和深市有什么区别?
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/168351.html原文链接:https://javaforall.cn
全栈程序员站长
2022/09/20
1.6K0
列表和元组有什么区别
如果有了解过python中的列表和元组,你可能会知道相对于列表,元组是不可变的,也就是说元组中的数据不能随意更改。除了列表是用中括号表示而元组是用小括号表示之外,这两种数据类型好像并没有什么不同,都是用来存放一系列的数据,事实真是如此吗? TypeError Traceback (most recent call last) in() 4 5 # 现在改变b中数据的值 — 6 b[2] = 4 TypeError: ‘tuple’ obje
企鹅号小编
2018/02/26
2K0
列表和元组有什么区别
Jsp和Servlet有什么区别?
Web容器加载Servlet并将其实例化后,Servlet生命周期开始,容器运行其init()方法进行Servlet的初始化;请求到达时调用Servlet的service()方法,service()方法会根据需要调用与请求对应的doGet或doPost等方法;当服务器关闭或项目被卸载时服务器会将Servlet实例销毁,此时会调用Servlet的destroy()方法。
李红
2019/08/28
2.5K0
Jsp和Servlet有什么区别?
集群 跟 分片 有什么区别
而 redis  这样的 “集群” 强调的是  数据 ,(因为redis 主要是来存数据的嘛)
矿泉水
2018/05/21
2.7K0
Exception和Error 有什么区别
checkedException 一般是外部错误,这个异常发生在编译阶段。Java 编译器会强制去捕获此类异常。一般会要求把这段可能出现的异常程序进行 try catch。
王小明_HIT
2019/10/15
1.7K0
final 、finally、finalize有什么区别
finall 是Java中保证代码一定要被执行的一种机制,我们可以使用 try-finally 或者 try-catch-finally 来进行类似关闭JDBC,unlock 锁等动作。
王小明_HIT
2019/11/04
8340
int 和 Integer 有什么区别?
int 是 java 的原始数据类型,Integer 是 java 为 int 提供的封装类。
MickyInvQ
2020/09/27
1.6K0
集群 跟 分片 有什么区别
而 redis  这样的 “集群” 强调的是  数据 ,(因为redis 主要是来存数据的嘛)
用户2141593
2019/02/20
7850

相似问题

BreakPointObserver角

34

BreakpointObserver不点火

10

wolfSSL对MBEDTLS对OpenSSL -有什么区别?

16

IoTivity对AllJoyn -有什么区别?

617

$dirty对$invalid:有什么区别?

53
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文