OpenCV立体矫正图像失真 我们有一个ELP 1百万像素双镜头USB立体相机,我们正在尝试使用OpenCV 3.1在C++中进行校准。但是,校准的结果是完全不可用的,因为调用StereoRective会完全扭曲图像。我们就是这样做的:

OpenCV立体矫正图像失真 我们有一个ELP 1百万像素双镜头USB立体相机,我们正在尝试使用OpenCV 3.1在C++中进行校准。但是,校准的结果是完全不可用的,因为调用StereoRective会完全扭曲图像。我们就是这样做的:,c++,opencv,camera-calibration,C++,Opencv,Camera Calibration,在两台摄像机中寻找校准(棋盘)模式,棋盘大小为5x7,无论拍摄的图像数量多少,结果几乎相同 findChessboardCorners(img[k], boardSize, corners, CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_NORMALIZE_IMAGE) cornerSubPix(img[k], corners, Size(11, 11), Size(-1, -1), TermCriteria(TermCriteria::COUNT+TermCriter

在两台摄像机中寻找校准(棋盘)模式,棋盘大小为5x7,无论拍摄的图像数量多少,结果几乎相同

findChessboardCorners(img[k], boardSize, corners, CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_NORMALIZE_IMAGE)
cornerSubPix(img[k], corners, Size(11, 11), Size(-1, -1), TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01));
所有棋盘都被正确检测到,并使用

drawChessboardCorners(img[k], boardSize, corners, bFound);
然后我们分别校准每个摄像头(但这一步对于立体校准似乎并不重要),但我们可以使用它分别验证每个摄像头

calibrateCamera(objectPoints, imagePoints[k], Size(320, 240), cameraMatrix[k], distCoeffs[k], rvecs, tvecs, 0)
然后我们做立体校准

stereoCalibrate(objectPoints, imagePoints[0], imagePoints[1], cameraMatrix[0], distCoeffs[0], cameraMatrix[1], distCoeffs[1],
    Size(320, 240), R, T, E, F, CALIB_USE_INTRINSIC_GUESS);
计算校正变换

stereoRectify(cameraMatrix[0], distCoeffs[0], cameraMatrix[1], distCoeffs[1], Size(320, 240), R, T, R1, R2, P1, P2, Q,
    CALIB_ZERO_DISPARITY, 1, Size(320, 240), &validRoI[0], &validRoI[1]);
初始化要重新映射的映射

Mat rmap[2][2];
initUndistortRectifyMap(cameraMatrix[0], distCoeffs[0], R1, P1, Size(FRAME_WIDTH, FRAME_HEIGHT), CV_16SC2, rmap[0][0], rmap[0][1]);
initUndistortRectifyMap(cameraMatrix[1], distCoeffs[1], R2, P2, Size(FRAME_WIDTH, FRAME_HEIGHT), CV_16SC2, rmap[1][0], rmap[1][1]);
...
remap(img, rimg, rmap[k][0], rmap[k][1], INTER_LINEAR);
imshow("Canvas", rimg);
结果是图像完全失真。正如我在开始时所说,所有校准/棋盘模式都被正确检测到,如果我们不调用StereoRective函数,未失真的图像(重新映射后)看起来很完美。如果我们调用立体校正函数,问题就来了

我们错过了什么吗? 校准图像的数量似乎没有任何影响(有时拍摄2张图像比拍摄10张图像效果更好(但仍然不可用)

这是校准模式的示例。我们采取了几个不同的方向:

如果我们不称之为StereoRective,则这是校准的结果:

如果我们称之为StereoRective,这是一个错误的结果(但大多数情况下会变得更糟):


提前感谢您提供的任何可能出错的帮助。

您是否尝试过更改函数中参数alpha的值。我记得,一旦我也得到了这样的结果,将alpha的值改为0,我就成功了。
请让我知道您使用alpha=-1、alpha=0.5和alpha=0得到的结果,以便总结一下,如果有人需要类似的帮助,我会这样做以获得最好的结果:

在角点检测之前放大棋盘图像:

Mat resized;
resize(img[k], resized, Size(FRAME_WIDTH * 2, FRAME_HEIGHT * 2), 0.0, 0.0, INTER_LINEAR);
 findChessboardCorners(resized, boardSize, corners, CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_NORMALIZE_IMAGE
缩小检测到的角点:

for (int i = 0; i < corners.size(); ++i) {
    corners[i].x /= 2.0;
    corners[i].y /= 2.0;
}
校准立体摄像机:

stereoCalibrate(objectPoints, imagePoints[0], imagePoints[1], cameraMatrix[0], distCoeffs[0], cameraMatrix[1], distCoeffs[1],
    Size(FRAME_WIDTH, FRAME_HEIGHT), R, T, E, F, 
    CALIB_FIX_INTRINSIC | CALIB_SAME_FOCAL_LENGTH,
    TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 30, 0));
计算校正(α=0.0):

这些是校准结果矩阵

内在的:

M1: !!opencv-matrix
   rows: 3
   cols: 3
   dt: d
   data: [ 2.6187262304487734e+02, 0., 1.5950000000000000e+02, 0.,
       2.6187262304487734e+02, 1.1950000000000000e+02, 0., 0., 1. ]
D1: !!opencv-matrix
   rows: 1
   cols: 5
   dt: d
   data: [ -4.6768074176991381e-01, 2.0221327568191746e-01, 0., 0., 0. ]
M2: !!opencv-matrix
   rows: 3
   cols: 3
   dt: d
   data: [ 2.6400975025525213e+02, 0., 1.5950000000000000e+02, 0.,
       2.6400975025525213e+02, 1.1950000000000000e+02, 0., 0., 1. ]
D2: !!opencv-matrix
   rows: 1
   cols: 5
   dt: d
   data: [ -4.5713211677198845e-01, 2.8855737500717565e-01, 0., 0., 0. ]
外在因素:

R: !!opencv-matrix
   rows: 3
   cols: 3
   dt: d
   data: [ 9.9963073433190641e-01, 4.6310793035473068e-04,
       2.7169477545556639e-02, -6.9475632716349024e-04,
       9.9996348636555088e-01, 8.5172324905818230e-03,
       -2.7164541091274301e-02, -8.5329635354663789e-03,
       9.9959455592785362e-01 ]
T: !!opencv-matrix
   rows: 3
   cols: 1
   dt: d
   data: [ -6.1830090720273198e+01, 1.6774590574449604e+00,
       1.8118983433925613e+00 ]

我的另一个问题是,是否有任何特殊的变量初始化请求,或者这就足够了

Mat cameraMatrix[2] = { Mat::eye(3, 3, CV_64F), Mat::eye(3, 3, CV_64F) };
Mat distCoeffs[2], R, T, E, F, R1, R2, P1, P2, Q;

谢谢你的建议。这帮了大忙,但我注意到以下几点:-至少CALIB_FIX_K3需要传递到CalibleCamera和CALIB_SAME_Focus_info stereoCalibrate,否则结果完全混乱-我从CalibleCamera得到的RMS约为0.1,但从StereoCalibleCamera得到的RMS非常高,约为20-尽管现在的结果看起来不错,在重新映射后,图像似乎被放大了一点-我有320x240,如果我在棋盘检测之前手动将图像调整为640x480,然后将结果缩小2.0,结果似乎很完美。您可以使用参数alpha控制图像的缩放级别,并且您的相机外部设置是否正确?因为在我的例子中,平移向量偏移了3-4厘米。虽然这不相关,但我要补充的是,我使用加州理工学院Matlab工具箱获得了更好的结果。Alpha参数确实影响缩放级别。然而,与alpha=0不同的任何东西都会对图像边缘进行波动,并用黑色区域包围它(这是可以理解的),但我得到的最好结果(=无失真、无扭曲等)是alpha=0,在找到棋盘角之前先放大棋盘图像,然后再缩小检测到的角。好的,我们刚刚用70幅图像进行了校准。CalibuteCamera返回的RMS约为0.13,但stereoCalibrate仍返回高RMS约为14。我删除了那个些给出高极线误差的图像,现在RMS在0.2左右,这看起来非常好。然而,对于校准图像,视差图要差得多-甚至远的物体也被标记为非常近。我们用棋盘在几个距离上执行了新的校准,结果非常好!深度是使用从StereoRective返回的Q矩阵计算的:((1/Q[3][2])*Q[2][3])/视差)我想你应该发布一个新问题。
R: !!opencv-matrix
   rows: 3
   cols: 3
   dt: d
   data: [ 9.9963073433190641e-01, 4.6310793035473068e-04,
       2.7169477545556639e-02, -6.9475632716349024e-04,
       9.9996348636555088e-01, 8.5172324905818230e-03,
       -2.7164541091274301e-02, -8.5329635354663789e-03,
       9.9959455592785362e-01 ]
T: !!opencv-matrix
   rows: 3
   cols: 1
   dt: d
   data: [ -6.1830090720273198e+01, 1.6774590574449604e+00,
       1.8118983433925613e+00 ]
Mat cameraMatrix[2] = { Mat::eye(3, 3, CV_64F), Mat::eye(3, 3, CV_64F) };
Mat distCoeffs[2], R, T, E, F, R1, R2, P1, P2, Q;