使用OpenCV校准鱼眼镜头的方法


Posted in Python onNovember 26, 2020

01.简介

当我们使用的鱼眼镜头视角大于160°时,OpenCV中用于校准镜头“经典”方法的效果可能就不是和理想了。即使我们仔细遵循OpenCV文档中的步骤,也可能会得到下面这个奇奇怪怪的照片:

使用OpenCV校准鱼眼镜头的方法

如果小伙伴也遇到了类似情况,那么这篇文章可能会对大家有一定的帮助。

从3.0版开始,OpenCV包含了cv2.fisheye可以很好地处理鱼眼镜头校准的软件包。但是,该模块没有针对读者的相关的教程。

02.相机参数获取

校准镜头其实只需要下面2个步骤。

  • 利用OpenCV计算镜头的2个固有参数。OpenCV称它们为K和D,我们只需要知道它们是numpy数组外即可。
  • 通过K和D对图像进行去畸变矫正。

计算K和D

  • 下载棋盘格图案并将其打印在纸上(字母或A4尺寸)。大家要尽量将这张纸粘在坚硬且平坦的物体表面,例如一块硬纸板上。因为这里的关键是直线必须是直线
  • 将图案放在相机前面拍摄一些图像,图案要取在不同的位置和角度。这里的关键是图案需要以不同的方式出现失真(以便OpenCV尽可能多地了解镜头相关参数)。

使用OpenCV校准鱼眼镜头的方法

我们先将这些图片保存在JPG文件夹中。

现在我们只需要将此Python脚本片段复制到calibrate.py先前保存这些图像的文件夹中的文件中,就可以对其进行命名。

import cv2
assert cv2.__version__[0] == '3', 'The fisheye module requires opencv version >= 3.0.0'
import numpy as np
import os
import glob
CHECKERBOARD = (6,9)
subpix_criteria = (cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER, 30, 0.1)
calibration_flags = cv2.fisheye.CALIB_RECOMPUTE_EXTRINSIC+cv2.fisheye.CALIB_CHECK_COND+cv2.fisheye.CALIB_FIX_SKEW
objp = np.zeros((1, CHECKERBOARD[0]*CHECKERBOARD[1], 3), np.float32)
objp[0,:,:2] = np.mgrid[0:CHECKERBOARD[0], 0:CHECKERBOARD[1]].T.reshape(-1, 2)
_img_shape = None
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)
  if _img_shape == None:
    _img_shape = img.shape[:2]
  else:
    assert _img_shape == img.shape[:2], "All images must share the same size."
  gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
  # Find the chess board corners
  ret, corners = cv2.findChessboardCorners(gray, CHECKERBOARD, cv2.CALIB_CB_ADAPTIVE_THRESH+cv2.CALIB_CB_FAST_CHECK+cv2.CALIB_CB_NORMALIZE_IMAGE)
  # If found, add object points, image points (after refining them)
  if ret == True:
    objpoints.append(objp)
    cv2.cornerSubPix(gray,corners,(3,3),(-1,-1),subpix_criteria)
    imgpoints.append(corners)
N_OK = len(objpoints)
K = np.zeros((3, 3))
D = np.zeros((4, 1))
rvecs = [np.zeros((1, 1, 3), dtype=np.float64) for i in range(N_OK)]
tvecs = [np.zeros((1, 1, 3), dtype=np.float64) for i in range(N_OK)]
rms, _, _, _, _ = \
  cv2.fisheye.calibrate(
    objpoints,
    imgpoints,
    gray.shape[::-1],
    K,
    D,
    rvecs,
    tvecs,
    calibration_flags,
    (cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER, 30, 1e-6)
  )
print("Found " + str(N_OK) + " valid images for calibration")
print("DIM=" + str(_img_shape[::-1]))
print("K=np.array(" + str(K.tolist()) + ")")
print("D=np.array(" + str(D.tolist()) + ")")

运行python calibrate.py。如果一切顺利,脚本将输出如下内容:

Found 36 images for calibration
DIM=(1600, 1200)
K=np.array([[781.3524863867165, 0.0, 794.7118000552183], [0.0, 779.5071163774452, 561.3314451453386], [0.0, 0.0, 1.0]])
D=np.array([[-0.042595202508066574], [0.031307765215775184], [-0.04104704724832258], [0.015343014605793324]])

03.图像畸变矫正

获得K和D后,我们可以对以下情况获得的图像进行失真矫正:我们需要取消失真的图像与校准期间捕获的图像具有相同的尺寸。也可以将边缘周围的某些区域裁剪掉,来保证使未失真图像的整洁。通过undistort.py使用以下python代码创建文件:

DIM=XXX
K=np.array(YYY)
D=np.array(ZZZ)
def undistort(img_path):
  img = cv2.imread(img_path)
  h,w = img.shape[:2]
  map1, map2 = cv2.fisheye.initUndistortRectifyMap(K, D, np.eye(3), K, DIM, cv2.CV_16SC2)
  undistorted_img = cv2.remap(img, map1, map2, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT)
  cv2.imshow("undistorted", undistorted_img)
  cv2.waitKey(0)
  cv2.destroyAllWindows()
