OpenCV中文网站

 找回密码
 立即注册
搜索
热搜: 安装 配置
楼主: guvcolie

【代码】单目摄像机标定程序_分享

[复制链接]
发表于 2012-5-4 12:56:53 | 显示全部楼层

【代码】单目摄像机标定程序_分享

谢谢,又有个问题:如果找完 N 幅棋盘图的内角点之后,再用cvCalibrateCamera2函数计算内外参数,这时得到的旋转矩阵是N*3的矩阵,平移向量是N*3的矩阵,这些两个矩阵该怎么用呢?肯定不能用在求一个三维坐标对应的图像坐标吧?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-5-4 16:51:32 | 显示全部楼层

【代码】单目摄像机标定程序_分享

谢谢,又有个问题:如果找完 N 幅棋盘图的内角点之后,再用cvCalibrateCamera2函数计算内外参数,这时得到的旋转矩阵是N*3的矩阵,平移向量是N*3的矩阵,这些两个矩阵该怎么用呢?肯定不能用在求一个三维坐标对应的图像坐标吧?
这两个矩阵是计算标定精度的时候才用的吧。标定几张图片,就有几组R和t,而且每组R和t只对应相应的图片。

Ps:回复时怎么添加图片啊?我点击Img的时候也是添加不了啊  ,晕了,那个标定方格宽度的问题我写好了  但是需要插图片,传不上去啊   郁闷了~~~
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-5-4 17:39:22 | 显示全部楼层

【代码】单目摄像机标定程序_分享

于仕琪老师编写的《learning OPenCV》一书的单目摄像机标定的程序原理是正确的,而且我的源码也是根据这个核心改写的,但是经过我的仔细分析和网上的一些见解,我认为于仕琪老师的这个代码默认定标版的方格宽度是1.0(单位任意,可以认为是mm,cm甚至是m)的,

循环中后三句就是设置标定板的世界坐标系的坐标!
首先看j的范围,是从0到total_per_image(每个标定板的角点总数,即等于49个),代码开始的时候声明了cube_length=7,这里的7指的是每行有7个角点,而不是指每个方格宽度为7mm(cm或m)。
现在再看j/cube_length和j%cube_length。分析j=0,1,2,3,。。。,7,8,。。。,48的情况。J=0时,j/cube_length=0,j%cube_length=0,j=1时,j/cube_length=0,j%cube_length=1,。。。J=7时,j/cube_length=1,j%cube_length=0,j=8时,j/cube_length=1.j%cube_length=1,直到j=48时,j/cube_length=6,j%cube_length=6。循环一遍后,三维坐标为

这样一看,我们能清楚地看到标定板的世界坐标系的坐标是怎么设置的了,即它默认每个格子的宽度为1.0f!
这个代码能不能标定?能!但是它不表示物体的实际长度!所以如果想获得基于实际长度的标定,可以用如下的方式设置世界坐标系的坐标,大家可以尝试基于我的代码修改成如下方式的设置,如果成功的话希望大家跟帖和大家分享,我如果有时间的话我也会修改和大家分享!

Ps:娘的这个论坛上传图片的方式真不友好~~~弄半天

点评

图片呢?你好!  发表于 2015-1-29 17:22
回复 支持 反对

使用道具 举报

发表于 2012-5-4 20:52:22 | 显示全部楼层

【代码】单目摄像机标定程序_分享

哪位牛哥可以研究下如何用lz这个标定程序在和笔记本连接的摄像头上采集图片呢?
现在运行打开的是笔记本的摄像头,而我需要对实验用的BASLER摄像头标定,摄像头有在VC下运行的驱动程序,是要把它加到lz这个标定程序中吗?
回复 支持 反对

使用道具 举报

发表于 2012-5-5 07:52:32 | 显示全部楼层

【代码】单目摄像机标定程序_分享

问题:在标定时,先不初始化方格的实际尺寸,让其默认是1.0f,对标定结果有影响吗?后面应如何再引入方格的实际尺寸呢?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-5-5 14:31:08 | 显示全部楼层

【代码】单目摄像机标定程序_分享

问题:在标定时,先不初始化方格的实际尺寸,让其默认是1.0f,对标定结果有影响吗?后面应如何再引入方格的实际尺寸呢?
我觉得得到的f,cx,cy的数值会有影响。
莫不如直接用实际的长度来标定,如果你的编程能力可以的话可以尝试改写下,我有时间也会改写下,这个改写还是很好实现的
回复 支持 反对

使用道具 举报

发表于 2012-5-6 10:24:17 | 显示全部楼层

