最近遇到问题:需要通过单应矩阵H(homography)分解出相机的R和t。当然,在opencv的C++版本中封装有实现这个功能的函数(然而在其js版本中就去掉了,不知道为什么…)。
但是,在opencv的官方文档中,函数的接口(输入输出参数)的参数类型全是清一色的Array或者ArrayOfArray。然而,opencv中Array的类型千千万,你如果用错了,他还会给你报错“内存X…… 出现错误”。
下文将展示我摸索出的可行参数类型。
decomposeHomographyMat函数该函数可以通过单应矩阵求出可能的四组R和t,然而想得到真实解,还需要结合filterHomographyDecompByVisibleRefpoints函数。
详细函数介绍见官方文档(我这里用的opencv3.4.15):
https://docs.opencv.org/3.4.15/d9/d0c/group__calib3d.html#ga7f60bdff78833d1e3fd6d9d0fd538d92
可以看到,这个说明文档为该函数提供的接口可以说是相当绝望。于是我找到该函数源码,见:
https://github.com/opencv/opencv/blob/master/modules/calib3d/src/homography_decomp.cpp
通过分析,下面直接放我使用这个函数时的代码:
vectorfilterHomographyDecompByVisibleRefpoints函数R, t, n;//旋转矩阵R、平移矩阵t、关键点所在平面的法向量n Mat homography_matrix = (Mat_ (3, 3) << 1.020205, -0.297803580, 150.1813964, 0.305915176, 0.929503381, -9.5677337, 0.00021775, -0.000026478477, 1); Mat K = (Mat_ (3, 3) << 20, 0, 320, 0, 20, 240, 0, 0, 1);//K是相机内参,这里我只知道光心,所以剩下的参数随便弄的。 //这样做问题不大,只要保证光心对就行,毕竟最后求出来的t也是无尺度的(也就是说对于这个H,相机的t可能是任意倍的t)。 //如果你想知道准确的K,opencv中有实现这个的函数。 int solutions = decomposeHomographyMat(homography_matrix, K, R, t, n);//这里的solutions是找到几组解,一般来说是4
该函数通过已知的匹配点坐标(2D),从求解出的4组解中筛选出真实解。但是据我实验,该函数好像并不能保证一定能找到真实解,有时候它只能将真实解所在范围缩小到两个解中,不过所幸的是大部分情况都能将真实解筛选出来(也可能是因为我的匹配点的canvas坐标到投影平面的坐标转换不对)。
详细函数介绍见官方文档(我这里用的opencv3.4.15):
https://docs.opencv.org/3.4.15/d9/d0c/group__calib3d.html#ga32f867159200f7bd55e72dca92d8494c
这个函数的源码见下面这个文见最后一点部分:
https://github.com/opencv/opencv/blob/master/modules/calib3d/src/homography_decomp.cpp
同样的,下面给出我是用这个函数的过程:
vector完整代码pointMask;//匹配点对是否有效 vector sol;//存放真实解序号 vector pattern_xy, screen_xy;//特征点与其对应的匹配点 for (int i = 0; i < 3; i++) { pointMask.push_back(1);//我当时找了三对点先试试,全设成有效 } pattern_xy.push_back(Point2f(149-320, 240-32));//因为我原本的坐标(149,32)是使用的canvas的坐标系,也就是原点在左上角,y轴冲下。 //虽然我不知道相机投影的缩放参数,但至少要根据光心(320,240)把坐标轴变过来。 pattern_xy.push_back(Point2f(212-320, 240-78)); pattern_xy.push_back(Point2f(186-320, 240-35)); screen_xy.push_back(Point2f(284-320, 240-64)); screen_xy.push_back(Point2f(327-320, 240-122)); screen_xy.push_back(Point2f(316-320, 240-76)); filterHomographyDecompByVisibleRefpoints(R, n, pattern_xy, screen_xy, sol, pointMask);
下面是我的整个完整代码:
#include#include #include #include #include // #include "extra.h" // use this if in OpenCV2 using namespace std; using namespace cv; int main() { vector R, t, n; vector pointMask; vector sol; vector pattern_xy, screen_xy; for (int i = 0; i < 3; i++) { pointMask.push_back(1); } pattern_xy.push_back(Point2f(149-320, 240-32)); pattern_xy.push_back(Point2f(212-320, 240-78)); pattern_xy.push_back(Point2f(186-320, 240-35)); screen_xy.push_back(Point2f(284-320, 240-64)); screen_xy.push_back(Point2f(327-320, 240-122)); screen_xy.push_back(Point2f(316-320, 240-76)); Mat homography_matrix = (Mat_ (3, 3) << 1.020205, -0.297803580, 150.1813964, 0.305915176, 0.929503381, -9.5677337, 0.00021775, -0.000026478477, 1); Mat K = (Mat_ (3, 3) << 20, 0, 320, 0, 20, 240, 0, 0, 1); int solutions = decomposeHomographyMat(homography_matrix, K, R, t, n); filterHomographyDecompByVisibleRefpoints(R, n, pattern_xy, screen_xy, sol, pointMask); for (int i = 0; i < solutions; ++i) { cout << "======== " << i << " ========" << endl; cout << "rotation" << i << " = " << endl; cout << R.at(i) << endl; cout << "translation" << i << " = " << endl; cout << t.at(i) << endl; cout << "n" << i << " = " << endl; cout << n.at(i) << endl; } cout << "the real solution num is : " << sol.size()<



