2025-12-19 17:08:28 +08:00
|
|
|
|
# 相机参考工具
|
|
|
|
|
|
# @路怀帅 2025.12.19 10:32am
|
|
|
|
|
|
# PS : 新增 加载相机畸变KD 视频对比显示功能
|
|
|
|
|
|
|
|
|
|
|
|
import cv2
|
|
|
|
|
|
import threading
|
|
|
|
|
|
import sys
|
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
import os
|
|
|
|
|
|
import argparse
|
|
|
|
|
|
import numpy as np
|
|
|
|
|
|
|
|
|
|
|
|
# 全局变量
|
|
|
|
|
|
frame = None
|
|
|
|
|
|
running = True
|
|
|
|
|
|
which_camera = 0
|
|
|
|
|
|
|
|
|
|
|
|
# Front 参数
|
|
|
|
|
|
K = np.array([[ 5.3382445956203196e+02, 0., 9.7253025945442369e+02],
|
|
|
|
|
|
[0., 5.3393792084343488e+02, 5.6249605531924215e+02],
|
|
|
|
|
|
[ 0., 0., 1. ]])
|
|
|
|
|
|
D = np.array([ -1.5749135021037808e-02, 2.9390620422222835e-03,
|
|
|
|
|
|
-4.3176357910129585e-03, 1.3296605027646462e-03 ])
|
|
|
|
|
|
|
|
|
|
|
|
# 加载鱼眼相机参数
|
|
|
|
|
|
|
|
|
|
|
|
W, H = 1920, 1080
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def video_thread():
|
|
|
|
|
|
global frame, running
|
2025-12-23 09:18:32 +08:00
|
|
|
|
cap = cv2.VideoCapture(which_camera, cv2.CAP_V4L2)
|
2025-12-19 17:08:28 +08:00
|
|
|
|
cap.set(cv2.CAP_PROP_FOURCC,cv2.VideoWriter_fourcc(*"YUYV"))
|
|
|
|
|
|
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
|
|
|
|
|
|
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
|
|
|
|
|
|
# cap.set(cv2.CAP_PROP_FPS, 30)
|
|
|
|
|
|
|
|
|
|
|
|
if not cap.isOpened():
|
|
|
|
|
|
print("[ERROR] Cannot open camera", file=sys.stderr)
|
|
|
|
|
|
running = False
|
|
|
|
|
|
return
|
|
|
|
|
|
# 鱼眼相机去畸变
|
|
|
|
|
|
map1, map2 = cv2.fisheye.initUndistortRectifyMap(K, D, np.eye(3), K, (W, H), cv2.CV_16SC2)
|
|
|
|
|
|
|
|
|
|
|
|
while running:
|
|
|
|
|
|
ret, f = cap.read()
|
|
|
|
|
|
if not ret:
|
|
|
|
|
|
break
|
|
|
|
|
|
frame = f.copy()
|
|
|
|
|
|
|
|
|
|
|
|
# 图像去畸变
|
|
|
|
|
|
undistorted = cv2.remap(f, map1, map2, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT)
|
|
|
|
|
|
# 拼接原视频和抗畸变后的视频 (左右显示)
|
|
|
|
|
|
comparison = np.hstack((f, undistorted))
|
|
|
|
|
|
|
|
|
|
|
|
scale = min(1920 / comparison.shape[1], 1080 / comparison.shape[0])
|
|
|
|
|
|
if scale < 1:
|
|
|
|
|
|
comparison = cv2.resize(comparison, (int(comparison.shape[1] * scale), int(comparison.shape[0] * scale)))
|
|
|
|
|
|
comparison = comparison.astype(np.uint8)
|
|
|
|
|
|
|
|
|
|
|
|
# 设置视频流全屏显示
|
|
|
|
|
|
text_info = f"Camera: {args.i.upper()} | Press 'q' to quit, 's' to screenshot"
|
|
|
|
|
|
cv2.putText(comparison, text_info, (10, 30),
|
|
|
|
|
|
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2, cv2.LINE_AA)
|
|
|
|
|
|
|
|
|
|
|
|
cv2.namedWindow('Video old vs new', cv2.WND_PROP_FULLSCREEN)
|
|
|
|
|
|
cv2.setWindowProperty('Video old vs new', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
|
|
|
|
|
|
cv2.imshow('Video old vs new', comparison)
|
|
|
|
|
|
|
|
|
|
|
|
if cv2.waitKey(1) & 0xFF == ord('q'):
|
|
|
|
|
|
running = False
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
|
|
cap.release()
|
|
|
|
|
|
cv2.destroyAllWindows()
|
|
|
|
|
|
|
|
|
|
|
|
def input_thread():
|
|
|
|
|
|
global running
|
|
|
|
|
|
print("Commands: 's' = screenshot, 'q' = quit")
|
|
|
|
|
|
while running:
|
|
|
|
|
|
try:
|
|
|
|
|
|
cmd = input().strip().lower()
|
|
|
|
|
|
if cmd == 's':
|
|
|
|
|
|
if frame is not None:
|
|
|
|
|
|
filename = f"./images/{args.i.lower()}.png"
|
|
|
|
|
|
cv2.imwrite(filename, frame)
|
|
|
|
|
|
print(f"[SSH] Saved: {os.path.abspath(filename)}")
|
|
|
|
|
|
else:
|
|
|
|
|
|
print("[SSH] No frame available yet.")
|
|
|
|
|
|
elif cmd == 'q':
|
|
|
|
|
|
running = False
|
|
|
|
|
|
break
|
|
|
|
|
|
else:
|
|
|
|
|
|
print("[SSH] Unknown command. Use 's' or 'q'.")
|
|
|
|
|
|
except EOFError:
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
|
|
|
|
|
|
|
# 获取用户参数启动
|
|
|
|
|
|
parser = argparse.ArgumentParser(description="Example script with argparse")
|
|
|
|
|
|
|
|
|
|
|
|
# 获取用户输入的摄像头方位 (front back left right)
|
|
|
|
|
|
parser.add_argument("--i", type=str, required=True, help="摄像头方位")
|
|
|
|
|
|
|
|
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
|
|
|
|
print("相机方位:", args.i)
|
|
|
|
|
|
|
|
|
|
|
|
if args.i == "front":
|
|
|
|
|
|
which_camera = 0
|
|
|
|
|
|
elif args.i == "back":
|
|
|
|
|
|
which_camera = 2
|
|
|
|
|
|
elif args.i == "left":
|
|
|
|
|
|
which_camera = 1
|
|
|
|
|
|
elif args.i == "right":
|
|
|
|
|
|
which_camera = 3
|
|
|
|
|
|
else:
|
|
|
|
|
|
print("[ERROR] Invalid camera direction. Use 'front', 'back', 'left', or 'right'.", file=sys.stderr)
|
|
|
|
|
|
running = False
|
|
|
|
|
|
exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
# 启动视频线程
|
|
|
|
|
|
vt = threading.Thread(target=video_thread, daemon=True)
|
|
|
|
|
|
vt.start()
|
|
|
|
|
|
|
|
|
|
|
|
# 主线程监听 SSH 输入
|
|
|
|
|
|
input_thread()
|
|
|
|
|
|
|
|
|
|
|
|
print("[INFO] Exiting...")
|