【代码】单目摄像机标定程序_分享

在MFC程序中,自定义了一个类,在该类中的成员函数里无法使用CV_MAT_ELEM这个宏对矩阵初始化,怎么办?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-5-6 13:17:16 | 显示全部楼层

【代码】单目摄像机标定程序_分享

在MFC程序中,自定义了一个类,在该类中的成员函数里无法使用CV_MAT_ELEM这个宏对矩阵初始化,怎么办?
抱歉  我没学过MFC   你可以到技术群咨询下
回复 支持 0 反对 1

使用道具 举报

 楼主| 发表于 2012-5-6 19:29:51 | 显示全部楼层

【代码】单目摄像机标定程序_分享

以下是我引入实际标定板方格宽度的标定程序,是以我发的帖子的基础修改的,代码如下
如果转载,请注明出处http://blog.csdn.net/guvcolie/article/details/7628406
#include "stdafx.h"
#include "cv.h"
#include "highgui.h"
#include <string>
#include <iostream>

using namespace std;

int main()
{
        CvCapture* capture;   //摄像头指针
        capture=cvCreateCameraCapture(0);
        if(capture==0){
                printf(&quot;无法捕获摄像头设备!\\n\\n&quot;);
                return 0;
        }else{
                printf(&quot;捕获摄像头设备成功!!\\n\\n&quot;);
        }
        IplImage* frame;   //图像指针
        cvNamedWindow(&quot;摄像机帧截取窗口&quot;,1);
        printf(&quot;按“C”键截取当前帧并保存为标定图片...\\n按“Q”键退出截取帧过程...\\n\\n&quot;);
        int number_image=1;   //文件名后的编号,从1开始,也是截取的图像帧数
        char filename[20]=&quot;&quot;;   //保存文件名的字符串数组
        while(true)
        {
                frame=cvQueryFrame(capture);
                if(!frame)
                         break;
                cvShowImage(&quot;摄像机帧截取窗口&quot;,frame);
               
                if(cvWaitKey(10)==\'c\'){
                        sprintf_s (filename,&quot;%d.jpg&quot;,number_image);
                        cvSaveImage(filename,frame);
                        cout<<&quot;成功获取当前帧,并以文件名&quot;<<filename<<&quot;保存...\\n\\n&quot;;
                        printf(&quot;按“C”键截取当前帧并保存为标定图片...\\n按“Q”键退出截取帧过程...\\n\\n&quot;);
                        number_image++;
                }else if(cvWaitKey(10)==\'q\'){
                        printf(&quot;截取图像帧过程完成...\\n\\n&quot;);
                        cout<<&quot;共成功截取&quot;<<--number_image<<&quot;帧图像!!\\n\\n&quot;;
                        break;
                }
        }
        cvReleaseImage(&frame);  //若您的是1.0版本,如果报错请修改为cvReleaseCapture(&capture),或将此句加在cvReleaseImage(&frame);后

        cvDestroyWindow(&quot;摄像机帧截取窗口&quot;);



        IplImage * show;   //RePlay图像指针
        cvNamedWindow(&quot;RePlay&quot;,1);          
        int number_image_copy=number_image;  //复制图像帧数
        CvSize board_size=cvSize(7,7);   //标定板角点数
        CvSize2D32f square_size=cvSize2D32f(18.2,18.2);                //假设我的每个标定方格长宽都是1.82厘米       
                float square_length=square_size.width;                //方格长度
        float square_height=square_size.height;                //方格高度
        int board_width=board_size.width;   //每行角点数
        int board_height=board_size.height;  //每列角点数
        int total_per_image=board_width*board_height;  //每张图片角点总数
        int count;  //存储每帧图像中实际识别的角点数
        int found;        //识别标定板角点的标志位
        int step;        //存储步长,step=successes*total_per_image;
        int successes=0;        //存储成功找到标定板上所有角点的图像帧数
        int a=1;        //临时变量,表示在操作第a帧图像

        CvPoint2D32f * image_points_buf = new CvPoint2D32f[total_per_image];   //存储角点图像坐标的数组
        CvMat * image_points=cvCreateMat(number_image*total_per_image,2,CV_32FC1);        //存储角点的图像坐标的矩阵               
        CvMat * object_points=cvCreateMat(number_image*total_per_image,3,CV_32FC1);        //存储角点的三维坐标的矩阵
        CvMat * point_counts=cvCreateMat(number_image,1,CV_32SC1);                //存储每帧图像的识别的角点数
        CvMat * intrinsic_matrix=cvCreateMat(3,3,CV_32FC1);                //内参数矩阵
        CvMat * distortion_coeffs=cvCreateMat(5,1,CV_32FC1);        //畸变系数


        while(a<=number_image_copy){
                sprintf_s (filename,&quot;%d.jpg&quot;,a);
                show=cvLoadImage(filename,-1);
                found=cvFindChessboardCorners(show,board_size,image_points_buf,&count,
                                                                         CV_CALIB_CB_ADAPTIVE_THRESH|CV_CALIB_CB_FILTER_QUADS);
                if(found==0){                //如果没找到标定板角点时
                        cout<<&quot;第&quot;<<a<<&quot;帧图片无法找到棋盘格所有角点!\\n\\n&quot;;
                        cvNamedWindow(&quot;RePlay&quot;,1);
                        cvShowImage(&quot;RePlay&quot;,show);
                        cvWaitKey(0);

                }else{                        //找到标定板角点时
                        cout<<&quot;第&quot;<<a<<&quot;帧图像成功获得&quot;<<count<<&quot;个角点...\\n&quot;;       
                        cvNamedWindow(&quot;RePlay&quot;,1);
                        IplImage * gray_image= cvCreateImage(cvGetSize(show),8,1);
                        cvCvtColor(show,gray_image,CV_BGR2GRAY);
                        cout<<&quot;获取源图像灰度图过程完成...\\n&quot;;
                        cvFindCornerSubPix(gray_image,image_points_buf,count,cvSize(11,11),cvSize(-1,-1),
                                                                cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,30,0.1));
                        cout<<&quot;灰度图亚像素化过程完成...\\n&quot;;
                        cvDrawChessboardCorners(show,board_size,image_points_buf,count,found);
                        cout<<&quot;在源图像上绘制角点过程完成...\\n\\n&quot;;
                        cvShowImage(&quot;RePlay&quot;,show);
                        cvWaitKey(0);
                }

                if(total_per_image==count){
                        step=successes*total_per_image;   //计算存储相应坐标数据的步长
                        for(int i=step,j=0;j<total_per_image;++i,++j){
                                CV_MAT_ELEM(*image_points,float,i,0)=image_points_buf[j].x;               
                                CV_MAT_ELEM(*image_points,float,i,1)=image_points_buf[j].y;
                                CV_MAT_ELEM(*object_points,float,i,0)=(float)((j/board_width)*square_length);
                                CV_MAT_ELEM(*object_points,float,i,1)=(float)((j%board_width)*square_height);
                                CV_MAT_ELEM(*object_points,float,i,2)=0.0f;
                        }
                        CV_MAT_ELEM(*point_counts,int,successes,0)=total_per_image;
                        successes++;
                }
                a++;
        }

        cvReleaseImage(&show);
        cvDestroyWindow(&quot;RePlay&quot;);


        cout<<&quot;*********************************************\\n&quot;;
        cout<<number_image<<&quot;帧图片中,标定成功的图片为&quot;<<successes<<&quot;帧...\\n&quot;;
        cout<<number_image<<&quot;帧图片中,标定失败的图片为&quot;<<number_image-successes<<&quot;帧...\\n\\n&quot;;
        cout<<&quot;*********************************************\\n\\n&quot;;

        cout<<&quot;按任意键开始计算摄像机内参数...\\n\\n&quot;;


        CvCapture* capture1;
        capture1=cvCreateCameraCapture(0);
        IplImage * show_colie;
        show_colie=cvQueryFrame(capture1);
       
       
        CvMat * object_points2=cvCreateMat(successes*total_per_image,3,CV_32FC1);
        CvMat * image_points2=cvCreateMat(successes*total_per_image,2,CV_32FC1);
        CvMat * point_counts2=cvCreateMat(successes,1,CV_32SC1);


        for(int i=0;i<successes*total_per_image;++i){
                CV_MAT_ELEM(*image_points2,float,i,0)=CV_MAT_ELEM(*image_points,float,i,0);
                CV_MAT_ELEM(*image_points2,float,i,1)=CV_MAT_ELEM(*image_points,float,i,1);
                CV_MAT_ELEM(*object_points2,float,i,0)=CV_MAT_ELEM(*object_points,float,i,0);
                CV_MAT_ELEM(*object_points2,float,i,1)=CV_MAT_ELEM(*object_points,float,i,1);
                CV_MAT_ELEM(*object_points2,float,i,2)=CV_MAT_ELEM(*object_points,float,i,2);
        }

        for(int i=0;i<successes;++i){
                CV_MAT_ELEM(*point_counts2,int,i,0)=CV_MAT_ELEM(*point_counts,int,i,0);
        }

       
        cvReleaseMat(&object_points);
        cvReleaseMat(&image_points);
        cvReleaseMat(&point_counts);


        CV_MAT_ELEM(*intrinsic_matrix,float,0,0)=1.0f;
        CV_MAT_ELEM(*intrinsic_matrix,float,1,1)=1.0f;
       

        cvCalibrateCamera2(object_points2,image_points2,point_counts2,cvGetSize(show_colie),
                                                intrinsic_matrix,distortion_coeffs,NULL,NULL,0);
       
        cout<<&quot;摄像机内参数矩阵为:\\n&quot;;
        cout<<CV_MAT_ELEM(*intrinsic_matrix,float,0,0)<<&quot;    &quot;<<CV_MAT_ELEM(*intrinsic_matrix,float,0,1)
                                                                                                                        <<&quot;    &quot;<<CV_MAT_ELEM(*intrinsic_matrix,float,0,2)
                                                                                                                        <<&quot;\\n\\n&quot;;
        cout<<CV_MAT_ELEM(*intrinsic_matrix,float,1,0)<<&quot;    &quot;<<CV_MAT_ELEM(*intrinsic_matrix,float,1,1)
                                                                                                                        <<&quot;    &quot;<<CV_MAT_ELEM(*intrinsic_matrix,float,1,2)
                                                                                                                        <<&quot;\\n\\n&quot;;
        cout<<CV_MAT_ELEM(*intrinsic_matrix,float,2,0)<<&quot;    &quot;<<CV_MAT_ELEM(*intrinsic_matrix,float,2,1)
                                                                                                                        <<&quot;          &quot;<<CV_MAT_ELEM(*intrinsic_matrix,float,2,2)
                                                                                                                        <<&quot;\\n\\n&quot;;

        cout<<&quot;畸变系数矩阵为:\\n&quot;;
        cout<<CV_MAT_ELEM(*distortion_coeffs,float,0,0)<<&quot;    &quot;<<CV_MAT_ELEM(*distortion_coeffs,float,1,0)
                                                                                                                        <<&quot;    &quot;<<CV_MAT_ELEM(*distortion_coeffs,float,2,0)
                                                                                                                        <<&quot;    &quot;<<CV_MAT_ELEM(*distortion_coeffs,float,3,0)
                                                                                                                        <<&quot;    &quot;<<CV_MAT_ELEM(*distortion_coeffs,float,4,0)
                                                                                                                        <<&quot;\\n\\n&quot;;

        cvSave(&quot;Intrinsics.xml&quot;,intrinsic_matrix);
        cvSave(&quot;Distortion.xml&quot;,distortion_coeffs);

        cout<<&quot;摄像机矩阵、畸变系数向量已经分别存储在名为Intrinsics.xml、Distortion.xml文档中\\n\\n&quot;;

        CvMat * intrinsic=(CvMat *)cvLoad(&quot;Intrinsics.xml&quot;);
        CvMat * distortion=(CvMat *)cvLoad(&quot;Distortion.xml&quot;);

        IplImage * mapx=cvCreateImage(cvGetSize(show_colie),IPL_DEPTH_32F,1);
        IplImage * mapy=cvCreateImage(cvGetSize(show_colie),IPL_DEPTH_32F,1);
       
        cvInitUndistortMap(intrinsic,distortion,mapx,mapy);

        cvNamedWindow(&quot;原始图像&quot;,1);
        cvNamedWindow(&quot;非畸变图像&quot;,1);

        cout<<&quot;按‘E’键退出显示...\\n\\n&quot;;

        while(show_colie){
                IplImage * clone=cvCloneImage(show_colie);
                cvShowImage(&quot;原始图像&quot;,show_colie);
                cvRemap(clone,show_colie,mapx,mapy);
                cvReleaseImage(&clone);
                cvShowImage(&quot;非畸变图像&quot;,show_colie);

                if(cvWaitKey(10)==\'e\'){
                        break;
                }

                show_colie=cvQueryFrame(capture1);
        }

        return 0;
       
}

以下是一个同学用我的这个程序标定的图片,他的是广角相机,左上角可能因为安装、质量原因,比其他角的畸变较大,但整体效果可以

如果这个程序有什么问题或者疑问,请回帖,我会尽快予以回复!
回复 支持 反对

使用道具 举报

发表于 2012-5-6 20:13:35 | 显示全部楼层

【代码】单目摄像机标定程序_分享

lz威武!~ 很给力!~
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|OpenCV中文网站

GMT+8, 2024-5-10 07:42 , Processed in 0.010387 second(s), 14 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表