操作系统:Win10
开发环境: Matlab 2019b(需要摄像头驱动包)
插上摄像头,在Matlab命令行窗口中输入如命令(webcam),如果出现如下界面,说明安装成功:
执行clear ans,清除刚才执行webcam得到的结果,断开摄像头连接。(注:由于上一步执行了webcam指令,Matlab默认自动连接了摄像头,这里先clear ans清除连接的摄像头)
执行webcam(1)或者webcam(‘3D_SHOP’),(注:这里的‘3D_SHOP’是从ans中的name元素中得到的,如果有多个摄像头,会存在多个名称,可指定连接哪一个名称)连接摄像头。
设置分分辨率
在进行标定工作之前,我们需要先采集图像数据,为方便后续的图像采集工作,先设计一款简单的双目摄像头拍照GUI,如上图所示。打开Matlab的GUI设计APP。如下图所示。
classdef M3 < matlab.apps.AppBase
% Properties that correspond to app components
properties (Access = public)
UIFigure matlab.ui.Figure
GridLayout matlab.ui.container.GridLayout
camLeft matlab.ui.control.UIAxes
startCam matlab.ui.control.Button
recordCam matlab.ui.control.Button
closeCam matlab.ui.control.Button
camRight matlab.ui.control.UIAxes
saveButton matlab.ui.control.Button
end
properties (Access = private)
end
properties (Access = public)
cam % Description
reImage = 0
imageLeft % Description
imageRight % Description
camImage % Description
saveUrl = '0'
end
% Callbacks that handle component events
methods (Access = private)
% Button pushed function: startCam
function startCamButtonPushed(app, event)
app.cam=webcam(1)
app.cam.Resolution = '2560x960'
app.camImage = snapshot(app.cam)
im=image(app.camLeft, zeros(size(app.camImage), 'uint8'))
axis(app.camLeft, 'image')
preview(app.cam, im)
end
% Button pushed function: closeCam
function closeCamButtonPushed(app, event)
delete(app)
end
% Button pushed function: recordCam
function recordCamButtonPushed(app, event)
app.camImage = snapshot(app.cam)
im = image(app.camRight, app.camImage)
axis(app.camRight, 'image')
app.imageLeft = app.camImage(1:960, 1:1280, 1:3)
app.imageRight = app.camImage(1:960, 1281:2560, 1:3)
app.reImage = app.reImage + 1
imwrite(app.imageLeft, sprintf('%s%s%d%s', app.saveUrl, '\left', app.reImage, '.bmp'))
imwrite(app.imageRight, sprintf('%s%s%d%s', app.saveUrl, '\right', app.reImage, '.bmp'))
end
% Button pushed function: saveButton
function saveButtonPushed(app, event)
app.saveUrl = uigetdir('\.')
if(app.saveUrl ~= '0')
app.recordCam.Enable = true
end
end
end
% Component initialization
methods (Access = private)
% Create UIFigure and components
function createComponents(app)
% Create UIFigure and hide until all components are created
app.UIFigure = uifigure('Visible', 'off');
app.UIFigure.Color = [0.9412 0.9412 0.9412];
app.UIFigure.Position = [100 100 685 499];
app.UIFigure.Name = 'UI Figure';
app.UIFigure.Scrollable = 'on';
% Create GridLayout
app.GridLayout = uigridlayout(app.UIFigure);
app.GridLayout.ColumnWidth = {'1.8x', 99.99, '1x', 44, 50.99, '1x', 99.99, '1.7x'};
app.GridLayout.RowHeight = {'5.12x', '1x', 36};
app.GridLayout.ColumnSpacing = 1.22318522135417;
app.GridLayout.Padding = [1.22318522135417 10 1.22318522135417 10];
% Create camLeft
app.camLeft = uiaxes(app.GridLayout);
title(app.camLeft, 'Left')
xlabel(app.camLeft, '')
ylabel(app.camLeft, '')
app.camLeft.XColor = [1 1 1];
app.camLeft.XTick = [];
app.camLeft.YColor = [1 1 1];
app.camLeft.YTick = [];
app.camLeft.ZColor = [1 1 1];
app.camLeft.TitleFontWeight = 'bold';
app.camLeft.Layout.Row = 1;
app.camLeft.Layout.Column = [1 4];
% Create startCam
app.startCam = uibutton(app.GridLayout, 'push');
app.startCam.ButtonPushedFcn = createCallbackFcn(app, @startCamButtonPushed, true);
app.startCam.HandleVisibility = 'off';
app.startCam.BusyAction = 'cancel';
app.startCam.IconAlignment = 'center';
app.startCam.FontSize = 14;
app.startCam.Layout.Row = 2;
app.startCam.Layout.Column = 1;
app.startCam.Text = '开始';
% Create recordCam
app.recordCam = uibutton(app.GridLayout, 'push');
app.recordCam.ButtonPushedFcn = createCallbackFcn(app, @recordCamButtonPushed, true);
app.recordCam.HandleVisibility = 'off';
app.recordCam.BusyAction = 'cancel';
app.recordCam.IconAlignment = 'center';
app.recordCam.FontSize = 15;
app.recordCam.Enable = 'off';
app.recordCam.Layout.Row = 2;
app.recordCam.Layout.Column = 6;
app.recordCam.Text = '拍照';
% Create closeCam
app.closeCam = uibutton(app.GridLayout, 'push');
app.closeCam.ButtonPushedFcn = createCallbackFcn(app, @closeCamButtonPushed, true);
app.closeCam.HandleVisibility = 'off';
app.closeCam.BusyAction = 'cancel';
app.closeCam.IconAlignment = 'center';
app.closeCam.FontSize = 15;
app.closeCam.Layout.Row = 2;
app.closeCam.Layout.Column = 8;
app.closeCam.Text = '关闭';
% Create camRight
app.camRight = uiaxes(app.GridLayout);
title(app.camRight, 'Right')
xlabel(app.camRight, '')
ylabel(app.camRight, '')
app.camRight.XColor = [1 1 1];
app.camRight.XTick = [];
app.camRight.YColor = [1 1 1];
app.camRight.YTick = [];
app.camRight.ZColor = [1 1 1];
app.camRight.TitleFontWeight = 'bold';
app.camRight.Layout.Row = 1;
app.camRight.Layout.Column = [5 8];
% Create saveButton
app.saveButton = uibutton(app.GridLayout, 'push');
app.saveButton.ButtonPushedFcn = createCallbackFcn(app, @saveButtonPushed, true);
app.saveButton.IconAlignment = 'center';
app.saveButton.FontSize = 14;
app.saveButton.Layout.Row = 2;
app.saveButton.Layout.Column = 3;
app.saveButton.Text = '保存';
% Show the figure after all components are created
app.UIFigure.Visible = 'on';
end
end
% App creation and deletion
methods (Access = public)
% Construct app
function app = M3
% Create UIFigure and components
createComponents(app)
% Register the app with App Designer
registerApp(app, app.UIFigure)
if nargout == 0
clear app
end
end
% Code that executes before app deletion
function delete(app)
% Delete UIFigure when app is deleted
delete(app.UIFigure)
end
end
end
上图中,白色部分为我加入的代码,其他是由Matlab APP GUI生成代码。
开始:GUI连接摄像头
保存:选择图片将要保存的路径
拍照:拍照,保存照片
close all;
clear all;
clc;
width=1024 ; %pattern的宽
height=768 ; %pattern的高
img_final=zeros(height,width);
reinforceconner=0 ;%是否加强角点
row=10; %pattern中棋盘格的行数
col=13 ; %pattern中棋盘格的列数
length=45; %pattern中棋盘格的大小
org_X=(height-row*length)/2; %pattern关于纵轴方向的位置,默认放在中间
org_Y=(width-col*length)/2; %pattern关于横轴方向的位置,默认放在中间
color1=1;
color2=color1;
img=zeros(row*length,col*length);
for i=0:(row-1)
color2=color1;
for j=0:(col-1)
if color2==1
img(i*length+1:(i+1)*length-1,j*length+1:(j+1)*length-1)=color2;
end
%不加的话,可以注释掉
%
color2=~color2;
end
color1=~color1;
end
img_final(org_X:org_X+row*length-1,org_Y:org_Y+col*length-1)=img;
img_final=~img_final;
figure;imshow(img_final);
imwrite(img_final, 'cheesBoard.bmp','bmp');
引用自zhouyelihuahttp://blog.csdn.net/zhouyelihua/article/details/46674191
stereoCameraCalibrator:Matlab双目相机标定工具箱
补充一个知识:
***重投影:***重投影也就是指的第二次投影。
其实第一次投影指的就是相机在拍照的时候三维空间点投影到图像上。
然后我们利用这些图像对一些特征点进行三角定位(triangulation),利用几何信息(对极几何) 构建三角形来确定三维空间点的位置
最后利用我们计算得到的三维点的坐标(注意不是真实的)和我们计算得到的相机位姿(当然也不是真实的)进行第二次投影,也就是重投影。
**对极几何:极线几何约束是一种点对直线的约束,而不是点与点的约束,尽管如此,极线约束给出了对应点重要的约束条件,它将对应点匹配从整幅图像寻找压缩到在一条直线上寻找对应点。在立体视觉测量中,立体匹配(对应点的匹配 )是一项关键技术,极线几何在其中起着重要作用。立体视觉系统中,有两个摄像机在不同角度拍摄物理空间中的一实体点,在两副图像上分别成有有两个成像点。立体匹配就是已知其中的一个成像点,在另一副图像上找出该成像点的对应点—极限搜索(高翔13.2讲)。极线几何约束是一种常用的匹配约束技术。(Mastering OpenCV with Practical Computer Vision Projects)
为了提高单目相机标定的精度,认真看了张正友标定法的原文,并且学习过网上一些牛人的方法,但是大部分时候说的很笼统,自己把这些经验总结起来并都测试了一下,感觉靠谱的结论列出如下:
(1)在标定时,标定模板所在平面与成像平面(image plane)之间的夹角不能太小,实验表明:当两者之间夹角较小时,会产生很大的误差。
(2)图像中标定板与相机的相对位姿,一般要让标定板占据整张图像的一半左右面积,并且标定板相对于相机要有正视、仰视、俯视、左斜视和右斜视等;
(3)标定板的位姿对标定结果影响比标定照片数目的影响大得多;
(4)标定板一定要平整,否则误差很大,标定板的平整度是最重要的因素;
(5)用于拍摄的照片的先后顺序对结果影响不大,小数点后前五位都是一样的,随机抽掉一张结果影响也不大;
(6)按照张正友标定法原文,拍照顺序是从正对图像开始,每次选择一个坐标轴,旋转45度的角度,拍摄16幅左右的图片就可以,但是感觉可以角度小一点;
-----------------------------------分割线------------------------------
列出当时自己实验时的拍摄角度方案,这七个方案拍摄标定出来的结果去畸变都没问题,但是光心的位移有一点不同,都往右下方向偏移但是偏移量不同,后来总结效果最好的方案应该 是方案 六,但是优势并不明显。如果以后有人想做这个实验,可以先看看我的不成功案例,也许可以节省时间。
方案一:三组,正视14张、仰视14张、俯视14张,所有照片仅相对水平轴旋转,正视照片占相机视野四分之三,俯仰视照片占相机视野四分之一,每组内的14张照片是划出了一个矩形的轮廓,中间2张,四周12张;
方案二:三组,正视14张、仰视14张、俯视14张,正视照片无转角(无任何旋转),仰视和俯视的照片成扇面状对着相机(既绕水平轴又绕铅垂轴),正视照片占相机视野四分之三,俯仰视照片占相机视野四分之一,14张照片是划出了一个矩形的轮廓,中间2张,四周12张;
方案三:其他与方案二一致,只是仰视和俯视的照片成楔子状对着相机;
方案四:三组,正视14张、仰视14张、俯视14张,正视、仰视和俯视的照片全部成扇面状对着相机,正视照片占相机视野四分之三,俯仰视照片占相机视野四分之一,14张照片是划出了一个矩形的轮廓,中间2张,四周12张;
方案五:其他与方案四一致,只是正视俯视仰视照片成楔子状对着相机;
方案六:先拍四张正视,然后左远右近(就是标定板的左边离相机远右边离相机近,下同)四张,左近右远四张,上远下近四张,上近下远四张——既不是楔子型也不是扇面形。
方案七:长轴中线上,均匀变换角度,拍9张,短轴中线上,均匀变化角度,拍9张,然后四个角各补一张。共22张。