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

您所在的位置:网站首页 vt图像距离怎么算 单目相机标定:由图像像素坐标系距离到世界坐标系真实距离

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

2024-06-29 04:25| 来源: 网络整理| 查看: 265

一、标定板拍摄图片

        拍摄图片,之后放入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 中国



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3