opencv实战项目二十四:棋盘格相机内参标定

文章目录

  • 前言
  • 一、简介:
  • 二、使用步骤
    • 2.1制作标定板
    • 2.2 拍摄不同角度的标定板
    • 2.3计算棋盘格角点并优化
    • 2.4计算相机参数
  • 三、整体代码实现:


前言

在数字图像处理计算机视觉领域,相机标定是一个至关重要的步骤。它为相机提供了一个准确的数学模型,使我们能够从二维图像中准确地恢复三维世界信息。而在众多标定方法中,使用棋盘格图案进行相机内参标定无疑是最经典且广泛采用的技术之一。
在这篇博客中,我们将深入探讨棋盘格相机内参标定的原理、步骤及其在实际应用中的重要性。我们将详细介绍如何使用棋盘格图案来获取相机的内参矩阵,包括焦距、主点坐标以及镜头畸变系数等关键参数并通过Opencv实现它。


一、简介:

相机内参标定是图像处理计算机视觉领域中的一个重要步骤,其必要性可以从以下几个方面进行介绍:

  • 校正镜头畸变:相机镜头通常存在一定的光学畸变,主要包括径向畸变和切向畸变。这些畸变会导致图像中的直线变弯,或者图像的某些部分相对于其他部分发生形变。通过内参标定,可以准确估计这些畸变参数,从而在后续的图像处理中对畸变进行校正。
  • 提高测量精度:在需要进行尺寸测量或三维重建的应用中,如工业检测、机器人导航等,准确的相机内参是必不可少的。内参标定提供了相机的焦距、主点位置等参数,这些参数对于从图像中提取准确的空间信息至关重要。
  • 统一图像坐标系:相机内参标定有助于将图像坐标转换到统一的坐标系中。这对于多相机系统或需要将不同时间或不同角度拍摄的图像进行拼接的场景尤为重要。
  • 优化算法性能:许多计算机视觉算法,如特征匹配、视觉SLAM(Simultaneous Localization andMapping)、立体视觉等,都依赖于相机的内参来进行优化。准确的内参可以显著提高这些算法的性能和鲁棒性。
  • 消除系统误差:相机内参标定有助于消除由于相机硬件特性引起的系统误差,从而提高图像质量和算法结果的可靠性。
  • 适应不同场景:不同的相机和镜头组合会有不同的内参。即使是同一相机,在不同的拍摄条件下(如不同的焦距、光圈设置),其内参也可能有所不同。因此,针对具体应用场景进行内参标定是必要的。

进行相机内参标定是为了确保相机成像系统的准确性和一致性,这对于依赖高质量图像数据进行进一步处理的计算机视觉应用来说是至关重要的。

二、使用步骤

2.1制作标定板

标定板制作可以点击此处:
在这里插入图片描述
选择好之后,点击图像下面的保存标定板作pdf即可,然后用a4纸打印

2.2 拍摄不同角度的标定板

保持相机的位置不变,移动标定板用来拍摄不同角度的图片,将图片放入一个文件夹下:
在这里插入图片描述

在这里插入图片描述

2.3计算棋盘格角点并优化

通过函数cv2.findChessboardCorners计算角点,函数 cv2.findChessboardCorners 是 OpenCV 库中的一个函数,用于检测图像中的棋盘格角点。这个函数在相机标定过程中非常关键,因为它能够帮助我们从标定图像中提取出用于计算相机内参的角点坐标。下面是对该函数及其参数的详细介绍:retval, corners = cv2.findChessboardCorners(image, patternSize, flags=None)

参数:
image: 输入图像,通常是灰度图像,因为它简化了处理过程并提高了角点检测的准确性。
patternSize: 一个元组,表示棋盘格的内部角点数量。例如,对于一个 6x9 的棋盘格,这个参数应该是 (5, 8),因为棋盘格内部的角点数是 5x8。
flags: 这个参数是可选的,用于指定各种操作标志,以优化角点检测过程。以下是一些可用的标志:
cv2.CALIB_CB_ADAPTIVE_THRESH: 使用自适应阈值来寻找角点,有助于在光照不均匀的条件下提高检测的鲁棒性。
cv2.CALIB_CB_NORMALIZE_IMAGE: 在处理之前对图像进行归一化,减少光照变化的影响。
cv2.CALIB_CB_FILTER_QUADS: 使用额外的标准(如角度、间隔、消失点的一致性)来过滤和保留可能的角点。
cv2.CALIB_CB_FAST_CHECK: 执行一个快速的检查,以确定图像中是否确实存在一个棋盘格。
返回值:
retval: 布尔值,表示是否找到了足够的角点。如果找到了足够的角点,则返回 True;否则返回 False。
corners: 检测到的角点的数组。每个角点由一个二维坐标表示,这些坐标是相对于输入图像的。

