图像仿射变换及其逆变换【Python实现】

详细步骤及示例代码

假设我们有8x8个点及其变换后的坐标,下面的代码展示了如何根据这些点还原放射变换矩阵:

# -*- coding: utf-8 -*-
'''
@Time    :   2024/09/06 16:43:10
@Author  :   wydxry
'''


import numpy as np
import cv2
from PIL import Image
import matplotlib.pyplot as plt

def generate_grid_points(image_size, grid_size):
    """
    生成均匀分布的网格点坐标
    """
    x = np.linspace(0, image_size[0] - 1, grid_size[0])
    y = np.linspace(0, image_size[1] - 1, grid_size[1])
    xv, yv = np.meshgrid(x, y)
    return np.vstack([xv.ravel(), yv.ravel()]).T


def random_affine_transform_matrix():
    """
    生成一个随机的放射变换矩阵
    """
    theta = np.random.uniform(-0.5, 0.5)  # 旋转角度
    tx = np.random.uniform(-50, 50)  # 平移 x
    ty = np.random.uniform(-50, 50)  # 平移 y
    matrix = np.array([
        [np.cos(theta), -np.sin(theta), tx],
        [np.sin(theta), np.cos(theta), ty],
        [0, 0, 1]
    ])
    return matrix

def apply_affine_transform(image, matrix):
    """
    应用放射变换到图像
    """
    rows, cols = image.shape[:2]
    return cv2.warpAffine(image, matrix[:2], (cols, rows))

def inverse_affine_transform(matrix):
    """
    计算放射变换矩阵的逆矩阵
    """
    print("matrix shape: ", matrix.shape)
    inverse_matrix = np.linalg.inv(matrix)
    return inverse_matrix

def apply_inverse_affine_transform(image, matrix):
    """
    应用逆放射变换到图像
    """
    inverse_matrix = inverse_affine_transform(matrix)
    print(inverse_matrix)
    rows, cols = image.shape[:2]
    return cv2.warpAffine(image, inverse_matrix[:2], (cols, rows))

def apply_inverse_affine_transform_to_points(points, matrix):
    """
    应用逆放射变换到点坐标
    """
    inverse_matrix = inverse_affine_transform(matrix)
    ones = np.ones((points.shape[0], 1))
    homogeneous_points = np.hstack([points, ones])
    original_points = (inverse_matrix @ homogeneous_points.T).T
    return original_points[:, :2]

def estimate_affine_transform(original_points, transformed_points):
    """
    根据原始点和变换后的点估计放射变换矩阵
    """
    assert original_points.shape == transformed_points.shape
    assert original_points.shape[0] >= 3  # 至少需要三个点来计算放射变换

    # 生成方程组的矩阵
    A = []
    B = []

    for (x, y), (x_prime, y_prime) in zip(original_points, transformed_points):
        A.append([x, y, 1, 0, 0, 0])
        A.append([0, 0, 0, x, y, 1])
        B.append(x_prime)
        B.append(y_prime)
    
    A = np.array(A)
    B = np.array(B)
    
    # 求解线性方程组
    X = np.linalg.lstsq(A, B, rcond=None)[0]
    
    # 构造放射变换矩阵
    matrix = np.array([
        [X[0], X[1], X[2]],
        [X[3], X[4], X[5]],
        [0, 0, 1]
    ])

    return matrix

def apply_affine_transform(image, matrix):
    """
    应用放射变换到图像
    """
    rows, cols = image.shape[:2]
    return cv2.warpAffine(image, matrix[:2], (cols, rows))

def apply_affine_transform_to_points(points, matrix):
    """
    应用放射变换到点坐标
    """
    ones = np.ones((points.shape[0], 1))
    homogeneous_points = np.hstack([points, ones])
    transformed_points = (matrix @ homogeneous_points.T).T
    return transformed_points[:, :2]

# 生成均匀分布的8x8坐标点
image_size = (2048, 2048)
grid_size = (8, 8)

# 读取图像
image_path = '1.jpg'
image = np.array(Image.open(image_path).resize(image_size))

# 随机生成放射变换矩阵
affine_matrix = random_affine_transform_matrix()
print("Affine Transform Matrix:\n", affine_matrix)

# 应用变换到图像
transformed_image = apply_affine_transform(image, affine_matrix)

# 假设原始点和变换后的点
original_points = generate_grid_points(image_size, grid_size)
transformed_points = apply_affine_transform_to_points(original_points, affine_matrix)

# 估计放射变换矩阵
estimated_affine_matrix = estimate_affine_transform(original_points, transformed_points)
print("Estimated Affine Transform Matrix:\n", estimated_affine_matrix)

# 验证:应用估计的矩阵到图像
restored_image = apply_affine_transform(image, estimated_affine_matrix)

# 显示结果
fig, ax = plt.subplots(1, 3, figsize=(18, 6))

# 显示原始图像和坐标
ax[0].imshow(image)
ax[0].scatter(original_points[:, 0], original_points[:, 1], color='red', label='Original Points')
ax[0].set_title('Original Image with Points')

# 显示变换后的图像和新坐标
ax[1].imshow(transformed_image)
ax[1].scatter(transformed_points[:, 0], transformed_points[:, 1], color='blue', label='Transformed Points')
ax[1].set_title('Transformed Image with Points')

# 显示估计的变换后的图像
ax[2].imshow(restored_image)
ax[2].scatter(transformed_points[:, 0], transformed_points[:, 1], color='green', label='Estimated Points')
ax[2].set_title('Restored Image with Estimated Points')

plt.show()
plt.savefig("result.jpg")


# 显示结果
fig, ax = plt.subplots(1, 3, figsize=(18, 6))

# 显示原始图像
ax[0].imshow(transformed_image, cmap='gray')
ax[0].set_title('Original Image')
ax[0].axis('off')

# 显示变换后的图像
ax[1].imshow(restored_image, cmap='gray')
ax[1].set_title('Transformed Image')
ax[1].axis('off')

# 显示差异图像
ax[2].imshow(restored_image - transformed_image, cmap='gray')
ax[2].set_title('Difference Image')
ax[2].axis('off')

plt.show()
plt.savefig("compare.jpg")

实验结果

在这里插入图片描述
在这里插入图片描述

解释

  1. 估计放射变换矩阵

    • estimate_affine_transform 函数根据原始点和变换后点的对应关系,建立方程组并求解,从而估计放射变换矩阵。
    • 方程组的建立基于放射变换的线性关系 ( (x', y', 1)^T = \text{matrix} \cdot (x, y, 1)^T )。
  2. 应用变换

    • apply_affine_transform 将估计的放射变换矩阵应用于图像。
    • apply_affine_transform_to_points 将估计的放射变换矩阵应用于点坐标。
  3. 验证结果

    • 显示原始图像、变换后的图像和应用估计的变换后的图像,并标记相应的点坐标。

注意事项

  • 至少需要三个非共线的点来计算放射变换矩阵,但在实际应用中,使用更多点可以提高估计的精度。
  • 确保你的环境中已经安装了 numpycv2(OpenCV)、PILmatplotlib
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wydxry

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值