OpenCV图像识别之相机校准Camera Calibration学习

 更新时间:2023年05月06日 09:44:32   作者:uncle_ll  
这篇文章主要为大家介绍了OpenCV图像识别之相机校准Camera Calibration学习,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

目标

在本节中,将学习

  • 由相机引起的失真类型
  • 如何找到相机的固有和非固有特性
  • 如何基于这些特性使图像不失真

基础

一些针孔相机会给图像带来明显的失真。两种主要的变形:

  • 径向变形( radial distortion)
  • 切向变形( tangential distortion)

径向变形

径向变形会导致直线出现弯曲。距图像中心越远,径向畸变越大。例如,下面显示一个图像,其中棋盘的两个边缘用红线标记。但是,会看到棋盘的边框不是直线,并且与红线不匹配。所有预期的直线都凸出。

径向变形的变形量可以用下面的式子表示:

除此之外,还需要其他一些信息,相机的内在和外在参数.

  • 外在参数对应于旋转和平移矢量,其将3D点的坐标平移为坐标系。

对于3D应用,首先需要纠正这些失真,就要找到这些参数。以国际象棋棋盘为示例图像,找到一些已经知道其相对位置的特定点(例如棋盘上的四角)。假设知道了现实世界空间中这些点的坐标,也知道图像中的坐标,就可以求解失真系数了。

代码

如上所述,相机校准至少需要10个测试图案。OpenCV项目中附带了一些国际象棋棋盘的图像,因此将利用这些图像进行讲解。假设给定一张棋盘图像,相机校准所需的重要输入数据是3D真实点集以及图像中这些点的相应2D坐标。2D图像点可以从图像中轻松找到点(这些图像点是国际象棋棋盘中两个黑色正方形相互接触的位置)。

真实3D点如何处理?这些图像是从静态相机拍摄的,而国际象棋棋盘放置在不同的位置和方向。因此,需要知道(X,Y,Z)(X, Y, Z)(X,Y,Z)值。但是为简单起见,可以说棋盘在XYXYXY平面上保持静止(因此Z始终为0),并且照相机也相应地移动了。这种考虑有助于仅找到X,Y值。现在对于X,Y值,可以简单地将点传递为(0,0),(1,0),(2,0),…,这表示点的位置。在这种情况下,得到的结果将是棋盘正方形的大小比例。但是,当我们知道正方形大小(例如30毫米),则可以将值传递为(0,0),(30,0),(60,0),…。因此,得到的结果以毫米为单位。(在这种情况下,我们不知道正方形的大小,因为我们没有拍摄那些图像,因此我们以正方形的大小进行传递)。

3D点称为对象点,而2D图像点称为图像点。

开始

为了在国际象棋棋盘图像中查找图案,可以使用函数cv2.findChessboardCorners()。该函数需要传递所需的图案,例如8x8网格,5x5网格等。在此示例中使用7x6网格。(通常,棋盘有8x8的正方形和7x7的内部角)。它返回角点和返回值,如果获得图案,则返回值为True。这些角将按顺序放置(从左到右,从上到下)

此函数可能无法在所有图像中找到所需的图案。因此一个不错的选择是编写代码,使它启动相机并检查每帧所需的图案。获得图案后,找到角并将其存储在列表中。另外,在读下一帧之前请设置一些时间间隔,以便可以在不同方向上调整棋盘。继续此过程,直到获得所需数量的良好图案为止。即使在此处提供的示例中,也不确定给出的14张图像中有多少张是好的。因此,必须阅读所有图像并仅保存好的团。 除了棋盘之外,还可以使用圆形网格。 在这种情况下,必须使用函数cv2.findCirclesGrid()来找到模式。 较少的图像足以使用圆形网格执行相机校准。

一旦找到拐角,就可以使用cv2.cornerSubPix()来提高其精度。还可以使用cv2.drawChessboardCorners()绘制图案。所有这些步骤都包含在以下代码中:

# 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(r'right*.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 ret:
       objpoints.append(objp)
       corners2 = cv2.cornerSubPix(gray, corners, (11,11), (-1,-1), criteria)
       imgpoints.append(corners)
       # draw and display the corners
       cv2.drawChessboardCorners(img, (7, 6), corners2, ret)
       cv2.imshow('img', img)
       cv2.waitKey(0)
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。

实例:

img = cv2.imread('right12.jpg')
h, w, _ = img.shape
newcameratx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 1, (w, h))

1使用cv2.undistort

只需调用该函数并使用上面获得的ROI裁剪结果即可。

