You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于OpenCV remap预计算映射图计算校正图像边界框角点坐标?

鱼眼图像校正后边界框角点坐标计算方案

问题背景

用180°鱼眼镜头采集图像,先检测目标得到边界框,触发事件时通过OpenCV的remap函数结合预计算映射图校正图像,代码及参数如下:

map1, map2 = cv2.fisheye.initUndistortRectifyMap(K, D, np.eye(3), P, DIM, cv2.CV_16SC2)
undistorted_img = cv2.remap(img, map1, map2, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT)

参数:

K = [[169.53432726   0.         322.5714669 ]
     [  0.         169.39413982 289.12455088]
     [  0.           0.           1.        ]]
D = [[ 0.11919361]
     [ 0.29904975]
     [-0.20295709]
     [ 0.05526085]]
P = [[121.41853905   0.         322.57040373]
     [  0.         121.31813842 289.11177491]
     [  0.           0.           1.        ]]
DIM = (640, 640)

需求:基于预计算的x、y映射图,高效计算校正图像中对应边界框的角点坐标。此前尝试相关方法未得到正确结果。

可行解决方案

方法一:基于鱼眼畸变模型直接计算(推荐)

利用已有的内参、畸变系数和投影矩阵,直接对原始图像的边界框角点进行坐标转换,无需依赖预计算映射图,效率高且准确。

步骤说明

  1. 像素坐标转归一化相机坐标:去除内参影响,得到归一化坐标
  2. 鱼眼畸变校正:用OpenCV鱼眼模型(θ多项式)校正归一化坐标
  3. 归一化坐标转校正图像像素坐标:通过投影矩阵P得到最终校正后的像素坐标

代码实现

import numpy as np

# 你的参数(转为numpy数组方便计算)
K = np.array([[169.53432726, 0., 322.5714669],
              [0., 169.39413982, 289.12455088],
              [0., 0., 1.]])
D = np.array([[0.11919361], [0.29904975], [-0.20295709], [0.05526085]])
P = np.array([[121.41853905, 0., 322.57040373],
              [0., 121.31813842, 289.11177491],
              [0., 0., 1.]])

def original_to_undistorted(x, y):
    # 1. 转换为归一化坐标
    x_norm = (x - K[0,2]) / K[0,0]
    y_norm = (y - K[1,2]) / K[1,1]
    
    # 2. 鱼眼畸变校正
    r = np.sqrt(x_norm**2 + y_norm**2)
    if r == 0:
        x_norm_undist, y_norm_undist = 0, 0
    else:
        theta = np.arctan(r)
        theta_d = theta * (1 + D[0]*theta**2 + D[1]*theta**4 + D[2]*theta**6 + D[3]*theta**8)
        x_norm_undist = (theta_d / r) * x_norm
        y_norm_undist = (theta_d / r) * y_norm
    
    # 3. 投影到校正图像像素坐标
    u = P[0,0] * x_norm_undist + P[0,2]
    v = P[1,1] * y_norm_undist + P[1,2]
    return round(u, 2), round(v, 2)

# 示例:原始图像边界框角点转换
original_corners = [(100, 100), (500, 100), (500, 500), (100, 500)]
undistorted_corners = [original_to_undistorted(x, y) for x, y in original_corners]

# 生成校正后的边界框
u_min, u_max = min([u for u, v in undistorted_corners]), max([u for u, v in undistorted_corners])
v_min, v_max = min([v for u, v in undistorted_corners]), max([v for u, v in undistorted_corners])

print(f"校正后边界框范围:({u_min}, {v_min}) 到 ({u_max}, {v_max})")

方法二:基于现有映射图构建反向索引

如果必须依赖预计算的map1和map2,可以构建反向映射表,实现原始点到校正点的快速查找。

步骤说明

  1. 遍历校正后图像的所有像素(u, v),读取map1[v][u]和map2[v][u]得到对应的原始图像坐标(x, y)
  2. 用字典存储反向映射:键为(x, y)元组,值为所有对应校正后坐标(u, v)的列表
  3. 查找原始边界框角点对应的校正后坐标集合,取极值得到边界框范围

代码实现(简化版)

import numpy as np
import cv2

# 假设已经生成map1和map2
# map1, map2 = cv2.fisheye.initUndistortRectifyMap(K, D, np.eye(3), P, DIM, cv2.CV_16SC2)

# 构建反向映射字典
reverse_map = {}
h, w = DIM
for v in range(h):
    for u in range(w):
        x = map1[v][u]
        y = map2[v][u]
        key = (x, y)
        if key not in reverse_map:
            reverse_map[key] = []
        reverse_map[key].append((u, v))

# 查找原始角点对应的校正后坐标
original_corner = (100, 100)
if original_corner in reverse_map:
    undistorted_points = reverse_map[original_corner]
    # 处理多对一情况,取极值或均值
    u_vals = [p[0] for p in undistorted_points]
    v_vals = [p[1] for p in undistorted_points]
    print(f"校正后对应坐标范围:({min(u_vals)}, {min(v_vals)}) 到 ({max(u_vals)}, {max(v_vals)})")
else:
    print("该原始点无对应校正后坐标")

注意事项

  • 方法一无需依赖映射图,单点点计算耗时极短,适合批量或实时处理场景,优先推荐。
  • 方法二需预构建反向索引,占用一定内存,且部分原始像素可能无对应校正后坐标(因校正裁剪),需额外处理。

内容的提问来源于stack exchange,提问作者Mackie Messer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 00:24:53