在获取到棋盘格每个角点之后,可以使用cv2.cornerSubPix ()对角点进行优化cv2.cornerSubPix 是 OpenCV 库中的一个函数,用于对已检测到的角点进行亚像素级精化。在计算机视觉中,尤其是在相机标定和特征点跟踪等应用中,提高角点坐标的精度是非常重要的。
cv2.cornerSubPix(image, corners, winSize, zeroZone, criteria)

参数:
image: 输入图像,通常是灰度图像。
corners: 一个数组,包含了初始检测到的角点的坐标。这些坐标通常是由 cv2.findChessboardCorners 或其他角点检测函数提供。
winSize: 窗口大小,用于考虑角点周围的像素。这个窗口用于计算角点的精确位置。通常,这个窗口大小应该足够大,以覆盖角点周围的区域,但又不能太大,以避免引入过多的噪声。
zeroZone: 这个参数是可选的,它指定了窗口内部的一个零区域,在这个区域内不进行像素值的加权计算。这有助于在某些情况下提高算法的稳定性。如果不需要,可以设置为 (-1, -1)。
criteria: 这个参数定义了迭代过程的停止准则。它是一个包含三个元素的元组 (type, maxCount, epsilon),其中:
type 是停止条件的类型,可以是 cv2.TERM_CRITERIA_EPS(达到指定的精度 epsilon)或 cv2.TERM_CRITERIA_MAX_ITER(达到最大迭代次数 maxCount)或两者的组合。
maxCount 是最大迭代次数。
epsilon 是所需的精度。
返回值:
函数没有直接的返回值,但它会直接修改输入的 corners 数组,填充更精确的角点坐标。

在检测到图像的角点后可以对它进行绘制,可以知道图像角点找的对不对,使用cv2.drawChessboardCorners可以绘制棋盘格角点,cv2.drawChessboardCorners(image, patternSize, corners, found)

参数:
image: 输入图像,通常是灰度图像。
patternSize: 一个元组,表示棋盘格的内部角点数量。例如,对于一个 6x9 的棋盘格,这个参数应该是 (5, 8),因为棋盘格内部的角点数是 5x8。
corners: 一个数组,包含了检测到的角点的坐标。这些坐标是相对于输入图像的。
found: 一个布尔值,表示是否找到了足够的角点。如果找到了足够的角点,则 found 为 True;否则为 False。
返回值:
函数没有直接的返回值,但它会直接修改输入的 image 数组,在其中绘制角点。

python">ret, corners = cv2.findChessboardCorners(gray, CHECKERBOARD, cv2.CALIB_CB_ADAPTIVE_THRESH +
                                             cv2.CALIB_CB_FAST_CHECK + cv2.CALIB_CB_NORMALIZE_IMAGE)
    """
    使用cornerSubPix优化探测到的角点
    """
    if ret == True:
        objpoints.append(objp)
        corners2 = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
        imgpoints.append(corners2)
        # 显示角点
        img = cv2.drawChessboardCorners(img, CHECKERBOARD, corners2, ret)

效果:
在这里插入图片描述

2.4计算相机参数

在获得精确的角点之后,就可以通过cv2.calibrateCamera获取相机自身的参数了,cv2.calibrateCamera 是 OpenCV 库中的一个函数,用于根据一系列带有标定板的图像来计算相机的内参(intrinsic parameters)和畸变系数(distortion coefficients)。这个函数是相机标定的核心步骤,它可以帮助我们理解相机的成像特性,并为后续的图像处理和三维重建等任务提供准确的相机模型。retval, cameraMatrix, distCoeffs, rvecs, tvecs = cv2.calibrateCamera(objectPoints, imagePoints, imageSize, None, None)

参数:
objectPoints: 一个数组,包含了所有标定图像中棋盘格在世界坐标系中的三维坐标。这些坐标通常是通过标定板上的角点坐标计算得到的。
imagePoints: 一个数组,包含了所有标定图像中棋盘格在图像平面上的二维坐标。这些坐标通常是由 cv2.findChessboardCorners 函数提供的。
imageSize: 一个元组,表示输入图像的尺寸。这通常是 (width, height) 格式。
cameraMatrix: 一个可选的参数,用于指定相机的内参矩阵。如果未指定,OpenCV 将使用默认值。
distCoeffs: 一个可选的参数,用于指定相机的畸变系数。如果未指定,OpenCV 将使用默认值。
返回值:
retval: 布尔值,表示标定是否成功。如果成功,返回 True;否则返回 False。
cameraMatrix: 一个浮点数数组,表示相机的内参矩阵。这个矩阵包含了焦距、主点坐标等信息。
distCoeffs: 一个浮点数数组,表示相机的畸变系数。这些系数用于描述镜头畸变。
rvecs: 一个浮点数数组,包含了所有标定图像中相机相对于世界坐标系的位置和方向。
tvecs: 一个浮点数数组,包含了所有标定图像中相机相对于世界坐标系的位置。

