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

问题描述

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

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

select *
from TableA
where not exists ( select 1 from table2 
                   where table1.studentid = tableb.studentid 
                   and schoolcol = 'college'
                 )

我得到:

enter image description here

并且在 python 中的各种仿射变换方法(piilow、opencv、skimage 和 e.t.c)中,我得到了非集中和剪切:

enter image description here

如何为 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,1]])

# Use only first two rows (affine transformation assumes last row is [0,1])
#trans = np.float32([[1,#                    [0,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,[w-1,h-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]),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 输出图像相同):
enter image description here