opencv系列


文章目录

  • opencv系列
  • 一、鱼眼镜头模型
  • 二、投影函数
    • 等距投影模型
    • 等立体角投影模型
    • 正交投影模型
    • 体视投影模型
  • 三、OpenCV中的鱼眼相机模型
  • 四、标定(C++)实现
    • 使用的函数
    • 采集标定图像
    • 标定代码
    • 标定结果

一、鱼眼镜头模型

鱼眼镜头一般是由十几个不同的透镜组合而成的,在成像的过程中,入射光线经过不同程度的折射,投影到尺寸有限的成像平面上,使得鱼眼镜头与普通镜头相比起来拥有了更大的视野范围。下图表示出了鱼眼相机的一般组成结构。最前面的两个镜头发生折射,使入射角减小,其余的镜头相当于一个成像镜头,这种多元件的构造结构使对鱼眼相机的折射关系的分析变得相当复杂。

研究表明鱼眼相机成像时遵循的模型可以近似为单位球面投影模型。可以将鱼眼相机的成像过程分解成两步:第一步,三维空间点线性地投影到一个球面上,它是一个虚拟的单位球面,它的球心与相机坐标系的原点重合;第二步,单位球面上的点投影到图像平面上,这个过程是非线性的。下图表示出了鱼眼相机的成像过程。

我们知道,普通相机成像遵循的是针孔相机模型,在成像过程中实际场景中的直线仍被投影为图像平面上的直线。但是鱼眼相机如果按照针孔相机模型成像的话,投影图像会变得非常大,当相机视场角达到180°时,图像甚至会变为无穷大。所以,鱼眼相机的投影模型为了将尽可能大的场景投影到有限的图像平面内,允许了相机畸变的存在。并且由于鱼眼相机的径向畸变非常严重,所以鱼眼相机主要的是考虑径向畸变,而忽略其余类型的畸变。

二、投影函数

为了将尽可能大的场景投影到有限的图像平面内,鱼眼相机会按照一定的投影函数来设计。根据投影函数的不同,鱼眼相机的设计模型大致能被分为四种:等距投影模型、等立体角投影模型、正交投影模型和体视投影模型。下面的四种鱼眼相机的投影模型反映出了空间中的一点P是如何投影到球面上,然后到图像平面上成像的。

等距投影模型


上述式子中,rd表示鱼眼图像中的点到畸变中心的距离,是鱼眼相机的焦距,是入射光线与鱼眼相机光轴之间的夹角,即入射角。

等立体角投影模型

正交投影模型


体视投影模型

三、OpenCV中的鱼眼相机模型

OpenCV中使用的模型是由Kannala提出的一种鱼眼相机的一般近似模型。在等距投影模型的基础上提出来的。下面来详细分析其鱼眼相机模型的提出过程。我们可以将鱼眼相机模型的形式统一以等距投影模型的形式来表示,即

对实际的鱼眼镜头来说,它们不可能精确地按照投影模型来设计,所以为了方便鱼眼相机的标定,Kannala提出了一种鱼眼相机的一般多项式近似模型。通过前面的四个模型,可以发现 θd是θ的奇函数,而且将这些式子按泰勒级数展开,发现 θd可以用θ 的奇次多项式表示,即

为了实际计算的方便,需要确定式中 θd取到的次幂数。Kannala提出取式的前五项即取到的九次方,就给出了足够的自由度来很好地近似各种投影模型。 θd的一次项系数可以为1,于是OpenCV中使用的鱼眼相机模型为:

上式表示的模型是根据四种鱼眼相机投影模型得出的一种通用鱼眼相机多项式模型。这种模型根据θ能够得到 θd ,即通过无畸变图像中的点能够计算出鱼眼图像中的畸变点。这种模型在OpenCV的鱼眼相机标定方法中是适用的,因为OpenCV借助标定板对鱼眼相机进行标定。从空间点到鱼眼图像上的点的变换过程可用式子表示为:

上面式子中, X表示空间点,Xc表示相机坐标系下对应的空间点, Rt分别是两个坐标系之间的旋转矩阵和平移向量, (u,v)T 表示投影到鱼眼图像上的对应点。OpenCV中对鱼眼相机的标定步骤能够分成四步:

(1)初始化内参数;
(2)初始化外参数;
(3)使用LM算法最小化定位的图像点和投影的图像点之间的投影误差;
(4)确定结果。

四、标定(C++)实现

使用的函数

由于鱼眼镜头和针孔镜头的模型不一样,对于鱼眼镜头的模型在之前的博客中已经做了详细介绍,这里直接使用OpenCV中的cv::fisheye::calibrate()函数进行标定。函数原型如下,需要输入目标点集,图像点集、图像尺寸。函数输出相机内参,畸变系数,旋转矩阵和平移向量,以及反投影误差。

 CV_EXPORTS double calibrate(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints, const Size& image_size,InputOutputArray K, InputOutputArray D, OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs, int flags = 0,TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100, DBL_EPSILON));

