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

如何计算透视变换与顺时针90度旋转后的点坐标

透视变换+顺时针90度旋转后的点坐标计算方案

需求背景

目标是将图像中的矩形对齐并转为横屏方向(宽度>高度)。原始矩形由四个顶点定义,部分场景下OpenCV会自动交换宽高,这时需要额外执行90度旋转,但旋转后可能出现矩形反向的情况。可以通过对比变换后左上(TL)和左下(BL)顶点的y坐标来修正这个问题。已知顶点映射关系(TL、TR、BR、BL),需要对原始顶点执行和图像相同的变换(仅透视变换,或透视变换+90度旋转),再通过y坐标判断是否需要180度修正。

核心问题

如何构建一个能表示「仅透视变换」或「透视变换+顺时针90度旋转」的组合变换矩阵,用来对已知相对位置的目标点执行坐标变换。

修正后的代码实现

import cv2
import numpy as np

# 原始矩形参数(中心坐标、宽高、旋转角度)
rectangle_area = [[270.2044677734375, 685.4646606445312], 
                  [417.27044677734375, 908.5230957031249], 
                  1.0000191926956177]
# 获取矩形四个顶点
rectangle = cv2.boxPoints(rectangle_area)
rectangle = np.int0(rectangle)
src_pts = rectangle.astype("float32")

width = int(rectangle_area[1][0])
height = int(rectangle_area[1][1])
# 判断是否需要执行90度旋转(宽<高时转为横屏)
rotate_90 = width < height

# 定义透视变换的目标顶点(对应TL、TR、BR、BL)
dst_pts = np.array([[0, height-1],
                    [0, 0],
                    [width-1, 0],
                    [width-1, height-1]], dtype="float32")

# 计算透视变换矩阵
M_perspective = cv2.getPerspectiveTransform(src_pts, dst_pts)

# 先执行透视变换得到矫正后的图像
warped = cv2.warpPerspective(img, M_perspective, (width, height))

points_reprojection_matrix = None

if rotate_90:
    # 对透视变换后的图像执行顺时针90度旋转
    warped = cv2.rotate(warped, cv2.ROTATE_90_CLOCKWISE)
    h_rot, w_rot = warped.shape[:2]
    
    # 构建顺时针90度旋转的齐次变换矩阵(3x3)
    # 顺时针90度旋转的矩阵:[0, 1, 0; -1, 0, w; 0, 0, 1],w为旋转前的宽度
    M_rotate = np.array([
        [0, 1, 0],
        [-1, 0, width],
        [0, 0, 1]
    ], dtype=np.float32)
    
    # 组合变换矩阵:先透视再旋转,矩阵乘法顺序为旋转矩阵 × 透视矩阵
    points_reprojection_matrix = M_rotate @ M_perspective
else:
    # 不需要旋转,直接使用透视变换矩阵
    points_reprojection_matrix = M_perspective

# 计算原始顶点经过变换后的坐标
points_reprojected = []
for pnt in src_pts:
    # 转为齐次坐标
    pnt_homogeneous = np.array([pnt[0], pnt[1], 1], dtype=np.float32)
    # 矩阵乘法计算变换后的齐次坐标
    pnt_reprojected_hom = points_reprojection_matrix @ pnt_homogeneous
    # 转为非齐次坐标(除以第三个分量)
    pnt_reprojected = pnt_reprojected_hom[:2] / pnt_reprojected_hom[2]
    points_reprojected.append(pnt_reprojected)

# 检查变换后左上顶点(索引0)和左下顶点(索引3)的y坐标,判断是否需要180度旋转修正
tl_y = points_reprojected[0][1]
bl_y = points_reprojected[3][1]
if tl_y > bl_y:
    # 构建180度旋转的齐次变换矩阵
    target_w = w_rot if rotate_90 else width
    target_h = h_rot if rotate_90 else height
    M_rotate_180 = np.array([
        [-1, 0, target_w],
        [0, -1, target_h],
        [0, 0, 1]
    ], dtype=np.float32)
    # 更新变换矩阵,加入180度旋转
    points_reprojection_matrix = M_rotate_180 @ points_reprojection_matrix
    # 重新计算所有点的坐标
    points_reprojected = []
    for pnt in src_pts:
        pnt_homogeneous = np.array([pnt[0], pnt[1], 1], dtype=np.float32)
        pnt_reprojected_hom = points_reprojection_matrix @ pnt_homogeneous
        pnt_reprojected = pnt_reprojected_hom[:2] / pnt_reprojected_hom[2]
        points_reprojected.append(pnt_reprojected)
    # 同时修正图像
    warped = cv2.rotate(warped, cv2.ROTATE_180)

关键说明

  • 变换矩阵组合规则:图像变换顺序是先透视再旋转,对应矩阵乘法要按「旋转矩阵 × 透视矩阵」的顺序计算(矩阵乘法为右乘,变换顺序从右到左)。
  • 齐次坐标处理:OpenCV的透视变换矩阵是3x3齐次矩阵,点需要转为(x,y,1)的齐次坐标计算,最后需除以第三个分量得到实际(x,y)坐标。
  • 90度旋转矩阵构建:顺时针90度旋转的齐次矩阵需考虑图像尺寸,旋转后原宽度变为高度,原高度变为宽度,矩阵中的偏移量要使用旋转前的宽度。
  • 180度修正逻辑:对比变换后左上和左下顶点的y坐标,若左上y值更大,说明矩形反向,通过180度旋转修正。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 00:55:21