单目相机标定:由图像像素坐标系距离到世界坐标系真实距离

一、标定板拍摄图片

        拍摄图片,之后放入matlab进行特征点提取,注意提取过程中可能世界坐标系下的原点不一样。一定要避免这种情况。

标定途径1:Matlab自带的APP:Camera Calibrator

        把误差大的标定图片删掉,整个误差在0.2以下就行了。最后导出数据,matlab代码如下,其中K是内参矩阵(一定记得要转置)。根据你要最终测量的面,提取外参,R是旋转矩阵,t是平移向量。我这里第55张标定图片是把标定板贴在最终被侧面上测量的,所以我的外参矩阵选第55组就行。

K = cameraParams.IntrinsicMatrix'; % 内参矩阵
R = cameraParams.RotationMatrices(:,:,55);  % 指定表面的旋转矩阵
t = cameraParams.TranslationVectors(55,:);  % 指定表面的平移向量

标定途径2:matlab calibration toolbox

        这个toolbox一般都需要自己下载安装(免费)。但是这个安装好之后,需要自己一张图一张图自己标定,我个人觉得这个非常麻烦,而且自己标定也不能保证精度。

标定途径3:matlab 代码直接计算参数
直接上代码

numImages = 55; %标定的图片总数
files = cell(1, 55);
path = 'E:\opencv_project\SPSI\spatial_phaseshift\1125\cc限';
counter=0;
% (因为我图片总共200张,命名是1-200,然后被我删掉了很多误差大的图,最后剩下55张,命名在1-200之间)
for i = 1:200 % 图片命名最大值
    currentFile = fullfile(path, sprintf('%dCamera.bmp', i));
    if exist(currentFile, 'file')
        counter = counter + 1;
        files{counter} = currentFile;
    end
end
% 对所有的标定图片进行角点检测
[imagePoints, boardSize] = detectCheckerboardPoints(files); 
squareSize = 5; % 标定板的小方格边长(mm)
worldPoints = generateCheckerboardPoints(boardSize, squareSize);

I = imread(files{1});
imageSize = [size(I, 1), size(I, 2)];
cameraParams = estimateCameraParameters(imagePoints, worldPoints, 'ImageSize', imageSize); %得到相机内参

% 显示误差
figure; showReprojectionErrors(cameraParams);
title("Reprojection Errors");

% 估算外参
im = imread(files{55}); % 输入要测量的最终表面的标定图
[imagePoints, boardSize] = detectCheckerboardPoints(im);

% 获取相机内参和外参
K = cameraParams.IntrinsicMatrix';
[R, t] = extrinsics(imagePoints, worldPoints, cameraParams);

二、使用内外参计算实际距离

        matlab有自带的img2world2d函数,但是这个函数在Computer Vision工具包里面,这个工具包似乎只有正版matlab才能用。。。。。我们被制裁孩子的盗版matlab就用不了了。所以我分别写了一个matlab和Python的版本。

Matlab:

function worldPoints = img2world2d(imagePoints, camExtrinsics, camIntrinsics)
    % imagePoints: 输入的像素坐标,Nx2 的矩阵
    % camExtrinsics: 相机外参矩阵,3x4 的矩阵
    % camIntrinsics: 相机内参矩阵,3x3 的矩阵
    % 将图像坐标转换为归一化坐标
    normalizedPoints = [imagePoints, ones(size(imagePoints, 1), 1)] / camIntrinsics';
    % 添加深度信息
    normalizedPoints(:, 3) = 1;
    % 利用相机外参矩阵将相机坐标映射到世界坐标
    worldPointsHomogeneous = (camExtrinsics \ normalizedPoints')';
    % 转换为非齐次坐标
    worldPoints = worldPointsHomogeneous(:, 1:3) ./ worldPointsHomogeneous(:, 4);
end

Python:

def img2world2d(p, M, K):
    # 将图像坐标转换为归一化坐标
    ones_column = np.ones((1))
    normalizedPoints = np.dot(np.hstack((p, ones_column)) ,  np.linalg.inv(np.transpose(K)))
    normalizedPoints = normalizedPoints.reshape(-1, 1)
    M = np.delete(M,2,axis=1)
    worldPointsHomogeneous = np.linalg.solve(M,normalizedPoints)
    worldPoints = worldPointsHomogeneous[:2, :] / worldPointsHomogeneous[2, :].reshape(-1, 1)
    return worldPoints

        目前已经实现了图片坐标到世界坐标的转化。输入两个像素点p1,p2,得到两个世界坐标点w1,w2,就可以利用范数求快速求距离了。

distance = norm(w2-w1);

三、实验验证

        给被测面的标定图片(就是我标定第55张),标两个点,输入,计算实际的距离。我的标定板每个格子是5mm,所以真值大概是5*6=30mm。

          最终计算结果是30.0177mm,竖着的也记得验证以下:

        最终计算结果是299846mm,结果非常靠谱!!!赢!!!!!以后就可以在不改变被测面和相机的前提下,对这个被测面进行任意的检测了!!!

四、参考的matlab官方demo:

(直接是运行不了的,只能学习思路)

Measuring Planar Objects with a Calibrated Camera - MATLAB & Simulink - MathWorks 中国

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宇智波洛必达

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值