双目立体视觉:四(双目标定matlab,图像校正,图像匹配,计算视差,disparity详解,)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a6333230/article/details/88245102

首先说明一点,需要用到matlab的stereoCameraCalibrator算法,该算法在2014a版本后添加的,因此之前的版本找不到,所以还是安装一个新版本的吧,我装的2016a。
这里说一下,换2016a可能会遇到打开图片特别慢,这里需要切换一下软件
opengl software(在matlab中执行)
切回硬件
opengl hardware
测试有没有stereo可以输入Enter stereoCameraCalibrator
我们在使用双目相机时,首先需要进行标定(就是相机有误差,我们需要消掉误差,如何消掉?加几个参数调节)

双目标定的流程

在这里插入图片描述
基本上按这个就可得到我们想要的校正双目误差的参数了。
下面强调几点过程中的注意事项
1.拍摄的图片是棋牌格,棋盘格需要是长方形,不能是矩形,要不matlab会报数据错误。
2.在计算完成后注意保存mat
下面是流程图
在这里插入图片描述
然后将上面的“Skew”、“Tangential Distortion”以及“3 Coefficients”等选项选上,将“2 Coefficients”选项去掉(这里图上为了方便直接默认着的):
在这里插入图片描述
Camera1代表左摄像头,Camera2代表右摄像头
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
保存后的参数在matlab的文件目录下,关掉该窗口后你就能看到
到这,我们的相机标定就结束了,我们最后得到一个mat文件。
mat文件解释
CameraParameters1为左摄像头的单独标定参数,CameraParameters2为右摄像头的单独标定参数。

stereoParams.TranslationOfCamera2:可以直接使用。
stereoParams.RotationOfCamera2:需转置以后才能使用。
在这里插入图片描述
CameraParameters1/CameraParameters2内
在这里插入图片描述
RadialDistortion:径向畸变,来源于光学透镜的特性,由K1,K2,K3确定。
TangentialDistortion:切向畸变,相机装配误差,传感器与光学镜头非完全平行,由两个参数P1,P2确定。
参数排序K1,K2,P1,P2,K3。

图像校正流程

标定后,图像的校正其实非常简单,只需要代入函数即可

clear all
clc

I1 = imread('zed_left2.png');%读取左右图片
I2 = imread('zed_right2.png');
figure
imshowpair(I1, I2, 'montage');
title('Original Images');

%加载stereoParameters对象。
load('my1stereoParams.mat');%加载你保存的相机标定的mat

[J1, J2] = rectifyStereoImages(I1, I2, stereoParams);
figure
imshowpair(J1, J2, 'montage');
title('Undistorted Images');

立体图像校正将图像投影到共同的图像平面上,使得对应的点具有相同的行坐标。
我们完成了校正之后,我们再进行特征点匹配就能将两张图联系到一起,进而求得距离信息。
很多做法中,校正后需要看一下校正的结果,把第一个图像的红通道和第二个图像的蓝通道和绿通道结合构成图像,可以看出浅浅的叠影,红色的就是我们的图1,其他色的就是我们的图2

figure; imshow(cat(3, J1(:,:,1), J2(:,:,2:3)), 'InitialMagnification', 50);%图像显示50%

或者也可以用二郎写的一个成像,挺有意思的,让两个物体同时显示,利用到(图像融合,边缘提取)

WL1 = abs(imfilter(rgb2gray(J1), fspecial('Laplacian'), 'replicate', 'conv'));
WL2 = abs(imfilter(rgb2gray(J2), fspecial('Laplacian'), 'replicate', 'conv'));
WL1(WL1(:)>=WL2(:)) = 1;WL1(WL1(:)<WL2(:)) = 0;
WL2(WL1(:)>=WL2(:)) = 0;WL2(WL1(:)<WL2(:)) = 1;
J_F(:,:,1) = J1(:,:,1).*WL1+J2(:,:,1).*WL2;
J_F(:,:,2) = J1(:,:,2).*WL1+J2(:,:,2).*WL2;
J_F(:,:,3) = J1(:,:,3).*WL1+J2(:,:,3).*WL2;
figure; imshow(J_F, 'InitialMagnification', 50);%图像显示50%

计算视差图disparity(matlab)

