基于opencv的相机标定代码(python、c++)

python和c++的代码对比验证,结果相同;

#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
@author:cong
@time: 2025/01/07 13:45:46
@theme:相机标定的目标是找到相机坐标系(由相机的位置和姿态决定)与世界坐标系(标定板的坐标系)之间的变换关系。改代码只输出相机内参,若需要外参,用cv2.solvePnP;
"""
import cv2
import numpy as np
import glob

# 棋盘格参数 (内角点数量)
CHESSBOARD_SIZE = (10, 7)
SQUARE_SIZE = 20  # 每个格子的真实边长 (单位: 米)

# 为棋盘格的角点在三维空间中构建真实世界坐标系,objp 作为世界坐标系中的参考点,用于计算相机内参和畸变系数
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)
objp *= SQUARE_SIZE  # 乘以每格边长,得到真实世界坐标

objpoints = []  # 3D点
imgpoints = []  # 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, CHESSBOARD_SIZE, None)
    if ret:
        objpoints.append(objp)
        # cv2.cornerSubPix 是 OpenCV 中的一个函数,用于提高角点检测的精度。它通过亚像素级别的优化来精确定位角点位置。
        # 通常,在检测到角点后,使用该函数可以进一步优化角点的位置
        corners2 = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1),
                                    (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001))
        imgpoints.append(corners2)

        # 显示检测结果
        cv2.drawChessboardCorners(img, CHESSBOARD_SIZE, corners2, ret)
        cv2.imshow('Corners', img)
        cv2.waitKey(500)

cv2.destroyAllWindows()

# 标定相机,会输出和图片数量一样个数的R和T
(rms, mtx, dist, rvecs, tvecs) = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)

# 打印标定结果
print("相机内参矩阵:\n", mtx)
print("畸变系数:\n", dist)
print("RMS error:", rms)
# print("旋转向量 (Rotation Vectors):\n", rvecs)
# print("平移向量 (Translation Vectors):\n", tvecs)


# RMS (cv2.calibrateCamera 的返回值): 是所有角点的均方根误差(平方和的均值再开平方)。
# total_error 的计算: 是所有图片的平均重投影误差,计算方式不同,但结果通常是相近的。
# 平均重投影误差通常应在 0.1 ~ 1 像素之间,越小越好。
# === 计算标定误差 (RMS) ===
total_error = 0
for i in range(len(objpoints)):
    imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
    error = cv2.norm(imgpoints[i], imgpoints2, cv2.NORM_L2) / len(imgpoints2)
    total_error += error

print("平均重投影误差:", total_error / len(objpoints))
# 保存标定参数
np.savez("calibration_data.npz", mtx=mtx, dist=dist, rvecs=rvecs, tvecs=tvecs)

c++代码如下:

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


using namespace cv;
using namespace std;

int main() {
    // 棋盘格尺寸:内角点数 (10x7)
    Size boardSize(10, 7);
    float squareSize = 20.f;  // 每个格子的大小,单位可以是毫米或厘米,取决于实际标定板的尺寸

    // 生成棋盘格的 3D 世界坐标
    vector<Point3f> objp;
    for (int i = 0; i < boardSize.height; i++) {
        for (int j = 0; j < boardSize.width; j++) {
            objp.push_back(Point3f(j * squareSize, i * squareSize, 0));  // 在Z轴为零的平面上
        }
    }

    // 用于存储每张图像对应的世界坐标和图像坐标
    vector<vector<Point3f>> objpoints;
    vector<vector<Point2f>> imgpoints;

    // 读取指定目录下的所有图像
    vector<String> images;
    glob("./calibration_images/*.jpg", images);  // 根据需要修改文件路径
    if (images.empty()) {
        cout << "没有找到图像文件!" << endl;
        return -1;
    }

    // 遍历所有图像文件
    for (size_t i = 0; i < images.size(); i++) {
        Mat img = imread(images[i]);
        if (img.empty()) {
            continue;
        }
        Mat gray;
        cvtColor(img, gray, COLOR_BGR2GRAY);  // 转为灰度图

        vector<Point2f> corners;
        bool found = findChessboardCorners(gray, boardSize, corners);  // 检测角点

        if (found) {
            // 进一步优化角点位置
            cornerSubPix(gray, corners, Size(11, 11), Size(-1, -1),
                TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 30, 0.001));

            objpoints.push_back(objp);  // 添加3D点
            imgpoints.push_back(corners);  // 添加2D点

            // 显示检测结果
            drawChessboardCorners(img, boardSize, corners, found);
            imshow("Chessboard", img);
            waitKey(500);  // 等待0.5秒显示每张图片
        }
    }

    destroyAllWindows();  // 关闭所有窗口

    // 进行相机标定
    Mat cameraMatrix = Mat::eye(3, 3, CV_64F);  // 相机内参矩阵 (3x3单位矩阵)
    Mat distCoeffs = Mat::zeros(1, 5, CV_64F);  // 畸变系数 (默认无畸变)
    vector<Mat> rvecs, tvecs;  // 旋转向量和平移向量

    double rms = calibrateCamera(objpoints, imgpoints, cv::Size(640,480), cameraMatrix, distCoeffs, rvecs, tvecs);
    cout << "相机标定完成!" << endl;
    cout << "RMS误差: " << rms << endl;
    cout << "相机矩阵: " << cameraMatrix << endl;
    cout << "畸变系数: " << distCoeffs << endl;

    // 保存标定结果到文件
    FileStorage fs("calibration_data.xml", FileStorage::WRITE);
    fs << "cameraMatrix" << cameraMatrix;
    fs << "distCoeffs" << distCoeffs;
    fs.release();

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值