不使用cv2.fisheye实现f-theta图像畸变:代码问题排查
手动实现F-Theta畸变的问题分析与修正方案
问题背景
我希望手动实现F-Theta畸变方程来夯实图像畸变的基础原理,但运行代码后得到异常输出。如何不借助cv2.fisheye库将F-Theta畸变方程应用到图像上?我的代码存在什么问题?
输入图像:
输出图像:
代码核心问题分析
- 映射方向完全错误:
cv2.remap要求传入的是目标图像每个像素对应原图像的坐标,但原代码是把原图像像素映射到目标位置,导致畸变逻辑完全反转。 - Theta定义混淆:F-Theta中的
theta是光线与光轴的夹角(极角,范围0到π/2),原代码用arctan2(dy, dx)计算的是方位角(-π到π),完全混淆了极角和方位角的概念。 - 坐标处理不当:
- 不必要的
cy - y反转y轴,导致坐标逻辑混乱; - 对映射坐标直接取整,丢失精度,
cv2.remap需要浮点型的映射数组。
- 不必要的
- 公式应用错误:正确的F-Theta映射是
r = f * theta(r为图像径向距离,theta为真实场景极角),原代码直接用方位角计算,导致畸变效果异常。
修正后的F-Theta畸变实现
import cv2 import numpy as np from PIL import Image def apply_f_theta_distortion(image): h, w = image.shape[:2] cx, cy = w / 2.0, h / 2.0 # 使用浮点型避免整数运算误差 f = min(cx, cy) # 焦距取图像短边的一半 # 创建映射数组:目标像素 -> 原图像像素的坐标 map_x = np.zeros((h, w), dtype=np.float32) map_y = np.zeros((h, w), dtype=np.float32) for y in range(h): for x in range(w): # 计算目标图像中当前像素到中心的径向距离和方位角 dx = x - cx dy = y - cy r_distorted = np.sqrt(dx**2 + dy**2) phi = np.arctan2(dy, dx) # 方位角,用于保持像素的方向 # F-Theta变换:畸变图像的r对应真实场景的极角theta = r/f theta = r_distorted / f # 原透视图像中对应的径向距离:r_undistorted = f * tan(theta) r_undistorted = f * np.tan(theta) # 转换回笛卡尔坐标,得到原图像中的对应位置 x_undistorted = cx + r_undistorted * np.cos(phi) y_undistorted = cy + r_undistorted * np.sin(phi) # 确保坐标在原图像范围内,超出则映射到中心 if 0 <= x_undistorted < w and 0 <= y_undistorted < h: map_x[y, x] = x_undistorted map_y[y, x] = y_undistorted else: map_x[y, x] = cx map_y[y, x] = cy # 应用映射生成畸变图像 distorted_image = cv2.remap(image, map_x, map_y, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT) return distorted_image # 测试用网格图像 N = 500 img = np.zeros((N, N), dtype=np.uint8) img[::10, :] = 255 img[:, ::10] = 255 # 生成并显示F-Theta畸变图像 distorted_img = apply_f_theta_distortion(img) Image.fromarray(distorted_img).show()
关键修正说明
- 反转映射逻辑:遍历目标图像的每个像素,计算它在原图像中对应的位置,完全符合
cv2.remap的输入要求。 - 正确的F-Theta映射关系:
- 先根据畸变图像的径向距离计算真实场景的极角
theta = r_distorted / f; - 再通过透视投影公式计算原图像中对应的径向距离
r_undistorted = f * tan(theta)。
- 先根据畸变图像的径向距离计算真实场景的极角
- 保留浮点精度:映射数组使用
np.float32类型,避免取整导致的锯齿和精度损失。 - 简化坐标系统:直接使用图像原生坐标系(左上角为原点,y轴向下),移除不必要的y轴反转逻辑。
内容的提问来源于stack exchange,提问作者JVG
相关产品推荐
相关产品推荐