二郎从网上看到好多,然而大部分有点想吐槽,都是罗列一堆公式……让人怎们看……这里二郎整理一下,包括公式解答和计算视差所用的算法(二郎之前也想过,它的计算视差,是已经内嵌了匹配了??往下看吧)

disparityMap = disparity(rgb2gray(J1), rgb2gray(J2), 'BlockSize',... 
'15',DisparityRange',[0,400],'BlockSize',15,'ContrastThreshold',0.5,'UniquenessThreshold',15);

上面的一大串是二郎平时用的,这里先说明一下,该算法的操作对象均为灰度图,因此用到了两个rgb2gray;如何看懂一个函数最主要的是明白它的输入是什么,可设参数是什么,输出是什么。
该函数的输入是

rgb2gray(J1), rgb2gray(J2),

可设参数是

'DisparityRange',[0,400],'BlockSize',15,'ContrastThreshold',0.5,'UniquenessThreshold',15

其中:
’BlockMatching’或’SemiGlobal’:视差估计算法的一种(该种算法为默认算法),通过比较图像中每个像素块的绝对差值之和(SAD)来计算视差。
(块匹配采用了基本块匹配1.Konolige,K。,Small Vision Systems:Hardware and Implementation,Proceedings of the 8th International Symposium in Robotic Research,pages 203-212,1997。或者半全局块匹配2.Hirschmuller, H., Accurate and Efficient Stereo Processing by Semi-Global Matching and Mutual Information, International Conference on Computer Vision and Pattern Recognition, 2005.)

’DisparityRange’,[0,400]:视差范围,范围可以自己设定,不能超过图像的尺寸,当双目距离较远或者物体距离较近时,应适当增大该参数的值。

’BlockSize’, 15:设置匹配时方块大小。

’ContrastThreshold’,0.5:对比度的阈值,阈值越大,错误匹配点越少,能匹配到的点也越少。

’UniquenessThreshold’,15:唯一性阈值,设置值越大,越破坏了像素的唯一性,设置为0,禁用该参数。

’DistanceThreshold’,400:从图像左侧到右侧检测的最大跨度,跨度越小越准确,但很容易造成无法匹配。禁用该参数[]。

’TextureThreshold’,0.0002(默认):最小纹理阈值,定义最小的可靠纹理,越大越造成匹配点少,越少越容易匹配到小纹理,引起误差。

输出是

disparityMap

返回的视差值,以图1为底板,以图2与图1的视差为灰度值。

整体计算的步骤:
1.使用Sobel滤波器计算图像对比度的度量。
2.通过使用块匹配和绝对差值之和(SAD)来计算每个像素的视差。
3.标记包含不可靠的像素 差异值。该函数将像素设置为 - realmax(’ single’)返回的值。

显示 disparityMap

多数情况下该图显示为彩色的更为直观

figure;imshow(disparityMap, [0, 400]);
title('Disparity Map');
colormap jet
colorbar

从视差图中提取三维信息

pointCloud3D = reconstructScene(disparityMap, stereoParams);

这里有两个参数,第一个为我们计算的视差图,第二个是我们利用matlab对两个相机进行标定后的标定文件。这里matlab已经集成,没有文档说明采用的什么策略。
返回的矩阵 pointCloud3D为三维,(:,:,1)x坐标,(:,:,2)y坐标,(:,:,3)z坐标。
这里需要注意,出来的参数类型时single,这里最好转化一下(single占用4个字节、double占用8个字节,single所需空间比double少,但是在特殊场合精度不够。但是matlab中一些自带的优化主要针对的double,虽然single占内存小,但是它并不一定比double快。)

 pointCloud3D = double(pointCloud3D);

还有,我们出来的数的单位均为厘米,因此为了方便,我们需要转化为米来使用

 pointCloud3D = pointCloud3D/100;

显示距离和图像

Z = double(points3D(:,:,3));
mask = repmat(Z> 5&Z <6,[1,1,3]);
J1(~mask)= 0;
figure;imshow(J1,'InitialMagnification',50);

这里的50指定了显示的时候放大倍数为50%,也就是缩小一半放大。
这里显示的是距离5~6米之间的物体,其他范围的物体都变成了黑色
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/a6333230/article/details/88245102