[OpenCV】相机标定之棋盘格角点检测与绘制

在OpenCV中,棋盘格角点检测与绘制是一个常见的任务,通常用于相机标定。
棋盘格自定义可参考: OpenCV: Create calibration pattern

摘自opencv官网

1. 棋盘格角点检测 findChessboardCorners()

函数原型是

//C++使用时,包含头文件
#include <opencv2/calib3d.hpp>

bool cv::findChessboardCorners	(InputArray image,
Size patternSize,
OutputArray corners,
int	flags = CALIB_CB_ADAPTIVE_THRESH+CALIB_CB_NORMALIZE_IMAGE)		
Python://opencv4.8.0
cv.findChessboardCorners(	image, patternSize[, corners[, flags]]	) ->	retval, corners

这里引用官方的文档内容–参数介绍
引用于opencv官方文档

参数成员
image 来源棋盘视图。它必须是8位灰度或彩色图像。
这里如果输入是彩色图像,最好先使用 cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 转换为灰度图像。
patternSize 棋盘格的内部角点数量,格式为 (columns, rows)。必须是棋盘格内部的角点数量,而不是棋盘格的方块数量。例如,一个 10x7 的棋盘格方块,其内部角点数量是 9x6。
注意:这里的角点是指棋盘格内部的交叉点,而不是棋盘格的方块数量。
corners 检测到的角点的输出数组。
如果找到角点,corners 将是一个包含所有角点坐标的数组,形状为 (N, 1, 2),其中 N 是角点的数量。
flags 各种操作标志,可以为零或以下值的组合:
*CALIB_CB_ADAPTIVE_THRESH 使用自适应阈值将图像转换为黑白,而不是固定的阈值水平(根据平均图像亮度计算)。
*CALIB_CB_NORMALIZE_IMAGE 在应用固定或自适应阈值之前,用均衡器归一化图像灰度系数。
*CALIB_CB_FILTER_QUADS 使用附加标准(如轮廓面积、周长、类似正方形的形状)过滤掉在轮廓检索阶段提取的错误四边形。
*CALIB_CB_FAST_CHECK 在图像上运行快速检查,寻找棋盘角,如果没有找到,则快捷调用。当没有观察到棋盘时,这可以显著地加速退化条件下的调用。
返回值
ret
布尔值,表示是否成功找到棋盘格角点。如果找到角点,返回 True;否则返回 False。
corners
检测到的角点坐标,是一个形状为 (N, 1, 2) 的 NumPy 数组,其中 N 是角点的数量。每个角点的坐标是 (x, y),表示其在图像中的像素位置。

该函数试图确定输入图像是否是棋盘图案的视图,并定位棋盘的内部角。如果找到了所有的角,并按一定的顺序(逐行,每行从左到右)放置,则该函数返回一个非零值。否则,如果函数未能找到所有的角或对它们重新排序,它将返回0。例如,一个规则的棋盘有8×8个正方形和7×7个内角,即黑色正方形相互接触的点。检测到的坐标是近似的,为了更精确地确定它们的位置,该函数调用cornerSubPix。如果返回的坐标不够精确,也可以使用带有不同参数的cornerSubPix函数。

2. 棋盘格角点绘制 drawChessboardCorners()

函数原型是

//头文件包含
#include <opencv2/calib3d.hpp>

void cv::drawChessboardCorners(InputOutputArray image,
Size patternSize,
InputArray corners,
bool patternWasFound )		
Python://opencv4.8.0
cv.drawChessboardCorners(image, patternSize, corners, patternWasFound)->image

参数介绍,引用于官方文档
引用于opencv官网

image ; 目标图像。它必须是8位彩色图像。
patternSize 棋盘行和列的内角数量(patternSize = cv::Size(points _ per _ row,points_per_column))。必须是棋盘格内部的角点数量,而不是棋盘格的方块数量。例如,一个 10x7 的棋盘格方块,其内部角点数量是 9x6。
corners: 检测到的角的数组,findChessboardCorners的输出。
patternWasFound: 这个参数表明是否找到了完整棋盘。此处应导入使用findChessboardCorners 函数时所获取到的返回值。
这个函数用于绘制单个棋盘角,如果没有找到棋盘,则显示为红色圆圈;如果找到了棋盘,则显示为用线条连接的彩色角。

3. 代码示例

以下是一个简单的步骤和代码示例,展示如何使用OpenCV检测棋盘格的角点并绘制它们。

C++版本

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    // 读取图像
    cv::Mat image = cv::imread("chessboard.png");
    if (image.empty()) {
        std::cerr << "无法加载图像!" << std::endl;
        return -1;
    }

    // 转换为灰度图像
    cv::Mat gray;
    cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);

    // 定义棋盘格的内部角点数量
    cv::Size patternSize(9, 6); // 例如,9x6 的棋盘格

    // 存储角点的容器
    std::vector<cv::Point2f> corners;

    // 查找棋盘格角点
    bool found = cv::findChessboardCorners(gray, patternSize, corners);

    if (found) {
        std::cout << "找到 " << corners.size() << " 个角点" << std::endl;

        // 优化角点位置
        cv::TermCriteria criteria(cv::TermCriteria::EPS + cv::TermCriteria::MAX_ITER, 30, 0.001);
        cv::cornerSubPix(gray, corners, cv::Size(11, 11), cv::Size(-1, -1), criteria);

        // 绘制角点
        cv::drawChessboardCorners(image, patternSize, cv::Mat(corners), found);

        // 显示结果
        cv::imshow("Chessboard Corners", image);
        cv::waitKey(0);
    } else {
        std::cout << "未找到棋盘格角点" << std::endl;
    }

    cv::destroyAllWindows();
    return 0;
}

