MATLAB 默认行为是扩展和集中输出图像,但这种行为是 MATLAB 独有的。
可能有一些我不知道的 Python 等效项,但我想专注于 OpenCV 解决方案。
在 OpenCV 中,您需要计算变换矩阵的系数,并计算输出图像的大小,才能得到与 MATLAB 中相同的结果。
考虑以下实现细节:
- 在 OpenCV 中,变换矩阵相对于 MATLAB 进行了转置(不同的约定)。
- 在 Python 中,第一个索引是 [0, 0],在 MATLAB 中是 [1, 1]。
- 您需要提前计算输出图像的尺寸(宽度和高度)。
您需要输出尺寸以包含整个转换后的图像(转换后的图像的所有角都应进入输出图像)。
我的建议是变换四个角,计算变换后角的max_x - min_x 和max_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 输出图像相同):