精华内容
下载资源
问答
  • 该算法能标定鱼眼畸变图像的原点和半径,利用球面坐标定位法校正畸变图像,使用双线性插值法填充校正后图像,本程序在vc6下实现鱼眼摄像头畸变图像校正,调试前必须安装OpenCV和vc6
  • 鱼眼标定

    2018-03-14 11:03:44
    只是粘贴出源码,有注释,可用(鱼眼标定函数fisheye只有在opencv3.0以上采有,本人用的opencv3.0)opencv下载链接:http://blog.csdn.net/yanzi1225627/article/details/47668021#include <opencv2\opencv....

    只是粘贴出源码,有注释,可用(鱼眼标定函数fisheye只有在opencv3.0以上采有,本人用的opencv3.0)

    opencv下载链接:http://blog.csdn.net/yanzi1225627/article/details/47668021

    #include <opencv2\opencv.hpp>
    #include <fstream>
    using namespace std;
    using namespace cv;
    
    int main()
    {
    	ofstream fout("caliberation_result.txt");  /**    保存定标结果的文件     **/
    
    	/************************************************************************
    	读取每一幅图像,从中提取出角点,然后对角点进行亚像素精确化
    	*************************************************************************/
    	cout << "开始提取角点………………" << endl;
    	int image_count = 14;                    /****    图像数量     ****/
    	Size board_size = Size(9, 6);            /****    定标板上每行、列的角点数       ****/
    	vector<Point2f> corners;                  /****    缓存每幅图像上检测到的角点       ****/
    	vector<vector<Point2f>>  corners_Seq;    /****  保存检测到的所有角点       ****/
    	vector<Mat>  image_Seq;
    	int successImageNum = 0;                /****   成功提取角点的棋盘图数量    ****/
    
    	int count = 0;
    	for (int i = 0; i != image_count; i++)
    	{
    		cout << "Frame #" << i + 1 << "..." << endl;
    		string imageFileName;
    		std::stringstream StrStm;
    		StrStm << i + 1;
    		StrStm >> imageFileName;
    		imageFileName += ".jpg";
    		//cv::Mat image = imread("img" + imageFileName);
    		cv::Mat image = imread(imageFileName);
    		/* 提取角点 */
    		Mat imageGray;
    		cvtColor(image, imageGray, CV_RGB2GRAY);
    		bool patternfound = findChessboardCorners(image, board_size, corners, CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE +
    			CALIB_CB_FAST_CHECK);
    		if (!patternfound)
    		{
    			cout << "找不到角点,需删除图片文件" << imageFileName << "重新排列文件名,再次标定" << endl;
    			getchar();
    			exit(1);
    		}
    		else
    		{
    			/* 亚像素精确化 */
    			cornerSubPix(imageGray, corners, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
    			/* 绘制检测到的角点并保存 */
    			Mat imageTemp = image.clone();
    			for (int j = 0; j < corners.size(); j++)
    			{
    				circle(imageTemp, corners[j], 10, Scalar(0, 0, 255), 2, 8, 0);
    			}
    			string imageFileName;
    			std::stringstream StrStm;
    			StrStm << i + 1;
    			StrStm >> imageFileName;
    			imageFileName += "_corner.jpg";
    			imwrite(imageFileName, imageTemp);
    			cout << "Frame corner#" << i + 1 << "...end" << endl;
    
    			count = count + corners.size();
    			successImageNum = successImageNum + 1;
    			corners_Seq.push_back(corners);
    		}
    		image_Seq.push_back(image);
    	}
    	cout << "角点提取完成!\n";
    	/************************************************************************
    	摄像机定标
    	*************************************************************************/
    	cout << "开始定标………………" << endl;
    	Size square_size = Size(26, 26);
    	vector<vector<Point3f>>  object_Points;        /****  保存定标板上角点的三维坐标   ****/
    
    	Mat image_points = Mat(1, count, CV_32FC2, Scalar::all(0));  /*****   保存提取的所有角点   *****/
    	vector<int>  point_counts;
    	/* 初始化定标板上角点的三维坐标 */
    	for (int t = 0; t<successImageNum; t++)
    	{
    		vector<Point3f> tempPointSet;
    		for (int i = 0; i<board_size.height; i++)
    		{
    			for (int j = 0; j<board_size.width; j++)
    			{
    				/* 假设定标板放在世界坐标系中z=0的平面上 */
    				Point3f tempPoint;
    				tempPoint.x = i*square_size.width;
    				tempPoint.y = j*square_size.height;
    				tempPoint.z = 0;
    				tempPointSet.push_back(tempPoint);
    			}
    		}
    		object_Points.push_back(tempPointSet);
    	}
    	for (int i = 0; i< successImageNum; i++)
    	{
    		point_counts.push_back(board_size.width*board_size.height);
    	}
    	/* 开始定标 */
    	Size image_size = image_Seq[0].size();
    	cv::Matx33d intrinsic_matrix;    /*****    摄像机内参数矩阵    ****/
    	cv::Vec4d distortion_coeffs;     /* 摄像机的4个畸变系数:k1,k2,k3,k4*/
    	std::vector<cv::Vec3d> rotation_vectors;                           /* 每幅图像的旋转向量 */
    	std::vector<cv::Vec3d> translation_vectors;                        /* 每幅图像的平移向量 */
    	int flags = 0;
    	flags |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC;
    	flags |= cv::fisheye::CALIB_CHECK_COND;
    	flags |= cv::fisheye::CALIB_FIX_SKEW;
    	fisheye::calibrate(object_Points, corners_Seq, image_size, intrinsic_matrix, distortion_coeffs, rotation_vectors, translation_vectors, flags, cv::TermCriteria(3, 20, 1e-6));
    	cout << "定标完成!\n";
    
    	/************************************************************************
    	对定标结果进行评价
    	*************************************************************************/
    	cout << "开始评价定标结果………………" << endl;
    	double total_err = 0.0;                   /* 所有图像的平均误差的总和 */
    	double err = 0.0;                        /* 每幅图像的平均误差 */
    	vector<Point2f>  image_points2;          /****   保存重新计算得到的投影点    ****/
    
    	cout << "每幅图像的定标误差:" << endl;
    	cout << "每幅图像的定标误差:" << endl << endl;
    	for (int i = 0; i<image_count; i++)
    	{
    		vector<Point3f> tempPointSet = object_Points[i];
    		/****    通过得到的摄像机内外参数,对空间的三维点进行重新投影计算,得到新的投影点     ****/
    		fisheye::projectPoints(tempPointSet, image_points2, rotation_vectors[i], translation_vectors[i], intrinsic_matrix, distortion_coeffs);
    		/* 计算新的投影点和旧的投影点之间的误差*/
    		vector<Point2f> tempImagePoint = corners_Seq[i];
    		Mat tempImagePointMat = Mat(1, tempImagePoint.size(), CV_32FC2);
    		Mat image_points2Mat = Mat(1, image_points2.size(), CV_32FC2);
    		for (size_t i = 0; i != tempImagePoint.size(); i++)
    		{
    			image_points2Mat.at<Vec2f>(0, i) = Vec2f(image_points2[i].x, image_points2[i].y);
    			tempImagePointMat.at<Vec2f>(0, i) = Vec2f(tempImagePoint[i].x, tempImagePoint[i].y);
    		}
    		err = norm(image_points2Mat, tempImagePointMat, NORM_L2);
    		total_err += err /= point_counts[i];
    		cout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;
    		fout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;
    	}
    	cout << "总体平均误差:" << total_err / image_count << "像素" << endl;
    	fout << "总体平均误差:" << total_err / image_count << "像素" << endl << endl;
    	cout << "评价完成!" << endl;
    
    	/************************************************************************
    	保存定标结果
    	*************************************************************************/
    	cout << "开始保存定标结果………………" << endl;
    	Mat rotation_matrix = Mat(3, 3, CV_32FC1, Scalar::all(0)); /* 保存每幅图像的旋转矩阵 */
    
    	fout << "相机内参数矩阵:" << endl;
    	fout << intrinsic_matrix << endl;
    	fout << "畸变系数:\n";
    	fout << distortion_coeffs << endl;
    	for (int i = 0; i<image_count; i++)
    	{
    		fout << "第" << i + 1 << "幅图像的旋转向量:" << endl;
    		fout << rotation_vectors[i] << endl;
    
    		/* 将旋转向量转换为相对应的旋转矩阵 */
    		Rodrigues(rotation_vectors[i], rotation_matrix);
    		fout << "第" << i + 1 << "幅图像的旋转矩阵:" << endl;
    		fout << rotation_matrix << endl;
    		fout << "第" << i + 1 << "幅图像的平移向量:" << endl;
    		fout << translation_vectors[i] << endl;
    	}
    	cout << "完成保存" << endl;
    	fout << endl;
    
    
    	/************************************************************************
    	显示定标结果
    	*************************************************************************/
    	Mat mapx = Mat(image_size, CV_32FC1);
    	Mat mapy = Mat(image_size, CV_32FC1);
    	Mat R = Mat::eye(3, 3, CV_32F);
    
    	cout << "保存矫正图像" << endl;
    	for (int i = 0; i != image_count; i++)
    	{
    		cout << "Frame #" << i + 1 << "..." << endl;
    		fisheye::initUndistortRectifyMap(intrinsic_matrix,distortion_coeffs,R,intrinsic_matrix,image_size,CV_32FC1,mapx,mapy);
    		//fisheye::initUndistortRectifyMap(intrinsic_matrix, distortion_coeffs, R,
    		//	getOptimalNewCameraMatrix(intrinsic_matrix, distortion_coeffs, image_size, 1, image_size, 0), image_size, CV_32FC1, mapx, mapy);
    		Mat t = image_Seq[i].clone();
    		cv::remap(image_Seq[i], t, mapx, mapy, INTER_LINEAR);
    		string imageFileName;
    		std::stringstream StrStm;
    		StrStm << i + 1;
    		StrStm >> imageFileName;
    		imageFileName += "_d.jpg";
    		imwrite(imageFileName, t);
    	}
    	cout << "保存结束" << endl;
    
    
    	/************************************************************************
    	测试一张图片
    	*************************************************************************/
    	if (0)
    	{
    		cout<<"TestImage ..."<<endl;
    		Mat testImage = imread("1.jpg",1);
    		fisheye::initUndistortRectifyMap(intrinsic_matrix, distortion_coeffs, R, intrinsic_matrix, image_size, CV_32FC1, mapx, mapy);
    		//fisheye::initUndistortRectifyMap(intrinsic_matrix,distortion_coeffs,R,
    		 //   getOptimalNewCameraMatrix(intrinsic_matrix, distortion_coeffs, image_size, 1, image_size, 0),image_size,CV_32FC1,mapx,mapy);
    		Mat t = testImage.clone();
    		cv::remap(testImage,t,mapx, mapy, INTER_LINEAR);
    
    		imwrite("TestOutput.jpg",t);
    		cout<<"保存结束"<<endl;
    
    		//cout << "TestImage ..." << endl;
    		//Mat distort_img = imread("a.jpg", 1);
    		//Mat undistort_img;
    		//Mat intrinsic_mat(intrinsic_matrix), new_intrinsic_mat;
    
    		//intrinsic_mat.copyTo(new_intrinsic_mat);
    		调节视场大小,乘的系数越小视场越大
    		//new_intrinsic_mat.at<double>(0, 0) *= 0.5;
    		//new_intrinsic_mat.at<double>(1, 1) *= 0.5;
    		调节校正图中心,建议置于校正图中心
    		//new_intrinsic_mat.at<double>(0, 2) = 0.5 * distort_img.cols;
    		//new_intrinsic_mat.at<double>(1, 2) = 0.5 * distort_img.rows;
    
    		//fisheye::undistortImage(distort_img, undistort_img, intrinsic_matrix, distortion_coeffs, new_intrinsic_mat);
    		//imwrite("output.jpg", undistort_img);
    		//cout << "保存结束" << endl;
    	}
    	return 0;
    }

    展开全文
  • 鱼眼标定校正 opencv3.0 视场大小可调 http://blog.csdn.net/qq_15947787/article/details/51441031
  • 鱼眼相机标定校正+批量加载多张标定图像+批量处理多张测试图像+角点坐标输出+相机参数输出
  • opencv 鱼眼镜头标定校正 ,见链接http://blog.csdn.net/qq_15947787/article/details/51441031
  • 1.想知道:一分钟详解鱼眼镜头标定基本原理及实现 1.将其转载,避免作者删除,就没有了 二.参考 1.一分钟详解鱼眼镜头标定基本原理及实现 三.注意 四.操作:备份原文 前言 一理论部分 二实践部分 三跋 参考...

    目录

    一.目的

    1.想知道:一分钟详解鱼眼镜头标定基本原理及实现

    1.将其转载,避免作者删除,就没有了

    二.参考

    1.一分钟详解鱼眼镜头标定基本原理及实现

    三.注意

    四.操作:备份原文

    前言

    一 理论部分

    二 实践部分

    三 跋

    参考文献:


    一.目的

    1.想知道:一分钟详解鱼眼镜头标定基本原理及实现

    1.将其转载,避免作者删除,就没有了

    二.参考

    1.一分钟详解鱼眼镜头标定基本原理及实现

    https://mp.weixin.qq.com/s/VyxoTaYtYPB-Bfh3JCXl1A

    1. 原文地址,值得多看

    三.注意

    四.操作:备份原文

    前言

    在VSLAM中,经常会使用鱼眼镜头或者广角镜头。本文主要分为理论部分与鱼眼镜头标定实践两部分,其中理论部分,主要参考《A generic camera model and calibration method for conventional, wide-angle, and fish-eye lenses》,作者为Juho Kannala和Sami S. Brandt,写于2006年,同时这篇文章的作者在2004年也写了一篇与鱼眼镜头标定相关的论文《A Generic Camera Calibration Method for Fish-Eye Lenses》,同样值得参考。

    一 理论部分

    对于大多数具有窄角甚至广角镜头的传统相机,针孔相机模型伴随着镜头畸变是一个比较不错的近似。但是针孔模型不太适用于鱼眼镜头。鱼眼镜头一般被设计用来覆盖相机前方的整个半球形视场,视角非常大,约180°。然而,不可能通过透视投影在有限的图像平面上投射半球形视场。因而,鱼眼镜头服从某些其他投影模型。这就是为什么鱼眼镜头本身固有的畸变不应该仅被认为是与针孔模型的偏差。

    很多作者对鱼眼镜头的适合的可能模型进行了研究。许多方法的思想是将原始鱼眼镜头成像为遵循针孔模型,畸变参数是通过变换后强制按直线来估计的,但问题是这些方法并不能完全校准。最近,鱼眼镜头相机的第一种自动校准方法也出现了,Claus 和Fitzgibbon[1]提出了一种畸变模型,它同样允许相机运动和镜头几何的同时线性估计,而Thirthala和Pollefeys[2]使用径向一维摄像机的多视图几何来估计非参数相机模型。此外,Barreto和Daniilidis最近的工作引入了径向基本矩阵来纠正广角镜头的失真[3]。然而,这些方法的重点更多的是在于自动校准技术,而不是真实镜头的精确建模。

    由于透视投影模型不适用于鱼眼镜头,我们使用更灵活的径向对称投影模型。

    图片

    图片

    图片

    不失一般性,甚至权重都被取消了。这是因为我们可以将r作为奇函数扩展到负数一侧,而奇数幂跨越连续奇函数集。对于计算,我们需要确定(6)中的各项。

    为了使得本文不那么枯燥,关于鱼眼镜头标定的理论部分我们仅介绍到这里,如果感兴趣的读者,可以去仔细研读论文《A generic camera model and calibration method for conventional, wide-angle, and fish-eye lenses》。

    二 实践部分

    在上述论文作者的主页,作者提供的Matlab标定代码:Camera Calibration Toolbox for Generic Lenses:http://www.ee.oulu.fi/~jkannala/calibration/calibration.html。

    此处,笔者简单为大家介绍一下OpenCV中关于鱼眼标定的流程。

    首先,可以参考OpenCV Documentation中提供的鱼眼镜头标定相关函数:

    https://docs.opencv.org/3.2.0/db/d58/group__calib3d__fisheye.html

    具体鱼眼镜头标定步骤如下:

    本次实验,使用小觅相机(标准版)进行实验,小觅相机的镜头视角较大,大约在140°左右。小觅相机实物如下图2所示。

    图片

    图2 小觅相机(标准版)实物图

    Step-1: 制作标定板。可以是圆,也可以是棋盘格,当然也可以是圆环。此处我们选择4*11的OpenCV提供的圆形标定板。为了使得标定结果趋于收敛,在工作距离附近,在不同姿态下,采集近20~30张标定图片,如下图3所示。

    图片

    图3 标定板采集样图

    Step-2:进行形态学处理。此处是由于在采集图片过程中,难免会在图片中引入环境光带来的噪声。

    Step-3:检测每一张图片中的圆心角点坐标,并排序。(OpenCV中findCirclesGrid函数同时解决了这个问题)。

    Step-4: 进行标定。(cv::fisheye:calibrate)

    Step-5: 计算重投影误差。在Step-3中,cv::fisheye::calibrate返回值为总重投影误差,当然也可以进一步计算x和y方向的重投影误差值。

    Step-6:(此步非必须)进行去畸变,进一步验证标定参数的正确性。

    组合使用函数:

    1)fisheye::estimateNewCameraMatrixForUndistortRectify
    2)cv::fisheye::initUndistortRectifyMap
    3)remap
    

    即可获得畸变矫正后的效果图。

    经过鱼眼标定后,使用标定好的参数进行去畸变后效果图(使用函数

    void estimateNewCameraMatrixForUndistortRectify(InputArray K, InputArray D, const Size &amp;image_size, InputArray R,<br>&nbsp;&nbsp;&nbsp;&nbsp;OutputArray P, double balance = 0.0, const Size&amp; new_size = Size(), double fov_scale = 1.0)

    进行估计新的相机矩阵用于畸变矫正或者校正时,图4为参数balance设为0时的畸变矫正效果图,图5为参数balance设为1时的效果图)。

    图片

    图4 鱼眼模型标定后,畸变矫正,balance=0时

    图片

    图5 鱼眼模型标定后,畸变矫正效果图,balance=1.0时

    如果选用针孔模型来进行标定,去畸变后的效果图如下所示。

    使用针孔模型进行标定后,同样对图3进行去畸变效果图如下(图6为balance=0,图7为balance=1时):

    图片

    图6 针孔模型标定后,畸变矫正效果图,balance=0时

    图片

    图7 针孔模型标定后,畸变矫正效果图,balance=1时

    由图可见,使用针孔模型去畸变后,整个画幅的图像的畸变不符合「枕形」或者「桶形」,因而使用针孔模型来进行标定鱼眼镜头是不太适合的。

    三 跋

    最后,留个大家一个问题可以去思考,作者在文章中提到,对于圆形的中心在经过透视变换后,由于较大的畸变存在,椭圆的中心已经不再对应圆形的中心。那么,对于椭圆的中心构象偏差,又该如何去矫正呢?

    图片

    参考文献:

    [1] Kannala J, Brandt S S. A generic camera model and calibration method for conventional, wide-angle, and fish-eye lenses[J]. IEEE transactions on pattern analysis and machine intelligence, 2006, 28(8): 1335-1340.

    [2] Claus, D. and Fitzgibbon, A. W.: “A rational function lens distortion model for general cameras”, Proc. CVPR, pp. 213-219, 2005

    [3] Thirthala, S. and Pollefeys, M.: “Multi-view geometry of 1D radial cameras and its application to omnidirectional camera calibration”, Proc. ICCV, pp. 1539-1546, 2005.

    [4] Barreto, J. P. and Daniilidis, K.: “Fundamental matrix for cameras with radial distortion”,Proc. ICCV, pp. 625-632, 2005.

    展开全文
  • OpenCV双目鱼眼相机标定

    千次阅读 2019-06-15 15:16:20
    单个摄像头的鱼眼标定在MATLAB工具箱中就有,但双目标定却是没有。找了一下OpenCV中(应该是3.0以后版本的)有相应的标定函数Fisheye camera model,就参照着其源文件sample下的stereo_calib.cpp改动了一下。 标定的...

    手头有一个双目鱼眼相机,虽然厂家SDK里提供了相应的参数,但中间发现一点小问题,索性自己重新标定一下。单个摄像头的鱼眼标定在MATLAB工具箱中就有,但双目标定却是没有。找了一下OpenCV中(应该是3.0以后版本的)有相应的标定函数Fisheye camera model,就参照着其源文件sample下的stereo_calib.cpp改动了一下。
    标定的逻辑很简单,先是提取角点,每一帧都需人工确认一下,防止出错;然后对单个摄像头进行鱼眼标定;最后进行双目标定。标定过程中发现,最好还是有一个较好的初始参数输入进去,不然在双目标定这一步很容易出错。以下是相关代码:

    #include "opencv2/calib3d.hpp"
    #include "opencv2/imgcodecs.hpp"
    #include "opencv2/highgui.hpp"
    #include "opencv2/imgproc.hpp"
    
    #include <vector>
    #include <string>
    #include <algorithm>
    #include <iostream>
    #include <iterator>
    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    
    using namespace cv;
    using namespace std;
    
    static void fisheyeStereoCalib(const vector<string>& imageList, const vector<Mat>& pre_calib, Size& boardSize, float squareSize, bool showRectified=true){
        if( imageList.size() % 2 != 0 )
        {
            cout << "Error: the image list contains odd (non-even) number of elements\n";
            return;
        }
    
        // ARRAY AND VECTOR STORAGE:
    
        vector<vector<Point2f> > imagePoints[2];
        vector<vector<Point3f> > objectPoints;
        Size imageSize;
    
        int i, j, k, n_images = (int)imageList.size()/2;
    
        imagePoints[0].resize(n_images);
        imagePoints[1].resize(n_images);
        vector<string> goodImageList;
    
        cout<<"Press the blank space if you think the corners are detected correctly. Otherwise press any other keys to continue."<<endl;
    
        for( i = j = 0; i < n_images; i++ )
        {
            for( k = 0; k < 2; k++ )
            {
                const string& filename = imageList[i*2+k];
                Mat img = imread(filename, 0);
                if(img.empty())
                    break;
                if( imageSize == Size() )
                    imageSize = img.size();
                else if( img.size() != imageSize )
                {
                    cout << "The image " << filename << " has the size different from the first image size. Skipping the pair\n";
                    break;
                }
                bool found = false;
                vector<Point2f>& corners = imagePoints[k][j];
    
                found = findChessboardCorners(img, boardSize, corners,
                                              CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_NORMALIZE_IMAGE);
    
                //display
                {
                    Mat c_img, c_img1;
                    cvtColor(img, c_img, COLOR_GRAY2BGR);
                    drawChessboardCorners(c_img, boardSize, corners, found);
                    double sf = 640./MAX(img.rows, img.cols);
                    resize(c_img, c_img1, Size(), sf, sf, INTER_LINEAR_EXACT);
                    imshow("corners"+to_string(k), c_img1);
                }
                if( !found )
                    break;
                cornerSubPix(img, corners, Size(11,11), Size(-1,-1),
                             TermCriteria(TermCriteria::COUNT+TermCriteria::EPS,
                                          30, 0.01));
            }
            if( k == 2 )
            {
                int isOK=waitKey(0);
                //press the blank space to validate
                if(isOK==32){
                    goodImageList.push_back(imageList[i*2]);
                    goodImageList.push_back(imageList[i*2+1]);
                    j++;
                }
                if(isOK==27)
                    return;
            }
        }
        cout << j << " pairs have been successfully detected.\n";
        n_images = j;
        if( n_images < 2 )
        {
            cout << "Error: too little pairs to run the calibration\n";
            return;
        }
    
        imagePoints[0].resize(n_images);
        imagePoints[1].resize(n_images);
        objectPoints.resize(n_images);
    
        for( i = 0; i < n_images; i++ )
        {
            for( j = 0; j < boardSize.height; j++ )
                for( k = 0; k < boardSize.width; k++ )
                    objectPoints[i].push_back(Point3f(k*squareSize, j*squareSize, 0));
        }
    
        cout << "Running single calibration first...\n";
    
        //single fisheye calibration
        Mat cameraMatrix[2], distCoeffs[2];
        Mat rvecs[2], tvecs[2];
    
        if(!pre_calib.empty()&&pre_calib.size()==4){
            cameraMatrix[0]=pre_calib[0];
            distCoeffs[0]=pre_calib[1];
            cameraMatrix[1]=pre_calib[2];
            distCoeffs[1]=pre_calib[3];
    
            fisheye::calibrate(objectPoints,imagePoints[0],imageSize,cameraMatrix[0],distCoeffs[0],rvecs[0],tvecs[0],
                               fisheye::CALIB_USE_INTRINSIC_GUESS+fisheye::CALIB_FIX_SKEW);
            fisheye::calibrate(objectPoints,imagePoints[1],imageSize,cameraMatrix[1],distCoeffs[1],rvecs[1],tvecs[1],
                               fisheye::CALIB_USE_INTRINSIC_GUESS+fisheye::CALIB_FIX_SKEW);
        }
        else{
            fisheye::calibrate(objectPoints,imagePoints[0],imageSize,cameraMatrix[0],distCoeffs[0],rvecs[0],tvecs[0],
                               fisheye::CALIB_FIX_SKEW);
            fisheye::calibrate(objectPoints,imagePoints[1],imageSize,cameraMatrix[1],distCoeffs[1],rvecs[1],tvecs[1],
                               fisheye::CALIB_FIX_SKEW);
        }
    
        cout<<"Intrinsic Matrix of left:\n"<<cameraMatrix[0]<<endl;
        cout<<"Distortion Matrix of left:\n"<<distCoeffs[0]<<endl;
        cout<<"Intrinsic Matrix of right:\n"<<cameraMatrix[1]<<endl;
        cout<<"Distortion Matrix of right:\n"<<distCoeffs[1]<<endl;
    
        // save intrinsic parameters
        FileStorage fs("intrinsics.yml", FileStorage::WRITE);
        if( fs.isOpened() )
        {
            fs << "M1" << cameraMatrix[0] << "D1" << distCoeffs[0] <<
               "M2" << cameraMatrix[1] << "D2" << distCoeffs[1];
            fs.release();
        }
        else
            cout << "Error: can not save the intrinsic parameters\n";
    
        cout << "Running stereo calibration ...\n";
    
        //stereo fisheye calibration
        Mat R, T;
        double rms=fisheye::stereoCalibrate(objectPoints,imagePoints[0],imagePoints[1],cameraMatrix[0],distCoeffs[0],
                cameraMatrix[1],distCoeffs[1],imageSize,R,T);
    
        cout<<"Extrinsic error (RMS):"<<rms<<endl;
        //cout<<"Extrinsic Matrix:\nRotation Matrix:\n"<<R<<"\nTranslation Matrix:\n"<<T<<endl;
    
        Mat R1, R2, P1, P2, Q;
    
        fisheye::stereoRectify(cameraMatrix[0],distCoeffs[0],cameraMatrix[1],distCoeffs[1],imageSize,
                R,T,R1,R2,P1,P2,Q,CALIB_ZERO_DISPARITY,imageSize);
    
        cout<<"Q:\n1 0 0 -c_x\n0 1 0 -c_y\n0 0 0 f\n0 0 -1/T_x (c_x-c'_x)/T_x\n\n"<<Q<<endl;
        cout<<"baseline: "<<1/Q.at<double>(3,2)<<endl;
    
        fs.open("extrinsics.yml", FileStorage::WRITE);
        if( fs.isOpened() )
        {
            fs << "R" << R << "T" << T << "R1" << R1 << "R2" << R2 << "P1" << P1 << "P2" << P2 << "Q" << Q;
            fs.release();
        }
        else
            cout << "Error: can not save the extrinsic parameters\n";
    
        // COMPUTE AND DISPLAY RECTIFICATION
        if( !showRectified )
            return;
    
        Mat r_map[2][2];
    
        fisheye::initUndistortRectifyMap(cameraMatrix[0],distCoeffs[0],R1,P1,imageSize,CV_32F,r_map[0][0],r_map[0][1]);
        fisheye::initUndistortRectifyMap(cameraMatrix[1],distCoeffs[1],R2,P2,imageSize,CV_32F,r_map[1][0],r_map[1][1]);
    
        for( i = 0; i < n_images; i++ )
        {
            Mat rec[2];
            for( k = 0; k < 2; k++ )
            {
                Mat img = imread(goodImageList[i*2+k], 0);
                remap(img, rec[k], r_map[k][0], r_map[k][1], INTER_LINEAR);
            }
    
            Mat align;
            hconcat(rec[0],rec[1],align);
    
            cvtColor(align,align,CV_GRAY2BGR);
    
            for( j = 0; j < align.rows; j += 20 )
                line(align, Point(0, j), Point(align.cols, j), Scalar(0, 255, 255), 1, 8);
    
            double sf = 640./MIN(align.rows, align.cols);
            resize(align, align, Size(), sf, sf, INTER_LINEAR_EXACT);
    
            imshow("rectified", align);
            int c = waitKey();
            if( c == 27 || c == 'q' || c == 'Q' )
                break;
        }
    }
    
    int main(int argc, char** argv)
    {
        if(argc!=5){
            cout<<"usage: path_of_images(should have two sub folders 'left' and 'right') length_of_squares(mm) points_per_row points_per_col"<<endl;
            return 1;
        }
    
        string image_path=argv[1];
        if(image_path.back()!='/')
            image_path.append("/");
    
        float squareSize=strtof(argv[2], nullptr);
    
        int cols=strtol(argv[3], nullptr,10);
        int rows=strtol(argv[4], nullptr,10);
        Size boardSize(cols,rows);
    
        vector<string> imageList;
        for(int i=0;i<34;++i){
            imageList.push_back(image_path+"left/"+to_string(i)+".jpg");
            imageList.push_back(image_path+"right/"+to_string(i)+".jpg");
        }
    
        //K1,D1,K2,D2
        //pre-set paras, maybe provided by the manufacturers
        //make it yourself!!!
        vector<Mat> pre_calib;
        pre_calib.push_back((Mat_<float>(3,3)<<495.4471360018053, 0, 606.3073724339264,
                                               0, 494.0535667349407, 406.3837502093948,
                                               0, 0, 1));
        pre_calib.push_back((Mat_<float>(4,1)<<0.5529121780480518,
                                               0.3197459950639739,
                                               -0.8405562489098664,
                                               0.4668200235897118));
        pre_calib.push_back((Mat_<float>(3,3)<<487.0684594864165, 0, 626.3955180818867,
                                               0, 486.9533501160483, 403.5345172057971,
                                               0, 0, 1));
        pre_calib.push_back((Mat_<float>(4,1)<<0.5748746843032233,
                                               0.2298043301962883,
                                               -0.7527926335516133,
                                               0.441431345733051));
    
        fisheyeStereoCalib(imageList,pre_calib, boardSize, squareSize, true);
        return 0;
    }
    
    展开全文
  • 鱼眼相机标定模型

    2020-03-08 15:24:15
    一旦你标定完成了一个camera,你即可从2维图像中去恢复3维图像。你同样可以在在一个鱼眼相机中获得未失真的图像鱼眼相机可以被用于里程计(odometry)以及vslam(simultaneous localization and mapping)。其他...

    Camera Calibration是计算Camera的extrinsic(外参)和 intrinsic(内参)的过程。一旦你标定完成了一个camera,你即可从2维图像中去恢复3维图像。你同样可以在在一个鱼眼相机中获得未失真的图像。

    鱼眼相机可以被用于里程计(odometry)以及vslam(simultaneous localization and mapping)。其他应用中,有包括监控系统(surveillance system),GoPro,虚拟现实(VR)要求捕获360度视场角(fov),和一些拼接算法中。这些camera使用了一些列用了复杂的镜头扩大了相机相机的fov,使它能够捕获广阔的全景(panoramic)或者半球形(hemispherical)图像。但是,镜头是通过扭曲图像中的视线来实现这种超广角视角。
    在这里插入图片描述
    由于鱼眼镜头会产生极大的变形,因此针孔模型无法为鱼眼镜头建模。在这里插入图片描述

    鱼眼相机模型

    为了将3维世界坐标系的点关联到2维图像坐标系中,必须获取相机的外部和固有参数。 使用外参将world Coordinate的点转换为Camera Coordinate的点。 使用内参将Camera Coordinat的点映射到Image Coordinate中。
    在这里插入图片描述

    外参

    外参包含了旋转向量R和平移向量T。原始的camera coordinate的原点位于其光学中心以及它的x-axis和y-axis定义在其image plane。
    在这里插入图片描述
    从world coordinate 到 camera coordinate 的变换关系:
    在这里插入图片描述

    内参

    对于鱼眼相机模型,内参包含了多项式映射系数的投影函数。相关的alignment系数,包括了传感器对齐以及从sensor plane到image plane的transformation。
    在这里插入图片描述

    • ( u , v ) (u,v) u,v 是real-world 点的投影到image的理想点。
    • λ \lambda λ 是scalar因子
    • a 0 , a 1 , a 2 , a 3 , a 4 a_{0},a_{1}, a_{2}, a_{3}, a_{4} a0,a1,a2,a3,a4是投影函数的多项式的系数。
    • ρ \rho ρ ( u , v ) (u,v) u,v 的函数,并且仅取决于点到图像中心的距离: ρ = u 2 + v 2 \rho=\sqrt{u^{2}+v^{2}} ρ=u2+v2

    内参还考虑了stretching和distortion。stretching矩阵补偿了sensors-to-lens的misalignment,distortion vector 是调整了image plane的 ( 0 , 0 ) (0,0) 0,0 坐标。
    在这里插入图片描述
    以下等式将实际失真坐标 ( u ′ ′ , v ′ ′ ) \left(u^{\prime \prime}, \quad v^{\prime \prime}\right) (u,v)与理想失真坐标 ( u , v ) (u,v) u,v 相关联。
    在这里插入图片描述

    展开全文
  • opencv3.0 鱼眼镜头标定校正代码

    千次下载 热门讨论 2016-05-22 10:27:36
    opencv3.0 鱼眼镜头标定校正 来自http://blog.csdn.net/qq_15947787/article/details/51441031 内有部分标定
  • 利用opencv棋盘格标定法对鱼眼图像校正分析

    万次阅读 多人点赞 2016-09-28 15:27:01
    利用opencv棋盘格标定法对鱼眼图像校正分析 一、开发环境 PC端、vs2013+opencv3.0、摄像头为淘宝购置的鱼眼摄像头外设+iphone6 二、镜头标定 1. 输入畸变的棋盘格图以及棋盘格的size(横纵坐标上的角点个数...
  • http://blog.csdn.net/photonfly/article/details/52507320
  • 最近在整理自己以前做过的一些东西,这是基于opencv的鱼眼摄像头畸变校正程序的github地址(https://github.com/WordZzzz/fisheye_calibration)(不知道怎么设置免积分下载,所以只能贴上github了)。 其中: ...
  • 利用opencv图像算法库实现对鱼眼相机内外参的标定,并利用标定结果对畸变图像进行校正。
  • 鱼眼镜头标定基本原理及实现

    千次阅读 2019-08-27 21:47:37
    原文首发于微信公众号——3D视觉工坊:一分钟详解鱼眼镜头标定基本原理及实现 前言 在VSLAM中,经常会使用鱼眼镜头或者广角镜头。本文主要分为理论部分与鱼眼镜头标定实践两部分,其中理论部分,主要参考《A generic...
  • 鱼眼相机标定与矫正FECC1.0(FishEye Camera Calibration and correction) 下载后请阅读ReadMe文档,有问题可以在评论区评价,我有时间会根据评价发布新版本 程序说明 1. 将待校正的拍摄棋盘格的图像放置于Len...
  • 传统的棋盘格角点检测方法难以准确提取鱼眼图像边缘处的角点,造成相机标定精度低,为此提出一种面向鱼眼镜头大畸变成像的棋盘格角点检测方法。该方法通过多次拍摄和逐级迭代估计和优化相机参数,利用远距中心小畸变...
  • 鱼眼相机标定-基于张正友标定

    千次阅读 2019-07-09 23:22:27
    这里介绍一下鱼眼相机的标定吧,也是相机标定的第二部分,主要还是代码解析和一些细节说明,为了让自己更好的理解相机标定标定目的是为了实现坐标转换,通过摄像头测定相机的内参和外参之后,需要基于公式得到精确...
  • 鱼眼图像校正

    2014-10-15 22:10:00
    鱼眼图像的参数标定和畸变校正,希望对大家有帮助,对学习鱼眼镜头摄像机很有帮助
  • OpenCV相机标定包括普通相机标定鱼眼相机标定,其中普通相机标定参考的是张正友标定法,而鱼眼相机的标定是基于等距投影模型进行标定的. 普通相机标定 张正友标定法 (1) 针孔模型内外参标定 针孔相机投影模型方程...
  • 鱼眼相机标定以及OpenCV实现

    万次阅读 热门讨论 2016-01-07 12:22:18
    在另一篇文章中我已经写过有关普通相机模型及其OpenCV标定实现,这篇文章将主要关注鱼眼相机模型及其OpenCV标定实现。...因此对于Gopro等鱼眼镜头拍摄出来的图像去畸变,最好的方法就是采用鱼眼相机标定方法进行标定
  • 图像处理--鱼眼图像

    千次阅读 2018-07-04 10:23:10
    鱼眼镜头--最开始(1919)是源于摄影的需求--因为鱼眼图像存在几何畸变&gt;&gt;&gt;鱼眼校正的需求优点:视角大,用于安防监视--降低成本
  • 提出了一种新的基于二维靶标的球面模型鱼眼镜头标定方法。根据球面成像模型中圆弧上的点与图像坐标系像点之间的约束关系,利用平面靶上的一根直线上的点,初步估计出摄像头的内部参数。利用平面靶上棋盘格角点在世界...
  • 前言在VSLAM中,经常会使用鱼眼镜头或者广角镜头。本文主要分为理论部分与鱼眼镜头标定实践两部分,其中理论部分,主要参考《A generic camera model and calibr...
  • 鱼眼相机图像畸变校正

    千次阅读 2020-01-02 15:33:20
    通过对鱼眼相机做内参标定,可以得到相机的内参和畸变参数。利用上述参数,可以对鱼眼相机获取的原始畸变图像做畸变校正。 1.畸变校正原理 简单回顾下鱼眼相机成像模型,上图中相机坐标系的X轴垂直屏幕向外;且...
  • 软件版本:VS2013+OPENCV2.4.13 OR VS2013+OPENCV3.4.0 编  者:WordZzzz 我的代码 可供参考资料 FishEye模型的畸变校正 ...  最近在整理自己以前做过的一些东西,这是基于opencv的鱼眼摄像头畸变校正程序的
  • Matlab工具箱标定和校正鱼眼镜头

    千次阅读 2019-04-04 19:15:58
    二 用标定结果参数 校正其他图像用 用undistortFisheyeImage函数 %利用matlab工具箱标定鱼眼之后,导出标定参数到工作区,然后运行程序 result = undistortFisheyeImage(img, cameraParams.Intrinsics); sub...
  • opencv3.0 鱼眼镜头标定校正,来自文章http://blog.csdn.net/qq_15947787/article/details/51441031 内含部分标定图像
  • 由于鱼眼相机成像存在较大的畸变, 采用二维标定板的方法难以在图像边缘区域获得准确可靠的角点, 从而导致标定精度下降, 而传统的三维标定法存在标定场建造复杂, 特征点数目有限等问题。为此, 提出一种基于激光扫描的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,299
精华内容 519
关键字:

鱼眼标定图像