代码说明
1. 图像读取与灰度转换
使用 cv::imread 读取图像,并检查是否成功加载。
使用 cv::cvtColor 将彩色图像转换为灰度图像。
2. 定义棋盘格尺寸
使用 cv::Size 定义棋盘格的内部角点数量(例如 9x6)。
3. 查找角点
使用 cv::findChessboardCorners 查找棋盘格角点。如果找到角点,返回 true,并将角点坐标存储在 corners 中。
4. 优化角点位置
使用 cv::cornerSubPix 对角点位置进行亚像素优化,以提高精度。
5. 绘制角点
使用 cv::drawChessboardCorners 在图像上绘制检测到的角点。
6. 显示结果
使用 cv::imshow 显示带有角点的图像,并等待用户按键退出。

python版本

步骤

  1. 导入必要的库:导入OpenCV和NumPy库。
  2. 读取图像:读取包含棋盘格的图像。
  3. 查找角点:使用cv2.findChessboardCorners函数查找棋盘格的角点。
  4. 优化角点位置:使用cv2.cornerSubPix函数优化角点位置。
  5. 绘制角点:使用cv2.drawChessboardCorners函数绘制检测到的角点。
  6. 显示结果:显示带有角点的图像。

代码示例

import cv2
import numpy as np

# 读取图像
image = cv2.imread('chessboard.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 定义棋盘格的尺寸(内部角点的数量)
pattern_size = (9, 6)  # 例如,9x6的棋盘格

# 查找棋盘格角点
ret, corners = cv2.findChessboardCorners(gray, pattern_size, None)

if ret:
 	print(f"找到 {len(corners)} 个角点")
    # 优化角点位置
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
    corners = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)

    # 绘制角点
    cv2.drawChessboardCorners(image, pattern_size, corners, ret)

    # 显示结果
    cv2.imshow('Chessboard Corners', image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
else:
    print("未找到棋盘格角点")

代码说明

  1. cv2.findChessboardCorners:这个函数用于查找棋盘格的角点。它需要输入灰度图像、棋盘格的尺寸(内部角点的数量),以及一些可选参数。如果找到角点,返回True和角点的坐标。
  2. cv2.cornerSubPix:这个函数用于优化角点的位置,使其更加精确。
  3. cv2.drawChessboardCorners:这个函数用于在图像上绘制检测到的角点。

注意事项

  • 棋盘格的尺寸(内部角点的数量)需要根据实际的棋盘格进行调整。
  • 如果图像中没有找到棋盘格角点,ret将为False,此时需要检查图像和棋盘格尺寸是否正确。

运行结果
运行代码后,你将看到图像上绘制了检测到的棋盘格角点。这些角点可以用于进一步的相机标定或其他计算机视觉任务。

<think>好的,我现在需要帮助用户了解张正友棋盘格标定法的相关信息或实现方法。用户特别提到了实现原理和代码示例。首先,我得回忆一下张正友标定法的基本概念和步骤。 根据用户提供的引用,张正友标定法是基于棋盘格标定板的,通过多个度的棋盘格图像来估计相机的内外参数。首先,我需要解释标定法的核心步骤,比如单应性矩阵计算、参数优化等。用户可能对原理和数学部分感兴趣,所以需要简明扼要地解释,同时确保使用正确的LaTeX格式。 接下来是代码示例部分。用户希望看到具体的实现,可能需要参考引用中的OpenCV实现。需要检查引用中的信息,比如引用[3]提到OpenCV的单目相机标定,应该使用OpenCV的函数如findChessboardCorners、calibrateCamera等。要确保代码示例正确,并且符合用户提供的引用内容。 另外,用户的问题还涉及到棋盘格的实现方法,所以需要提到棋盘格的规格,比如通常使用的黑白相间方格,检测的重要性。这部分需要结合引用[1]和[2]中的内容,说明棋盘格的作用和标定过程。 在回答结构方面,需要分步骤解释原理,然后给出代码示例,并最后生成相关问题。确保每个部分清晰,使用标题和分段。同时,注意引用标识的正确添加,比如在提到标定目的或步骤时引用对应的文献。 还要检查是否有遗漏的关键,比如畸变系数的计算、重投影误差等。这些在相机标定中都是重要的指标,用户可能想知道标定后的应用,比如图像矫正,这也需要提到。 最后,生成的相关问题需要围绕用户可能感兴趣的扩展,比如其他方法的比较、实际应用中的注意事项、标定精度影响因素等。确保问题有针对性,能够引导用户进一步探索。 现在需要组织这些内容,确保符合用户的要求:使用中文,正确的LaTeX格式,代码块,引用标识,结构清晰。可能还需要验证代码示例是否正确,比如OpenCV的函数调用和参数是否正确,避免错误信息。</think>### 张正友棋盘格标定法详解 #### 一、实现原理 1. **核心思想** 张正友标定法通过拍摄多张棋盘格图像,利用棋盘格的几何关系求解相机的内参矩阵$K$、外参矩阵$(R,t)$和畸变系数$D$[^1]。其关键步骤如下: - **单应性矩阵计算**:建立棋盘格平面(3D)图像平面(2D)的映射关系,单应性矩阵$H$满足: $$ s \begin{bmatrix}u \\ v \\ 1\end{bmatrix} = K \begin{bmatrix}R & t\end{bmatrix} \begin{bmatrix}X_w \\ Y_w \\ 0 \\ 1\end{bmatrix} = H \begin{bmatrix}X_w \\ Y_w \\ 1\end{bmatrix} $$ - **参数初始化**:通过$H$矩阵约束推导内参矩阵$K$的初始值[^2]。 - **非线性优化**:利用最大似然估计优化参数,最小化重投影误差: $$ \sum_{i=1}^{n} \sum_{j=1}^{m} \|p_{ij} - \hat{p}(K, D, R_i, t_i, P_j)\|^2 $$ 2. **棋盘格作用** 棋盘格坐标已知且规则排列(如$9 \times 6$黑白方格),便于自动检测特征[^3]。每个的世界坐标可设为$(k \cdot w, l \cdot h, 0)$,其中$w,h$为方格尺寸。 --- #### 二、代码示例(基于OpenCV) ```python import cv2 import numpy as np # 定义棋盘格参数 pattern_size = (9, 6) # 内数量 square_size = 25.0 # 棋盘格方格边长(毫米) # 准备世界坐标系中的坐标 obj_points = np.zeros((pattern_size[0]*pattern_size[1], 3), np.float32) obj_points[:, :2] = np.mgrid[0:pattern_size[0], 0:pattern_size[1]].T.reshape(-1, 2) * square_size # 存储标定数据 obj_points_list = [] # 3D img_points_list = [] # 2D # 遍历所有标定图像 images = glob.glob('calibration_images/*.jpg') for fname in images: img = cv2.imread(fname) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 检测 ret, corners = cv2.findChessboardCorners(gray, pattern_size, None) if ret: # 亚像素级精化 criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) cv2.cornerSubPix(gray, corners, (11,11), (-1,-1), criteria) obj_points_list.append(obj_points) img_points_list.append(corners) # 执行标定 ret, K, D, rvecs, tvecs = cv2.calibrateCamera( obj_points_list, img_points_list, gray.shape[::-1], None, None ) print("内参矩阵:\n", K) print("畸变系数:\n", D) ``` --- #### 三、关键步骤说明 1. **检测** 使用`findChessboardCorners`定位棋盘格,通过亚像素优化提升精度[^3]。 2. **参数标定** `calibrateCamera`函数通过最小化重投影误差,返回内参矩阵$K$、畸变系数$D$和每张图的外参(旋转向量rvecs、平移向量tvecs)。 3. **结果验证** 可通过计算重投影误差(通常要求<0.5像素)或对测试图像进行畸变矫正来验证标定质量。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值