单目视觉测距(个人探究记录)

1、前言

单目测距通常有两种方式:

       1)已知物体实际尺寸和相机焦距利用相似三角形求得相机与物体之间的距离。

       2)已知相机高度以及被测物体与地面的接触点求距离,这种方式与第一种方式相比为被测物体的实际尺寸是未知的。

          ---已知参照物的实际大小,求未知物的实际尺寸。

实际上,单目测距在mathwork上有一篇demo,但是这篇demo求得的是与标定板在同一个平面上的例子。这个例子使用单目相机标定的结果即用来测相机与硬币的距离,也用测量硬币的大小。

在mathwork论坛中也有不少同样的需求。如下链接中可以看到有用的信息。

1、https://ww2.mathworks.cn/matlabcentral/answers/404250-how-can-i-measure-the-distance-between-camera-and-object-usingle-single-camera

2、https://ww2.mathworks.cn/matlabcentral/answers/177941-camera-measurements-after-calibration

(1)里面的部分有用信息:

Without a properly calibrated camera and a reference object of some sort this is not possible. You can estimate the distance with some tricks, but with a single camera its not easy.

Right now im writing my final year project about exacly that topic, took me 2 months and a special designed marker to achieve the measurement of distance and angle from the camera to the object. If i dont have the marker the results are wrong. If i want to measure a distance behind or in front of the marker: wrong.

If you take a image with a single camera you only have a 2D picture, if you have a reference you can restore 3D information to the reference, but everything else without reference cant be restored properly. For that you would need another picture from a second camera (stereo vision).

One thing you could try is this: https://de.mathworks.com/help/vision/examples/measuring-planar-objects-with-a-calibrated-camera.html

EDIT: I should note that i have a moving camera and the object (marker) is stationary, so i cant just calibrate the camera once for a set distance and then use that as reference, since my distance changes.

(2)一篇论文(两次沿光轴不同距离拍照测距-利用相似三角形与成像原理中的高斯公式--还有未明白的极坐标转换....):

https://zone.biblio.laurentian.ca/bitstream/10219/2458/1/Peyman%20Alizadeh%20MSc.%20Thesis%20Corrected_2_2.pdf

使用点特征匹配在杂乱场景中进行目标检测:

https://www.mathworks.com/help/vision/examples/object-detection-in-a-cluttered-scene-using-point-feature-matching.html

以下是:https://www.mathworks.com/help/vision/examples/measuring-planar-objects-with-a-calibrated-camera.html?searchHighlight=coins&s_tid=doc_srchtitle中的代码简单注释:

%% more details you can visit the web:
%https://www.mathworks.com/help/vision/examples/measuring-planar-objects-with-a-calibrated-camera.html?searchHighlight=coins&s_tid=doc_srchtitle
%code:
web('https://www.mathworks.com/help/vision/examples/measuring-planar-objects-with-a-calibrated-camera.html?searchHighlight=coins&s_tid=doc_srchtitle','-browser')%在浏览器中打开
%%
clear
clc
numImages = 9;
files = cell(1, numImages);%构建元胞数组为:1X9cell
%% 填充数组,元胞数组通常包含文本列表、文本和数字的组合或者不同大小的数值数组
for i = 1:numImages
files{i} = fullfile(matlabroot, 'toolbox', 'vision', 'visiondata', ...
'calibration', 'slr', sprintf('image%d.jpg', i));%图的路径
end
% Display one of the calibration images
magnification = 25;%放大系数,由于图像太大无法在屏幕上显示,以百分比缩小--以25%显示
I = imread(files{1});
figure; imshow(I, 'InitialMagnification', magnification);
title('One of the Calibration Images');
%% Detect the checkerboard corners in the images.
[imagePoints, boardSize] = detectCheckerboardPoints(files);
% Generate the world coordinates of the checkerboard corners in the
% pattern-centric coordinate system, with the upper-left corner at (0,0).
squareSize = 29; % in millimeters棋盘格尺寸
worldPoints = generateCheckerboardPoints(boardSize, squareSize);
%worldPoints的数量可计算:M = (boardSize(1)-1) * (boardSize(2)-1)
%boardSize=[7 10],即M=6*9=54
% Calibrate the camera.
imageSize = [size(I, 1), size(I, 2)];%图像大小
cameraParams = estimateCameraParameters(imagePoints, worldPoints, ...
'ImageSize', imageSize);
% Evaluate calibration accuracy.评估校准精度
figure; showReprojectionErrors(cameraParams);
title('Reprojection Errors');
%% 可视化图像位置
h2=figure; showExtrinsics(cameraParams, 'CameraCentric');%以相机为中心
h3=figure; showExtrinsics(cameraParams, 'PatternCentric');%以图像为中心