三、整体代码实现:

python">import glob

import cv2
import numpy as np
from PIL import Image

# 8行11列棋盘角点
CHECKERBOARD = (8, 11)
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)

# 世界坐标中的3D角点,z恒为0
objpoints = []
# 像素坐标中的2D点
imgpoints = []

# 利用棋盘定义世界坐标系中的角点
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)

# 从文件夹中读取所有图片
images = glob.glob(r'F:\cccc/*.png')
print(images)
gray = None
for i in range(len(images)):
    fname = images[i]
    print(fname)
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 查找棋盘角点
    ret, corners = cv2.findChessboardCorners(gray, CHECKERBOARD, cv2.CALIB_CB_ADAPTIVE_THRESH +
                                             cv2.CALIB_CB_FAST_CHECK + cv2.CALIB_CB_NORMALIZE_IMAGE)
    """
    使用cornerSubPix优化探测到的角点
    """
    if ret == True:
        objpoints.append(objp)
        corners2 = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
        imgpoints.append(corners2)
        # 显示角点
        img = cv2.drawChessboardCorners(img, CHECKERBOARD, corners2, ret)
        # new_img = Image.fromarray(img.astype(np.uint8))
        # new_img.save('chessboard_{}.png'.format(i))
        # plt.imshow(img)
        # plt.show()

# cv2.destroyAllWindows()
# 标定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)

print("重投影误差:\n")
print(ret)
print("内参 : \n")
print(mtx)
print("畸变 : \n")
print(dist)
print("旋转向量 : \n")
print(rvecs)
print("平移向量 : \n")
print(tvecs)

http://www.niftyadmin.cn/n/5665873.html

相关文章

Python 入门教程(4)数据类型 | 4.3、数字类型

文章目录 一、数字类型1、整数(Integer)2、浮点数(Float)3、数学计算 前言: 在Python中,数字类型是其基本数据类型之一,用于表示数学中的数值。Python提供了多种数字类型,每种类型都…

【Git】常见命令(仅笔记)

文章目录 创建/初始化本地仓库添加本地仓库配置项提交文件查看仓库状态回退仓库查看日志分支删除文件暂存工作区代码远程仓库使用 .gitigore 文件让 git 不追踪一些文件标签 创建/初始化本地仓库 git init添加本地仓库配置项 git config -l #以列表形式显示配置项git config …

机器学习-监督学习:朴素贝叶斯分类器

机器学习-监督学习:朴素贝叶斯分类器 一、引言 在机器学习的广阔领域中,监督学习占据着核心地位,它通过已知的数据集(包括输入和输出)来训练模型,以期对新的、未见过的数据做出准确的预测。朴素贝叶斯分类…

Python基础(六)——PyEcharts数据可视化初级版

案例 【前言:为了巩固之前的Python基础知识(一)到(五),并为后续使用Python作为数据处理的好帮手,我们一起来看几个例子】 使用工具:Echarts Echarts 是一个由百度开源的数据可视化…

JSON.parseArray 内存溢出

实际上我的JSON如下: 如果用以下代码:JVM的内存直接飙到内存溢出,报错OutOfMemoryError: Java heap space Object oo JSON.parseArray(json, TestVo.class) 如果我换成了这样,就没事: Object oo JSON.parseObject(…

闲鱼网页版开放,爬虫的难度指数级降低。

爬虫,可以说是程序员最基础的热手项目。 之前我也一直说阿里系的签名系统搞得太复杂,风控太高,很不利于正常的自动化工具开发,这对于需要阿里应用的客户来说,也是一个很难覆盖的成本支出不是。 当然,我做项…

计算机人工智能前沿进展-大语言模型方向-2024-09-14

计算机人工智能前沿进展-大语言模型方向-2024-09-14 1. Multimodal learning using large language models to improve transient identification of nuclear power plants B Qi, J Sun, Z Sui, X Xiao, J Liang - Progress in Nuclear Energy, 2024 使用大型语言模型进行多…

PgMP和CSPM-3有什么不同?是什么关系?

CSPM-3和PgMP在项目管理领域都是具有权威性和认可度的证书,但两者并不直接等同。CSPM-3是中国国内的项目管理专业人员能力等级证书,而PgMP则是美国项目管理协会推出的项目集管理专业人士认证。下面给大家讲解一下他们的区别。 一、概念不同 什么是CSPM…