Python使用OpenCV进行标定


Posted in Python onMay 08, 2018

本文结合OpenCV官方样例,对官方样例中的代码进行修改,使其能够正常运行,并对自己采集的数据进行实验和讲解。

一、准备

OpenCV使用棋盘格板进行标定,如下图所示。为了标定相机,我们需要输入一系列三维点和它们对应的二维图像点。在黑白相间的棋盘格上,二维图像点很容易通过角点检测找到。而对于真实世界中的三维点呢?由于我们采集中,是将相机放在一个地方,而将棋盘格定标板进行移动变换不同的位置,然后对其进行拍摄。所以我们需要知道(X,Y,Z)的值。但是简单来说,我们定义棋盘格所在平面为XY平面,即Z=0。对于定标板来说,我们可以知道棋盘格的方块尺寸,例如30mm,这样我们就可以把棋盘格上的角点坐标定义为(0,0,0),(30,0,0),(60,0,0),···,这个结果的单位是mm。

3D点称为object points,2D图像点称为image points。

Python使用OpenCV进行标定

二、检测棋盘格角点

为了找到棋盘格模板,我们使用openCV中的函数cv2.findChessboardCorners()。我们也需要告诉程序我们使用的模板是什么规格的,例如8*8的棋盘格或者5*5棋盘格等,建议使用x方向和y方向个数不相等的棋盘格模板。下面实验中,我们使用的是10*7的棋盘格,每个方格边长是20mm,即含有9*6的内部角点。这个函数如果检测到模板,会返回对应的角点,并返回true。当然不一定所有的图像都能找到需要的模板,所以我们可以使用多幅图像进行定标。除了使用棋盘格,我们还可以使用圆点阵,对应的函数为cv2.findCirclesGrid()。

找到角点后,我们可以使用cv2.cornerSubPix()可以得到更为准确的角点像素坐标。我们也可以使用cv2.drawChessboardCorners()将角点绘制到图像上显示。如下图所示:

Python使用OpenCV进行标定

三、标定

通过上面的步骤,我们得到了用于标定的三维点和与其对应的图像上的二维点对。我们使用cv2.calibrateCamera()进行标定,这个函数会返回标定结果、相机的内参数矩阵、畸变系数、旋转矩阵和平移向量。

四、去畸变

第三步我们已经得到了相机内参和畸变系数,在将图像去畸变之前,我们还可以使用cv.getOptimalNewCameraMatrix()优化内参数和畸变系数,通过设定自由自由比例因子alpha。当alpha设为0的时候,将会返回一个剪裁过的将去畸变后不想要的像素去掉的内参数和畸变系数;当alpha设为1的时候,将会返回一个包含额外黑色像素点的内参数和畸变系数,并返回一个ROI用于将其剪裁掉。

然后我们就可以使用新得到的内参数矩阵和畸变系数对图像进行去畸变了。有两种方法进行去畸变:

(1)使用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)

下图显示将一张图片去畸变后,保留黑色像素的结果:

Python使用OpenCV进行标定

(2)使用remmaping

这是一个分两步的方法,首先计算一个从畸变图像到非畸变图像的映射,然后使用这个映射关系对图像进行去畸变。
代码如下:

# 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)

五、反投影误差

通过反投影误差,我们可以来评估结果的好坏。越接近0,说明结果越理想。通过之前计算的内参数矩阵、畸变系数、旋转矩阵和平移向量,使用cv2.projectPoints()计算三维点到二维图像的投影,然后计算反投影得到的点与图像上检测到的点的误差,最后计算一个对于所有标定图像的平均误差,这个值就是反投影误差。

代码

所有步骤的代码如下所示:

#coding:utf-8
import cv2
import numpy as np
import glob

# 找棋盘格角点
# 阈值
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
#棋盘格模板规格
w = 9
h = 6
# 世界坐标系中的棋盘格点,例如(0,0,0), (1,0,0), (2,0,0) ....,(8,5,0),去掉Z坐标,记为二维矩阵
objp = np.zeros((w*h,3), np.float32)
objp[:,:2] = np.mgrid[0:w,0:h].T.reshape(-1,2)
# 储存棋盘格角点的世界坐标和图像坐标对
objpoints = [] # 在世界坐标系中的三维点
imgpoints = [] # 在图像平面的二维点

images = glob.glob('calib/*.png')
for fname in images:
 img = cv2.imread(fname)
 gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
 # 找到棋盘格角点
 ret, corners = cv2.findChessboardCorners(gray, (w,h),None)
 # 如果找到足够点对,将其存储起来
 if ret == True:
  cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
  objpoints.append(objp)
  imgpoints.append(corners)
  # 将角点在图像上显示
  cv2.drawChessboardCorners(img, (w,h), corners, ret)
  cv2.imshow('findCorners',img)
  cv2.waitKey(1)
