下面是一个完整的 使用 OpenCV 进行相机内参标定(Camera Calibration) 的示例,包括 C++ 和 Python 两个版本,基于棋盘格图案标定。
一、目标:相机标定
通过拍摄多张带有棋盘格图案的图像,估计相机的内参:
- 相机矩阵(内参)
K
- 畸变系数
distCoeffs
- 可选外参(R, T)
- 标定精度指标(如重投影误差)
二、棋盘格参数设置(根据自己的棋盘格设置):
- 棋盘格角点数:
9 x 6
(内角点,9列×6行); - 每个格子实际尺寸为:
25.0 mm
(自定义); - 图像列表已存为多张 JPG /或者其他格式图片。
三、Python 示例(
python
import cv2
import numpy as np
import glob
# 设置棋盘格参数
chessboard_size = (9, 6)
square_size = 25.0 # mm
# 生成世界坐标系下的 3D 点
objp = np.zeros((np.prod(chessboard_size), 3), np.float32)
objp[:, :2] = np.indices(chessboard_size).T.reshape(-1, 2)
objp *= square_size
# 储存所有图像的角点
objpoints = [] # 3D points
imgpoints = [] # 2D points
# 读取图片
images = glob.glob("calib_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)
corners2 = cv2.cornerSubPix(gray, corners, (11,11), (-1,-1),
criteria=(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001))
imgpoints.append(corners2)
# 可视化角点
cv2.drawChessboardCorners(img, chessboard_size, corners2, ret)
cv2.imshow('img', img)
cv2.waitKey(100)
cv2.destroyAllWindows()
# 标定相机
ret, K, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
print("相机内参矩阵 K:\n", K)
print("畸变系数 dist:\n", dist)
print("重投影误差:", ret)
四、C++ 示例
cpp
#include <opencv2/opencv.hpp>
#include <vector>
#include <iostream>
#include <filesystem>
using namespace cv;
using namespace std;
int main() {
Size boardSize(9, 6);
float squareSize = 25.0f;
vector<vector<Point3f>> objectPoints;
vector<vector<Point2f>> imagePoints;
vector<Point3f> objp;
for (int i = 0; i < boardSize.height; ++i)
for (int j = 0; j < boardSize.width; ++j)
objp.emplace_back(j * squareSize, i * squareSize, 0);
vector<String> imageFiles;
glob("calib_images/*.jpg", imageFiles);
for (const auto& fname : imageFiles) {
Mat img = imread(fname);
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::EPS + TermCriteria::MAX_ITER, 30, 0.001));
imagePoints.push_back(corners);
objectPoints.push_back(objp);
drawChessboardCorners(img, boardSize, corners, found);
imshow("Corners", img);
waitKey(100);
}
}
destroyAllWindows();
Mat K, distCoeffs;
vector<Mat> rvecs, tvecs;
calibrateCamera(objectPoints, imagePoints, Size(640, 480),
K, distCoeffs, rvecs, tvecs);
cout << "Camera Matrix K:\n" << K << endl;
cout << "Distortion Coefficients:\n" << distCoeffs << endl;
}
五、输出参数解释
参数 | 含义 |
---|---|
K / cameraMatrix |
相机内参矩阵 (fx, fy, cx, cy) |
distCoeffs |
畸变参数 [k1, k2, p1, p2, k3] |
rvecs |
每张图像的旋转向量 |
tvecs |
每张图像的平移向量 |
ret |
平均重投影误差(数值越小越好) |
六、应用建议
- 拍摄图像时应尽量覆盖各个角度、不同距离;
- 建议图像 >10 张以上;
- 标定结果可用于
cv::undistort
、cv::initUndistortRectifyMap
做图像矫正; - 也可以用 fisheye 模型标定 (
cv::fisheye::calibrate
),适用于广角相机。