185 lines
5.8 KiB
Python
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()
|