# undistort
dst = cv2.undistort(img, mtx, dist, None, newcameratx)
# copy the image
x, y, w, h = roi
dst = dst[y:y+h, x:x+w]
cv2.imshow('calibresult.png', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

2. 使用remapping

该方式有点困难。首先,找到从扭曲图像到未扭曲图像的映射函数。然后使用重映射函数。

尽管如此,两种方法都给出相同的结果。看到下面的结果:

# undistort
mapx, mapy = cv2.initUndistortRectifyMap(mtx, dist, None, newcameratx, (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.imshow('calibresult.png', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

可以看到所有边缘都是笔直的。 另外,可以使用NumPy中的写入功能(np.savez,np.savetxt

等)存储相机矩阵和失真系数,以备将来使用。

重投影误差|Re-projection Error

重投影误差可以很好地估计找到的参数的精确程度。重投影误差越接近零,表明发现的参数越准

确。给定固有,失真,旋转和平移矩阵,必须首先使用cv2.projectPoints()将对象点转换为

图像点。然后,可以计算出通过变换得到的绝对值和拐角发现算法之间的绝对值范数。为了

找到平均误差,计算为所有校准图像计算的误差的算术平均值。

# re projection error
mean_error = 0
for i in range(len(objpoints)):
    imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
    error = cv2.norm(imgpoints[i], imgpoints2, cv2.NORM_L2)/len(imgpoints2)
    mean_error += error
print( "total error: {}".format(mean_error/len(objpoints)) )

total error: 0.025365426097625716

保存相机矩阵和失真系数与加载 可以以json或者pickle等方式保存相机矩阵和失真系数

import pickle
# save data
cam_calib = {"cam_matrix": mtx, "dist_coeffs": dist}
with open("cam_calib.p", "wb") as f:
    pickle.dump(cam_calib, f)
# load previously save data
with open(r"cam_calib.p", "rb") as f:
    data = pickle.load(f)
    mtx = data['cam_matrix']
    dist = data['dist_coeffs']

附加资源

en.wikipedia.org/wiki/Distor…

docs.opencv.org/4.1.2/dc/db…

以上就是OpenCV图像识别之相机校准Camera Calibration学习的详细内容,更多关于OpenCV图像识别相机校准的资料请关注脚本之家其它相关文章!

相关文章

  • Python optparse模块及简单使用

    Python optparse模块及简单使用

    optparse,是一个更够让程序设计人员轻松设计出简单明了、易于使用、符合标准的Unix命令例程式的Python模块,生成使用和帮助信息,这篇文章主要介绍了Python optparse模块简单使用,需要的朋友可以参考下
    2022-12-12
  • Python利用xlwings实现考勤表制作

    Python利用xlwings实现考勤表制作

    这篇文章主要为大家详细介绍了Python如何利用xlwings库操作excel实现考勤表的制作,文中的实现步骤讲解详细,感兴趣的可以尝试一下
    2023-04-04
  • 使用Python操作Redis所有数据类型的方法

    使用Python操作Redis所有数据类型的方法

    当今互联网时代,数据处理已经成为了一个非常重要的任务,而Redis作为一款高性能的NoSQL数据库,越来越受到了广大开发者的喜爱,本篇博客将介绍如何使用Python操作Redis的所有类型,以及一些高级用法,需要的朋友可以参考下
    2023-11-11
  • python实现网页链接提取的方法分享

    python实现网页链接提取的方法分享

    这篇文章主要介绍了python实现的网页链接提取的方法,需要的朋友可以参考下
    2014-02-02
  • python发送告警邮件脚本

    python发送告警邮件脚本

    这篇文章主要介绍了python发送告警邮件脚本的配置方法,zabbix通过python脚本发告警邮件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-09-09
  • Python字典fromkeys()方法使用代码实例

    Python字典fromkeys()方法使用代码实例

    这篇文章主要介绍了Python字典fromkeys()方法使用代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-07-07
  • 关于Torch torchvision Python版本对应关系说明

    关于Torch torchvision Python版本对应关系说明

    这篇文章主要介绍了关于Torch torchvision Python版本对应关系说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-05-05
  • Pandas的数据过滤实现

    Pandas的数据过滤实现

    这篇文章主要介绍了Pandas的数据过滤实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • next在python中返回迭代器的实例方法

    next在python中返回迭代器的实例方法

    在本篇文章里小编给大家整理的是一篇关于next在python中返回迭代器的实例方法,有兴趣的朋友们可以尝试下。
    2020-12-12
  • Python unittest discover批量执行代码实例

    Python unittest discover批量执行代码实例

    这篇文章主要介绍了Python unittest discover批量执行代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09

最新评论