cv2.destroyAllWindows()

# 标定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)

# 去畸变
img2 = cv2.imread('calib/00169.png')
h, w = img2.shape[:2]
newcameramtx, roi=cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),0,(w,h)) # 自由比例参数
dst = cv2.undistort(img2, mtx, dist, None, newcameramtx)
# 根据前面ROI区域裁剪图片
#x,y,w,h = roi
#dst = dst[y:y+h, x:x+w]
cv2.imwrite('calibresult.png',dst)

# 反投影误差
total_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)
 total_error += error
print "total error: ", total_error/len(objpoints)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
通过Python使用saltstack生成服务器资产清单
Mar 01 Python
Python编程在flask中模拟进行Restful的CRUD操作
Dec 28 Python
Python实现的IP端口扫描工具类示例
Feb 15 Python
Python实现Mysql数据统计及numpy统计函数
Jul 15 Python
python selenium 查找隐藏元素 自动播放视频功能
Jul 24 Python
Python3实现zip分卷压缩过程解析
Oct 09 Python
Python3的unicode编码转换成中文的问题及解决方案
Dec 10 Python
简单了解python filter、map、reduce的区别
Jan 14 Python
Django重设Admin密码过程解析
Feb 10 Python
Python坐标轴操作及设置代码实例
Jun 04 Python
浅谈多卡服务器下隐藏部分 GPU 和 TensorFlow 的显存使用设置
Jun 30 Python
python模板入门教程之flask Jinja
Apr 11 Python
Python 统计字数的思路详解
May 08 #Python
Django中STATIC_ROOT和STATIC_URL及STATICFILES_DIRS浅析
May 08 #Python
Django学习教程之静态文件的调用详解
May 08 #Python
Python实现计算圆周率π的值到任意位的方法示例
May 08 #Python
Python实现抓取HTML网页并以PDF文件形式保存的方法
May 08 #Python
Python读写docx文件的方法
May 08 #Python
python docx 中文字体设置的操作方法
May 08 #Python
You might like
php连接数据库代码应用分析
2011/05/29 PHP
php对数组排序代码分享
2014/02/24 PHP
ThinkPHP中的系统常量和预定义常量集合
2014/07/01 PHP
配置eAccelerator和XCache扩展来加速PHP程序的执行
2015/12/22 PHP
php Session无效分析资料整理
2016/11/29 PHP
PHP设计模式之建造者模式(Builder)原理与用法案例详解
2019/12/12 PHP
在IE下:float属性会影响offsetTop的取值
2006/12/22 Javascript
JavaScript之appendChild、insertBefore和insertAfter使用说明
2010/12/30 Javascript
30个最好的jQuery 灯箱插件分享
2011/04/25 Javascript
Js使用WScript.Shell对象执行.bat文件和cmd命令
2014/12/18 Javascript
AngularJs $parse、$eval和$observe、$watch详解
2016/09/21 Javascript
自己封装的一个原生JS拖动方法(推荐)
2016/11/22 Javascript
js实现各浏览器全屏代码实例
2018/07/03 Javascript
详解javascript appendChild()的完整功能
2018/08/18 Javascript
vee-validate vue 2.0自定义表单验证的实例
2018/08/28 Javascript
Node.js npm命令运行node.js脚本的方法
2018/10/10 Javascript
layui数据表格实现重载数据表格功能(搜索功能)
2019/07/27 Javascript
vue实现简单学生信息管理
2020/05/30 Javascript
Python3 queue队列模块详细介绍
2018/01/05 Python
python贪婪匹配以及多行匹配的实例讲解
2018/04/19 Python
通过python将大量文件按修改时间分类的方法
2018/10/17 Python
python提取xml里面的链接源码详解
2019/10/15 Python
如何在 Matplotlib 中更改绘图背景的实现
2020/11/26 Python
HTML5触摸事件(touchstart、touchmove和touchend)的实现
2020/05/08 HTML / CSS
加拿大便宜的隐形眼镜商店:Clearly
2016/09/15 全球购物
空字符串(“”)和null的区别
2012/11/13 面试题
先进事迹报告会感言
2014/01/24 职场文书
泸县召开党的群众路线教育实践活动总结大会新闻稿
2014/10/21 职场文书
社区党员群众路线教育实践活动心得体会
2014/11/03 职场文书
2014年科研工作总结
2014/12/03 职场文书
爱岗敬业事迹材料
2014/12/24 职场文书
离婚代理词范文
2015/05/23 职场文书
大学生团支书竞选稿
2015/11/21 职场文书
爱心捐款倡议书:点燃希望,传递温暖
2019/11/04 职场文书
vue-element-admin项目导入和导出的实现
2021/05/21 Vue.js
浅谈Python从全局与局部变量到装饰器的相关知识
2021/06/21 Python