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

使用cv2.getPerspectiveTransform出现异常输出的问题咨询

问题描述

尝试使用OpenCV计算透视变换,代码如下:

import numpy as np
import cv2

original_pts = np.array([[745, 1233], [1505, 1581], [1502, 1212], [855, 1229]], dtype=np.float32)
desired_pts = np.array([[46., 50.], [949., 490.], [949., 50.], [175., 50.]], dtype=np.float32)
M = cv2.getPerspectiveTransform(original_pts, desired_pts)
cv2.perspectiveTransform(np.float32(original_pts[None, :, :]), M)[0]

输出结果:

array([[  46.,   50.],
       [   0.,    0.],
       [ 949.,   50.],
       [ 175.,   50.]], dtype=np.float32)

其中第二个点的变换结果明显错误。为排查问题,自行实现了线性系统:

x = original_pts[:, 0]
y = original_pts[:, 1]
xt = desired_pts[:, 0]
yt = desired_pts[:, 1]
A = []
for i in range(4):
    equation = [x[i], y[i], 1, 0, 0, 0, 0, 0]
    equation += [0] * i
    equation += [-xt[i]]
    equation += [0] * (3 - i)
    A.append(equation)

    equation = [0, 0, 0, x[i], y[i], 1, 0, 0]
    equation += [0] * i
    equation += [-yt[i]]
    equation += [0] * (3 - i)
    A.append(equation)

    equation = [0, 0, 0, 0, 0, 0, x[i], y[i]]
    equation += [0] * i
    equation +=  [-1]
    equation += [0] * (3 - i)
    A.append(equation)

A = np.array(A)

b = np.array([0]*8 + [-1]*4)
res = np.linalg.solve(A, b)
my_M = np.array([[res[0], res[1], res[2]], [res[3], res[4], res[5]], [res[6], res[7], 1]])
cv2.perspectiveTransform(np.float32(original_pts[None, :, :]), my_M)[0]

得到的结果:

array([[  47.653404,   51.79718 ],
       [ 975.5118  ,  503.6889  ],
       [ 949.      ,   50.      ],
       [ 175.0361  ,   50.036106]], dtype=np.float32)

疑问:是使用cv2.getPerspectiveTransform的方式有误,还是该函数在某些场景下无法正常工作?认为自定义实现是该函数的非优化版本。

分析与解答
  1. 核心问题:目标点集退化
    cv2.getPerspectiveTransform要求输入的两组对应点必须构成非退化的四边形(四个点无三点共线),因为透视变换的数学基础是求解一个8自由度的线性系统,只有当输入点集非退化时,系统才有唯一有效解。

你提供的desired_pts中有3个点的y坐标均为50,这三个点共线,属于退化的点集。这种情况下,线性系统会出现奇异矩阵,导致cv2.getPerspectiveTransform计算出的变换矩阵无效,最终出现第二个点变换结果为(0,0)的异常情况。

  1. 自定义实现的错误
    你的自定义实现额外添加了第三个约束方程,强行对齐次坐标的w分量进行限制,这不符合透视变换的数学定义。透视变换中,齐次坐标的w分量是由变换矩阵和原始点共同决定的,不能人为约束。这种错误的约束在点集退化的场景下,反而得到了看似接近预期的结果,但该变换矩阵并不满足透视变换的基本要求,无法正确应用于其他点的变换。

  2. 解决方法

  • 修正desired_pts,确保四个点构成非退化的四边形(无三点共线);
  • 保证original_pts和desired_pts的点顺序完全匹配(比如均按顺时针/逆时针的顺序排列,对应四边形的同一顶点);
  • 若需要将原始四边形映射到一条直线附近的区域,建议使用仿射变换(cv2.getAffineTransform),但仿射变换仅需要3组对应点,且要求点集共面。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 19:54:58