立体校准和 3D 重建问题
Stereo Calibration and 3D Reconstruction Issue
我正在尝试对计算出的视差图像执行立体相机校准和 3D 重投影。
为了简单起见,我在 Matlab 中做了这个例子,但在 Python 和 OpenCV 中得到了相同的结果。
我用这段代码来校准:
% Detect checkerboards in images
[imagePoints, boardSize, imagesUsed] = detectCheckerboardPoints(imageFileNames_left, imageFileNames_right);
% Generate world coordinates of the checkerboard keypoints
squareSize = 108; % in units of 'millimeters'
worldPoints = generateCheckerboardPoints(boardSize, squareSize);
% Read one of the images from the first stereo pair
I1 = imread(imageFileNames_left{1});
[mrows, ncols, ~] = size(I1);
% Calibrate the camera
[stereoParams, pairsUsed, estimationErrors] = estimateCameraParameters(imagePoints, worldPoints, ...
'EstimateSkew', false, 'EstimateTangentialDistortion', true, ...
'NumRadialDistortionCoefficients', 3, 'WorldUnits', 'millimeters', ...
'InitialIntrinsicMatrix', [], 'InitialRadialDistortion', [], ...
'ImageSize', [mrows, ncols]);
image_FileNames
包含各个校准图像的路径。我使用印在尺寸为 A0 的刚性面板上的棋盘校准图案。
校准结果看起来很有希望:
Link to example rectified stereo image
Link to reprojection errors plot
平均重投影误差 < 0.3
修正后的图像有平行线
我使用了 100 多张图像进行校准
但是计算视差并将其重新投影到 3D 会产生奇怪的结果:
Link to reprojected point cloud image
我使用以下代码片段进行 3D 投影:
I1 = imread(strcat(dirs_left{i}, '/', names_left{i}));
I2 = imread(strcat(dirs_right{i}, '/', names_right{i}));
% Rectify using calibration data
[J1, J2] = rectifyStereoImages(I1,I2,stereoParams);
% Calculate Disparity
disparityRange = [0 128];
disparityMap = disparitySGM(rgb2gray(J1),rgb2gray(J2),'DisparityRange', disparityRange);
% Project to 3D
point3D = reconstructScene(disparityMap, stereoParams);
% Convert from millimeters to meters.
point3D = point3D ./ 1000;
% Visualize the 3-D Scene
ptCloud = pointCloud(point3D, 'Color', J1);
h1 = figure; pcshow(ptCloud);
对应的视差图(使用SGBM计算)看起来不错:
Link to disparity image
这是校准数据:(注意:OpenCV 符号,我转置了所有矩阵以与 OpenCV 兼容):
camera matrix 0:
- 2362.9276056, 0.0000006, 1034.4700766,
- 0.0000006, 2366.4078916, 728.4543626,
- 0.0000006, 0.0000006, 1.0000006,
camera matrix 1:
- 2366.2683866, 0.0000006, 1030.6057166,
- 0.0000006, 2366.4804296, 740.0748076,
- 0.0000006, 0.0000006, 1.0000006,
lens dist 0: ()
-0.201011, 0.094025, -0.000569, 0.000521, 0.252866
lens dist 1:
-0.191647, 0.046607, -0.000569, 0.000521, 0.205665
rotation matrix camera 1:
- 0.9994606, -0.0068816, 0.0321416,
- 0.0055786, 0.9991666, 0.0404456,
- -0.0323936, -0.0402446, 0.9986656,
translation vector camera 1:
- -485.0037626, -48.0975216, 48.2236646,
我使用 OpenCV 而不是 Matlab 获得了类似的点云进行重新投影,上述校准信息。
我还发现了,
投影后他们似乎得到了类似的输出。
但在我的例子中,所有的重投影误差都相当小(平均 0.26 像素),视差范围默认设置为 0-128,这是最大值,视差图看起来很棒。
有什么想法吗?
预测的相机参数与所用相机镜头的物理属性相匹配。
这导致我限制投影 space,基本上按照 fdermishin 的建议。
移除 45 m 距离以外的所有点给出了合理的结果!
我用了下面这段代码来过滤点:
roi = [-50 50 -10 40 0 45]; % filter x, y, and z
indices = findPointsInROI(ptCloud,roi);
ptCloud_clean = select(ptCloud,indices);
我正在尝试对计算出的视差图像执行立体相机校准和 3D 重投影。
为了简单起见,我在 Matlab 中做了这个例子,但在 Python 和 OpenCV 中得到了相同的结果。
我用这段代码来校准:
% Detect checkerboards in images
[imagePoints, boardSize, imagesUsed] = detectCheckerboardPoints(imageFileNames_left, imageFileNames_right);
% Generate world coordinates of the checkerboard keypoints
squareSize = 108; % in units of 'millimeters'
worldPoints = generateCheckerboardPoints(boardSize, squareSize);
% Read one of the images from the first stereo pair
I1 = imread(imageFileNames_left{1});
[mrows, ncols, ~] = size(I1);
% Calibrate the camera
[stereoParams, pairsUsed, estimationErrors] = estimateCameraParameters(imagePoints, worldPoints, ...
'EstimateSkew', false, 'EstimateTangentialDistortion', true, ...
'NumRadialDistortionCoefficients', 3, 'WorldUnits', 'millimeters', ...
'InitialIntrinsicMatrix', [], 'InitialRadialDistortion', [], ...
'ImageSize', [mrows, ncols]);
image_FileNames
包含各个校准图像的路径。我使用印在尺寸为 A0 的刚性面板上的棋盘校准图案。
校准结果看起来很有希望:
Link to example rectified stereo image
Link to reprojection errors plot
平均重投影误差 < 0.3
修正后的图像有平行线
我使用了 100 多张图像进行校准
但是计算视差并将其重新投影到 3D 会产生奇怪的结果:
Link to reprojected point cloud image
我使用以下代码片段进行 3D 投影:
I1 = imread(strcat(dirs_left{i}, '/', names_left{i}));
I2 = imread(strcat(dirs_right{i}, '/', names_right{i}));
% Rectify using calibration data
[J1, J2] = rectifyStereoImages(I1,I2,stereoParams);
% Calculate Disparity
disparityRange = [0 128];
disparityMap = disparitySGM(rgb2gray(J1),rgb2gray(J2),'DisparityRange', disparityRange);
% Project to 3D
point3D = reconstructScene(disparityMap, stereoParams);
% Convert from millimeters to meters.
point3D = point3D ./ 1000;
% Visualize the 3-D Scene
ptCloud = pointCloud(point3D, 'Color', J1);
h1 = figure; pcshow(ptCloud);
对应的视差图(使用SGBM计算)看起来不错:
Link to disparity image
这是校准数据:(注意:OpenCV 符号,我转置了所有矩阵以与 OpenCV 兼容):
camera matrix 0:
- 2362.9276056, 0.0000006, 1034.4700766,
- 0.0000006, 2366.4078916, 728.4543626,
- 0.0000006, 0.0000006, 1.0000006,
camera matrix 1:
- 2366.2683866, 0.0000006, 1030.6057166,
- 0.0000006, 2366.4804296, 740.0748076,
- 0.0000006, 0.0000006, 1.0000006,
lens dist 0: ()
-0.201011, 0.094025, -0.000569, 0.000521, 0.252866
lens dist 1:
-0.191647, 0.046607, -0.000569, 0.000521, 0.205665
rotation matrix camera 1:
- 0.9994606, -0.0068816, 0.0321416,
- 0.0055786, 0.9991666, 0.0404456,
- -0.0323936, -0.0402446, 0.9986656,
translation vector camera 1:
- -485.0037626, -48.0975216, 48.2236646,
我使用 OpenCV 而不是 Matlab 获得了类似的点云进行重新投影,上述校准信息。
我还发现了
有什么想法吗?
预测的相机参数与所用相机镜头的物理属性相匹配。 这导致我限制投影 space,基本上按照 fdermishin 的建议。 移除 45 m 距离以外的所有点给出了合理的结果!
我用了下面这段代码来过滤点:
roi = [-50 50 -10 40 0 45]; % filter x, y, and z
indices = findPointsInROI(ptCloud,roi);
ptCloud_clean = select(ptCloud,indices);