主要内容

用标定相机测量平面物体

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

概述

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

校准摄像机

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

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

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

准备校正图像

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

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

图包含一个轴对象。标题为“校准图像之一”的轴对象包含一个图像类型的对象。

估计相机参数

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

图包含一个轴对象。标题为Reprojection Errors的坐标轴对象包含3个类型为bar, line的对象。该对象表示总体平均误差:0.90像素。

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

读取待测物体的图像

加载包含要测量对象的图像。此图像包含校准图案,该图案与要测量的对象在同一平面上。在这个例子中,图案和硬币都在同一个桌面上。

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

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

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

消除图像扭曲

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

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

图包含一个轴对象。标题为“未失真图像”的坐标轴对象包含一个图像类型的对象。

请注意,这幅图像显示很少的镜头畸变。如果你使用的是广角镜头或低端网络摄像头,那么防失真的步骤要重要得多。

段硬币

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

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

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

检测硬币

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

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

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

计算外在

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

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

测量第一枚硬币

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

调整坐标系统移位的边界框的左上角%由于未失真图像导致输出视图为“满”。这不会是如果输出“相同”,则需要%。调整使点兼容%与原始图像的相机参数。boxes = boxes + [newOrigin, 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,:);diameter inmm = 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,:);diameter inmm = hypot(d(1), d(2));流(“另一枚硬币的直径= %0.2f mm\n”, diameterInMillimeters);
另一枚硬币的直径为18.86毫米

测量到第一枚硬币的距离

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

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

总结

这个例子展示了如何使用校准相机来测量平面物体。请注意,测量结果精确到0.2 mm以内。

参考文献

[1]张志强。一种灵活的摄像机标定新技术。模式分析与机器智能学报,22(11):1330- 1334,2000。