主要内容

用校准相机测量平面物体

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

概述

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

校准相机

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

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

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

准备校准图像

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

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

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

预估相机参数

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

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

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

读取待测物体的图像

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

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

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

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

消除图像失真

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

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

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

请注意,这张照片的镜头失真很小。如果你使用广角镜头或低端摄像头,那么不失真的步骤要重要得多。

段硬币

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

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

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

检测硬币

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

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

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

计算外在

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

检测棋盘。[imagePoints, boardSize] = detectCheckerboardPoints(im);调整图像点,使它们在坐标系统中表示%用于原始图像,在未被扭曲之前。这种调整%使它与为原始图像计算的cameraParameters对象兼容。imagePoints = imagePoints + newOrigin;%将newOrigin添加到每行imagePoints提取相机的内在。camintrinsic = cameraparams . intrinsic;计算相机的外部参数。camExtrinsics = estimateExtrinsics(imagePoints, worldPoints, camintrinsic);

测量第一枚硬币

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

调整包围框左上角的坐标系统移位%由undistortion timage导致,输出视图为'full'。这不是如果输出“相同”,则需要%。这一调整使各点相互兼容%与原始图像的camer参数。boxes = boxes + [newOrigin, 0,0];为宽度和高度添加% 0填充获取左上角和右上角。Box1 = double(boxes(1,:));imagePoints1 = [box1(1:2);...Box1 (1) + Box1 (3), Box1 (2)];获取角落的世界坐标worldPoints1 = img2world2d(imagePoints1, camExtrinsics, camintrinsic);以毫米为单位计算硬币的直径。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 = img2world2d(imagePoints2, camExtrinsics, camintrinsic);以毫米为单位计算硬币的直径。d = worldpoint2 (2,:) - worldPoints2(1,:);diameter inmm = hypot(d(1), d(2));流(“另一便士的直径= %0.2f mm\n”, diameterInMillimeters);
另一枚硬币的直径= 18.85毫米

测量到第一枚硬币的距离

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

计算图像中第一枚硬币的中心。。Center1_image = box1(1:2) + box1(3:4)/2;%转换为世界坐标。center1_world = img2world2d(center1_image, camExtrinsics, camintrinsic ics);记得加上z坐标为0。Center1_world = [Center1_world 0];计算到相机的距离。cameraPose = extr2pose(camExtrinsics);cameraLocation = cameraPose.Translation;distanceToCamera = norm(center1_world - cameraLocation);流(“相机到第一枚硬币的距离= %0.2f mm\n”...distanceToCamera);
相机到第一枚硬币的距离= 719.52毫米

总结

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

参考文献

[1]张震。一种灵活的摄像机标定新技术。机械工程学报,22(11):1330-1334,2000。