主要内容

用校准的相机测量平面物体

这个例子展示了如何测量硬币直径在世界单位使用一个校准相机。

概述

这个例子展示了如何校准相机,然后用它来测量平面物体的大小,比如硬币。该方法的一个应用实例是测量传送带上的零件以进行质量控制。

校准相机

摄像机标定是对镜头和图像传感器的参数进行估计的过程。这些参数是测量相机捕捉到的物体所需要的。这个例子展示了如何以编程方式校准相机。或者,您可以校准相机使用cameraCalibrator应用程序。

为了校准相机,我们首先需要从不同的角度拍摄多个校准模式的图像。一个典型的校准模式是一个不对称的棋盘,其中一面包含偶数个正方形,包括黑色和白色,而另一面包含奇数个正方形。

图案必须贴在一个平坦的表面上,并且它与相机的距离应该与你要测量的物体大致相同。正方形的大小必须用世界单位来测量,例如毫米,要尽可能精确。在本例中,我们使用9张模式图像,但在实践中,建议使用10到20张图像进行精确校准。

准备校准图片

创建一个单元格数组的文件名校准图像。

numImages = 9;= cell(1, numImages);i = 1:numImages files{i} = fullfile(matlabroot,“工具箱”“愿景”“visiondata”...“校准”“单反”sprintf (“图像% d.jpg”,我));结束%显示其中一个校准图像放大倍数= 25;I = imread(文件{1});图;imshow(我“InitialMagnification”、放大);标题(“其中一幅校正图像”);

图中包含一个轴对象。标题为“One of The Calibration Images”的轴对象包含一个类型为image的对象。

估计摄像机参数

%检测图像中的棋盘角。[imagePoints, boardSize] = detectCheckerboardPoints(files); / /检查文件中生成棋盘角的世界坐标%模式中心坐标系,左上角为(0,0)。squareSize = 29;%在毫米worldPoints = generateCheckerboardPoints(boardSize, squareSize);校准相机。imageSize = [size(I, 1), size(I, 2)];cameraParams = estimatecamerparameters (imagePoints, worldPoints,...“图象尺寸”、图象尺寸);评估校准精度。图;showReprojectionErrors (cameraParams);标题(“Reprojection错误”);

图中包含一个轴对象。标题为“重投影错误”的轴对象包含3个类型为bar, line的对象。这个对象表示总体平均误差:0.90像素。

条形图表明了校准的准确性。每个柱状图显示了对应校准图像的平均重投影误差。重投影误差是指图像中检测到的角点与投影到图像中的理想世界点之间的距离。

读取待测物体的图像

加载包含要测量的对象的图像。这个图像包含了校准模式,并且这个模式与你要测量的物体在同一个平面上。在这个例子中,图案和硬币都在同一个桌面上。

或者,您可以使用两个独立的图像:一个包含模式,另一个包含要测量的对象。同样,物体和图案必须在同一个平面上。此外,图像必须从完全相同的视角捕捉,这意味着相机必须固定在合适的位置。

imOrig = imread (fullfile (matlabroot“工具箱”“愿景”“visiondata”...“校准”“单反”“image9.jpg”));图;imshow (imOrig“InitialMagnification”、放大);标题(输入图像的);

图中包含一个轴对象。标题为Input Image的axes对象包含一个Image类型的对象。

Undistort图像

使用camerarameters对象从图像中移除镜头失真。这是精确测量所必需的。

由于镜头引入了小失真,使用“全”输出视图来说明%图像未被还原。如果我们使用默认的“相同”选项,那将会很困难%以注意与原始图像相比的任何差异。注意小的黑色边框。[im, newOrigin] = undistortion timage (imOrig, cameraParams,“OutputView”“全部”);图;imshow (im,“InitialMagnification”、放大);标题(“无畸变的图像”);

图中包含一个轴对象。标题为untwisted Image的axis对象包含一个类型为Image的对象。

注意,这幅图像显示出非常小的镜头失真。如果你使用的是广角镜头或低端摄像头,那么不失真这一步就重要得多。

段硬币

在这种情况下,硬币是彩色的白色背景。使用图像HSV表示的饱和度分量来分割它们。

%将图像转换为HSV颜色空间。imHSV = rgb2hsv (im);%获取饱和通道。饱和度= imHSV(:,:, 2);图像阈值t = graythresh(饱和);imCoin =(饱和度> t);图;imshow (imCoin“InitialMagnification”、放大);标题(“分段硬币”);

