(Python 3)opencv相机标定

前言

  • 相机将三维世界中的坐标点(单位为米)映射到二维图像平面(单位为像素)的过程能够用一个几何模型进行描述。这个模型有很多种,其中最简单的称为针孔模型
    在这里插入图片描述
  • 为了获得好的成像效果,我们在相机的前方加了透镜。透镜的加入对成像过程中光线的传播会产生新的影响: 一是透镜自身的形状对光线传播的影响;二是在机械组装过程中,透镜和成像平面不可能完全平行,这也会使得光线穿过透镜投影到成像面时的位置发生变化。
  • 由透镜形状引起的畸变称之为径向畸变。在针孔模型中,一条直线投影到像素平面上还是一条直线。可是,在实际拍摄的照片中,摄像机的透镜往往使得真实环境中的一条直线在图片中变成了曲线 。越靠近图像的边缘,这种现象越明显。由于实际加工制作的透镜往往是中心对称的,这使得不规则的畸变通常径向对称。它们主要分为两大类,桶形畸变枕形畸变
    在这里插入图片描述
  • 桶形畸变是由于图像放大率随着离光轴的距离增加而减小,而枕形畸变却恰好相反。在这两种畸变中,穿过图像中心和光轴有交点的直线还能保持形状不变。除了透镜的形状会引入径向畸变外,在相机的组装过程中由于不能使得透镜和成像面严格平行也会引入切向畸变。

在这里插入图片描述
在这里插入图片描述
实际应用中可以灵活选择纠正模型,比如只选择 k 1 , p 1 , p 2 这三项等。

上述概述均采用高翔视觉SLAM14讲 从理论到实践》书本里面的说法。

  • 一言以蔽之,由于相机存在畸变,因此要通过标定,来矫正图片,来减小误差。

参考书籍:

  • 高翔《视觉SLAM14讲 从理论到实践》

参考链接:

  • https://blog.csdn.net/AdamShan/article/details/78712120

环境

  • Ubuntu16.04
  • pycharm
  • opencv
  • python3.5

相机标定

  • 先考虑一张棋盘图片的情况

原图

可以看到图片边缘的直线扭曲的比较厉害。

在这里插入图片描述
代码

# 相机标定

import cv2

# 首先读取图像并转为灰度图
img = cv2.imread('./camera_cal/calibration1.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# cv2.imshow("img",img)
# cv2.imshow("gray",gray)

# 使用OpenCV的cv2.findChessboardCorners()函数找出棋盘图中的对角(即图片中黑白相对的点的坐标),
# 同时使用cv2.drawChessboardCorners()将之画出来

# cv2.findChessboardCorners参数patternSize取(9,5)--棋盘图中每行和每列交点的个数
# 取(9,5)下面打印corners才会有输出,不然是None,
# 其原因在于导入的图片./camera_cal/calibration1.jpg数一下交点的数目,一行有9个,一列有5个
# Adam博客当中取(9,6)原因在于他的图和我的图不一样,认真数一下可以发现他的图确实是一行9个一列6个角点
# 事实证明,(9,4)也可以,只要size小于图片中的交点数即可

# 函数解析参见官网https://docs.opencv.org/3.3.0/dc/dbb/tutorial_py_calibration.html
# It returns the corner points and retval which will be True if pattern is obtained.
# These corners will be placed in an order (from left-to-right, top-to-bottom)
ret, corners = cv2.findChessboardCorners(gray, (9, 5),None)
print(ret)
# print(corners)  # 交点坐标

if ret == True:
    img = cv2.drawChessboardCorners(img, (9, 5), corners, ret)

cv2.imshow("final",img)

cv2.waitKey()
cv2.destroyAllWindows()
  • 打印输出
True
  • 结果图

在这里插入图片描述
到此为止也就只是完成了找出交点并且标注出来,接下来应该还要对其进行矫正。构造这些对角点在在现实世界中的相对位置,将这些位置简化成整数值。
完整代码如下:

# 相机标定

import cv2
import numpy as np

# 首先读取图像并转为灰度图
img = cv2.imread('./camera_cal/calibration1.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# cv2.imshow("img",img)
# cv2.imshow("gray",gray)

# 使用OpenCV的cv2.findChessboardCorners()函数找出棋盘图中的对角(即图片中黑白相对的点的坐标),
# 同时使用cv2.drawChessboardCorners()将之画出来

# cv2.findChessboardCorners参数patternSize取(9,5)--棋盘图中每行和每列交点的个数
# 取(9,5)下面打印corners才会有输出,不然是None,
# 其原因在于导入的图片./camera_cal/calibration1.jpg数一下交点的数目,一行有9个,一列有5个
# Adam博客当中取(9,6)原因在于他的图和我的图不一样,认真数一下可以发现他的图确实是一行9个一列6个角点
# 事实证明,(9,4)也可以,只要size小于图片中的交点数即可

# 函数解析参见官网https://docs.opencv.org/3.3.0/dc/dbb/tutorial_py_calibration.html
# It returns the corner points and retval which will be True if pattern is obtained.
# These corners will be placed in an order (from left-to-right, top-to-bottom)
ret, corners = cv2.findChessboardCorners(gray, (9, 5),None)
# print(ret)
# print(corners)  # 交点坐标

if ret == True:
    img = cv2.drawChessboardCorners(img, (9, 5), corners, ret)

cv2.imshow("result",img)

# 构造这些对角点在在现实世界中的相对位置,我们将这些位置简化成整数值
objp = np.zeros((5*9, 3), np.float32)
objp[:, :2] = np.mgrid[0:9, 0:5].T.reshape(-1, 2)

img_points = []
obj_points = []

img_points.append(corners)
obj_points.append(objp)

# 最后我们使用OpenCV中的 cv2.calibrateCamera() 即可求得这个相机的畸变系数,在后面的所有图像的矫正都可以使用这一组系数来完成
image_size = (img.shape[1], img.shape[0])
#  It returns the camera matrix, distortion coefficients, rotation and translation vectors etc.
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points,image_size, None, None)

test_img = cv2.imread("./camera_cal/calibration3.jpg")
# 这里cv2.undistort的最后一个参数依旧选用原来的相机矩阵mtx
# 也可以尝试做opencv官网举例的使用cv2.getOptimalNewCameraMatrix()基于自由缩放参数来优化相机矩阵,之后再带入
undist = cv2.undistort(test_img, mtx, dist, None, mtx)

cv2.imshow("test_img",test_img)
cv2.imshow("undist",undist)

cv2.waitKey()
cv2.destroyAllWindows()
  • 实验效果大致如下,图中undist为矫正后的结果,最底下的图片为test_img

在这里插入图片描述

不足之处:

  • 正如前文提到的这里只考虑了用一张棋盘图片来求得相机的相关畸变参数,实际上应当有10张以上效果较好,之后再改进一下。正如代码中写的,可以试着用cv2.getOptimalNewCameraMatrix()基于自由缩放参数来优化相机矩阵。
  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值