%% Read the Image of Objects to Be Measured读取需要测量的图
MeasureImage = imread(fullfile(matlabroot, 'toolbox', 'vision', 'visiondata', ...
'calibration', 'slr', 'image9.jpg'));%已拍好,在路径中读出的
figure; imshow(MeasureImage, 'InitialMagnification', magnification);
title('Input Image-被测图像');
%% Since the lens introduced little distortion, use 'full' output view to illustrate that
% the image was undistored. If we used the default 'same' option, it would be difficult
% to notice any difference when compared to the original image. Notice the small black borders.
%使用cameraParameters对象从图像中删除镜头失真。(使用intrinsic内参)
[im, newOrigin] = undistortImage(MeasureImage, cameraParams, 'OutputView', 'full');
%im为返回的矫正不失真的图像。newOrigin是一个2元素向量,包含输入图像MeasureImage的内部坐标中输出图像im原点的[x,y]位置。
%在使用extrinsics,pointsToWorld或triangulate函数之前,
%必须将newOrigin添加到坐标在未失真图像im中检测到的点,以便将它们转换成原始图像MeasureImage的固有坐标。
%如果OutputView设置为same时,newOrigin为[0,0]--详细打开undistortImage查看
figure; imshow(im, 'InitialMagnification', magnification);
title('Undistorted Image-不失真图像');
%% Convert the image to the HSV color space.转到HSV颜色空间
imHSV = rgb2hsv(im);
% Get the saturation channel.获取饱和通道
saturation = imHSV(:, :, 2);
% Threshold the image 指定图像阈值
t = graythresh(saturation);
imCoin = (saturation > t);
figure; imshow(imCoin, 'InitialMagnification', magnification);
title('Segmented Coins-分割出硬币');
%% Find connected components.连通阈
blobAnalysis = vision.BlobAnalysis('AreaOutputPort', true,...
'CentroidOutputPort', false,...
'BoundingBoxOutputPort', true,...
'MinimumBlobArea', 200, 'ExcludeBorderBlobs', true);%计算并统计二值化图像中的连接区域
%斑点统计属性,输出区域--true,质心--false,边界框--true,最小斑点区域排除小于200--true。

