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

是否存在可实现仅缩放修改区域的4点非均匀扭曲Python函数?

实现基于4点的非均匀图像扭曲(Python)

当然可以实现这种非均匀扭曲效果,核心思路是通过自定义坐标映射+插值来实现,避开透视变换的全局特性,只针对宽度/高度做局部缩放。下面是具体的实现方案:

核心原理

仿射变换只能处理平行性不变的线性变换,透视变换是全局的投影变换,都不符合你的需求。我们可以手动构建输出图像像素到原始图像像素的映射关系,基于4个控制点定义局部缩放规则,再通过插值填充像素值。

代码实现(OpenCV + NumPy)

以下是针对「宽度随高度线性变化」的非均匀扭曲实现,你可以根据需求调整映射逻辑:

import cv2
import numpy as np
from scipy.ndimage import map_coordinates

def non_uniform_width_warp(img, src_pts, dst_pts, output_shape):
    """
    实现基于4点的非均匀宽度扭曲(高度方向上宽度线性变化)
    :param img: 原始输入图像
    :param src_pts: 原始图像4个控制点,格式[[左上x,左上y], [右上x,右上y], [左下x,左下y], [右下x,右下y]]
    :param dst_pts: 目标图像对应4个控制点,格式同src_pts
    :param output_shape: 输出图像尺寸(高, 宽, 通道数)
    """
    h_out, w_out = output_shape[:2]
    # 创建输出图像的坐标网格
    y_out, x_out = np.mgrid[0:h_out, 0:w_out]
    
    # 转换为浮点型数组方便计算
    src = np.float32(src_pts)
    dst = np.float32(dst_pts)
    
    # 拆分四个角点
    src_tl, src_tr, src_bl, src_br = src
    dst_tl, dst_tr, dst_bl, dst_br = dst
    
    # 计算当前y在目标垂直方向的比例(0到1)
    y_ratio = (y_out - dst_tl[1]) / (dst_bl[1] - dst_tl[1])
    y_ratio = np.clip(y_ratio, 0.0, 1.0)  # 避免超出边界
    
    # 计算目标图像当前y对应的左右边界x坐标
    dst_x_left = dst_tl[0] + y_ratio * (dst_bl[0] - dst_tl[0])
    dst_x_right = dst_tr[0] + y_ratio * (dst_br[0] - dst_tr[0])
    
    # 计算当前x在目标左右边界间的比例
    x_ratio = (x_out - dst_x_left) / (dst_x_right - dst_x_left)
    x_ratio = np.clip(x_ratio, 0.0, 1.0)
    
    # 映射到原始图像的x坐标
    src_x_left = src_tl[0] + y_ratio * (src_bl[0] - src_tl[0])
    src_x_right = src_tr[0] + y_ratio * (src_br[0] - src_tr[0])
    src_x = src_x_left + x_ratio * (src_x_right - src_x_left)
    
    # 映射到原始图像的y坐标
    src_y = src_tl[1] + y_ratio * (src_bl[1] - src_tl[1])
    
    # 使用scipy的map_coordinates做线性插值(替代手动双线性插值)
    coords = np.vstack([src_y.flatten(), src_x.flatten()])
    output_img = np.zeros(output_shape, dtype=img.dtype)
    
    for channel in range(img.shape[2]):
        channel_data = map_coordinates(img[..., channel], coords, order=1)
        output_img[..., channel] = channel_data.reshape(h_out, w_out)
    
    return output_img

# 示例使用
if __name__ == "__main__":
    # 读取图像
    original_img = cv2.imread("original_image.png")
    h, w = original_img.shape[:2]
    
    # 定义原始图像四个角点
    src_points = [[0, 0], [w-1, 0], [0, h-1], [w-1, h-1]]
    # 定义目标点:模拟底部宽度收缩的非均匀效果
    dst_points = [[0, 0], [w-1, 0], [w//4, h-1], [3*w//4, h-1]]
    
    # 执行扭曲
    warped_img = non_uniform_width_warp(original_img, src_points, dst_points, original_img.shape)
    
    # 保存或展示结果
    cv2.imwrite("non_uniform_warped.png", warped_img)
    cv2.imshow("Original", original_img)
    cv2.imshow("Non-uniform Warped", warped_img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

调整与扩展

  • 如果需要高度随宽度变化的扭曲,只需要交换x和y的映射逻辑,计算x方向的比例来控制高度变化。
  • 若要实现非线性扭曲(比如弧形收缩),可以将y_ratio替换为非线性函数(如二次函数y_ratio ** 2),让缩放变化更自然。
  • 如果你不需要依赖scipy,也可以用手动实现的双线性插值替换map_coordinates,代码逻辑可参考插值公式自行编写。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 19:44:50