基于Matlab-采用张正友标定法对双目相机进行标定

一、工作环境

操作系统:Win10

开发环境: Matlab 2019b(需要摄像头驱动包)

相机:USB双目相机,支持UVC标准协议
基于Matlab-采用张正友标定法对双目相机进行标定_第1张图片

1、安装摄像头驱动包(OS Generic Video Interface)

基于Matlab-采用张正友标定法对双目相机进行标定_第2张图片

插上摄像头,在Matlab命令行窗口中输入如命令(webcam),如果出现如下界面,说明安装成功:

基于Matlab-采用张正友标定法对双目相机进行标定_第3张图片

2、测试摄像头

  • 执行clear ans,清除刚才执行webcam得到的结果,断开摄像头连接。(注:由于上一步执行了webcam指令,Matlab默认自动连接了摄像头,这里先clear ans清除连接的摄像头

  • 执行webcam(1)或者webcam(‘3D_SHOP’),(注:这里的‘3D_SHOP’是从ans中的name元素中得到的,如果有多个摄像头,会存在多个名称,可指定连接哪一个名称)连接摄像头。

  • 设置分分辨率

基于Matlab-采用张正友标定法对双目相机进行标定_第4张图片

  • 显示视频流

基于Matlab-采用张正友标定法对双目相机进行标定_第5张图片

二、标定前的准备工作

基于Matlab-采用张正友标定法对双目相机进行标定_第6张图片

1、设计GUI

在进行标定工作之前,我们需要先采集图像数据,为方便后续的图像采集工作,先设计一款简单的双目摄像头拍照GUI,如上图所示。打开Matlab的GUI设计APP。如下图所示。

基于Matlab-采用张正友标定法对双目相机进行标定_第7张图片
基于Matlab-采用张正友标定法对双目相机进行标定_第8张图片

1)设计界面

基于Matlab-采用张正友标定法对双目相机进行标定_第9张图片

2)切换到代码界面

基于Matlab-采用张正友标定法对双目相机进行标定_第10张图片

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-采用张正友标定法对双目相机进行标定_第11张图片

上图中,白色部分为我加入的代码,其他是由Matlab APP GUI生成代码。

3)GUI操作方法

基于Matlab-采用张正友标定法对双目相机进行标定_第12张图片

开始:GUI连接摄像头

保存:选择图片将要保存的路径

拍照:拍照,保存照片

2、采用Matlab设计棋盘格

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

基于Matlab-采用张正友标定法对双目相机进行标定_第13张图片

三、采集图像,对双目标机进行标定

stereoCameraCalibrator:Matlab双目相机标定工具箱


基于Matlab-采用张正友标定法对双目相机进行标定_第14张图片

补充一个知识:

***重投影:***重投影也就是指的第二次投影。

  • 其实第一次投影指的就是相机在拍照的时候三维空间点投影到图像上。

  • 然后我们利用这些图像对一些特征点进行三角定位(triangulation),利用几何信息(对极几何) 构建三角形来确定三维空间点的位置

  • 最后利用我们计算得到的三维点的坐标(注意不是真实的)和我们计算得到的相机位姿(当然也不是真实的)进行第二次投影,也就是重投影

**对极几何:极线几何约束是一种点对直线的约束,而不是点与点的约束,尽管如此,极线约束给出了对应点重要的约束条件,它将对应点匹配从整幅图像寻找压缩到在一条直线上寻找对应点。在立体视觉测量中,立体匹配(对应点的匹配 )是一项关键技术,极线几何在其中起着重要作用。立体视觉系统中,有两个摄像机在不同角度拍摄物理空间中的一实体点,在两副图像上分别成有有两个成像点。立体匹配就是已知其中的一个成像点,在另一副图像上找出该成像点的对应点—极限搜索(高翔13.2讲)。极线几何约束是一种常用的匹配约束技术。(Mastering OpenCV with Practical Computer Vision Projects)

1、利用Matlab中的stereoCameraCalibrator工具箱进行双目相机标定

基于Matlab-采用张正友标定法对双目相机进行标定_第15张图片

基于Matlab-采用张正友标定法对双目相机进行标定_第16张图片





基于Matlab-采用张正友标定法对双目相机进行标定_第17张图片

2、补充(以下内容引用自单目相机提高标定精度的经验_zilanpotou182的博客-CSDN博客_提高相机标定精度)

为了提高单目相机标定的精度,认真看了张正友标定法的原文,并且学习过网上一些牛人的方法,但是大部分时候说的很笼统,自己把这些经验总结起来并都测试了一下,感觉靠谱的结论列出如下:

(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张。

你可能感兴趣的:(matlab,开发语言,计算机视觉)