第七节、双目视觉之空间坐标计算

 在上一节我们已经介绍了如何对相机进行标定。然后获取相机的内部参数,外部参数。

内参包括焦距、主点、倾斜系数、畸变系数:

$$M=\begin{bmatrix} f_x & γ & u_0 \\ 0 & f_y & v_0  \\ 0  & 0 & 1\end{bmatrix}$$

其中$\gamma$为坐标轴倾斜参数,理想情况下为0。

外参包括旋转矩阵$R$、平移向量$T$,它们共同描述了如何把点从世界坐标系转换到摄像机坐标系,旋转矩阵描述了世界坐标系的坐标轴相对于摄像机坐标轴的方向,平移向量描述了在摄像机坐标系下空间原点的位置。

人类可以看到3维立体的世界,是因为人的两只眼睛,从不同的方向看世界,两只眼睛中的图像的视差,让我们可以看到三维立体的世界。类似的,要想让计算机“看到”三维世界,就需要使用至少两个摄像头构成双目立体视觉系统。

这里我们想要通过获取三维空间物体的坐标有两种方法,下面会介绍。

一、自己动手实现(只进行图片矫正、不进行立体校正)

1、标定双目后,首先要根据其畸变系数来矫正原图,这里用来去除图片的畸变:

        cv::Mat mapx = cv::Mat(imageSize, CV_32FC1);
        cv::Mat mapy = cv::Mat(imageSize, CV_32FC1);
        cv::Mat R = cv::Mat::eye(3, 3, CV_32F);
        std::cout << "显示矫正图像" << endl;
        for (int i = 0; i != imageCount; i++)
        {
            std::cout << "Frame #" << i + 1 << "..." << endl;
            //计算图片畸变矫正的映射矩阵mapx、mapy(不进行立体校正,立体校正需要利用双摄)
            initUndistortRectifyMap(cameraMatrix, distCoeffs, R, cameraMatrix, imageSize, CV_32FC1, mapx, mapy);
            //读取一张图片
            Mat imageSource = imread(filenames[i]);
            Mat newimage = imageSource.clone();
            //另一种不需要转换矩阵的方式
            //undistort(imageSource,newimage,cameraMatrix,distCoeffs);
            //进行校正
            remap(imageSource, newimage, mapx, mapy, INTER_LINEAR);
            imshow("原始图像", imageSource);
            imshow("矫正后图像", newimage);
            waitKey();
        }

2、坐标计算

上一节我们介绍了从世界坐标系到像素坐标系的转换:

其中${\begin{bmatrix} u & v & 1 \end{bmatrix}}^T$为矫正后的图像中的点在像素坐标系中的坐标,${\begin{bmatrix} x_w & y_w &  z_w & 1 \end{bmatrix}}^T$为点在世界坐标系中的坐标。

现在我们来研究一下从像素坐标系到世界坐标系的转换:

光轴会聚模型(两个摄像机的像平面不是平行的):

对于左右相机分别有:

将上面两式整理可以得到:

采用最小二乘法求解$X$,$Y$,$Z$,在opencv中可以用solve(A,B,XYZ,DECOMP_SVD)求解:

代码如下(来源于网上):

//opencv2.4.9 vs2012
#include <opencv2\opencv.hpp>
#include <fstream>
#include <iostream>
 
using namespace std;
using namespace cv;
 
Point2f xyz2uv(Point3f worldPoint,float intrinsic[3][3],float translation[1][3],float rotation[3][3]);
Point3f uv2xyz(Point2f uvLeft,Point2f uvRight);
 
//图片对数量
int PicNum = 14;
 
//左相机内参数矩阵
float leftIntrinsic[3][3] = {
   4037.82450,             0,        947.65449,
                                      0,    3969.79038,        455.48718,
                                      0,             0,                1};
//左相机畸变系数
float leftDistortion[1][5] = {
   0.18962, -4.05566, -0.00510, 0.02895, 0};
//左相机旋转矩阵
float leftRotation[3][3] = {
   0.912333,        -0.211508,         0.350590, 
                            0.023249,        -0.828105,        -0.560091, 
                            0.408789,         0.519140,        -0.750590};
//左相机平移向量
float leftTranslation[1][3] = {-127.199992, 28.190639, 1471.356768};
 
//右相机内参数矩阵
float rightIntrinsic[3][3] = {
   3765.83307,             0,        339.31958,
                                        0,    3808.08469,        660.05543,
                                        0,             0,                1};
//右相机畸变系数
float rightDistortion[1][5] = {-0.24195, 5.97763, -0.02057, -0.01429, 0};
//右相机旋转矩阵
float rightRotation[3][3] = {-0.134947,         0.989568,        -0.050442, 
                              0.752355,         0.069205,        -0.655113, 
                             -0.644788,        -0.126356,        -0.753845};
//右相机平移向量
float rightTranslation[1][3] = {
   50.877397, -99.796492, 1507.312197};
 
 
int main()
{
    //已知空间坐标求像素坐标
    Point3f point(700,220,530);
    cout<<"左相机中坐标:"<<endl;
    cout<<xyz2uv(point,leftIntrinsic,leftTranslation,leftRotation)<<endl;
    cout<<"右相机中坐标:"<<endl;
    cout<<xyz2uv(point,rightIntrinsic,rightTranslation,rightRotation)<<endl;
 
    //已知左右相机像素坐标求空间坐标
    Point2f l = xyz2uv(point,leftIntrinsic,leftTranslation,leftRotation);
    Point2f r = xyz2uv(point,rightIntrinsic,rightTranslation,rightRotation);
    Point3f worldPoint;
    worldPoint = uv2xyz(l,r);
    cout<<"空间坐标为:"<<endl<<uv2xyz(l,r)<<endl;
 
    system("pause");
 
    return 0;
}
 
 
//************************************
//
  • 9
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值