[areas, boxes] = step(blobAnalysis, imCoin);%areas面积,boxes起点,长宽
% Sort connected components in descending order by area按区域按降序对连接的组件进行排序
[DA, idx] = sort(areas, 'Descend');%从areas中排序,DA为数,idx为对应序号
% Get the two largest components.获取最大的两个连通域
boxes = double(boxes(idx(1:2), :));%在idx中的前两个为最大的components
%boxes为保存俩个最大在像素坐标系下起始坐标及矩形的长宽
% Reduce the size of the image for display.
scale = magnification / 100;
imDetectedCoins = imresize(im, scale);%将图像im调整大小以scal缩放
%% Insert labels for the coins.标签---插入注释
imDetectedCoins = insertObjectAnnotation(imDetectedCoins, 'rectangle', ...
scale * boxes, 'penny');%对imDetectedCoins插入标签-矩形-位置为boxes缩放后位置--标签名-penny
figure; imshow(imDetectedCoins);
title('Detected Coins');
%% Detect the checkerboard.检测棋盘格点
% [imagePoints, boardSize] = detectCheckerboardPoints(files);
[imagePoints,boardSize] = detectCheckerboardPoints(im);
%im为不失真图像
% Adjust the imagePoints so that they are expressed in the coordinate system
% used in the original image, before it was undistorted.  This adjustment
% makes it compatible with the cameraParameters object computed for the original image.
%boardSize将棋盘尺寸指定为[rows,cols],以方块为单位--棋盘格有多少方格
%imagePoints为方格角点位置(x,y)
imagePoints = imagePoints + newOrigin; % adds newOrigin to every row of imagePoints
%% Compute rotation and translation of the camera.计算旋转、平移矩阵外参
[R, t] = extrinsics(imagePoints, worldPoints, cameraParams);
%imagePoints为图像坐标上角点坐标,worldPoints为世界坐标系上的角点坐标。
%在测距时,外参的计算利用标定板与被测物在同一平面上,在获取图像时可以将被测物放置与
%标定板一旁(本例中是采用这种方式的);或者让相机保证同一位置,分别采集出含标定板和含被测物的图像
%% Adjust upper left corners of bounding boxes for coordinate system shift
% caused by undistortImage with output view of 'full'. This would not be
% needed if the output was 'same'. The adjustment makes the points compatible
% with the cameraParameters of the original image.
%调整使点与原始图像的cameraParameters兼容。
boxes = boxes + [newOrigin, 0, 0]; % zero padding is added for widht and height
%boxes为最大的两个连通域--硬币
% Get the top-left and the top-right corners.获取左上角、右上角
box1 = double(boxes(1, :));%第一个硬币在像素坐标系的起始坐标和长宽
imagePoints1 = [box1(1:2); ...
box1(1) + box1(3), box1(2)];
%imagePoints1为第一个硬币在图像下像素宽度?
% Get the world coordinates of the corners
%计算像素坐标在世界坐标下的二维坐标
worldPoints1 = pointsToWorld(cameraParams, R, t, imagePoints1);
% Compute the diameter of the coin in millimeters.
d = worldPoints1(2, :) - worldPoints1(1, :);
diameterInMillimeters = hypot(d(1), d(2));%hypot平方和的平方根--直角三角形斜边
fprintf('Measured diameter of one penny = %0.2f mm\n', diameterInMillimeters);
%% Get the top-left and the top-right corners.
box2 = double(boxes(2, :));
imagePoints2 = [box2(1:2); ...
box2(1) + box2(3), box2(2)];
% Apply the inverse transformation from image to world
worldPoints2 = pointsToWorld(cameraParams, R, t, imagePoints2);
% Compute the diameter of the coin in millimeters.
d = worldPoints2(2, :) - worldPoints2(1, :);
diameterInMillimeters = hypot(d(1), d(2));
fprintf('Measured diameter of the other penny = %0.2f mm\n', diameterInMillimeters);
%% Compute the center of the first coin in the image.
center1_image = box1(1:2) + box1(3:4)/2;%box1(1:2)为起始坐标,box1(3:4)/2为矩形长宽的一半。
% Convert to world coordinates.
center1_world  = pointsToWorld(cameraParams, R, t, center1_image);
% Remember to add the 0 z-coordinate.
center1_world = [center1_world 0];
% Compute the distance to the camera.
[orientation, cameraLocation] = extrinsicsToCameraPose(R, t);
% orientation = rotationMatrix'----R'
% cameralocation    = -translationVector * rotationMatrix'----> -t*R'
distanceToCamera = norm(center1_world - cameraLocation);%norm欧几里德范数-向量的长度
%物体到相机的距离
fprintf('Distance from the camera to the first penny = %0.2f mm\n', ...
distanceToCamera);

 

猜你喜欢

转载自blog.csdn.net/weixin_39090239/article/details/101101477
今日推荐