如何像在 matlab 中一样在 python 中进行集中仿射变换

how to make centralized affine transform in python like in matlab

我可以在 python 中暗示像 matlab 中的 imtransform 这样的集中化转换吗(看它是精确的语义,它非常相关)。

例如在matlab中: 对于此格式:

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

我得到:

并且在 python 中,在大量的仿射变换方法(piilow、opencv、skimage 和 e.t.c)中,我将其非集中化并剪切:

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

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]]) #  (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)])

我们很幸运得到零差异 - imwarp 在 MATLAB 中的结果给出了微小的差异(但 imtransform 结果与 OpenCV 相同)。


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