Python+OpenCV实现相机标定

  • 相机标定的原理及各个坐标系之间的关系可参见上一篇博客,这里直接介绍工程实践部分,如何用Python+OpenCV完后相机标定。

1.相机标定的目的

  • 获取摄像机的内参和外参矩阵(同时也会得到每一幅标定图像的旋转和平移矩阵),内参和外参系数可以对之后相机拍摄的图像就进行矫正,得到畸变相对很小的图像。

2.相机标定的输入

  • 标定图像上所有内角点的图像坐标,标定板图像上所有内角点的空间三维坐标(一般情况下假定图像位于Z=0平面上)。

3.相机标定的输出

  • 摄像机的内参、外参系数。

4.相机标定的实现

  • 上述三个问题基本决定了使用OpenCV实现张正友法标定相机的标定流程、标定结果评价以及使用标定结果矫正原始图像的完整流程:
    1.准备标定图片;
    2.对每一张标定图片,提取棋盘格内部的角点信息;
    3.对每一张标定图片,进一步提取棋盘格内部的亚像素角点信息;
    4.在棋盘标定图上绘制找到的内角点(非必须,仅为了显示);
    5.相机标定;
    6.对标定结果进行评价;
    7.查看标定效果——利用标定结果对棋盘图进行矫正。
4.1实验准备:

主要准备图片即可,10张左右的标定图片,黑白棋盘格。可以给图片进行一定的缩小,加快运算速度。拍摄过程中,如果方格纸是横着摆的就一直横着摆着拍,因为横纵角点个数是要提前设置好的。
我准备的是下图这种格子数为9×7,内角点为8×6的棋盘格图片。
在这里插入图片描述

4.2代码实现:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import cv2
import numpy as np
import glob

# 设置寻找亚像素角点的参数,采用的停止准则是最大循环次数30和最大误差容限0.001
criteria = (cv2.TERM_CRITERIA_MAX_ITER | cv2.TERM_CRITERIA_EPS, 30, 0.001)

# 获取标定板角点的位置
objp = np.zeros((8 * 6, 3), np.float32)  #格子数为9行7列,内角点为8*6的棋盘格图片
objp[:, :2] = np.mgrid[0:6, 0:8].T.reshape(-1, 2)  # 将世界坐标系建在标定板上,所有点的Z坐标全部为0,所以只需要赋值x和y

obj_points = []  # 存储3D点
img_points = []  # 存储2D点

images = glob.glob("./image/*.jpg")
for fname in images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    size = gray.shape[::-1]
    ret, corners = cv2.findChessboardCorners(gray, (8, 6), None)  #提取角点:第一个参数为图片,第二个为图片横纵角点的个数。

    if ret:
        obj_points.append(objp)

        corners2 = cv2.cornerSubPix(gray, corners, (5, 5), (-1, -1), criteria)  # 在原角点的基础上寻找亚像素角点
        # 找寻亚像素角点:cornerSubPix(gray, corners, (winsize, winsize), (-1, -1), criteria)
        # winsize为搜索窗口边长的一半。
        # zeroZone:搜索区域中间的dead region边长的一半,有时用于避免自相关矩阵的奇异性。如果值设为(-1,-1)则表示没有这个区域。
        # criteria:角点精准化迭代过程的终止条件。也就是当迭代次数超过criteria.maxCount,或者角点位置变化小于criteria.epsilon时,停止迭代过程。

        if [corners2]:
            img_points.append(corners2)
        else:
            img_points.append(corners)

        cv2.drawChessboardCorners(img, (8, 6), corners, ret)  # 记住,OpenCV的绘制函数一般无返回值
        # 可以使用该函数把角点画出来:drawChessboardCorners(image, (w, h), corners, ret);其中corners和ret为第一个函数的输出值。
        cv2.imshow('img', img)
        cv2.waitKey(0) # 直到你按下任意一个键,才被关掉
        # 在delaytime时间内,按键盘,返回所按键的ASCII值; 若未在delaytime时间内按任何键,返回-1; 其中,dalaytime: 单位ms