采集标定图像

采集若干拍摄有标定棋盘格的图像,并使棋盘格出现在画面的各个位置,特别是边缘位置。如下图所示:

标定代码

#include "stdio.h"
#include <iostream>
#include <fstream>
#include <io.h>#include "opencv2/opencv.hpp"
#include <opencv2/core/core.hpp>
#include "opencv2/calib3d/calib3d.hpp"
#include <opencv2/highgui/highgui.hpp>using namespace std;
using namespace cv;void getFiles(string path, vector<string>& files)
{//文件句柄intptr_t hFile = 0;//文件信息struct _finddata_t fileinfo;string p;if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1){do{//如果是目录,迭代之//如果不是,加入列表if ((fileinfo.attrib &  _A_SUBDIR)){if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)getFiles(p.assign(path).append("\\").append(fileinfo.name), files);}else{files.push_back(p.assign(path).append("\\").append(fileinfo.name));}} while (_findnext(hFile, &fileinfo) == 0);_findclose(hFile);}
}int main(int argc, char** argv)
{   string filePath = ".\\720PPcalib\\front";vector<string> files;获取该路径下的所有文件getFiles(filePath, files);const int board_w = 6;const int board_h = 4;const int NPoints = board_w * board_h;//棋盘格内角点总数const int boardSize = 30; //mmMat image,grayimage;Size ChessBoardSize = cv::Size(board_w, board_h);vector<Point2f> tempcorners;int flag = 0;flag |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC;//flag |= cv::fisheye::CALIB_CHECK_COND;flag |= cv::fisheye::CALIB_FIX_SKEW;//flag |= cv::fisheye::CALIB_USE_INTRINSIC_GUESS;vector<Point3f> object;for (int j = 0; j < NPoints; j++){object.push_back(Point3f((j % board_w) * boardSize, (j / board_w) * boardSize, 0)); }cv::Matx33d intrinsics;//z:相机内参cv::Vec4d distortion_coeff;//z:相机畸变系数vector<vector<Point3f> > objectv;vector<vector<Point2f> > imagev;Size corrected_size(1280, 720);Mat mapx, mapy;Mat corrected;ofstream intrinsicfile("intrinsics_front1103.txt");ofstream disfile("dis_coeff_front1103.txt");int num = 0;bool bCalib = false;while (num < files.size()){image = imread(files[num]);if (image.empty())break;imshow("corner_image", image);waitKey(10);cvtColor(image, grayimage, CV_BGR2GRAY);IplImage tempgray = grayimage;bool findchessboard = cvCheckChessboard(&tempgray, ChessBoardSize);if (findchessboard){bool find_corners_result = findChessboardCorners(grayimage, ChessBoardSize, tempcorners, 3);if (find_corners_result){cornerSubPix(grayimage, tempcorners, cvSize(5, 5), cvSize(-1, -1), cvTermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));drawChessboardCorners(image, ChessBoardSize, tempcorners, find_corners_result);imshow("corner_image", image);cvWaitKey(100);objectv.push_back(object);imagev.push_back(tempcorners);cout << "capture " << num << " pictures" << endl;}}tempcorners.clear();num++;}cv::fisheye::calibrate(objectv, imagev, cv::Size(image.cols,image.rows), intrinsics, distortion_coeff, cv::noArray(), cv::noArray(), flag, cv::TermCriteria(3, 20, 1e-6));  fisheye::initUndistortRectifyMap(intrinsics, distortion_coeff, cv::Matx33d::eye(), intrinsics, corrected_size, CV_16SC2, mapx, mapy);for(int i=0; i<3; ++i){for(int j=0; j<3; ++j){intrinsicfile<<intrinsics(i,j)<<"\t";}intrinsicfile<<endl;}for(int i=0; i<4; ++i){disfile<<distortion_coeff(i)<<"\t";}intrinsicfile.close();disfile.close();num = 0;while (num < files.size()){image = imread(files[num++]);if (image.empty())break;remap(image, corrected, mapx, mapy, INTER_LINEAR, BORDER_TRANSPARENT);imshow("corner_image", image);imshow("corrected", corrected);cvWaitKey(200); }cv::destroyWindow("corner_image");cv::destroyWindow("corrected");image.release();grayimage.release();corrected.release();mapx.release();mapy.release();return 0;
}

标定结果

使用标定的结果进行畸变校正后的结果如下所示,可以看到,原本弯曲的曲线已经变直。

