【问题标题】:how to make centralized affine transform in python like in matlab如何像在matlab中一样在python中进行集中仿射变换
【发布时间】:2021-06-02 05:17:51
【问题描述】:

我能在 python 中暗示一个像 matlab 中的 imtransform 那样集中的转换吗(看看它的确切语义,它非常相关)。

例如在 matlab 中: 对于这个 tform:

tform = maketform('affine',[1 0 0; -1 1 0; 0 0 1]);

我得到:

在 python 中,有多种仿射变换方法(piilow、opencv、skimage 和 e.t.c),我得到它是非集中式和剪切的:

如何为 python 库选择我的 3*3 tform 矩阵,以便在这样的倾斜后集中图像?

【问题讨论】:

标签: image image-processing computer-vision cgaffinetransform skew


【解决方案1】:

MATLAB 默认行为是扩展和集中输出图像,但这种行为是 MATLAB 独有的。

可能有一些我不知道的 Python 等效项,但我想专注于 OpenCV 解决方案。
在 OpenCV 中,您需要计算变换矩阵的系数,并计算输出图像的大小,才能得到与 MATLAB 中相同的结果。

考虑以下实现细节:

  • 在 OpenCV 中,变换矩阵相对于 MATLAB 进行了转置(不同的约定)。
  • 在 Python 中,第一个索引是 [0, 0],在 MATLAB 中是 [1, 1]。
  • 您需要提前计算输出图像的尺寸(宽度和高度)。
    您需要输出尺寸以包含整个转换后的图像(转换后的图像的所有角都应进入输出图像)。
    我的建议是变换四个角,计算变换后角的max_x - min_xmax_y - min_y
  • 为了集中输出,您需要计算平移系数(OpenCV 矩阵中的最后一列)。
    假设:源中心被转换(移动)到目标中心。
    为了计算平移,您可以使用逆变换,并计算从源中心到目标中心的平移(以像素为单位)。

这是一个 Python 代码示例(使用 OpenCV):

import numpy as np
import cv2

# Read input image
src_im = cv2.imread('peppers.png')

# Build a transformation matrix (the transformation matrix is transposed relative to MATLAB)
t = np.float32([[1, -1, 0],
                [0,  1, 0],
                [0,  0, 1]])

# Use only first two rows (affine transformation assumes last row is [0, 0, 1])
#trans = np.float32([[1, -1, 0],
#                    [0,  1, 0]])
trans = t[0:2, :]

inv_t = np.linalg.inv(t)
inv_trans = inv_t[0:2, :]

# get the sizes
h, w = src_im.shape[:2]

# Transfrom the 4 corners of the input image
src_pts = np.float32([[0, 0], [w-1, 0], [0, h-1], [w-1, h-1]]) # https://stackoverflow.com/questions/44378098/trouble-getting-cv-transform-to-work (see comment).
dst_pts = cv2.transform(np.array([src_pts]), trans)[0]

min_x, max_x = np.min(dst_pts[:, 0]), np.max(dst_pts[:, 0])
min_y, max_y = np.min(dst_pts[:, 1]), np.max(dst_pts[:, 1])

# Destination matrix width and height
dst_w = int(max_x - min_x + 1) # 895
dst_h = int(max_y - min_y + 1) # 384

# Inverse transform the center of destination image, for getting the coordinate on the source image.
dst_center = np.float32([[(dst_w-1.0)/2, (dst_h-1.0)/2]])
src_projected_center = cv2.transform(np.array([dst_center]), inv_trans)[0]

# Compute the translation of the center - assume source center goes to destination center
translation = src_projected_center - np.float32([[(w-1.0)/2, (h-1.0)/2]])

# Place the translation in the third column of trans
trans[:, 2] = translation

# Transform
dst_im = cv2.warpAffine(src_im, trans, (dst_w, dst_h))

# Show dst_im as output
cv2.imshow('dst_im', dst_im)
cv2.waitKey()
cv2.destroyAllWindows()

# Store output for testing
cv2.imwrite('dst_im.png', dst_im)

比较结果的MATLAB代码:

I = imread('peppers.png');

tform = maketform('affine',[1 0 0; -1 1 0; 0 0 1]);
J = imtransform(I, tform);
figure;imshow(J)

% MATLAB recommends using affine2d and imwarp instead of maketform and imtransform.
% tform = affine2d([1 0 0; -1 1 0; 0 0 1]);
% J = imwarp(I, tform);
% figure;imshow(J)

pyJ = imread('dst_im.png');
figure;imagesc(double(rgb2gray(J)) - double(rgb2gray(pyJ)));
title('MATLAB - Python Diff');impixelinfo
max_abs_diff = max(imabsdiff(J(:), pyJ(:)));
disp(['max_abs_diff = ', num2str(max_abs_diff)])

我们很幸运能够获得零差异 - MATLAB 中 imwarp 的结果存在细微差异(但 imtransform 的结果与 OpenCV 相同)。


Python 输出图像(与 MATLAB 输出图像相同):

【讨论】:

    猜你喜欢
    • 2016-01-07
    • 2022-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-08
    相关资源
    最近更新 更多