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

如何用Python变换矩阵裁剪经旋转缩放平移后的无黑边图像

解决图像对齐后黑边裁剪问题

要去除平移、旋转、缩放组合变换后产生的黑边,核心是追踪原图像所有顶点经过完整变换后的位置,找到包裹所有有效内容的最小矩形,以此作为裁剪区域。以下是具体实现方案:

关键原理

图像对齐过程包含平移、旋转、缩放三个连续变换,我们可以将这三个变换合并为一个总变换矩阵,然后用这个矩阵计算原图像四个顶点(左上角、右上角、右下角、左下角)变换后的坐标。通过这些坐标的极值(最小/最大x、y),就能确定有效内容的边界,从而精准裁剪掉黑边。

修改后的完整代码

import numpy as np
import cv2
import pandas as pd
import math  # 补充缺失的math模块导入

def alignFromReferenceImage(image1, imgname1, image2, imgname2):
    df = pd.read_csv("./image_metadata.csv", delimiter=';')

    # 优化参考点查找逻辑:直接匹配id列,避免isin的误匹配
    img1_id = imgname1.split('.')[0]
    filter_data = df[df['id'] == img1_id].iloc[0]
    x1_s, y1_s = filter_data['x_s'], filter_data['y_s']
    x1_a, y1_a = filter_data['x_a'], filter_data['y_a']

    img2_id = imgname2.split('.')[0]
    filter_data2 = df[df['id'] == img2_id].iloc[0]
    x2_s, y2_s = filter_data2['x_s'], filter_data2['y_s']
    x2_a, y2_a = filter_data2['x_a'], filter_data2['y_a']

    # 1. 计算平移变换矩阵
    tx = x2_s - x1_s
    ty = y2_s - y1_s
    rows1, cols1 = image1.shape[:2]
    rows2, cols2 = image2.shape[:2]  # 获取原图像2的尺寸
    M_trans = np.float32([[1, 0, -tx], [0, 1, -ty]])

    # 2. 计算旋转缩放变换矩阵
    d1 = math.sqrt((x1_a - x1_s)**2 + (y1_a - y1_s)**2)
    d2 = math.sqrt((x2_a - x2_s)**2 + (y2_a - y2_s)**2)
    scale = d1 / d2

    dx1 = x1_a - x1_s
    dy1 = -(y1_a - y1_s)
    alpha1 = math.degrees(math.atan2(dy1, dx1))
    alpha1 = alpha1 if alpha1 >= 0 else alpha1 + 360

    dx2 = x2_a - x2_s
    dy2 = -(y2_a - y2_s)
    alpha2 = math.degrees(math.atan2(dy2, dx2))
    alpha2 = alpha2 if alpha2 >= 0 else alpha2 + 360

    ang = alpha1 - alpha2
    centre = (x1_s, y1_s)
    M_rot_scale = cv2.getRotationMatrix2D(centre, ang, scale)

    # 3. 合并变换矩阵:先平移,再旋转缩放,总矩阵为 M_rot_scale @ M_trans(齐次坐标下)
    # 补充平移矩阵的齐次维度,方便矩阵乘法
    M_trans_homo = np.vstack([M_trans, [0, 0, 1]])
    M_rot_scale_homo = np.vstack([M_rot_scale, [0, 0, 1]])
    M_total = M_rot_scale_homo @ M_trans_homo
    M_total = M_total[:2, :]  # 转回2x3的OpenCV变换矩阵格式

    # 4. 计算原图像2四个顶点变换后的坐标
    # 原图像2的四个顶点(齐次坐标)
    vertices = np.float32([
        [0, 0, 1],
        [cols2 - 1, 0, 1],
        [cols2 - 1, rows2 - 1, 1],
        [0, rows2 - 1, 1]
    ])
    # 应用总变换
    transformed_vertices = (M_total @ vertices.T).T
    # 提取x和y坐标
    xs = transformed_vertices[:, 0]
    ys = transformed_vertices[:, 1]

    # 5. 确定裁剪边界:取坐标的极值,确保在图像范围内
    min_x = max(int(np.floor(xs.min())), 0)
    max_x = min(int(np.ceil(xs.max())), cols1 - 1)
    min_y = max(int(np.floor(ys.min())), 0)
    max_y = min(int(np.ceil(ys.max())), rows1 - 1)

    # 6. 执行变换和裁剪
    aligned_image = cv2.warpAffine(image2, M_total, (cols1, rows1))
    cropped_image = aligned_image[min_y:max_y+1, min_x:max_x+1]

    return cropped_image

代码说明

  • 变换矩阵合并:将平移、旋转缩放的变换矩阵合并为一个,确保顶点变换计算的准确性,避免两次独立变换带来的误差。
  • 顶点追踪:通过计算原图像四个顶点的变换后位置,精准定位有效内容的边界,这比仅依赖旋转场景的裁剪逻辑更通用,覆盖了平移和缩放的影响。
  • 边界修正:裁剪边界会被限制在目标图像(image1)的尺寸范围内,避免出现超出图像的索引错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 14:25:18