相机标定——OpenCV-Python Tutorials
目标
- 我们将了解导致相机失真、扭曲的内因与外因
- 我们将试着找到这些畸变参数,并消除畸变
基础
如今大量廉价的摄像机导致了很多照片畸变。两个主要的畸变是径向畸变和切向畸变。
由于径向畸变,直线会变弯。距离图片中心越远,它的影响越大。如下面这张图片,棋盘格中被红线标记的边缘。你会发现棋盘格的边缘并不与直红线重合,而是变弯了。可以到维基百科查看更多细节Distortion (optics) 。
这种畸变可以用如下公式消除:
同样的,另一种畸变-切向畸变是由于相机镜头没有与被拍摄物体平行造成的。因为有些区域会看起来更近。这可以通过下面公式消除:
总的来说,我们需要找到5个参数,即畸变系数:
除此之外,我们还需要找到一些另外的信息,如相机的内在和外部参数。内在参数是由相机内部决定的,它取决于特定的相机。它包括焦距(),光心(
)等。这些也称作相机矩阵。它们只取决于相机本身,因此只需要计算一次。
外部参数对应于旋转和平移向量,它将三维点的坐标转换为坐标系统。
对于三维应用程序,上面这些畸变需要先被计算。要找到所有这些参数,我们需要做的是提供一些定义好的模式的示例图像(如棋盘格)。我们找到模式中特定的点(格子的交点)。这样,我们知道这些点在真实世界中的坐标,也知道它们在图片中的坐标。有了这些数据,就可以解决一些数学问题,从而得到畸变系数。这就是解决整个问题的思路。为了得到更好的结果,我们至少需要10张测试模式图片。
代码
如上所述,我们至少需要10张测试模板图片来进行相机标定。OpenCV提供了一些棋盘格图片(samples/cpp/left01.jpg -- left14.jpg)。为了便于理解,只考虑一张棋盘格的图片。相机标定需要的重要数据是一系列3D世界的点和它相对的2D图片上的点。2D图片上的点我们很容易从图片上计算它们的位置。(这些图像点是两个黑色块相接触的地方)
那么3D世界的点怎么得到呢?这些图像是静态的摄像机拍摄放置在不同的位置和方向的棋盘格得到的。所以我们需要知道(X,Y,Z)的值。为了简单起见,我们假设图片就放在XY片面上,(因此Z值总是等于0)同时相机相对移动。这种简化之后,我们只需要找出X,Y的值。对于X,Y的值我们可以简单的用(0,0),(1,0),(2,0),...来代表点的位置。这样,我们得到的结果就是与棋盘格等比例的大小。如果我们知道了格子的大小,(比如30mm),我们就可以传递(0,0),(30,0),(60,0),...这样的值。然后以mm为单位。(在这种情况下,我们不知道正方形的大小,因为我们没有采集照片,所以,我们只是就正方形大小而言)。
3D点称作物体点,2D点称作图片点。
设置
为了找到棋盘格的样式,我们使用cv2.findChessboardCorners()这个函数。我们同样需要传递我们要找什么样式,比如你这个棋盘格是8*8的,或是5*5的。在这个例子中,我们使用7*6的棋盘格。(通常棋盘格有8*8个方格,有7*7个内格点)。它返回每一一个角点,如果匹配到了模式,它将返回是True。这些角点将按一定顺序标注出来(从左到右,从上到下)
注意
这个函数并不能识别每张图片的样式。因此一个更好的选择是按照如下的思路写代码,打开摄像头检查每一帧图片是否包含样式。如果包含了需要的样式,找到角点并把他们存到一个列表中。同时提供一些间隔的时间,以便于我们调整棋盘格到不同的方向。重复这些步骤,直到足够多的图片被采集。即使在我们提供的例子中,我们也不确定14张图片中有多少合格的图片。因此我们要使用所有的图片,然后在其中找合适的一些。
注意
除了使用棋盘格,我们也可以使用圆形格子,这就需要使用cv2.findCirclesGrid() 来寻找样式。据说,使用圆形网格的时候可以减少图片的采样数。
当我们找到角点之后,我们可以使用cv2.cornerSubPix()这个函数来增加坐标精度。也可以使用cv2.drawChessboardCorners()将角点标注出来。所有这些步骤都包含在以下代码中:
import numpy as np
import cv2
import glob # termination criteria
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) # prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((6*7,3), np.float32)
objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2) # Arrays to store object points and image points from all the images.
objpoints = [] # 3d point in real world space
imgpoints = [] # 2d points in image plane. images = glob.glob('*.jpg') for fname in images:
img = cv2.imread(fname)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # Find the chess board corners
ret, corners = cv2.findChessboardCorners(gray, (7,6),None) # If found, add object points, image points (after refining them)
if ret == True:
objpoints.append(objp) corners2 = cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
imgpoints.append(corners2) # Draw and display the corners
img = cv2.drawChessboardCorners(img, (7,6), corners2,ret)
cv2.imshow('img',img)
cv2.waitKey(500) cv2.destroyAllWindows()
一张标记了角点的图片如下所示:
标定
现在我们有了物体坐标和图片坐标,是时候开始标定相机了。我们使用cv2.calibrateCamera()这个函数。它返回相机矩阵、畸变系数、旋转和平移向量等。
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1],None,None)
消除畸变
我们已经得到了所有数据。现在我们可以拿一张图片来消除它的畸变。OpenCV中有两种方法,我们一一来看。在那之前,我们可以根据一个自由尺度参数来改进相机矩阵。cv2.getOptimalNewCameraMatrix() 变换参数alpha=0,它使用最小不需要的像素返回校正的图像。如果alpha=1 所有的像素都保留下来,并且包括一些额外的黑色图像。它还返回一个图像ROI,可以用来裁剪结果。
我们选取一张新图片(left2.jpg)
img = cv2.imread('left12.jpg')
h, w = img.shape[:2]
newcameramtx, roi=cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h))
1. Using cv2.undistort()
这是最简单的办法,通过调用函数,传递ROI参数就可以复制结果。
# undistort
dst = cv2.undistort(img, mtx, dist, None, newcameramtx) # crop the image
x,y,w,h = roi
dst = dst[y:y+h, x:x+w]
cv2.imwrite('calibresult.png',dst)
2. Using remapping
这种方法麻烦一点。首先找到原图片与校正图片之间映射函数。然后使用重映射函数。
# undistort
mapx,mapy = cv2.initUndistortRectifyMap(mtx,dist,None,newcameramtx,(w,h),5)
dst = cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR) # crop the image
x,y,w,h = roi
dst = dst[y:y+h, x:x+w]
cv2.imwrite('calibresult.png',dst)
两种方法都可以得到同样的结果,如下图:
你会看到结果中,所有的边都是直的。
现在你可以使用Numpy的函数(np.savez,np.savetxt etc)将相机矩阵和畸变系数存起来,以便以后使用。
重投影误差
重投影误差给出了一个很好的判别方式来检测找到的畸变参数的准确度。它尽可能的趋近于0. 考虑到固有的,扭曲的,旋转和平移矩阵,我们首先将物体点坐标变换到图片点坐标,使用cv2.projectPoints()函数。然后我们计算我们变换后得到的图片点和我们通过算法得到的角点坐标间的绝对范数。为了找到平均误差,我们计算了所有校准图像的误差的算术平均值。
mean_error = 0
for i in xrange(len(objpoints)):
imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
error = cv2.norm(imgpoints[i],imgpoints2, cv2.NORM_L2)/len(imgpoints2)
tot_error += error print "total error: ", mean_error/len(objpoints)
相机标定——OpenCV-Python Tutorials的更多相关文章
- 张正友相机标定Opencv实现以及标定流程&&标定结果评价&&图像矫正流程解析(附标定程序和棋盘图)
使用Opencv实现张正友法相机标定之前,有几个问题事先要确认一下,那就是相机为什么需要标定,标定需要的输入和输出分别是哪些? 相机标定的目的:获取摄像机的内参和外参矩阵(同时也会得到每一幅标定图像的 ...
- 【视频开发】【计算机视觉】相机标定(Camera calibration)原理、步骤
相机标定(Camera calibration)原理.步骤 author@jason_ql(lql0716) http://blog.csdn.net/lql0716 在图像测量过程以及机器视觉应用 ...
- SLAM入门之视觉里程计(6):相机标定 张正友经典标定法详解
想要从二维图像中获取到场景的三维信息,相机的内参数是必须的,在SLAM中,相机通常是提前标定好的.张正友于1998年在论文:"A Flexible New Technique fro Cam ...
- 相机标定:PNP基于单应面解决多点透视问题
利用二维视野内的图像,求出三维图像在场景中的位姿,这是一个三维透视投影的反向求解问题.常用方法是PNP方法,需要已知三维点集的原始模型. 本文做了大量修改,如有不适,请移步原文: ...
- 相机标定 matlab opencv ROS三种方法标定步骤(3)
三 , ROS 环境下 如何进行相机标定 刚开始做到的时候遇到一些问题没有记录下来,现在回头写的时候都是没有错误的结果了,首先使用ROS标定相机, 要知道如何查看节点之间的流程图 rosrun r ...
- 相机标定 matlab opencv ROS三种方法标定步骤(1)
一 . 理解摄像机模型,网上有很多讲解的十分详细,在这里我只是记录我的整合出来的资料和我的部分理解 计算机视觉领域中常见的三个坐标系:图像坐标系,相机坐标系,世界坐标系,实际上就是要用矩阵来表 示各个 ...
- 使用OpenCV进行相机标定
1. 使用OpenCV进行标定 相机已经有很长一段历史了.但是,伴随着20世纪后期的廉价针孔照相机的问世,它们已经变成我们日常生活的一种常见的存在.不幸的是,这种廉价是由代价的:显著的变形.幸运的是, ...
- opencv 角点检测+相机标定+去畸变+重投影误差计算
https://blog.csdn.net/u010128736/article/details/52875137 https://blog.csdn.net/h532600610/article/d ...
- OpenCV相机标定和姿态更新
原帖地址: http://blog.csdn.net/aptx704610875/article/details/48914043 http://blog.csdn.net/aptx704610875 ...
- 相机标定 matlab opencv ROS三种方法标定步骤(2)
二 ubuntu下Opencv的相机标定 一般直接用Opencv的源码就可以进行相机的标定,但是可能只是会实现结果,却不懂实现的过程,我也是模模糊糊的看了<计算机视觉中的多视图几何>以及 ...
随机推荐
- #考研笔记#计算机之word问题
Word 问题:1. 如何为文档加密保存?单击 office 按钮\另存为\工具按钮\常规选项\设置打开文件时的密码 2. 怎样在横格稿纸中录入古诗?单击 office 按钮\新建\模板\信纸\稿纸( ...
- 3.python中的基本概念
注释: 单行注释 # 多行注释 """ ''' 变量: 把程序运行中产生的值,暂时存储在内存,方便后面的程序调用. 变量命名的规则: 1.用数字.字母.下划线组成. 2. ...
- Python 面向对象编程(进阶部分)
静态方法: 通过 @staticmethod 装饰器即可把其装饰的方法变为一个静态方法.普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实 ...
- 1.2.2 Excel中手机号或身份证号批量加密星号
在对应的单元格中我们输入公式: =LEFT(C4,3)&"****"&RIGHT(C4,4)或=MID(C4,1,3)&"****"&a ...
- 2.5 Visio2007不规则图形填充
1.确保线和线接口的地方正好相交,没有多出来的线: 2.将图形选中>组合: 3.选中图形>形状>操作>连接>填充颜色. 因为图形式几条线段拼合的,不是封闭图形,所以需要将 ...
- Window离线环境下如何安装pyhanlp
Hanlp在离线环境下的安装我是没有尝试过的,分享SunJW_2017的这篇文章就是关于如何在离线环境下安装hanlp的.我们可以一起来学习一下! HanLP是一款优秀的中文自然语言处理工具,可以实现 ...
- Linux cp命令详解
Linux cp命令 Linux cp命令主要用于复制文件或目录,将源文件复制至目标文件,或将多个源文件复制至目标目录 用法: cp [选项]... [-T] 源文件 目标文件 cp [选项]... ...
- 如何增加黑客通过ssh入侵的难度--保护ssh的三把锁
源文档:https://blog.csdn.net/cnbird2008/article/details/6130696 简介 如果需要远程访问计算机并启用了 Secure Shell (SSH) 连 ...
- Oracle 语句整理
1 查出列当中重复的值 select ip2,count(*) from vm_info group by ip2 having count(*)>1 期中ip2为列名 vm_inf ...
- 深度森林DeepForest
级联森林(Cascade Forest) 级联森林结构的图示.级联的每个级别包括两个随机森林(蓝色字体标出)和两个完全随机树木森林(黑色). 假设有三个类要预测,因此,每个森林将输出三维类向量,然后将 ...