(转)OpenCV版本的摄像机标定
摄像机的标定问题是机器视觉领域的入门问题,可以分为传统的摄像机定标方法和摄像机自定标方法。定标的方法有很多中常见的有: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说的是不考虑畸变的投影值,这个就太简单了)。
*************************************************************************************
#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";
}
转载于:https://www.cnblogs.com/milier-otw/archive/2013/02/23/OpenCV.html
(转)OpenCV版本的摄像机标定相关推荐
- 三维重建 - 摄像机标定和立体匹配中极线约束方法
摘自http://www.ahcit.com/lanmuyd.asp?id=2677,以作备录,若有版本问题,请告知. 关于摄像机标定和立体匹配中极线约束方法方面,描述的比较清楚. 一种基于OpenC ...
- 鱼眼摄像头标定与畸变校正(双OPENCV版本)
转载请注明作者和出处:http://blog.csdn.net/u011475210 代码地址:https://github.com/WordZzzz/fisheye_calibration 软件版本 ...
- MFC+OPENCV摄像机标定
摄像机的追踪标定 本文是我第一次在csdn上写的博客,有不详之处,望大家见谅,也希望大家多多支持. 废话不多说,直接进入正题.对于摄像机标定,是学习图像处理和机器视觉不可回避的话题,这方面的现有理论已 ...
- 用OpenCV进行摄像机标定
用OpenCV进行摄像机标定 照相机已经存在很长时间了.然而,随着廉价针孔相机在20世纪末的引入,日常生活中变得司空见惯.不幸的是,这种廉价伴随着它的代价:显著的扭曲.幸运的是,这些常数,通过校准和一 ...
- Python+OpenCV学习(17)---摄像机标定
Python+OpenCV学习(17)---摄像机标定 原文:http://blog.csdn.net/firemicrocosm/article/details/48594897 利用python学 ...
- 张正友摄像机标定的研究(MATLAB+OpenCV)
张正友 本科浙大,本来以为是中国人论文是中文呢,哎 张正友的主页: http://research.microsoft.com/en-us/um/people/zhang/Calib/ 不过里面的棋盘 ...
- Python+OpenCV:摄像机标定(Camera Calibration)
Python+OpenCV:摄像机标定(Camera Calibration) 理论 Some pinhole cameras introduce significant distortion to ...
- matlab张正友摄像机标定算法应用,张正友摄像机标定的研究(MATLAB+OpenCV)
张正友 本科浙大,本来以为是中国人论文是中文呢,哎 不过里面的棋盘格跟我的不一样啊,why???,我决定先看看中文的论文吧,我的首要任务是弄清楚输入输出,流程,怎么用吧 matlab 跟 opencv ...
- 基于opencv的摄像机标定
原理简述: 三维世界中的点的位置与其对应的二维投影,遵从以下公式: 其中, M表示三维世界中的点: [R|T]表示欧氏变换,是一个3*4矩阵 A表示相机参数矩阵,存放相机内部参数 P表示M ...
最新文章
- Windows xp/2003 中安装虚拟网卡 Microsoft Loopback Adapter
- 安装scala之后,命令行中输入scala报错nullpointException
- sap 实战 table
- nasm汇编:段的申明、$$、$
- 关于一道数据库例题的解析。为什么σ age22 (πS_ID,SCORE (SC) ) 选项是错的?
- 获取随机数的方式Random类对象的方法 java 0913
- lamp源码三层结构
- mysql 随机函数 效率_MySQL 随机函数获取数据速度和效率分析
- 代替人工批卷?基于目标检测模型的试卷自动批阅实践
- C语言自学笔记(16)
- 富爸爸,穷爸爸(财务自由之路)
- Redis 报错: WRONGTYPE Operation against a key holding the wrong kind of value
- element input限制输入数字
- stream filter 多条件筛选
- 路由协议之:WSN网络的RPL路由协议 for 6LOWPAN
- html表单直接发送邮件,html表单匿名发送电子邮件
- kali-linux u盘便携性系统,暗组u盘怎么进入kali linux系统
- python中什么是一个无序的不重复元素序列_无序Python集的“顺序”
- openldap 匿名访问
- oracle级联 drop,请教:oralce自带主外键级联删除的原理?
热门文章
- oracle ocr组成员替换,Oracle RAC 迁移替换 OCR 盘
- Java综合知识总结_基础篇
- Java设计模式(装饰者模式-组合模式-外观模式-享元模式)
- 一位刚刚成功上岸的智能车队员对于参赛经历总结与对比赛的建议
- 智能车竞赛,AI视觉组赛题浅析
- 第十六届智能车竞赛创意组比赛-筹划初稿
- Tenda路由器设置
- 2021西南位育高考成绩查询,上海近40所高中2020高考录取情况汇总!
- c语言移数有n个整数使其,有N个整数,使其前面各数顺序向后移动M个位置,最后M个数变成前面的...
- python 生产消费者_python之生产者消费者模型实现详解