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

如何将四边形上的CGPoint转换到矩形坐标系并计算对应点坐标

解决方案

实现思路

你要实现的是平面透视投影变换,核心是求解单应性矩阵(Homography Matrix),无需依赖系统的CIPerspectiveCorrection接口,也不需要引入第三方库,纯原生代码即可实现:

  • 首先确定目标输出矩形的四个顶点坐标(可自定义尺寸,也可以直接用原四边形的包围盒尺寸作为输出矩形大小)
  • 利用原四边形4个顶点和目标矩形4个顶点的对应关系,求解3x3的单应性变换矩阵
  • 用得到的变换矩阵对E点做坐标映射,即可得到其在目标矩形上的对应坐标

核心代码实现(Swift)

import CoreGraphics

// 求解单应性矩阵
func computeHomography(from srcPoints: [CGPoint], to dstPoints: [CGPoint]) -> [CGFloat]? {
    guard srcPoints.count == 4, dstPoints.count == 4 else { return nil }
    
    var A = Array(repeating: Array(repeating: 0.0, count: 8), count: 8)
    var B = Array(repeating: 0.0, count: 8)
    
    for i in 0..<4 {
        let x = srcPoints[i].x
        let y = srcPoints[i].y
        let xPrime = dstPoints[i].x
        let yPrime = dstPoints[i].y
        
        A[2*i][0] = x
        A[2*i][1] = y
        A[2*i][2] = 1
        A[2*i][6] = -x * xPrime
        A[2*i][7] = -y * xPrime
        B[2*i] = xPrime
        
        A[2*i + 1][3] = x
        A[2*i + 1][4] = y
        A[2*i + 1][5] = 1
        A[2*i + 1][6] = -x * yPrime
        A[2*i + 1][7] = -y * yPrime
        B[2*i + 1] = yPrime
    }
    
    // 高斯消元求解线性方程组
    guard let h = gaussianElimination(A, B) else { return nil }
    // 单应性矩阵共9个元素,最后一个固定为1
    return h + [1.0]
}

// 高斯消元实现
func gaussianElimination(_ A: [[CGFloat]], _ B: [CGFloat]) -> [CGFloat]? {
    let n = B.count
    var aug = A.enumerated().map { $0.element + [B[$0.offset]] }
    
    for i in 0..<n {
        // 找主元
        var maxRow = i
        for j in i..<n {
            if abs(aug[j][i]) > abs(aug[maxRow][i]) {
                maxRow = j
            }
        }
        aug.swapAt(i, maxRow)
        
        // 主元为0则矩阵奇异,无解
        if abs(aug[i][i]) < 1e-8 {
            return nil
        }
        
        // 归一化主元行
        let div = aug[i][i]
        for j in i...n {
            aug[i][j] /= div
        }
        
        // 消去其他行
        for j in 0..<n {
            if j != i && abs(aug[j][i]) > 1e-8 {
                let factor = aug[j][i]
                for k in i...n {
                    aug[j][k] -= factor * aug[i][k]
                }
            }
        }
    }
    
    return aug.map { $0[n] }
}

// 用单应性矩阵变换点坐标
func applyHomography(_ h: [CGFloat], point: CGPoint) -> CGPoint {
    let x = point.x
    let y = point.y
    let w = h[6] * x + h[7] * y + h[8]
    let xPrime = (h[0] * x + h[1] * y + h[2]) / w
    let yPrime = (h[3] * x + h[4] * y + h[5]) / w
    return CGPoint(x: xPrime, y: yPrime)
}

使用示例

// 1. 定义原四边形的四个顶点,顺序要和目标矩形对应:左上、右上、右下、左下
let srcPoints = [A, B, C, D]
// 2. 定义目标矩形的四个顶点,这里示例输出1080x1920的矩形,你也可以自定义尺寸
let dstPoints = [
    CGPoint(x: 0, y: 0),
    CGPoint(x: 1080, y: 0),
    CGPoint(x: 1080, y: 1920),
    CGPoint(x: 0, y: 1920)
]
// 3. 求解单应性矩阵
guard let homography = computeHomography(from: srcPoints, to: dstPoints) else {
    print("变换矩阵求解失败,请检查输入点是否共线")
    return
}
// 4. 变换E点得到目标坐标
let targetPoint = applyHomography(homography, point: E)

注意事项

  • 输入的原四边形4个点和目标矩形4个点的顺序必须严格对应,否则映射结果会出错
  • 如果原四边形存在三点共线的情况,会导致矩阵求解失败,需要保证输入是有效的凸四边形
  • 目标矩形的尺寸可以根据业务需求自定义,也可以直接计算原四边形的外接矩形尺寸作为输出大小

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 03:36:03