鱼眼相机成像模型以及基于OpenCV标定鱼眼镜头(C++)相关推荐

  1. 机器视觉——鱼眼相机成像模型

    一.鱼眼镜头模型   鱼眼镜头一般是由十几个不同的透镜组合而成的,在成像的过程中,入射光线经过不同程度的折射,投影到尺寸有限的成像平面上,使得鱼眼镜头与普通镜头相比起来拥有了更大的视野范围.下图表示出 ...

  2. 鱼眼相机成像模型学习

    0.前言 相机将三维世界中的坐标点(单位为米)映射到二维图像平面(单位为像素),这个过程可以用一个几何模型进行描述,其中最简单的一个模型称为针孔模型.之所以说它简单,是因为这是个线性变换:但是实际的相 ...

  3. 相机标定(三)-相机成像模型

    >>>文章索引<<< 相机标定(一)-原理及内参.外参 相机标定(二)-畸变校正,张正友标定法 相机标定(三)-相机成像模型 1 人眼&相机结构 1.1 类 ...

  4. 从零开始一起学习SLAM(8)相机成像模型

    文章目录 小孔成像 纷繁复杂的坐标系 针孔相机成像原理 相机畸变   此文发于公众号:计算机视觉life.   原文链接:从零开始一起学习SLAM | 相机成像模型 上一篇文章<从零开始一起学习 ...

  5. 相机成像模型、相机内参、外参、以及相机标定

    看了一圈各个平台讲解相机模型.相机标定的文章,很多只是简单罗列几个公式,其中的细节都没说明,本着学习的出发点写下这篇文章,希望能给初学者解惑.本文主要讲解相机模型,一步步推导从世界坐标系到图像坐标系的 ...

  6. 【鱼眼相机模型】鱼眼相机投影模型理解

    一.从普通镜头到鱼眼镜头 如图1所示,普通镜头下的光线依据针孔相机模型进行成像(该部分可参考相机投影关系).但该模型存在一个缺陷:相机视野范围越大,所需的成像平面也越大,当相机视野范围要求在180°时 ...

  7. 9.2【彩色模型】-----基于Opencv实现-----把一幅RGB图转为CMY图

    (一)CMY模型 CMY(Cyan,Magenta,Yellow)模型是采用青,品红,黄色3种基本原色按一定比例合成颜色的方法,由于色彩的显示不是直接来自于光线的色彩,而是光线被物理吸收掉一部分之后反 ...

  8. 单目相机成像模型——针孔相机模型

    高翔:SLAM十二讲阅读笔记 本节主要注意四个坐标:世界,相机,归一化相机,像素. 针孔相机模型 相机坐标转换成像素坐标,由内参数矩阵决定. 相机位姿决定世界坐标转换成相机坐标:即外参数矩阵 内参数矩 ...

  9. 视觉SLAM学习--相机成像模型及标定

    相机模型1:B站热心网友的视频讲解,比较清楚 链接:https://www.bilibili.com/video/BV1Rh411o7Jb/?spm_id_from=333.788.recommend ...

最新文章

  1. 公众平台模板消息所在行业_第三方工具微信公众号模板消息群发如何操作?
  2. 将类似html数据打印机,机器人和3D打印机的架构有哪些相似之处
  3. mysql创建表时报150_Mysql创建表时报错error150
  4. db2如何锁定一张表_如何通过一张表,提高20%的工作效率?
  5. c语言输出图形之小飞机
  6. 三菱plc pwm指令_三菱PLC高速处理指令编程(新手教学)
  7. IE associate Fix
  8. mfc 控件显示 被遮挡_MFC控件显示和隐藏的问题
  9. 人脸识别活体检测技术
  10. 云解析 dns 服务器,你知道为什么云解析DNS又快又安全吗?
  11. linux 下的igv软件,IGV软件使用指南
  12. PAT(甲级)渡劫(一)-Public Bike Management
  13. 关于Python绘制柱状图等图形,以及数据拆分与合并详细讲解
  14. latex初学者入门(二)
  15. 深入理解机器学习——集成学习(二):提升法Boosting与Adaboost算法
  16. php模拟登陆青果教务系统,模拟登录 - php CURL模拟登陆正方教务系统
  17. Mybatis新增数据,存在就更新,不存在就添加
  18. C/C++中的日期和时间 TIME_T与STRUCT TM转换
  19. 温室大棚控制系统智能轻松种菜
  20. fairyguiUI适配问题

热门文章

  1. 全网最详细XSS跨站脚本攻击,不是过来打死我!!
  2. 测试一款LMV358, DIP8封装
  3. 腾讯云首款自研星星海服务器云上应用规模增长已超30倍
  4. 快快修改您的头像,凸显您的个性
  5. 爬取豆瓣电影中:华语、欧美、韩国、日本电影每个标签下按评价排序的全部电影。
  6. virtualbox 安装帝国时代2无法初始化图像系统,请确认显卡与directdraw兼容
  7. Docker: Create Image from Container
  8. 【layui】layui loading窗口的使用
  9. NBU: nbcertcmd -getCAcertificate -server master_server_name command fails with EXIT STATUS 8500
  10. 隐马尔可夫模型(HMM) - 2 - 概率计算方法