OmniCV鱼眼相机fisheye2equirect步骤2结果异常及参数存储求助
OmniCV鱼眼转等距柱状投影参数调试问题
问题描述
使用Python调用OmniCV库处理鱼眼相机图像,预期复现官方参数GUI校准流程步骤2的正确输出效果,实际运行结果不符合预期,需要完成两个目标:
- 输出正确的鱼眼到等距柱状投影转换结果
- 准确将
RADIUS、aperture、delx、dely参数写入fisheyeParams.txt文件,保证映射坐标准确
相关素材
- 失败运行结果截图:

- 原始输入鱼眼图像:

原始使用代码
import cv2 import numpy as np from omnicv import fisheyeImgConv def nothing(x): pass WINDOW_NAME = "image" Image_Path = './input/fisheye.png' RADIUS = None # Example of using the converter class frame = cv2.imread(Image_Path) frame = cv2.resize(frame, (800,800)) cv2.namedWindow(WINDOW_NAME, cv2.WINDOW_NORMAL) cv2.resizeWindow(WINDOW_NAME, 800, 800) N = 2 * max(frame.shape) cv2.createTrackbar("radius", WINDOW_NAME, 0, N, nothing) cv2.createTrackbar("Cx", WINDOW_NAME, N // 2, N, nothing) cv2.createTrackbar("Cy", WINDOW_NAME, N // 2, N, nothing) while True: if True: frame = cv2.imread(Image_Path) radius = cv2.getTrackbarPos("radius", WINDOW_NAME) Cx = cv2.getTrackbarPos("Cx", WINDOW_NAME) Cy = cv2.getTrackbarPos("Cy", WINDOW_NAME) frame = cv2.circle(frame, (Cx, Cy), radius, (0, 200, 0), 2) cv2.imshow(WINDOW_NAME, frame) if cv2.waitKey(1) & 0xFF == 27: RADIUS = radius cv2.destroyAllWindows() break WINDOW_NAME = "set aperture" cv2.namedWindow(WINDOW_NAME, cv2.WINDOW_NORMAL) cv2.resizeWindow(WINDOW_NAME, 1200, 600) cv2.createTrackbar("aperture", WINDOW_NAME, 0, 1000, nothing) cv2.createTrackbar("del Cx", WINDOW_NAME, 500, 1000, nothing) cv2.createTrackbar("del Cy", WINDOW_NAME, 500, 1000, nothing) # Example of using the converter class frame = cv2.imread(Image_Path) frame = cv2.circle(frame, (frame.shape[1] // 2, frame.shape[0] // 2), 4, (255, 255, 255), -1) frame = cv2.circle(frame, (frame.shape[1] // 2, frame.shape[0] // 2), 2, (0, 0, 0), -1) outShape = [400,800] inShape = frame.shape[:2] mapper = fisheyeImgConv() mapper.fisheye2equirect(frame, outShape, edit_mode=True) while True: if True: aperture = cv2.getTrackbarPos("aperture", WINDOW_NAME) delx = cv2.getTrackbarPos("del Cx", WINDOW_NAME) - 500 dely = cv2.getTrackbarPos("del Cy", WINDOW_NAME) - 500 frame2 = mapper.fisheye2equirect( frame, outShape, aperture=aperture, delx=delx, dely=dely, radius=RADIUS, edit_mode=True) cv2.imshow("image3", frame2) frame2 = cv2.line( frame2, (int(frame2.shape[1] * 0.25), 0), (int(frame2.shape[1] * 0.25), int(frame2.shape[0])), (0, 180, 0), 1, ) frame2 = cv2.line( frame2, (int(frame2.shape[1] * 0.75), 0), (int(frame2.shape[1] * 0.75), int(frame2.shape[0])), (0, 180, 0), 1, ) frame2 = cv2.line( frame2, (0, int(frame2.shape[0] * 0.5)), (int(frame2.shape[1]), int(frame2.shape[0] * 0.5)), (0, 180, 0), 1, ) frame2 = cv2.line( frame2, (int(frame2.shape[1] * 0.5), 0), (int(frame2.shape[1] * 0.5), int(frame2.shape[0])), (0, 180, 0), 1, ) cv2.imshow(WINDOW_NAME, frame2) if cv2.waitKey(1) & 0xFF == 27: print("aperture : ", aperture) print("delx : ", delx) print("dely : ", dely) f = open("./input/fisheyeParams.txt", "w+") f.write(str(RADIUS) + "\n") f.write(str(aperture) + "\n") f.write(str(delx) + "\n") f.write(str(dely) + "\n") f.close() break frame2[:, :, :] = 0 # cv2.imshow("image", frame2)
问题根因
代码存在5个核心错误,直接导致转换结果异常:
- 第一步标定鱼眼圆时,初始读取的帧被resize到800*800,但循环内每次重新读取的原图没有做相同resize,导致画圆的坐标和实际图像尺寸不匹配,选出来的半径值完全错误
- 第一步只保存了半径
RADIUS,没有保存标定的鱼眼光心坐标Cx、Cy,第二步默认以图像中心为光心,和实际鱼眼圆位置存在偏移 aperture(鱼眼视场角)滑块范围设置错误,官方要求取值范围为0-180(单位:度),代码设置为0-1000,初始值为0时视场角为0,无法输出有效投影- 第二步循环末尾手动将
frame2所有像素置0,同时额外创建了image3显示窗口,导致画面闪烁、显示内容错位 - 第一步滑块最大值
N设置为2倍resize后图像的长边,和循环内读取的未resize原图尺寸不匹配,拖动滑块时容易出现坐标越界报错
修正后可运行代码
import cv2 import numpy as np from omnicv import fisheyeImgConv def nothing(x): pass # 配置参数 WINDOW_NAME_RADIUS = "标定鱼眼圆范围" WINDOW_NAME_APERTURE = "标定视场与偏移" IMAGE_PATH = './input/fisheye.png' PARAM_SAVE_PATH = './input/fisheyeParams.txt' RESIZE_STEP1 = (800, 800) OUT_SHAPE = [400, 800] # 等距柱状投影输出尺寸 高*宽 # 第一步:标定鱼眼圆半径与光心位置 frame_raw = cv2.imread(IMAGE_PATH) frame_step1 = cv2.resize(frame_raw, RESIZE_STEP1) h_resize, w_resize = frame_step1.shape[:2] cv2.namedWindow(WINDOW_NAME_RADIUS, cv2.WINDOW_NORMAL) cv2.resizeWindow(WINDOW_NAME_RADIUS, w_resize, h_resize) max_slider = max(h_resize, w_resize) # 初始化滑块:半径默认设为短边一半,光心默认在图像中心 cv2.createTrackbar("radius", WINDOW_NAME_RADIUS, min(h_resize, w_resize)//2, max_slider, nothing) cv2.createTrackbar("Cx", WINDOW_NAME_RADIUS, w_resize//2, w_resize, nothing) cv2.createTrackbar("Cy", WINDOW_NAME_RADIUS, h_resize//2, h_resize, nothing) RADIUS = None Cx = None Cy = None while True: frame_show = frame_step1.copy() radius = cv2.getTrackbarPos("radius", WINDOW_NAME_RADIUS) cx = cv2.getTrackbarPos("Cx", WINDOW_NAME_RADIUS) cy = cv2.getTrackbarPos("Cy", WINDOW_NAME_RADIUS) # 画鱼眼圆参考线 cv2.circle(frame_show, (cx, cy), radius, (0, 200, 0), 2) cv2.circle(frame_show, (cx, cy), 3, (0,0,255), -1) cv2.imshow(WINDOW_NAME_RADIUS, frame_show) key = cv2.waitKey(1) & 0xFF if key == 27: # ESC键确认第一步参数 # 把resize后的坐标换算回原图尺寸 scale = frame_raw.shape[1] / w_resize RADIUS = int(radius * scale) Cx = int(cx * scale) Cy = int(cy * scale) cv2.destroyAllWindows() break # 第二步:标定视场角与光心偏移 cv2.namedWindow(WINDOW_NAME_APERTURE, cv2.WINDOW_NORMAL) cv2.resizeWindow(WINDOW_NAME_APERTURE, 1200, 600) # 修正滑块范围:aperture为0-180度,偏移范围-200到200像素 cv2.createTrackbar("aperture(度)", WINDOW_NAME_APERTURE, 180, 180, nothing) cv2.createTrackbar("del Cx", WINDOW_NAME_APERTURE, 200, 400, nothing) cv2.createTrackbar("del Cy", WINDOW_NAME_APERTURE, 200, 400, nothing) mapper = fisheyeImgConv() # 预计算映射表 mapper.fisheye2equirect(frame_raw, OUT_SHAPE, edit_mode=True) while True: aperture = cv2.getTrackbarPos("aperture(度)", WINDOW_NAME_APERTURE) # 偏移初始值为0,滑块0对应-200,滑块400对应+200 delx = cv2.getTrackbarPos("del Cx", WINDOW_NAME_APERTURE) - 200 dely = cv2.getTrackbarPos("del Cy", WINDOW_NAME_APERTURE) - 200 # 传入正确的光心坐标:基准Cx/Cy相对中心的偏移 + 微调偏移 equi_frame = mapper.fisheye2equirect( frame_raw, OUT_SHAPE, aperture=aperture, delx=delx + (Cx - frame_raw.shape[1]//2), dely=dely + (Cy - frame_raw.shape[0]//2), radius=RADIUS, edit_mode=False ) # 画等距柱状投影参考线 h_equi, w_equi = equi_frame.shape[:2] cv2.line(equi_frame, (w_equi//4, 0), (w_equi//4, h_equi), (0,180,0), 1) cv2.line(equi_frame, (w_equi*3//4, 0), (w_equi*3//4, h_equi), (0,180,0), 1) cv2.line(equi_frame, (0, h_equi//2), (w_equi, h_equi//2), (0,180,0), 1) cv2.line(equi_frame, (w_equi//2, 0), (w_equi//2, h_equi), (0,180,0), 1) cv2.imshow(WINDOW_NAME_APERTURE, equi_frame) key = cv2.waitKey(1) & 0xFF if key == 27: # ESC键确认参数并保存 final_delx = delx + (Cx - frame_raw.shape[1]//2) final_dely = dely + (Cy - frame_raw.shape[0]//2) print(f"保存参数:RADIUS={RADIUS}, aperture={aperture}, delx={final_delx}, dely={final_dely}") with open(PARAM_SAVE_PATH, "w+", encoding="utf-8") as f: f.write(f"{RADIUS}\n{aperture}\n{final_delx}\n{final_dely}\n") cv2.destroyAllWindows() break
使用说明
- 运行代码后第一个窗口会显示鱼眼图,拖动三个滑块让绿色圆圈刚好贴合鱼眼图像的有效圆形边缘,红色点对准鱼眼光心,按ESC进入下一步
- 第二个窗口会显示实时转换的等距柱状投影图,拖动
aperture(度)滑块调整视场角直到鱼眼圆边缘刚好填满投影的垂直范围,拖动del Cx/del Cy微调让参考线对齐场景中的水平/垂直线条,调整完成后按ESC,参数会自动写入指定的fisheyeParams.txt文件
内容的提问来源于stack exchange,提问作者NSA
相关产品推荐
相关产品推荐

