Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
基于OpenCV(Python)的运动结构摄像机标定_Python_Opencv_Camera Calibration_3d Reconstruction_Structure From Motion - Fatal编程技术网

基于OpenCV(Python)的运动结构摄像机标定

基于OpenCV(Python)的运动结构摄像机标定,python,opencv,camera-calibration,3d-reconstruction,structure-from-motion,Python,Opencv,Camera Calibration,3d Reconstruction,Structure From Motion,我想校准一个汽车录像机,并用它进行三维重建结构运动(SfM)。我用这台相机拍的照片的原始尺寸是1920x1080。基本上,我一直在使用来自的源代码进行校准 但是有一些问题,我真的很感激任何帮助 因此,与往常一样(至少在上述源代码中),以下是管道: 使用findChessboardCorners 使用cornerSubPix 使用drawhessboardCorners 然后,我们通过调用calibrateCamera 调用getOptimalNewCameraMatrix和undistort函数

我想校准一个汽车录像机,并用它进行三维重建结构运动(SfM)。我用这台相机拍的照片的原始尺寸是1920x1080。基本上,我一直在使用来自的源代码进行校准

但是有一些问题,我真的很感激任何帮助

因此,与往常一样(至少在上述源代码中),以下是管道:

  • 使用
    findChessboardCorners
  • 使用
    cornerSubPix
  • 使用
    drawhessboardCorners
  • 然后,我们通过调用
    calibrateCamera
  • 调用
    getOptimalNewCameraMatrix
    undistort
    函数以取消图像的扭曲
  • 在我的例子中,由于图像太大(1920x1080),我已将其大小调整为640x320(在SfM期间,我也将使用此大小的图像,因此,我认为这不会有任何问题)。此外,我还使用了一个9x6棋盘角进行校准

    在这里,问题出现了。调用
    getOptimalNewCameraMatrix
    后,失真完全错误。甚至返回的ROI也是
    [0,0,0,0]
    。以下是原始图像及其未失真版本:

    您可以看到未失真图像中的图像位于左下角

    但是,如果我没有调用
    getOptimalNewCameraMatrix
    直接
    undistort
    它,我会得到一个非常好的图像。

    所以,我有三个问题

  • 为什么会这样?我尝试了用同一台相机拍摄的另一个数据集,以及我的iPhone6Plus,但结果与上面相同

  • 另一个问题是,
    getOptimalNewCameraMatrix
    的作用是什么?我已经读了好几遍了,但还是不明白。从我观察到的情况来看,如果我不调用
    getOptimalNewCameraMatrix
    ,我的图像将保持其大小,但会被缩放和模糊。有人能给我更详细地解释一下这个函数吗

  • 对于SfM,我想调用
    getOptimalNewCameraMatrix
    很重要吧?因为如果没有,未失真的图像将被放大和模糊,使得关键点检测更加困难(在我的情况下,我将使用光流)

  • 我已经用opencv示例图片测试了代码,结果很好

    下面是我的源代码:

    from sys import argv
    import numpy as np
    import imutils  # To use the imutils.resize function. 
                           # Resizing while preserving the image's ratio.
                           # In this case, resizing 1920x1080 into 640x360.
    import 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((9*6,3), np.float32)
    objp[:,:2] = np.mgrid[0:9,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(argv[1] + '*.jpg')
    width = 640
    
    for fname in images:
        img = cv2.imread(fname)
        if width:
            img = imutils.resize(img, width=width)
    
        gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    
        # Find the chess board corners
        ret, corners = cv2.findChessboardCorners(gray, (9,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(corners2)
    
            # Draw and display the corners
            img = cv2.drawChessboardCorners(img, (9,6), corners2,ret)
            cv2.imshow('img',img)
            cv2.waitKey(500)
    
    cv2.destroyAllWindows()
    ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1],None,None)
    
    for fname in images:
        img = cv2.imread(fname)
        if width:
            img = imutils.resize(img, width=width)
    
        h,  w = img.shape[:2]
        newcameramtx, roi=cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h))
    
        # undistort
        dst = cv2.undistort(img, mtx, dist, None, newcameramtx)
    
        # crop the image
        x,y,w,h = roi
        dst = dst[y:y+h, x:x+w]
        cv2.imshow("undistorted", dst)
        cv2.waitKey(500)
    
    mean_error = 0
    for i in xrange(len(objpoints)):
        imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
        error = cv2.norm(imgpoints[i],imgpoints2, cv2.NORM_L2)/len(imgpoints2)
        mean_error += error
    
    print "total error: ", mean_error/len(objpoints)
    
    已经在answers.opencv.org上询问了某人,他成功地尝试了我的代码和数据集。我想知道到底是什么错了。

    问题2:

    使用
    cv::getOptimalNewCameraMatrix(…)
    可以根据自由缩放参数
    alpha
    计算新的摄影机矩阵

    如果将
    alpha
    设置为
    1
    ,则所有源图像像素将保留在未失真图像中,即您将看到沿未失真图像的黑色和弯曲边界(如枕形)。这种情况对于一些计算机视觉算法来说是不吉利的,因为新的边缘会出现在未失真的图像上

    默认情况下,
    cv::undistort(…)
    调节源图像的子集,该子集将在校正后的图像中可见,这就是为什么该子集上只显示敏感像素-校正后的图像周围没有枕状突起,但数据丢失

    无论如何,您可以控制源图像的子集,该子集将在校正后的图像中可见:

    cv::Mat image, cameraMatrix, distCoeffs;
    // ...
    
    cv::Mat newCameraMatrix = cv::getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, image.size(), 1.0);
    
    cv::Mat correctedImage;
    cv::undistort(image, correctedImage, cameraMatrix, distCoeffs, newCameraMatrix);
    
    问题1:

    这只是我的感觉,但您也应该注意,如果您在校准后调整图像大小,那么相机矩阵也必须“缩放”,例如:

    cv::Mat cameraMatrix;
    cv::Size calibSize; // Image during the calibration, e.g. 1920x1080
    cv::Size imageSize; // Your current image size, e.g. 640x320
    // ...
    
    cv::Matx31d t(0.0, 0.0, 1.0);
    t(0) = (double)imageSize.width / (double)calibSize.width;
    t(1) = (double)imageSize.height / (double)calibSize.height;
    
    cameraMatrixScaled = cv::Mat::diag(cv::Mat(t)) * cameraMatrix;
    
    这必须仅对相机矩阵执行,因为失真系数不取决于分辨率

    问题#3:


    无论我怎么想,
    cv::getOptimalNewCameraMatrix(…)
    在您的案例中并不重要,未失真的图像可以缩放和模糊,因为您消除了非线性变换的影响。如果我是你,我会尝试光流而不调用
    cv::undistort(…)
    。我认为,即使是扭曲的图像也可以包含许多良好的跟踪功能。

    在校准期间,我已经将图像大小调整为640x320。所以,我不需要重新缩放我的内在参数,不是吗?至于cv::Underist,我确实需要它,因为对于SfM,我需要图像的未失真版本,这样您就不必重新缩放内部函数,只需在
    cv::Underist(…)
    中使用与
    cv::CalibleCamera(…)
    中相同大小的图像即可。而且实现您的方法而不使用
    cv::getOptimalNewCameraMatrix(…)
    也更好。但这让我感到奇怪。有什么问题?漏洞?因为直接调用
    cv2.undistort
    可以解决这个问题,所以我可以假设校准成功了?
    cv::calibrateCamera(…)
    返回最终的重新投影错误,如果这是在0.1和1.0(像素)之间,那么可以认为您的校准已经足够好了。RMS误差小于1.0 px意味着亚像素精度。您能分享一下您如何调用
    getOptimalNewCameraMatrix
    的代码吗?