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

如何用Python PIL通过内部四边形扭曲图像且不裁剪四边形外区域

使用Python PIL实现指定四点的透视扭曲(保留完整图像)

要实现将图像内部任意四边形映射为矩形,同时保留原图像的全部内容(不裁剪),核心是通过透视变换(Homography)完成坐标映射,并提前计算变换后的图像边界以确定输出尺寸。以下是完整的实现方案:

实现步骤与代码

1. 依赖库导入

需要用到Pillow和numpy(用于矩阵计算),先安装依赖:

pip install pillow numpy

2. 核心函数实现

from PIL import Image
import numpy as np

def compute_perspective_matrix(src_points, dst_points):
    """计算透视变换矩阵(3x3)"""
    A = []
    for (x, y), (u, v) in zip(src_points, dst_points):
        A.append([x, y, 1, 0, 0, 0, -u*x, -u*y])
        A.append([0, 0, 0, x, y, 1, -v*x, -v*y])
    A = np.array(A, dtype=np.float32)
    B = np.array(dst_points).reshape(8, 1).astype(np.float32)
    
    # 求解线性方程组得到变换矩阵
    matrix, _, _, _ = np.linalg.lstsq(A, B, rcond=None)
    return np.append(matrix, 1).reshape(3, 3)

def get_transformed_bounds(image, matrix):
    """计算变换后图像的边界与尺寸,确保容纳全部内容"""
    width, height = image.size
    # 原图像四个角坐标
    corners = [(0, 0), (width, 0), (width, height), (0, height)]
    transformed_corners = []
    
    for x, y in corners:
        nx, ny, w = matrix @ np.array([x, y, 1])
        transformed_corners.append((nx/w, ny/w))
    
    xs = [p[0] for p in transformed_corners]
    ys = [p[1] for p in transformed_corners]
    min_x, max_x = min(xs), max(xs)
    min_y, max_y = min(ys), max(ys)
    
    # 输出尺寸取整,确保覆盖所有像素
    new_width = int(np.ceil(max_x - min_x))
    new_height = int(np.ceil(max_y - min_y))
    # 偏移量:将变换后的图像移至正坐标区域
    return (-min_x, -min_y), (new_width, new_height)

def warp_to_rectangle(image_path, src_points, dst_rect):
    """
    将图像中指定四点映射为目标矩形,保留完整图像
    :param image_path: 输入图像路径
    :param src_points: 原始四点(顺时针/逆时针顺序,如左上、右上、右下、左下)
    :param dst_rect: 目标矩形,格式为(x, y, width, height)
    :return: 变换后的图像对象
    """
    img = Image.open(image_path).convert("RGB")
    
    # 生成目标矩形的四个顶点(与原始点顺序对应)
    dst_points = [
        (dst_rect[0], dst_rect[1]),
        (dst_rect[0] + dst_rect[2], dst_rect[1]),
        (dst_rect[0] + dst_rect[2], dst_rect[1] + dst_rect[3]),
        (dst_rect[0], dst_rect[1] + dst_rect[3])
    ]
    
    # 计算透视变换矩阵
    perspective_matrix = compute_perspective_matrix(src_points, dst_points)
    # 获取变换后的边界与偏移
    offset, new_size = get_transformed_bounds(img, perspective_matrix)
    
    # 构造平移矩阵,将变换后的图像移至正坐标区域
    translation_matrix = np.array([
        [1, 0, offset[0]],
        [0, 1, offset[1]],
        [0, 0, 1]
    ])
    final_matrix = translation_matrix @ perspective_matrix
    
    # 转换为PIL要求的8元素矩阵(3x3矩阵的前8个元素)
    pil_matrix = final_matrix.flatten()[:8]
    
    # 执行透视变换,fillcolor为背景色(可改为透明(0,0,0,0)如果用RGBA模式)
    warped_img = img.transform(
        new_size, 
        Image.PERSPECTIVE, 
        pil_matrix, 
        Image.BILINEAR, 
        fillcolor=(255, 255, 255)
    )
    return warped_img

3. 使用示例

# 原始图像内部的四个目标点(按顺时针顺序:左上、右上、右下、左下)
src_points = [(120, 110), (310, 130), (300, 320), (110, 300)]
# 目标矩形:(起始x, 起始y, 宽度, 高度)
dst_rect = (60, 60, 220, 220)

# 处理图像
result_img = warp_to_rectangle("input.jpg", src_points, dst_rect)
# 保存结果
result_img.save("output.jpg")
# 显示图像
result_img.show()

关键说明

  • 点顺序一致性:原始四点和目标矩形的四点必须保持相同的顺序(如顺时针或逆时针),否则变换会出现错位。
  • 背景色设置:如果需要透明背景,可将图像转为RGBA模式(img.convert("RGBA")),并设置fillcolor=(0,0,0,0)。
  • 插值方式:Image.BILINEAR是平衡速度与质量的插值方式,也可改用Image.LANCZOS获得更高质量(但速度稍慢)。

内容的提问来源于stack exchange,提问作者Eric H.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 03:26:17