当前位置: 首页 > article >正文

图像仿射变换及其逆变换【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

http://www.kler.cn/news/293542.html

相关文章:

  • 如何恢复格式化的 Android 智能手机
  • 使用NetBackup GUI 图形化进行oracle备份和恢复
  • 日志轮转方案和脚本
  • EvoSuite使用总结
  • Java+Swing+sqlserver学生成绩管理系统
  • springboot中上传图片到阿里云的oss云存储
  • CSS学习9[重点]--盒子模型大小、布局稳定性、CSS3盒模型以及盒子阴影
  • 端侧 ChatGPT 时刻到来!面壁小钢炮 3.0 重磅发布
  • Docker 在 Windows 上的使用指南
  • JVM性能调优之5种垃圾收集器
  • 【AI大模型应用开发】1.3 Prompt攻防(安全) 和 Prompt逆向工程
  • 滚珠花键助力生产加工精准化!
  • Python知识点:如何使用Python实现图像分类
  • 【Python】Requests:请求发送
  • log4j2 与 log4j使用时的几点小区别 - log4j2上手说明
  • WebStorm用Debug模式调试Vue等前端项目
  • 如何编写Linux PCI设备驱动器 之一
  • K8s中如何使用etcd进行集群信息的备份与恢复
  • el-table setCurrentRow会触发current-change函数 解决方案
  • php实用命令
  • 12,sql 中分组查询
  • GenBook RK3588一款模块化开源ARM笔记本电脑,具有高达32GB内存和模块化扩展功能
  • Vue3+vite中使用import.meta.glob
  • 【神经网络系列(高级)】神经网络Grokking现象的电路效率公式——揭秘学习飞跃的秘密【通俗理解】
  • STM32+ESP8266+MQTT协议连接阿里云实现温湿度上传
  • vue多环境配置和打包
  • 【基础】Three.js 自定义几何体和复制几何体
  • 研1日记5
  • IP学习——twoday
  • 43. 1 ~ n 整数中 1 出现的次数【难】