print len(img_points)
cv2.destroyAllWindows()

# 标定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points, size, None, None)

print "ret:", ret
print "mtx:\n", mtx  # 内参数矩阵
print "dist:\n", dist  # 畸变系数   distortion cofficients = (k_1,k_2,p_1,p_2,k_3)
print "rvecs:\n", rvecs  # 旋转向量  # 外参数
print "tvecs:\n", tvecs  # 平移向量  # 外参数

print("-----------------------------------------------------")

# 畸变校正
img = cv2.imread(images[9])
h, w = img.shape[:2]
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 1, (w, h))  #显示更大范围的图片(正常重映射之后会删掉一部分图像)
print newcameramtx

print("------------------使用undistort函数-------------------")
dst = cv2.undistort(img, mtx, dist, None, newcameramtx)
x, y, w, h = roi
dst1 = dst[y:y + h, x:x + w]
cv2.imwrite('calibresult21.jpg', dst1)
print "方法一:dst的大小为:", dst1.shape

# undistort方法二
print("-------------------使用重映射的方式-----------------------")
mapx, mapy = cv2.initUndistortRectifyMap(mtx, dist, None, newcameramtx, (w, h), 5)  # 获取映射方程
dst = cv2.remap(img, mapx, mapy, cv2.INTER_LINEAR)      # 重映射
# dst = cv2.remap(img, mapx, mapy, cv2.INTER_CUBIC)  # 重映射后,图像变小了
x, y, w, h = roi
dst2 = dst[y:y + h, x:x + w]
cv2.imwrite('calibresult22.jpg', dst2)
print "方法二:dst的大小为:", dst2.shape  # 图像比方法一的小

print("-------------------计算反向投影误差-----------------------")
tot_error = 0
for i in xrange(len(obj_points)):
    img_points2, _ = cv2.projectPoints(obj_points[i], rvecs[i], tvecs[i], mtx, dist)
    error = cv2.norm(img_points[i], img_points2, cv2.NORM_L2) / len(img_points2)
    tot_error += error

mean_error = tot_error / len(obj_points)
print "total error: ", tot_error
print "mean error: ", mean_error

注意:代码中的11、12、22、38行中的角点数根据自己的棋盘格大小进行更改。

  • 6
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
以下是使用PythonOpenCV进行相机标定的步骤和代码实现: 1.准备棋盘格图像,并确定棋盘格的大小。 2.使用cv2.findChessboardCorners()函数在棋盘格图像中检测角点。 3.使用cv2.calibrateCamera()函数计算相机的内部参数矩阵和畸变系数。 4.使用cv2.undistort()函数对图像进行去畸变处理。 ```python import numpy as np import cv2 import glob # 准备棋盘格图像 chessboard_size = (9, 6) images = glob.glob('chessboard/*.jpg') # 棋盘格角点的三维坐标 objp = np.zeros((chessboard_size[0] * chessboard_size[1], 3), np.float32) objp[:, :2] = np.mgrid[0:chessboard_size[0], 0:chessboard_size[1]].T.reshape(-1, 2) # 存储棋盘格角点的二维坐标和三维坐标 objpoints = [] imgpoints = [] for fname in images: img = cv2.imread(fname) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 检测棋盘格角点 ret, corners = cv2.findChessboardCorners(gray, chessboard_size, None) if ret == True: objpoints.append(objp) imgpoints.append(corners) # 绘制棋盘格角点 cv2.drawChessboardCorners(img, chessboard_size, corners, ret) cv2.imshow('img', img) cv2.waitKey(500) cv2.destroyAllWindows() # 相机标定 ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None) # 去畸变处理 img = cv2.imread('chessboard/test_image.jpg') h, w = img.shape[:2] newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 1, (w, h)) dst = cv2.undistort(img, mtx, dist, None, newcameramtx) # 显示去畸变处理前后的图像 cv2.imshow('original', img) cv2.imshow('undistorted', dst) cv2.waitKey(0) cv2.destroyAllWindows() ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值