MOVE_AI/calibration/test/camera_calibration.py

185 lines
5.8 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
相机校准应用程序
使用检测到的棋盘格参数进行图像矫正和去畸变
"""
import cv2
import numpy as np
import json
import os
class CameraCalibration:
def __init__(self, calibration_file='chessboard_detection_output/calibration_result.json'):
"""
加载校准参数
Args:
calibration_file: 校准结果JSON文件路径
"""
self.calibration_file = calibration_file
self.camera_matrix = None
self.dist_coeffs = None
self.load_calibration()
def load_calibration(self):
"""从JSON文件加载校准参数"""
if not os.path.exists(self.calibration_file):
raise FileNotFoundError(f"校准文件不存在: {self.calibration_file}")
with open(self.calibration_file, 'r', encoding='utf-8') as f:
data = json.load(f)
self.camera_matrix = np.array(data['camera_matrix'])
self.dist_coeffs = np.array(data['distortion_coefficients'])
print("✓ 校准参数加载成功")
print(f" 重投影误差: {data['reprojection_error']:.4f} 像素")
print(f" 使用图像数: {data['num_images']}")
def undistort_image(self, image):
"""
对图像进行去畸变处理
Args:
image: 输入图像
Returns:
undistorted: 去畸变后的图像
"""
h, w = image.shape[:2]
new_camera_matrix, roi = cv2.getOptimalNewCameraMatrix(
self.camera_matrix, self.dist_coeffs, (w, h), 1, (w, h)
)
# 去畸变
undistorted = cv2.undistort(image, self.camera_matrix, self.dist_coeffs, None, new_camera_matrix)
# 裁剪图像
x, y, w, h = roi
undistorted = undistorted[y:y+h, x:x+w]
return undistorted
def undistort_video(self, input_video, output_video='undistorted_video.avi'):
"""
对视频进行去畸变处理
Args:
input_video: 输入视频路径
output_video: 输出视频路径
"""
cap = cv2.VideoCapture(input_video)
if not cap.isOpened():
print(f"无法打开视频: {input_video}")
return
# 获取视频参数
fps = cap.get(cv2.CAP_PROP_FPS)
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
# 读取第一帧获取尺寸
ret, frame = cap.read()
if not ret:
print("无法读取视频帧")
return
h, w = frame.shape[:2]
new_camera_matrix, roi = cv2.getOptimalNewCameraMatrix(
self.camera_matrix, self.dist_coeffs, (w, h), 1, (w, h)
)
x, y, w_roi, h_roi = roi
# 创建视频写入器
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter(output_video, fourcc, fps, (w_roi, h_roi))
print(f"开始处理视频 (共 {total_frames} 帧)...")
# 重置到开头
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
frame_count = 0
while True:
ret, frame = cap.read()
if not ret:
break
frame_count += 1
# 去畸变
undistorted = cv2.undistort(frame, self.camera_matrix, self.dist_coeffs, None, new_camera_matrix)
undistorted = undistorted[y:y+h_roi, x:x+w_roi]
out.write(undistorted)
if frame_count % 50 == 0:
print(f" 处理进度: {frame_count}/{total_frames} ({100*frame_count/total_frames:.1f}%)")
cap.release()
out.release()
print(f"\n✓ 视频处理完成,已保存到: {output_video}")
def compare_images(self, image_path, output_path='comparison.jpg'):
"""
生成原始图像和去畸变图像的对比图
Args:
image_path: 输入图像路径
output_path: 输出对比图路径
"""
image = cv2.imread(image_path)
if image is None:
print(f"无法读取图像: {image_path}")
return
undistorted = self.undistort_image(image)
# 调整尺寸以便并排显示
h1, w1 = image.shape[:2]
h2, w2 = undistorted.shape[:2]
h = min(h1, h2)
image_resized = cv2.resize(image, (int(w1 * h / h1), h))
undistorted_resized = cv2.resize(undistorted, (int(w2 * h / h2), h))
# 并排拼接
comparison = np.hstack([image_resized, undistorted_resized])
# 添加文字标注
cv2.putText(comparison, 'Original', (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0, 0, 255), 3)
cv2.putText(comparison, 'Undistorted', (w1 + 50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0, 255, 0), 3)
cv2.imwrite(output_path, comparison)
print(f"✓ 对比图已保存到: {output_path}")
def main():
"""主函数 - 演示如何使用校准参数"""
print("=== 相机校准应用程序 ===\n")
# 加载校准参数
calib = CameraCalibration()
# 示例1: 对检测结果图像进行去畸变
output_dir = 'chessboard_detection_output'
detected_images = [f for f in os.listdir(output_dir) if f.startswith('detected_') and f.endswith('.jpg')]
if detected_images:
print(f"\n找到 {len(detected_images)} 张检测图像")
sample_image = os.path.join(output_dir, detected_images[0])
print(f"生成对比图: {sample_image}")
calib.compare_images(sample_image, os.path.join(output_dir, 'comparison.jpg'))
# 示例2: 对原始视频进行去畸变
print("\n是否要对原始视频进行去畸变处理?")
print("注意: 这将处理整个视频,可能需要一些时间")
print("如需处理,请取消注释下面的代码行:")
print("# calib.undistort_video('Video_20260303114232727.avi', 'undistorted_video.avi')")
if __name__ == '__main__':
main()