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

OpenCV透视变换后:RoI片段/坐标回原图像失败求助

问题:RoI透视变换后逆变换及坐标映射异常

我需要从图像中提取RoI(感兴趣区域),基于该片段完成计算后,将片段转回原位置,或是把计算得到的坐标映射回原图像,但过程中遇到了问题。

提取RoI与透视变换代码

x, y, w, h = cv2.boundingRect(localized_mask)

p1 = [x, y + h]
p4 = [x, y]
p3 = [x + w, y]
p2 = [x + w, y + h]

w1 = int(np.linalg.norm(np.array(p2) - np.array(p3)))
w2 = int(np.linalg.norm(np.array(p4) - np.array(p1)))
h1 = int(np.linalg.norm(np.array(p1) - np.array(p2)))
h2 = int(np.linalg.norm(np.array(p3) - np.array(p4)))

maxWidth = max(w1, w2)
maxHeight = max(h1, h2)

neighbor_points = [p1, p2, p3, p4]
output_poins = np.float32(
    [
        [0, 0],
        [0, maxHeight],
        [maxWidth, maxHeight],
        [maxWidth, 0],
    ]
)

matrix = cv2.getPerspectiveTransform(np.float32(neighbor_points), output_poins)
result = cv2.warpPerspective(
    mask, matrix, (maxWidth, maxHeight), cv2.INTER_LINEAR
)

逆变换尝试及问题

我尝试用以下代码将片段转回原位置,但结果均为与片段或原图尺寸一致的全黑图像:

test2 = cv2.warpPerspective(
    result, matrix, (maxHeight, maxWidth), cv2.WARP_INVERSE_MAP
)
test3 = cv2.warpPerspective(
    result, matrix, (img.shape[1], img.shape[0]), cv2.WARP_INVERSE_MAP
)

手动坐标映射的问题

我更关注片段内的白色标记,于是尝试手动逆变换坐标,但得到的坐标(左上区域的白点)未处于预期位置:

inverse_matrix = cv2.invert(matrix)[1]
inverse_left=[]
for point in output_dict["left"]["knots"]:
    trans_point = [point.x, point.y] + [1]
    trans_point = np.float32(trans_point)

    x, y, z = np.dot(inverse_matrix, trans_point)
    new_x = np.uint8(x/z)
    new_y = np.uint8(y/z)
    inverse_left.append([new_x, new_y])       

问题分析与解决方案

1. 核心问题:透视变换的点顺序不匹配

OpenCV的cv2.getPerspectiveTransform要求输入的源点和目标点必须保持一致的顺时针/逆时针顺序,否则生成的变换矩阵会完全错误,导致逆变换或坐标映射失效。你当前的源点(neighbor_points)和目标点(output_poins)顺序混乱,是所有问题的根源。

2. 修正后的透视变换实现

统一采用左上→右上→右下→左下的顺时针顺序定义点:

x, y, w, h = cv2.boundingRect(localized_mask)

# 原图RoI的四个角,按顺时针顺序:左上、右上、右下、左下
src_points = np.float32([
    [x, y],          # 左上
    [x + w, y],      # 右上
    [x + w, y + h],  # 右下
    [x, y + h]       # 左下
])

# 变换后图像的对应点,同样顺时针顺序
maxWidth = w
maxHeight = h
dst_points = np.float32([
    [0, 0],
    [maxWidth, 0],
    [maxWidth, maxHeight],
    [0, maxHeight]
])

# 生成从原图RoI到变换后图像的透视矩阵
matrix = cv2.getPerspectiveTransform(src_points, dst_points)
result = cv2.warpPerspective(mask, matrix, (maxWidth, maxHeight), cv2.INTER_LINEAR)

3. 正确执行逆变换(将片段转回原位置)

有两种可靠方式实现逆变换:

方式一:直接计算逆矩阵

# 计算透视矩阵的逆矩阵
inv_matrix = cv2.invert(matrix)[1]
# 逆变换,输出尺寸为原图的宽高(注意:OpenCV中尺寸是(宽, 高))
restored_img = cv2.warpPerspective(result, inv_matrix, (img.shape[1], img.shape[0]))

方式二:重新生成逆变换矩阵

# 生成从变换后图像到原图RoI的透视矩阵
inv_matrix = cv2.getPerspectiveTransform(dst_points, src_points)
restored_img = cv2.warpPerspective(result, inv_matrix, (img.shape[1], img.shape[0]))

4. 正确映射坐标到原图

修正点顺序后,手动逆变换坐标的逻辑即可正常工作,注意用int而非uint8避免坐标溢出(当坐标超过255时uint8会截断):

inv_matrix = cv2.invert(matrix)[1]
inverse_left = []
for point in output_dict["left"]["knots"]:
    # 构造齐次坐标 [x, y, 1]
    trans_point = np.float32([point.x, point.y, 1])
    # 矩阵乘法完成逆变换
    x, y, z = np.dot(inv_matrix, trans_point)
    # 归一化得到原图绝对坐标
    new_x = int(x / z)
    new_y = int(y / z)
    inverse_left.append([new_x, new_y])

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 15:30:52