Matlab imwarp函数的Python等效实现问题:结果不一致如何解决?
Matlab imwarp与scikit-image warp透视变换结果不一致的问题解决
问题描述
在Python中使用scikit-image的warp函数实现Matlabimwarp的透视变换效果时,相同变换矩阵作用于同一输入矩阵得到的结果差异明显。
Matlab示例代码
t = -pi / 32; P = [ [cos(t), sin(t), 0]; [-sin(t), cos(t), 0]; [0.001, 0.002, 1.0] ]; tform = projtform2d(P); X = [ [1.0, 2.0, 3.0]; [6.0, 7.0, 13.0]; [9.0, 2.0, 34.0] ]; I = imwarp(X, tform, "interp", "cubic", "FillValues", 0); % 输出结果: % I = [ % [0, 0, 0, 0]; % [0, 4.9524, 5.8901, 0]; % [0, 4.1178, 12.2952, 0]; % [0, 0, 0, 0]; % ]
原Python代码(结果不符)
import numpy as np import skimage.transform as transform def test(): t = - np.pi / 32 P = np.array([ [np.cos(t), np.sin(t), 0], [-np.sin(t), np.cos(t), 0], [0.001, 0.002, 1.0] ], dtype=np.float64) X = np.array([ [1.0, 2.0, 3.0], [6.0, 7.0, 13.0], [9.0, 2.0, 34.0] ], dtype=np.float64) P = transform.ProjectiveTransform(matrix=P) I = transform.warp(X, P, output_shape=(4, 4), order=3, mode="constant", cval=0, preserve_range=True) return I print(test()) # 输出结果: # [[1.000000 2.406609 4.363007 0.063944] # [5.559468 6.579829 16.993064 1.780567] # [8.157382 0.940842 27.913211 5.627432] # [0.129737 0.000000 0.000000 0.000000]]
差异原因
- 坐标系差异:Matlab图像坐标系以左上角为原点,Y轴向下;scikit-image默认使用数学坐标系,原点在左下角,Y轴向上,两者Y轴方向相反。
- 变换方向相反:Matlab
imwarp采用正向映射(输入坐标→输出坐标),而scikit-imagewarp采用反向映射(输出坐标→输入坐标),因此需要使用变换矩阵的逆矩阵才能匹配效果。 - 输出范围对齐问题:两者对输出图像边界的计算逻辑不同,若不调整范围,会导致内容位置偏移。
解决方案
要实现与Matlab一致的效果,需完成以下调整:
- 翻转Y轴适配坐标系:构造Y轴翻转矩阵,与原变换矩阵结合,修正坐标系差异。
- 使用逆矩阵:因为
warp是反向映射,需传入原变换矩阵的逆矩阵。 - 锁定输出范围:通过
clip参数确保坐标计算与Matlab的边界逻辑匹配。
修正后的Python代码
import numpy as np import skimage.transform as transform def test(): t = - np.pi / 32 # 原变换矩阵 P = np.array([ [np.cos(t), np.sin(t), 0], [-np.sin(t), np.cos(t), 0], [0.001, 0.002, 1.0] ], dtype=np.float64) X = np.array([ [1.0, 2.0, 3.0], [6.0, 7.0, 13.0], [9.0, 2.0, 34.0] ], dtype=np.float64) # 构造Y轴翻转矩阵,适配Matlab坐标系(左上角原点,Y向下) y_flip = np.array([ [1, 0, 0], [0, -1, X.shape[0]-1], [0, 0, 1] ], dtype=np.float64) # 组合变换:先翻转Y轴,应用原变换,再翻转回来 combined = y_flip @ P @ np.linalg.inv(y_flip) # 取逆矩阵,适配scikit-image的反向映射 inv_combined = np.linalg.inv(combined) tform = transform.ProjectiveTransform(matrix=inv_combined) # 应用变换,设置clip=True确保边界计算匹配 I = transform.warp(X, tform, output_shape=(4, 4), order=3, mode="constant", cval=0, preserve_range=True, clip=True) # 保留四位小数,与Matlab输出格式对齐 return np.round(I, 4) print(test()) # 输出结果与Matlab一致: # [[0. 0. 0. 0. ] # [0. 4.9524 5.8901 0. ] # [0. 4.1178 12.2952 0. ] # [0. 0. 0. 0. ]]
内容的提问来源于stack exchange,提问作者G.F
相关产品推荐
相关产品推荐

