【OpenCV】【python】相机校正(张氏标定法)

课程目录

  • API使用流程
  • 参考文章
  • 代码位置
  • 完整代码
  • 遇到的问题
  • 效果展示

>>> 点击进入:OpenCV专栏<<<


API使用流程

  1. 相机去畸变利用的是张氏矫正法,里面使用了极大似然估计,模拟近似畸变系数,所以需要N>=4个匹配点对。(一般来说,一张图片,全捕捉到或者全丢失。)

  2. 计算畸变系数,使用的API为:cv2.calibrateCamera。由于这里求的是畸变系数,是一个比例,所以传参不用考虑实际尺寸。传入单位尺寸即可。这里需要传入

  • Object_points:世界坐标系中的点,在使用棋盘的场合,我们令z的坐标值为0,而x,y坐标用里面来度量,选用英寸单位,那么所有参数计算的结果也是用英寸表示。最简单的方式是我们定义棋盘的每一个方块为一个单位。
  • image_points:在图像中寻找到的角点的坐标,包含object_points所提供的所有点。用api:cv2.findChessboardCorners
  • image_size: 图像的大小,以像素为衡量单位
  1. 可以画出找到的点cv2.drawChessboardCorners
  2. 使用cv2.calibrateCamera计算校正后的相机内参和畸变系数
  3. 使用 cv2.undistort ,输入畸变系数和相机内参以后,得到校正后的图片

参考文章

函数的使用:
角点检测与FindChessboardCorners函数


代码位置

【OpenCV】【python】相机校正(张氏标定法)_第1张图片


完整代码

# -*- coding:utf-8 -*-
'''
@Author: knocky
@Blog: https://blog.csdn.net/zzx188891020
@E-mail: [email protected]
@File: calibrate.py
@CreateTime: 2020/6/8 22:26
'''
import glob
import cv2
import numpy as np
import matplotlib.pyplot as plt


# 相机校正:外参,内参,畸变系数
def cal_calibrate_params(file_paths):
    '''
    说明:cv2.calibrateCamera需要直接传入所有图片的关键点List ,所以需要构造成响应的格式。
    通过cv2.findChessboardCorners找到全部内角点,如果有一个丢失,则此图片失效。
    '''
    # 存储角点数据的坐标
    object_points = []  # 角点在三维空间的位置
    image_points = []  # 角点在图像空间中的位置
    # 生成角点在真实世界中的位置
    objp = np.zeros((nx * ny, 3), np.float32)

    # 生成对应的角点(x,y)集合,扫描的顺序为先行后列
    # [[0, 0],[1, 0],[2, 0],[3, 0],[4, 0]..... [5, 5],[6, 5],[7, 5],  [8, 5]
    objp[:, :2] = np.mgrid[0:nx, 0:ny].T.reshape(-1, 2)

    # 角点检测
    for file_path in file_paths:
        img = cv2.imread(file_path)
        # 灰度化
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        # 角点检测
        # rect:输出是否找到角点,找到角点返回1,否则返回0
        # coners: shape(54,1,2)  54 是坐标点个数, 2 是(x,y)
        # [[[545.3228  343.05032]]  [[602.6792  342.8268 ]]  [[660.09796 341.2892 ]]....

        rect, coners = cv2.findChessboardCorners(gray, (nx, ny), None)


        imgcopy = img.copy()
        # 检测完角点之后我们可以将将测到的角点绘制在图像上
        cv2.drawChessboardCorners(imgcopy, (nx, ny), coners, rect)
        # 这个是自定义函数,绘制对比图
        plot_contrast_image(img, imgcopy)
        if rect == True:
            object_points.append(objp)
            image_points.append(coners)
    # 相机校正
    ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(object_points, image_points, gray.shape[::-1], None, None)
    return ret, mtx, dist, rvecs, tvecs


# 图像去畸变:利用相机校正的内参,畸变系数
def img_undistort(img, mtx, dist):
    dis = cv2.undistort(img, mtx, dist, None, mtx)
    return dis


# 绘制对比图
def plot_contrast_image(origin_img, converted_img, origin_img_title="origin_img", converted_img_title="converted_img",
                        converted_img_gray=False):
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 20))
    ax1.set_title = origin_img_title
    ax1.imshow(origin_img)
    ax2.set_title = converted_img_title
    if converted_img_gray == True:
        ax2.imshow(converted_img, cmap="gray")
    else:
        ax2.imshow(converted_img)
    plt.show()


if __name__ == '__main__':
    "参数设置"
    nx = 9
    ny = 6
    file_paths = glob.glob("../camera_cal/calibration*.jpg")

    ret, mtx, dist, rvecs, tvecs = cal_calibrate_params(file_paths)
    if np.all(mtx != None):
        img = cv2.imread("../test/test1.jpg")
        undistort_img = img_undistort(img, mtx, dist)
        plot_contrast_image(img, undistort_img)
        print("done")
    else:
        print("failed")


遇到的问题

使用objp[:, :2] = np.mgrid[0:nx, 0:ny].T.reshape(-1, 2)构造目标点的相对坐标,如何与扫描顺序正好匹配呢?

这里提到了,好像和设置的坐标有关系。
一分钟详解OpenCV之相机标定函数calibrateCamera()

根据输出的20张图来看,几乎都是一个输出模式,所以感觉只要按照一个固定的方式设置就可以,不用纠结乱序问题。


效果展示

【OpenCV】【python】相机校正(张氏标定法)_第2张图片

【OpenCV】【python】相机校正(张氏标定法)_第3张图片

你可能感兴趣的:(OpenCV,python)