本文目录导读:

我来详细说明如何使用OpenCV进行相机标定,包含完整案例:
准备工作
安装依赖
pip install opencv-python numpy
准备标定板
- 打印棋盘格标定板(如9×6的内角点)
- 或使用显示器显示棋盘格
- 从不同角度拍摄15-20张照片
完整相机标定代码
import cv2
import numpy as np
import glob
import os
class CameraCalibration:
def __init__(self, chessboard_size=(9, 6), square_size=25):
"""
初始化相机标定器
:param chessboard_size: 棋盘格内角点数量 (列数, 行数)
:param square_size: 棋盘格方格大小(毫米)
"""
self.chessboard_size = chessboard_size
self.square_size = square_size
# 准备对象点(3D坐标)
self.object_points = [] # 世界坐标系中的3D点
self.image_points = [] # 图像坐标系中的2D点
# 棋盘格角点的世界坐标
self.objp = np.zeros((chessboard_size[0] * chessboard_size[1], 3), np.float32)
self.objp[:, :2] = np.mgrid[0:chessboard_size[0], 0:chessboard_size[1]].T.reshape(-1, 2)
self.objp *= square_size
def find_corners(self, image_paths):
"""
查找棋盘格角点
:param image_paths: 图像路径列表
:return: 成功检测到角点的图像数量
"""
successful_images = 0
for image_path in image_paths:
# 读取图像
img = cv2.imread(image_path)
if img is None:
print(f"无法读取图像: {image_path}")
continue
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 查找棋盘格角点
ret, corners = cv2.findChessboardCorners(gray,
self.chessboard_size,
None)
if ret:
# 亚像素精确化角点位置
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
corners_refined = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
# 保存点集
self.object_points.append(self.objp)
self.image_points.append(corners_refined)
# 可视化角点
cv2.drawChessboardCorners(img, self.chessboard_size,
corners_refined, ret)
cv2.imshow('Chessboard Corners', img)
cv2.waitKey(100)
successful_images += 1
print(f"成功检测: {image_path}")
else:
print(f"未能检测到棋盘格: {image_path}")
cv2.destroyAllWindows()
return successful_images
def calibrate(self, image_size):
"""
执行相机标定
:param image_size: 图像尺寸 (width, height)
:return: 标定结果
"""
if len(self.object_points) < 3:
print("至少需要3张有效图像进行标定")
return None
# 执行标定
ret, camera_matrix, dist_coeffs, rvecs, tvecs = cv2.calibrateCamera(
self.object_points,
self.image_points,
image_size,
None,
None
)
return ret, camera_matrix, dist_coeffs, rvecs, tvecs
def evaluate_calibration(self, image_paths):
"""
评估标定结果(重投影误差)
"""
total_error = 0
for i, image_path in enumerate(image_paths):
img = cv2.imread(image_path)
if img is None:
continue
# 计算重投影错误
imgpoints2, _ = cv2.projectPoints(
self.object_points[i],
rvecs[i],
tvecs[i],
camera_matrix,
dist_coeffs
)
error = cv2.norm(self.image_points[i], imgpoints2, cv2.NORM_L2) / len(imgpoints2)
total_error += error
return total_error / len(self.object_points)
def main():
"""
主函数:演示相机标定流程
"""
# 设置参数
CHESSBOARD_SIZE = (9, 6) # 棋盘格内角点数
SQUARE_SIZE = 25 # 方格大小(毫米)
# 创建标定器
calibrator = CameraCalibration(CHESSBOARD_SIZE, SQUARE_SIZE)
# 获取标定图像路径
input_dir = "calibration_images" # 存放标定图像的文件夹
print("=== 相机标定程序 ===")
print(f"棋盘格配置: {CHESSBOARD_SIZE[0]}x{CHESSBOARD_SIZE[1]} 内角点")
print(f"方格大小: {SQUARE_SIZE}mm")
print()
# 检查目录是否存在
if not os.path.exists(input_dir):
print(f"错误: 找不到目录 {input_dir}")
print("请在程序同目录下创建 'calibration_images' 文件夹")
print("并将棋盘格照片放入该文件夹")
return
# 获取所有图像
image_paths = glob.glob(os.path.join(input_dir, "*.jpg")) + \
glob.glob(os.path.join(input_dir, "*.png"))
if len(image_paths) == 0:
print("未找到图像文件,请将棋盘格照片放入文件夹")
return
print(f"找到 {len(image_paths)} 张图像")
print("开始检测棋盘格角点...")
# 查找角点
successful = calibrator.find_corners(image_paths)
print(f"\n成功检测: {successful}/{len(image_paths)} 张图像")
if successful < 3:
print("有效图像不足,请拍摄更多照片")
return
# 获取图像尺寸
sample_img = cv2.imread(image_paths[0])
image_size = (sample_img.shape[1], sample_img.shape[0])
# 执行标定
print("\n正在执行相机标定...")
results = calibrator.calibrate(image_size)
if results is None:
return
ret, camera_matrix, dist_coeffs, rvecs, tvecs = results
# 输出标定结果
print("\n=== 标定结果 ===")
print(f"重投影误差: {ret:.6f}")
print(f"\n相机内参矩阵 (K):")
print(f"{camera_matrix}")
print(f"\n畸变系数 (k1, k2, p1, p2, k3):")
print(f"{dist_coeffs.flatten()}")
# 评估标定质量
mean_error = calibrator.evaluate_calibration(image_paths[:successful])
print(f"\n平均重投影误差: {mean_error:.6f} 像素")
# 保存标定结果
save_calibration_results(camera_matrix, dist_coeffs)
# 演示畸变校正
demonstrate_undistortion(image_paths[0], camera_matrix, dist_coeffs)
print("\n标定完成!")
def save_calibration_results(camera_matrix, dist_coeffs):
"""
保存标定结果到文件
"""
np.savez("calibration_results.npz",
camera_matrix=camera_matrix,
dist_coeffs=dist_coeffs)
print("\n标定结果已保存到 calibration_results.npz")
def demonstrate_undistortion(image_path, camera_matrix, dist_coeffs):
"""
演示畸变校正效果
"""
# 读取原始图像
img = cv2.imread(image_path)
if img is None:
return
h, w = img.shape[:2]
# 计算新的相机矩阵(优化视野)
new_camera_matrix, roi = cv2.getOptimalNewCameraMatrix(
camera_matrix, dist_coeffs, (w, h), 1, (w, h))
# 畸变校正
undistorted_img = cv2.undistort(img, camera_matrix, dist_coeffs,
None, new_camera_matrix)
# 裁剪图像(去除黑色边缘)
x, y, w, h = roi
undistorted_img = undistorted_img[y:y+h, x:x+w]
# 显示结果
cv2.imshow('Original Image', img)
cv2.imshow('Undistorted Image', undistorted_img)
# 保存结果
cv2.imwrite('original.jpg', img)
cv2.imwrite('undistorted.jpg', undistorted_img)
print("原图和校正后图像已保存")
print("按任意键关闭窗口...")
cv2.waitKey(0)
cv2.destroyAllWindows()
def load_and_use_calibration():
"""
加载标定结果并应用于新图像
"""
# 加载标定结果
with np.load('calibration_results.npz') as data:
camera_matrix = data['camera_matrix']
dist_coeffs = data['dist_coeffs']
# 创建标定对象
calibrator = CameraCalibration()
# 测试图像校正
test_image_path = "test_image.jpg"
if os.path.exists(test_image_path):
img = cv2.imread(test_image_path)
if img is not None:
h, w = img.shape[:2]
new_camera_matrix, _ = cv2.getOptimalNewCameraMatrix(
camera_matrix, dist_coeffs, (w, h), 1, (w, h))
# 畸变校正
dst = cv2.undistort(img, camera_matrix, dist_coeffs, None, new_camera_matrix)
cv2.imshow('Test Image', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
使用方法
步骤1:准备标定图像
# 创建目录存放标定图像 mkdir calibration_images # 将棋盘格照片(从不同角度拍摄15-20张)放入该目录
步骤2:运行标定程序
python camera_calibration.py
步骤3:使用标定结果
# 加载保存的标定结果
import numpy as np
import cv2
# 加载标定数据
with np.load('calibration_results.npz') as data:
camera_matrix = data['camera_matrix']
dist_coeffs = data['dist_coeffs']
# 校正新图像
def undistort_image(image, camera_matrix, dist_coeffs):
h, w = image.shape[:2]
new_camera_matrix, roi = cv2.getOptimalNewCameraMatrix(
camera_matrix, dist_coeffs, (w, h), 1, (w, h))
dst = cv2.undistort(image, camera_matrix, dist_coeffs, None, new_camera_matrix)
return dst
# 使用示例
img = cv2.imread('new_image.jpg')
undistorted = undistort_image(img, camera_matrix, dist_coeffs)
关键参数说明
棋盘格配置
CHESSBOARD_SIZE = (9, 6) # 内角点数量(不是方格数量) SQUARE_SIZE = 25 # 方格实际尺寸(单位:mm)
标定质量评估指标
- 重投影误差:< 0.5 像素表示标定质量良好
- 焦距参数:fx, fy 应接近相机规格
- 主点坐标:cx, cy 应在图像中心附近
注意事项
-
图像拍摄要求:
- 尽量从不同角度拍摄
- 棋盘格要占据图像的30-50%
- 保持图像清晰,避免模糊
- 保证光照均匀
-
棋盘格要求:
- 使用平整的棋盘格
- 避免棋盘格有污渍或损坏
- 确保棋盘格在图像中完整可见
-
常见问题:
- 角点检测失败:调整光照或使用亚像素处理
- 标定结果差:增加图像数量(至少15张)
- 畸变校正不理想:检查标定参数是否保存正确
这个案例提供了完整的相机标定解决方案,可以直接使用或根据具体需求修改。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播