精华内容
下载资源
问答
  • 这个程序的作用是输入三角化和观测点的地图坐标和位姿,输出计算图像平面重投影误差
  • 在SFM(structure from motion)的计算中BA(Bundle Adjustment)作为最后一步优化具有很重要的作用,在近几年兴起的基于图的SLAM(simultaneous localization and mapping)算法里面使用了图优化替代了原来的滤波器...
  • 该方法以位姿估计初值为中心设置了约束区间, 建立新的罚函数将约束非线性优化转化为无约束非线性优化, 分析像平面重投影误差与约束区间的关系并建立相应的数学模型, 根据模型自动调节约束区间, 基于自适应重投影误差...
  • 重投影误差

    千次阅读 2019-09-25 11:33:13
    在计算机视觉中,经常会用到重投影误差(Reprojection error)。比如在计算平面单应矩阵和投影矩阵的时候,往往会使用重投影误差来构造代价函数,然后最小化这个代价函数,以优化单应矩阵或者投影矩阵。之所以使用...

    计算机视觉中,经常会用到重投影误差(Reprojection error)。比如在计算平面单应矩阵和投影矩阵的时候,往往会使用重投影误差来构造代价函数,然后最小化这个代价函数,以优化单应矩阵或者投影矩阵。之所以使用重投影误差,是因为它不光考虑了单应矩阵的计算误差,也考虑了图像点的测量误差,所以其精度会更高。 


     最小化重投影误差问题(Bundle Adjustment问题)---可以将位姿和三维特征点P同时优化

    在SLAM中优化求解相机运动位姿时(3D-2D),会用到重投影误差:是像素坐标(观测到的投影位置)与3D点按照当前估计的位姿进行投影得到的位置相比较得到的误差。

    如下图所示,我们通过特征匹配知道,观测值和  是同一个空间点的投影,的投影与观测值之间有一定的距离,也就是重投影误差。于是我们调整相机的位姿,使这个距离变小,由于这个调整需要考虑很多个点,所以最后每个点的误差通常不会精确到0。


     
     
     
    考虑到n个三维空间点P和他们的投影,我们希望计算R,t,用李代数表示为。假设某空间点,其投影的像素坐标为

    像素位置与空间点位置的关系如下:

    写成矩阵形式就是:

     由于相机位姿未知以及观测点的噪声,该等式存在一个误差。我们将误差求和,构建最小二乘问题,然后寻找做好的相机位姿,使它最小化:
    用高斯牛顿法/列文伯格-马夸尔特方法求解。

     

    补充:

    平面的单应性:从一个平面到另一个平面的投影映射 。
    用单应性描述平面物体的观测:从物体平面到图像平面的映射,同时表征了这两个平面的相对位置(外参)和相机投影矩阵(内参)。   


    以平面单应矩阵的计算为例,假设两幅图像中的对应点满足: 

    这里写图片描述 
    其中,H是平面单应矩阵,x和x’是图像中的对应点,则重投影误差的形式如下: 
    这里写图片描述 
    subject to: 
    这里写图片描述 
    其中,x^是x的估计值,H^是H的估计。最小化重投影误差就是优化H^和x^。从重投影误差公式可以看出,模型认为测量点并非绝对精确,而是存在一定的测量误差,因此需要重新估计图像点的坐标,而估计得到的新的图像点之间完美的满足单应关系。下图就是重投影误差的几何表述,d和d’的和即为重投影误差: 
    这里写图片描述 
    上面都是在假设图像点有测量误差的情况下讨论的,如果x和x’都是图像上的点,那么确实是满足上面的模型的。但是有一种特殊情形,那就是摄像机定位时通常都会遇见的,x不是图像点,而是平面标志点在世界坐标系下的坐标,只有x’是图像点。在这种情况下,由于标志点(例如:棋盘图上的角点)通常都是很标准的,都是严格按尺寸制定的,所以我们可以认为x是绝对准确的,那么此时只有x’存在测量误差。如下图: 
    这里写图片描述 
    此时,x的估计x^就是它本身,即x=x^,所以有: 
    这里写图片描述 
    那么重投影误差在强约束条件x=x^下就退化为: 
    这里写图片描述 
    上式即为单边变换误差(Transfer error)。 
    也就是说,如果给重投影误差加上约束条件x=x^,重投影误差就退化为单边变换误差,并且极大地简化了优化算法。同时,从上面的推导也可以得出结论:在使用已知标志点给摄像机定位时,重投影误差并非最好的选择,因为重投影误差模型会认为标志点存在误差,从而重新估计标志点的坐标,引入多余的误差;而此时,事实上,重投影误差已经退化为单边几何变换误差,所以在这种情况下,单边几何变换误差才是最好的代价函数。

     

    重投影误差与对称转移误差

                                                                                                                                                                                                            

    转载于:https://www.cnblogs.com/Jessica-jie/p/7242179.html

    展开全文
  • 为了解决这些问题,我们建议广义重投影误差最小化的两阶段优化方法(TwGREM),其中提出了一种广义的重投影误差框架,以将立体和轮廓提示整合到一个统一的能量中功能。 为了使函数最小化,我们首先在3D体积网格上...
  • Kalibr源码学习(一): 重投影误差 给自己挖一个大坑, 从标定结果来学习Kalibr的标定源码, 这里基本以KB模型为例, 也就是标定时, kalibr的模型设定为 --model pinhole-equi , 这里以重投影误差开始,希望能坚持; 重投影...

    Kalibr源码学习(一): 重投影误差

    给自己挖一个大坑, 从标定结果来学习Kalibr的标定源码, 这里基本以KB模型为例, 也就是标定时, kalibr的模型设定为 --model pinhole-equi , 这里以重投影误差开始,希望能坚持;

    重投影误差标定结果

    首先以重投影误差的txt文档的结果开始,
    标定结果
    可以看到上面的标定结果中, 重投影误差显示为 reprojection error: [-0.000002, -0.000000] +- [0.535272, 0.572115]
    这里的两项对应的分别是 reprojection error: [x方向的重投影误差均值, y方向的重投影误差均值] +- [x方向重投影误差方差, y方向重投影误差方差]

    其对应的代码片为:

    //获取当前检测的角点,重投影坐标, 重投影误差
    corners, reprojs, rerrs = getReprojectionErrors(cself, cidx) 
     if len(rerrs)>0:
     //获取重投影误差的均值me和方差se
     me, se = getReprojectionErrorStatistics(rerrs)
     //打印输出到txt文档中
     print >> dest, "\t reprojection error: [%f, %f] +- [%f, %f]" % (me[0], me[1], se[0], se[1])
     print >> dest
    

    这里可以再说以下计算均值和方差的python代码:

    在这里插入代码片
    ```def getReprojectionErrorStatistics(all_rerrs):
        #传入值是所有的误差 errors, 这里代码里面举出的例子usage是错误的,传入的应该是error,不是重投影
        if not len(all_rerrs)>0:
            raise RuntimeError("rerrs has invalid dimension")
    
        gc.disable() #append speed up
        rerr_matrix=list();
        for view_id, view_rerrs in enumerate(all_rerrs):
            if view_rerrs is not None: #if cam sees target in this view
                for rerr in view_rerrs:
                    if not (rerr==np.array([None,None])).all(): #if corner was observed
                        rerr_matrix.append(rerr) #将误差值统一放入到rerr_matrix中
        rerr_matrix = np.array(rerr_matrix)
        gc.enable()
        
        mean = np.mean(rerr_matrix, 0, dtype=np.float)#计算均值
        std = np.std(rerr_matrix, 0, dtype=np.float)#计算方差
     
        return mean, std
    

    重投影误差图像显示

    重投影误差
    这个图对应的代码为:

    def plotAllReprojectionErrors(cself, cam_id, fno=1, noShow=False, clearFigure=True, title=""):
        # left: observations and projecitons
        # right: scatterplot of reprojection errors
        all_corners, reprojections, rerrs_xy = getReprojectionErrors(cself, cam_id)
        resolution = (cself.cameras[cam_id].geometry.projection().ru(), cself.cameras[cam_id].geometry.projection().rv())
    
        #创建图像
        values = np.arange(len(cself.views))/np.double(len(cself.views))
        cmap = pl.cm.jet(values,alpha=0.5)
        
        #子图一用来画重投影后的坐标 省略
        a=pl.subplot(121)
    
        #子图二用来画重投影误差
        sub = pl.subplot(122)
        for view_id, rerrs in enumerate(rerrs_xy):
            if rerrs is not None: #if this camerea sees the target in this view
                color = cmap[view_id,:]
                pl.plot(rerrs[:,0], rerrs[:,1], 'x', lw=3, mew=3, color=color)
       # 主要是这里,x代表的是重投影的x误差, y表示的是重投影的y值误差, 以 error_x 为横坐标, 以error_y为纵坐标,画图
        pl.axis('equal')
        pl.grid('on')
        pl.xlabel('error x (pix)')
        pl.ylabel('error y (pix)')
    
        #省略...
    

    这里重点说一下获取重投影误差的函数, 经过层层调用, 最后计算出的其实是将三维点投影到图像上

    //将传入的三维点投影到图像上
    template<typename DISTORTION_T>
    template<typename DERIVED_P, typename DERIVED_K>
    bool PinholeProjection<DISTORTION_T>::euclideanToKeypoint(const Eigen::MatrixBase<DERIVED_P> & p,
        const Eigen::MatrixBase<DERIVED_K> & outKeypointConst) const {
      EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE_OR_DYNAMIC(Eigen::MatrixBase<DERIVED_P>, 3);
      EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE_OR_DYNAMIC(Eigen::MatrixBase<DERIVED_K>, 2);
      Eigen::MatrixBase<DERIVED_K> & outKeypoint = const_cast<Eigen::MatrixBase<DERIVED_K> &>(outKeypointConst);
       //shinan note: 转换到归一化相机平面 --> 加畸变 -->转换到像素平面
      outKeypoint.derived().resize(2);
      double rz = 1.0 / p[2];
      outKeypoint[0] = p[0] * rz;
      outKeypoint[1] = p[1] * rz;
       //加畸变
      _distortion.distort(outKeypoint);
    
      outKeypoint[0] = _fu * outKeypoint[0] + _cu;
      outKeypoint[1] = _fv * outKeypoint[1] + _cv;
    
      return isValid(outKeypoint) && p[2] > 0;
    }
    

    其中加畸变函数如下:

    //将传入的归一化相机坐标系的三维点按照公式加畸变
    template<typename DERIVED_Y>
    void EquidistantDistortion::distort(const Eigen::MatrixBase<DERIVED_Y> & yconst) const {
      EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE_OR_DYNAMIC(Eigen::MatrixBase<DERIVED_Y>, 2);
      Eigen::MatrixBase<DERIVED_Y> & y = const_cast<Eigen::MatrixBase<DERIVED_Y> &>(yconst);
      y.derived().resize(2);
      double r, theta, theta2, theta4, theta6, theta8, thetad, scaling;
      r = sqrt(y[0] * y[0] + y[1] * y[1]);
      theta = atan(r);
      theta2 = theta * theta;
      theta4 = theta2 * theta2;
      theta6 = theta4 * theta2;
      theta8 = theta4 * theta4;
      thetad = theta* (1 + _k1 * theta2 + _k2 * theta4 + _k3 * theta6 + _k4 * theta8);
    
      scaling = (r > 1e-8) ? thetad / r : 1.0;
      y[0] *= scaling;
      y[1] *= scaling;
    }
    

    总结

    这里有一点就是这里的重投影误差的均值很小, 主要的原因可以从上面的彩色图中看出, 重投影误差有正有负,均值会出现互相抵消的状态; 总体来讲是以(-0.000002, -0.000000)为中心, 方差分别是0.535272, 0.572115的正态分布;

    所以说,均值不可信,方差大概率更靠谱一些: 如下面标定的很好的结果中:
    reprojection error: [0.000000, 0.000001] ± [0.115878, 0.107625]
    方差仅为0.1, 其对应的重投影误差的值也都偏小:
    重投影误差较小一点
    根据3*sigma原则, 要想让大部分的重投影误差小于1个像素, 那么其所对应的方差应该是小于0.33.

    展开全文
  • 得到重投影误差很大达到了1.8像素。 然后我将同样的照片用ps将分辨率改为1080*对应的高,再次用matlab标定,重投影误差能降低到0.5以下,满足文献的要求。 为什么呢,同样一组照片,...
  • 主要是讲解Python利用OpenCV进行相机校正过程中,几个重点参数的分析...准确描述opencv自带的函数,和各个博客、教程里面所说的重投影误差计算的流程进行分析和对比,描述官方的重投影误差和教程实现重投影误差的差别。

    OpenCV 校正过程中,calibrateCamera函数的ret和重投影误差的分析


    一、前言

    本文主要是讲解Python利用OpenCV进行相机校正过程中,几个重点参数的分析。标定的过程就不再一一赘述了,很多博客和网站都在讲解怎么进行标定。本文章主要分析,标定过程中的误差计算公式,和对calibrateCamera( )projectPoints( ) 两个函数得到的误差不同的原因进行分析。

    本文重点分析重投影误差的计算方式。准确描述OpenCV自带的函数,和各个文档,教程里面所说的重投影误差计算的流程进行分析和对比,描述官方的重投影误差和教程实现重投影误差的差别。 我认为OpenCV官方和其他大多数地方的教程,给的重新计算重投影误差的结果,其计算的表达式,也是不准确的。

    正确的方法是相机校正的方法输出的重投影误差ret。使用的是RMS均方根误差。另外教程和博客,给的是MSE均方误差

    二、calibrateCamera( )函数分析

    ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(x_world, y_voltage, (224, 224), None, None)
    

    这里,ret表示的是重投影误差;mtx是相机的内参矩阵;dist表述的相机畸变参数;rvecs表示标定棋盘格世界坐标系到相机坐标系的旋转参数:rotation vectors,需要进行罗德里格斯转换;tvecs表示translation vectors,主要是平移参数。
    其他几个参数,OpenCV的官网都进行了仔细分析,在这个网站上去仔细的看,每个参数对应的数学公式。https://docs.opencv.org/3.4/dc/dbb/tutorial_py_calibration.html

    主要分析ret这个值,也就是retval,这个是重投影误差。

    import numpy as np
    import cv2 as cv2
    import glob
    # termination criteria
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
    # prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
    objp = np.zeros((6*7,3), np.float32)
    objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2)
    # Arrays to store object points and image points from all the images.
    objpoints = [] # 3d point in real world space
    imgpoints = [] # 2d points in image plane.
    images = glob.glob('*.jpg')
    for fname in images:
        img = cv2.imread(fname)
        gray = cv2.cvtColor(img, cv.COLOR_BGR2GRAY)
        # Find the chess board corners
        ret, corners = cv2.findChessboardCorners(gray, (7,6), None)
        # If found, add object points, image points (after refining them)
        if ret == True:
            objpoints.append(objp)
            corners2 = cv2.cornerSubPix(gray,corners, (11,11), (-1,-1), criteria)
            imgpoints.append(corners)
            # Draw and display the corners
            cv2.drawChessboardCorners(img, (7,6), corners2, ret)
            cv2.imshow('img', img)
            cv2.waitKey(500)
    cv2.destroyAllWindows()
    
    # Calibration, Now that we have our object points and image points, we are ready to go for 
    # calibration. We can use the function, cv.calibrateCamera() which returns the camera matrix, 
    # distortion coefficients, rotation and translation vectors etc.
    ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
    print("ret:", ret)
    print("Camera matrix : \n")
    print(mtx)
    print("dist : \n")
    print(dist)
    print("rvecs : \n")
    print(rvecs)
    print("tvecs : \n")
    print(tvecs)
    
    

    其中,这个ret也就是retval,表示的是重投影误差,是算法自动返回的,其表达式为:
    R e p p o i n t s   x ′ = k [ R ∣ T ] X   . Reppoints \ x'= k [R|T]X \,. Reppoints x=k[RT]X.
    其中,Reppoints x’是[Nx2],表示的图像像素平面的2维坐标点,X是[Nx3]表示的3D世界坐标系下的3维坐标点。也就是棋盘格所构造的3D坐标系的大小。
    r e t = r e p r o _ e r r o r = ∣ ∣ x ′ − x ∣ ∣ 2 2 t o t a l _ p o i n t s = ∣ ∣ x ′ − x ∣ ∣ 2 t o t a l _ p o i n t s ret =repro \_error =\sqrt{\frac{ ||x'-x||_{2}^2}{total\_points}}={\frac{ ||x'-x||_{2}}{\sqrt{total\_points}}} ret=repro_error=total_pointsxx22 =total_points xx2
    这就是cv2.calibrateCamera()返回的值中,ret也就是重投影误差的计算公式。求的是RMS均方根误差,对所有的点,求二范数,然后求平均再开根号,得到RMS误差。

    其中,二范数用的是:cv2.norm(data1, data2, cv2.NORM_L2)计算得到:
    n o r m ( x , x ′ ) = ∣ ∣ x − x ′ ∣ ∣ 2 = ∣ ∣ x − x ′ ∣ ∣ 2 2 = ( x 1 − x 1 ′ ) 2 + . . . + ( x n − x n ′ ) 2 norm(x,x')=||x-x'||_2=\sqrt{|| x-x'||_{2}^2}=\sqrt{(x_1-x'_1)^2+...+(x_n-x'_n)^2} norm(x,x)=xx2=xx22 =(x1x1)2+...+(xnxn)2

    三、projectPoints()函数分析

    imgpoints2, _ = cv.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
    
    1. 原始的计算方法,大多数教程和博客,以及OpenCV文档,给出的重投影误差计算方法。

    对相机标定得到的参数,带回原始的投影公式,重新计算从3D世界坐标系投影到2D图像平面坐标系的新的图像像素值,然后计算重投影误差。其中,objpoints表示世界坐标系的坐标,也就是棋盘格的坐标系,rvecs,tvecs,mtx,dist就是相机标定得到的那些参数。

    mean_error = 0
    for i in range(len(objpoints)):
        imgpoints2, _ = cv.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
        error = cv.norm(imgpoints[i], imgpoints2, cv.NORM_L2)/len(imgpoints2)
        mean_error += error
    print( "total error: {}".format(mean_error/len(objpoints)) )
    

    这里计算误差的方式,我们将得到的值和上面相机校正返回的值ret,不一样。因此,需要考虑,将这个官方给定的计算方式,进行重新计算。如果你不在意准确的值,就不用进行优化。

    本文是准确的探索,重投影误差的计算方式。按照上面的算法流程,我们可以得到以下的计算重投影误差的公式:
    r e p r o _ e r r o r = ∣ ∣ x ′ − x ∣ ∣ 2 t o t a l _ p o i n t s repro\_error={\frac{ {||x'-x||_{2}}}{total\_points}} repro_error=total_pointsxx2
    很明显,均方误差的计算,按照上述的表达式,是不准确的。误差开根号,然后除以点数多少,只能说是每个点的平均欧式误差。MSE误差。

    1. 校正之后的重投影误差计算方法或者代码。

    因此,需要求得准确的均方根误差,我们应该是先求平方,求平均,在开根号。因此,需要将代码改为:

    mean_error = 0
    for i in range(len(objpoints)):
        imgpoints2, _ = cv.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
        error = cv.norm(imgpoints[i], imgpoints2, cv.NORM_L2)
        total_error += error*error
    print( "rms error: {}".format(np.sqrt(total_error/(len(objpoints)*len(imgpoints2))))
    

    上述的流程才是:
    r e p r o _ e r r o r = ( ∣ ∣ x − x ′ ∣ ∣ 2 2 t o t a l _ p o i n t s repro\_error=\sqrt{\frac{(||x-x'||_2^2}{total\_points}} repro_error=total_points(xx22

    • 与我们的cv2.calibrateCamera()返回的值是一样的。

    四、具体实验和算法对比

    1. 相机校正返回的值
      相机校正返回的值

    2. 函数的返回值
      其中的返回的误差项,真实值:ret 为 ret: 0.008683449668964258
      返回值

    3. 使用大多数教程和博客的算法来计算的误差值,是有差别的:
      在这里插入图片描述

    4. 参考代码给出的输出误差结果
      total error: 0.0018512112930950482

    5. 按照自己修正的代码,来进行重投影误差计算:
      在这里插入图片描述
      输出的重投影误差为:total error: 0.008683459017710442

    因此,和我们相机校正输出的=重投影误差是一样的。

    五、参考附录

    下面是原始C++函数,计算重投影误差的流程,我上面的公式就是按照这个算法来解释的:

    static double computeReprojectionErrors(
            const vector<vector<Point3f> >& objectPoints,
            const vector<vector<Point2f> >& imagePoints,
            const vector<Mat>& rvecs, const vector<Mat>& tvecs,
            const Mat& cameraMatrix, const Mat& distCoeffs,
            vector<float>& perViewErrors )
    {
        vector<Point2f> imagePoints2;
        int i, totalPoints = 0;
        double totalErr = 0, err;
        perViewErrors.resize(objectPoints.size());
    
        for( i = 0; i < (int)objectPoints.size(); i++ )
        {
            projectPoints(Mat(objectPoints[i]), rvecs[i], tvecs[i],
                          cameraMatrix, distCoeffs, imagePoints2);
            err = norm(Mat(imagePoints[i]), Mat(imagePoints2), NORM_L2);
            int n = (int)objectPoints[i].size();
            perViewErrors[i] = (float)std::sqrt(err*err/n);
            totalErr += err*err;
            totalPoints += n;
        }
    
        return std::sqrt(totalErr/totalPoints);
    }
    

    需要准确描述如何计算重投影误差的同学,需要仔细修改你的代码,因为RMS误差来描述的,是需要求平方差,然后求平均,再求平方根。

    正确的方法是相机校正的方法输出的重投影误差,而不是大多数,包括OpenCV官方,给出的,都是不一样的,或者是不准确的重投影误差的计算函数。

    参考网站:

    1. https://stackoverflow.com/questions/29628445/meaning-of-the-retval-return-value-in-cv2-calibratecamera
    2. https://docs.opencv.org/master/dc/dbb/tutorial_py_calibration.html
    展开全文
  • 1.重投影误差的概念 在相机标定后,我们可以通过计算重投影误差来判断标定地精准程度。在标定后每个三维点根据相机的投影矩阵计算得到的图像位置与实际图像位置之间总存在一个距离,这个距离的累加和就是重投影误差...

    目录

    1.重投影误差的概念

    2.基于摄像机模型的重投影误差

    3.畸变校正算法

    3.1利用畸变模型正向求解

    3.2利用畸变模型反向求解


    1.重投影误差的概念

    在相机标定后,我们可以通过计算重投影误差来判断标定地精准程度。在标定后每个三维点根据相机的投影矩阵计算得到的图像位置与实际图像位置之间总存在一个距离,这个距离的累加和就是重投影误差。重投影误差不仅考虑的单应矩阵间的计算误差,也考虑了图像的测量误差,因此适合用来评价标定结果。重投影误差受镜头畸变等因素的影响,因此本文比较了畸变矫正前后的重投影误差大小。

    2.基于摄像机模型的重投影误差

    我们知道有限射影摄像机模型下,三维点X\left ( x_w,y_w,z_w,1 \right )和图像点x\left ( u,v,1 \right )之间的映射关系如下:

    \rho x=K\left [R\quad t \right ]X,K=\begin{bmatrix} f_x &0 &u_0 \\ 0&f_y &v_0 \\ 0& 0 & 1 \end{bmatrix},R=\begin{bmatrix} r_1 &r_2 &r_3 \\ r_4& r_5 &r_6 \\ r_7&r_8 &r_9 \end{bmatrix},t=\begin{bmatrix} t_x\\ t_y\\ t_z \end{bmatrix}

    则计算得到的图像点位置可以用世界坐标系坐标表示为:

    \rho u=(f_xr_1+u_0r_7)x_w+(f_xr_2+u_0r_8)y_w+(f_xr_3+u_0r_9)z_w+f_xt_x+u_0t_z

    \rho v=(f_yr_4+v_0r_7)x_w+(f_yr_5+v_0r_8)y_w+(f_yr_6+v_0r_9)z_w+f_yt_y+v_0t_z\rho =r_7x_w+r_8y_w+r_9z_w+t_z

    将求得的图像点与实际图像点间求二范数即反投影误差,各点反投影误差之和即重投影误差。笔者猜想,这就是OpenCV中调用projectPoints()函数时,令畸变系数为0时所采用的算法,笔者通过实验发现结果与猜想基本一致。

    值得注意的是,这里没有考虑镜头的畸变。 

    3.畸变校正算法

    我们在相机标定结束后获得的五个畸变系数:k1,k2,k3,p1,p2分别代表了径向畸变和切向畸变的系数,公式如下:

    径向畸变公式
    切向畸变公式
    综合径向畸变和切向畸变的公式

     注意,\left ( x,y \right )为理想坐标,(x_{distorted},y_{distorted})为畸变后的坐标,且两个坐标均在归一化平面上。因此原始图像的已知坐标为(x_{distorted},y_{distorted}),畸变矫正的过程就是根据原始图像计算理想坐标\left ( x,y \right )的过程。

     笔者在OpenCV官方文档上找到了使用该模型的矫正算法。

    3.1利用畸变模型正向求解

    OpenCV官方文档由理想坐标点到带畸变坐标点的正向求解的算法如下:

    该算法的基本思路为:

    理想图像坐标系(u,v),转移到相面坐标(x,y),再通过归一化,得到归一化平面上的坐标(x',y'),利用畸变模型(图中的畸变参数k_4,k_5,k_6,s_1,s_2暂未用到,默认为0)得到畸变后的坐标(x'',y'')(如果是双目相机模型,还需要利用相机间的旋转矩阵,得到该点在某一相机相面上的图像位置(x''',y'''))。再利用图像坐标系和相面坐标系的关系还原到图像系中,得到畸变后的(u,v),从而得到了畸变前后图像坐标系的映射关系,利用这种映射关系就能对图像进行矫正。

    该算法的对应OpenCV函数为:initUndistortRectifyMap(),函数原型如下:

    CV_EXPORTS_W
    void initUndistortRectifyMap(
    InputArray cameraMatrix, // computed camera matrix
    InputArray distCoeffs,                  
    InputArray R, 
    InputArray newCameraMatrix,
    Size size, 
    int m1type, 
    OutputArray map1, 
    OutputArray map2);

    得到映射后,调用remap()来矫正每幅图像。

    CV_EXPORTS_W 
    void remap( 
    InputArray src, 
    OutputArray dst,
    InputArray map1, 
    InputArray map2,
    int interpolation, 
    int borderMode = BORDER_CONSTANT,
    const Scalar& borderValue = Scalar());

    如果仅需要矫正一幅图像,可以将两个函数组合起来方便调用,OpenCV提供了这种函数undistort(),其函数原型如下:

    CV_EXPORTS_W 
    void undistort( 
    InputArray src, 
    OutputArray dst,
    InputArray cameraMatrix,
    InputArray distCoeffs,
    InputArray newCameraMatrix = noArray() );

    3.2利用畸变模型反向求解

    OpenCV还提供了根据带畸变点坐标计算理想点坐标的算法。

    注意,其中undistort()是一种近似的迭代算法,它从归一化的畸变点坐标中估计归一化的原始点坐标(“归一化”意味着坐标不依赖于相机矩阵)。

    使用该算法对应的函数为undistortPoints(),函数原型如下:

    CV_EXPORTS_W
    void undistortPoints(
    InputArray src, 
    OutputArray dst,                
    InputArray cameraMatrix, 
    InputArray distCoeffs,
    InputArray R = noArray(), 
    InputArray P = noArray());

    展开全文
  • 重投影误差-LM优化(数学基础)

    千次阅读 2019-11-27 14:20:10
    那现在就该说下什么叫重投影误差了,投影也就是指的第二次投影: 其实第一次投影指的就是相机在拍照的时候三维空间点投影到图像上 然后我们利用这些图像对一些特征点进行三角定位(triangulation),利用几何信息...
  • 2*6的那个雅克比矩阵是误差对于扰动的小量位姿的偏导数
  • 基于OpenCV-Python的机器人手眼标定和投影...但在张正友标定法中,是有一个重投影误差的概念的。 即将算出来的变换矩阵M,代入变换公式中,计算出新的目标坐标,和原坐标的的误差。 用公式表达即: new_target_pos =
  • VINS 初始化 ceres计算重投影误差

    千次阅读 2018-05-03 17:18:19
    详细分析一下VINS在初始化的时候对计算出的相机位姿和特征点的3D坐标用ceres进行最小化重投影误差的操作。参考资料:【1】https://www.jianshu.com/p/e5b03cf22c80【2】http://www.ceres-solver.org/index.html【3】...
  • CMakeLists.txt cmake_minimum_required(VERSION 2.8) project(vo1) set(CMAKE_BUILD_TYPE "Release") add_definitions("-DENABLE_SSE") set(CMAKE_CXX_FLAGS "-std=c++11 -O2 ${SSE_FLAGS} -msse4") ...
  • 重投影误差与对称转移误差

    千次阅读 2018-05-22 08:10:13
    @[机器视觉] [多视图几何] 最近在阅读相机标定相关知识,发现自己对于重投影误差(Reprojection Error)的理解居然是对称转移误差(Symmetric transfer error),今天在这里对这两个名词作个解释。重投影误差The ...
  • SLAM | 双目重投影误差雅克比推导

    千次阅读 2018-05-21 13:46:52
    1. 双目重投影误差项(给的是归一化坐标) //i时刻相机坐标系下的map point坐标 Eigen::Vector3d pts_camera_i = pts_i / inv_dep_i; //i时刻IMU坐标系下的map point坐标 Eigen::Vector3d pts_imu_i = qic * pts_...
  • 引用:我认为比较好懂的对最小化重投影误差的理解: https://www.cnblogs.com/Jessica-jie/p/7739775.html
  • 该项目的目的是使使用Nelder Mead方法的Zhang方法的重投影误差最小。 第一步 给定具有平面图案的图像(例如,棋盘),将提取角点,并且知道棋盘每个正方形的真实尺寸可以计算真实世界的点。 第二步 使用Nelder Mead...
  • *单目相机 经过对极几何初始化(八点法 、单应矩阵)求解一些3D点后 ...*可使用3D点-2D点对 使用 直接线性变换DLT(Direct Linear Transform) n点透视问题(PnP) 最小二乘最小化重投影误差 非线性优化算法G2O
  • homogeneousToKeypoint: 表示二维平面点到二维平面点的投影; euclideanToKeypoint: 表示三维空间点到二维平面点的投影.   kalibr/aslam_cv/aslam_cameras/include/aslam/cameras/implementation/...
  • 重投影残差,按照字面意思解释就是在第二次重新投影的二维像素点与第一次投影得到的像素点之间的残差(欧式距离)大小,残差的大小反映的就是测量仪器的精度以及外界因素对测量结果的干扰,即测量误差的大小。...
  • 摄像机标定的归一化误差matlab代码。摄像机标定的归一化误差matlab代码。摄像机标定的归一化误差matlab代码。摄像机标定的归一化误差matlab代码。摄像机标定的归一化误差matlab代码。
  • 反向投影误差的计算

    千次阅读 2017-05-26 14:55:17
    通过上一讲3D-2D的位姿计算后,现在求取反向投影误差 首先通过cv::solvePnPRansac(pts3d,pts2d,K,Mat(),rvec,tvec,false,100,4.0,0.99,inliers);cv::solvePnPRansac( pts3d, pts2d, K, Mat(), rvec, tvec, false, ...
  • 文章目录摄像机标定结果精度评价1 图像误差ErmsE_{rms}Erms​2 归一化标定误差EnceE_{nce}Ence​3 空间点与模型计算点的距离误差EptE_{pt}Ept​4 空间点到投影射线的距离误差ErayE_{ray}Eray​5 模型计算点之间...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 25,069
精华内容 10,027
关键字:

重投影误差