图中包含一个轴对象。标题为分割硬币的轴对象包含一个类型为image的对象。

检测硬币

我们可以假设分割后的图像中最大的两个连通分量对应于硬币。

%查找连接的组件。blobAnalysis =愿景。BlobAnalysis (“AreaOutputPort”,真的,...“CentroidOutputPort”假的,...“BoundingBoxOutputPort”,真的,...“MinimumBlobArea”, 200,“ExcludeBorderBlobs”,真正的);[area, boxes] = step(blobAnalysis, imCoin);%按区域降序排列连接组件[~, idx] = sort(区域,“下”);%得到两个最大的分量。box = double(box (idx(1:2),:))); / /指定一个值减少显示的图像的大小。比例=放大倍数/ 100;imDetectedCoins = imresize(im, scale);%为硬币插入标签。imDetectedCoins = insertObjectAnnotation (imDetectedCoins,“矩形”...规模*盒子,“一分钱”);图;imshow (imDetectedCoins);标题(“发现硬币”);

图中包含一个轴对象。标题为Detected Coins的轴对象包含一个类型为image的对象。

计算外在

为了将图像坐标中的点映射到世界坐标中的点,我们需要计算相机相对于校准模式的旋转和平移。请注意,外在函数假设没有透镜畸变。在这种情况下,imagePoints已经检测到的图像已经被纠正使用undistortImage

%检测棋盘。[imagePoints, boardSize] = detectCheckerboardPoints(im);%调整imagePoints,使其在坐标系统中表示%用于原始图像,在它未被扭曲之前。这种调整%使它与为原始图像计算的camerarameters对象兼容。imagePoints = imagePoints + newOrigin;%添加newOrigin到imagePoints的每一行%计算相机的旋转和平移。[R, t] = extrinsics(imagePoints, worldPoints, cameraParams);

测量第一枚硬币

为了测量第一枚硬币,我们将边界框的左上角和右上角转换为世界坐标。然后我们计算它们之间的欧氏距离,单位是毫米。请注意,一美分硬币的实际直径是19.05毫米。

调整边界框的左上角以实现坐标系统的移位%由undistortion timage造成,输出视图为'full'。这就不是如果输出“相同”,则需要%。调整使各点兼容%与相机参数的原始图像。[newworigin, 0, 0]; / /点击[newworigin, 0, 0]宽度和高度添加了% 0填充%获取左上角和右上角。Box1 = double(boxes(1,:));imagePoints1 = [box1 (1:2);...Box1 (1) + Box1 (3), Box1 (2)];得到各个角落的世界坐标worldPoints1 = pointsToWorld(cameraParams, R, t, imagePoints1);用毫米计算硬币的直径。d = worldPoints1(2,:) - worldPoints1(1,:);直径in毫米= hypot(d(1), d(2));流('测量一便士的直径= %0.2f mm\n', diameterInMillimeters);
测量直径一便士= 19.00毫米

测量第二枚硬币

测量第二枚硬币的方法与测量第一枚硬币的方法相同。

%获取左上角和右上角。Box2 = double(boxes(2,:));imagePoints2 = [box2 (1:2);...Box2 (1) + Box2 (3), Box2 (2)];%应用从图像到世界的逆变换worldPoints2 = pointsToWorld(cameraParams, R, t, imagePoints2);用毫米计算硬币的直径。d = worldPoints2(2,:) - worldPoints2(1,:);直径in毫米= hypot(d(1), d(2));流('测量的另一便士直径= %0.2f mm\n', diameterInMillimeters);
另一枚硬币的直径为18.85毫米

测量到第一枚硬币的距离

除了测量硬币的大小,我们还可以测量它离相机有多远。

%计算图像中第一枚硬币的中心。Center1_image = box1(1:2) + box1(3:4)/2;%转换为世界坐标。center1_world = pointsToWorld(cameraParams, R, t, center1_image);%记得添加0 z坐标。[Center1_world 0];%计算到摄像机的距离。[~, cameraLocation] = extrinsicsToCameraPose(R, t);distanceToCamera = norm(center1_world - cameraLocation);流('从相机到第一便士的距离= %0.2f mm\n'...distanceToCamera);
从相机到第一便士的距离= 719.52毫米

总结

这个例子展示了如何使用一个校准的相机来测量平面物体。注意,测量精度在0.2 mm以内。

参考文献

[1] z。一种灵活的摄像机标定新技术。计算机工程与应用,2017,36(11):1330-1334,2000。