if __name__ == '__main__':
  for p in sys.argv[1:]:
    undistort(p)

现在运行python undistort.py file_to_undistort.jpg。

使用OpenCV校准鱼眼镜头的方法

矫正前

使用OpenCV校准鱼眼镜头的方法

矫正后

如果大家仔细观察,可能会注意到一个问题:原始图像中的大部分会在此过程中被裁剪掉。例如,图像左侧的橙色RC汽车只有一半的车轮保持在未变形的图像中。实际上,原始图像中约有30%的像素丢失了。小伙伴们可以思考思考如果我们想找回丢失的像素该这么办呢?

到此这篇关于使用OpenCV校准鱼眼镜头的方法的文章就介绍到这了,更多相关OpenCV校准鱼眼镜内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
wxPython中文教程入门实例
Jun 09 Python
简单总结Python中序列与字典的相同和不同之处
Jan 19 Python
Python读取图片为16进制表示简单代码
Jan 19 Python
python smtplib模块自动收发邮件功能(一)
May 22 Python
Python字典的基本用法实例分析【创建、增加、获取、修改、删除】
Mar 05 Python
Python实现的栈、队列、文件目录遍历操作示例
May 06 Python
Dlib+OpenCV深度学习人脸识别的方法示例
May 14 Python
python实现简单聊天室功能 可以私聊
Jul 12 Python
django 使用全局搜索功能的实例详解
Jul 18 Python
python logging.info在终端没输出的解决
May 12 Python
python自动化测试三部曲之unittest框架的实现
Oct 07 Python
python 第三方库paramiko的常用方式
Feb 20 Python
最新PyCharm 2020.2.3永久激活码(亲测有效)
Nov 26 #Python
Django-celery-beat动态添加周期性任务实现过程解析
Nov 26 #Python
Django celery异步任务实现代码示例
Nov 26 #Python
Django通过设置CORS解决跨域问题
Nov 26 #Python
Django利用elasticsearch(搜索引擎)实现搜索功能
Nov 26 #Python
python模拟点击在ios中实现的实例讲解
Nov 26 #Python
如何在 Matplotlib 中更改绘图背景的实现
Nov 26 #Python
You might like
自动跳转中英文页面
2006/10/09 PHP
关于使用key/value数据库redis和TTSERVER的心得体会
2013/06/28 PHP
php 使用ActiveMQ发送消息,与处理消息操作示例
2020/02/23 PHP
Yii 框架使用Forms操作详解
2020/05/18 PHP
为指定元素增加样式的js代码
2009/12/09 Javascript
Javascript 面向对象 对象(Object)
2010/05/13 Javascript
JQuery之拖拽插件实现代码
2011/04/14 Javascript
jquery实现当滑动到一定位置时固定效果
2014/06/17 Javascript
跟我学习javascript的隐式强制转换
2015/11/16 Javascript
整理关于Bootstrap警示框的慕课笔记
2017/03/29 Javascript
Express之get,pos请求参数的获取
2017/05/02 Javascript
使用vue-router完成简单导航功能【推荐】
2018/06/28 Javascript
小程序实现多选框功能
2018/10/30 Javascript
vue.js层叠轮播效果的实例代码
2018/11/08 Javascript
Node.js实现简单的爬取的示例代码
2019/06/25 Javascript
[01:02:48]2018DOTA2亚洲邀请赛 4.1 小组赛 A组 LGD vs OG
2018/04/02 DOTA
[02:42]岂曰无衣,与子同袍!DOTA2致敬每一位守护人
2020/02/17 DOTA
Python continue语句用法实例
2014/03/11 Python
Windows和Linux下Python输出彩色文字的方法教程
2017/05/02 Python
Php多进程实现代码
2018/05/07 Python
python中的变量如何开辟内存
2018/06/26 Python
Python多线程处理实例详解【单进程/多进程】
2019/01/30 Python
了解不常见但是实用的Python技巧
2019/05/23 Python
pyqt5使用按钮进行界面的跳转方法
2019/06/19 Python
Python 异步协程函数原理及实例详解
2019/11/13 Python
使用卷积神经网络(CNN)做人脸识别的示例代码
2020/03/27 Python
细说NumPy数组的四种乘法的使用
2020/12/18 Python
美国蔬菜和植物种子公司:Burpee
2017/02/01 全球购物
经济实惠的豪华家具:My-Furniture
2019/03/12 全球购物
中国专业的音频分享平台:喜马拉雅
2019/05/24 全球购物
我的未来不是梦演讲稿
2014/09/02 职场文书
实习介绍信模板
2015/01/30 职场文书
2019毕业论文致谢词
2019/06/24 职场文书
浅谈 JavaScript 沙箱Sandbox
2021/11/02 Javascript
CSS 左边固定宽右边自适应的6种方法
2022/05/15 HTML / CSS