张正友双目标定
来源:互联网 发布:linux ssh限制ip 编辑:程序博客网 时间:2024/04/20 02:27
摄像机的标定问题是机器视觉领域的入门问题,可以分为传统的摄像机定标方法和摄像机自定标方法。定标的方法有很多中常见的有:Tsai(传统)和张正友(介于传统和自定标)等, 摄像机成像模型和四个坐标系(通用原理)。
摄像机模型采用经典的小孔模型,如图中Oc(光心),像面π表示的是视野平面,其到光心的距离为f(镜头焦距)。
四个坐标系分别为:世界坐标系(Ow),摄像机坐标系(Oc),图像物理坐标系(O1,单位mm),图像像素坐标系(O,位于视野平面的左上角,单位pix)。
空间某点P到其像点p的坐标转换过程主要是通过这四套坐标系的三次转换实现的,首先将世界坐标系进行平移和转换得到摄像机坐标系,然后根据三角几何变换得到图像物理坐标系,最后根据像素和公制单位的比率得到图像像素坐标系。(实际的应用过程是这个的逆过程,即由像素长度获知实际的长度)。
ps:通过摄像头的标定,可以得到视野平面上的mm/pix分辨率,对于视野平面以外的物体还是需要通过坐标转换得到视野平面上。
转化的过程和公式参见:摄像机标定原理(关键是三个坐标系).ppt
2 张正友算法的原理
zhang法通过对一定标板在不同方向多次(三次以上)完整拍照,不需要知道定标板的运动方式。直接获得相机的内参(参考文献上矩阵A)和畸变系数。该标定方法精度高于自定标法,且不需要高精度的定位仪器。
ZHANG的算法包含两个模型:一.经典针孔模型,包含四个坐标系,二畸变模型(这个来源未知)
公式三项依次表示,径向畸变,切线畸变,薄棱镜畸变。OPENCV中函数只能给出k1,k2,p1,p2。
还存在另外一种畸变模型,见《摄像机标定算法库的设计和试验验证》一文26 page。(也不知道出处)
ps:单从公式推导的过程来看,第一组公式等号右边应该是U0。
Key:这个方程怎么求?x,y 代表理想的图像坐标(mm),是未知数(不太可能是已知数,xike说的是不考虑畸变的投影值,这个就太简单了)。
cvmat);
#include "cvut.h"#include <iostream>#include <fstream>#include <string>using namespace cvut;using namespace std; void main() { ifstream fin("calibdata.txt"); ofstream fout("caliberation_result.txt"); cout<<"开始提取角点………………"; int image_count=0; CvSize image_size; CvSize board_size = cvSize(5,7); CvPoint2D32f * image_points_buf = new CvPoint2D32f[board_size.width*board_size.height]; Seq<CvPoint2D32f> image_points_seq; string filename; while (std::getline(fin,filename)) { cout<<"\n 将鼠标焦点移到标定图像所在窗口并输入回车进行下一幅图像的角点提取 \n"; image_count++; int count; Image<uchar> view(filename); if (image_count == 1) { image_size.width = view.size().width; image_size.height = view.size().height; } if (0 == cvFindChessboardCorners( view.cvimage, board_size, image_points_buf, &count, CV_CALIB_CB_ADAPTIVE_THRESH )) { cout<<"can not find chessboard corners!\n"; exit(1); } else { Image<uchar> view_gray(view.size(),8,1); rgb2gray(view,view_gray); cvFindCornerSubPix( view_gray.cvimage, image_points_buf, count, cvSize(11,11), cvSize(-1,-1), cvTermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 30, 0.1 )); image_points_seq.push_back(image_points_buf,count); cvDrawChessboardCorners( view.cvimage, board_size, image_points_buf, count, 1); view.show("calib"); cvWaitKey(); view.close(); } } delete []image_points_buf; cout<<"角点提取完成!\n"<<endl; cout<<"开始定标………………"<<"\n"<<endl; CvSize square_size = cvSize(10,10); Matrix<double> object_points(1,board_size.width*board_size.height*image_count,3); Matrix<double> image_points(1,image_points_seq.cvseq->total,2); Matrix<int> point_counts(1,image_count,1); Matrix<double> intrinsic_matrix(3,3,1); Matrix<double> distortion_coeffs(1,4,1); Matrix<double> rotation_vectors(1,image_count,3); Matrix<double> translation_vectors(1,image_count,3); int i,j,t; for (t=0;t<image_count;t++) { for (i=0;i<board_size.height;i++) { for (j=0;j<board_size.width;j++) { object_points(0,t*board_size.height*board_size.width + i*board_size.width + j,0) = i*square_size.width; object_points(0,t*board_size.height*board_size.width + i*board_size.width + j,1) = j*square_size.height; object_points(0,t*board_size.height*board_size.width + i*board_size.width + j,2) = 0; } } } char str[10]; itoa(image_points_seq.cvseq->total,str,10); cout<<str<<"\n"<<endl; for (i=0;i<image_points_seq.cvseq->total;i++) { image_points(0,i,0) = image_points_seq[i].x; image_points(0,i,1) = image_points_seq[i].y; } for (i=0;i<image_count;i++) point_counts(0,i) = board_size.width*board_size.height; cvCalibrateCamera2(object_points.cvmat, image_points.cvmat, point_counts.cvmat, image_size, intrinsic_matrix.cvmat, distortion_coeffs.cvmat, rotation_vectors.cvmat, translation_vectors.cvmat, 0); cout<<"定标完成!\n"; cout<<"标定结果显示\n"; cout<<"*************************************************\n"; cout<<"相机内参intrinsic_matrix\n"; for(int h=0;h<3;h++) { cout<<"X:"<<intrinsic_matrix(h,0,0)<<"\tY:"<<intrinsic_matrix(h,1,0)<<"\tZ:"<<intrinsic_matrix(h,2,0)<<"\n"; } cout<<"\n畸变系数:distortion_coeffs\n"; for(int ndis=0;ndis<4;ndis++) { cout<<distortion_coeffs(0,ndis,0)<<"\\"; } cout<<"\n"; cout<<"\nrotation_vectors\n"; for(int rot=0;rot<7;rot++) { cout<<"X:"<<rotation_vectors(0,rot,0)<<"\tY:"<<rotation_vectors(0,rot,1)<<"\tZ:"<<rotation_vectors(0,rot,2)<<"\n"; } cout<<"\ntranslation_vectors\n"; for(i=0;i<7;i++) { cout<<"第"<<i+1<<"张图"<<"\tX:"<<translation_vectors(0,i,0)<<"\tY:"<<translation_vectors(0,i,1)<<"\tZ:"<<translation_vectors(0,i,2)<<"\n"; } cout<<"***************************************************\n"; cout<<"开始评价定标结果………………\n"; double total_err = 0.0; double err = 0.0; Matrix<double> image_points2(1,point_counts(0,0,0),2); int temp_num = point_counts(0,0,0); cout<<"\t每幅图像的定标误差:\n"; fout<<"每幅图像的定标误差:\n"; for (i=0;i<image_count;i++) { cvProjectPoints2(object_points.get_cols(i * point_counts(0,0,0),(i+1)*point_counts(0,0,0)-1).cvmat, rotation_vectors.get_col(i).cvmat, translation_vectors.get_col(i).cvmat, intrinsic_matrix.cvmat, distortion_coeffs.cvmat, image_points2.cvmat, 0,0,0,0); err = cvNorm(image_points.get_cols(i*point_counts(0,0,0),(i+1)*point_counts(0,0,0)-1).cvmat, image_points2.cvmat, CV_L1); total_err += err/=point_counts(0,0,0); cout<<"******************************************************************\n"; cout<<"\t\t第"<<i+1<<"幅图像的平均误差:"<<err<<"像素"<<'\n'; fout<<"\t第"<<i+1<<"幅图像的平均误差:"<<err<<"像素"<<'\n'; cout<<"显示image_point2\n"; for(int ih=0;ih<7;ih++) { cout<<"X:"<<image_points2(0,ih,0)<<"\tY:"<<image_points2(0,ih,1)<<"\n"; } cout<<"显示object_Points\n"; for(int iw=0;iw<7;iw++) { cout<<"X:"<<image_points.get_cols(i*point_counts(0,0,0),(i+1)*point_counts(0,0,0)-1)(0,iw,0) <<"\tY:"<<image_points.get_cols(i*point_counts(0,0,0),(i+1)*point_counts(0,0,0)-1)(0,iw,1)<<"\n"; } } cout<<"\t总体平均误差:"<<total_err/image_count<<"像素"<<'\n'; fout<<"总体平均误差:"<<total_err/image_count<<"像素"<<'\n'<<'\n'; cout<<"评价完成!\n"; cout<<"开始保存定标结果………………"; Matrix<double> rotation_vector(3,1); Matrix<double> rotation_matrix(3,3); fout<<"相机内参数矩阵:\n"; fout<<intrinsic_matrix<<'\n'; fout<<"畸变系数:\n"; fout<<distortion_coeffs<<'\n'; for (i=0;i<image_count;i++) { fout<<"第"<<i+1<<"幅图像的旋转向量:\n"; fout<<rotation_vectors.get_col(i); for (j=0;j<3;j++) { rotation_vector(j,0,0) = rotation_vectors(0,i,j); } cvRodrigues2(rotation_vector.cvmat,rotation_matrix.cvmat); fout<<"第"<<i+1<<"幅图像的旋转矩阵:\n"; fout<<rotation_matrix; fout<<"第"<<i+1<<"幅图像的平移向量:\n"; fout<<translation_vectors.get_col(i)<<'\n'; } cout<<"完成保存\n";}
- 张正友双目标定
- 双目标定
- OpenCV双目标定
- 双目标定代码
- MATLAB双目标定步骤
- 双目视觉的标定
- 双目摄像头标定参数
- opencv 双目标定程序
- 双目标定log文件
- 双目视觉立体标定
- opencv 双目摄像头标定
- opencv双目标定
- 利用matlab标定工具箱进行双目标定
- 双目标定中stereoCalibrate()函数
- OPENCV3.0 双目立体标定
- OPENCV3.0 双目立体标定
- Opencv双目标定的实现
- OPENCV3.0 双目立体标定
- npm 优质文章汇总
- iOS程序生命周期
- c语言实现简单通讯录
- [数据库事务与锁]详解七: 深入理解乐观锁与悲观锁
- Oracle触发器
- 张正友双目标定
- 第一个小项目完成总结(sql数据库自动备份工具)
- [数据库事务与锁]详解六: MySQL中的共享锁与排他锁
- 文章标题
- log4j 1,2配置
- [数据库事务与锁]详解五: MySQL中的行级锁,表级锁,页级锁
- WinPcap教程:(1)获取设备列表
- 03_模板、类型转换、新数组、Lamdbda表达式、New高级用法
- VMWare Centos 设置时区和时间