skimage.transform.warp与cv2.warpPerspective结果不一致问题排查
问题
近期遇到一个问题:skimage几何变换与OpenCV中对应函数存在差异。尝试用cv2.warpPerspective替换示例中的skimage.transform.warp函数,二者默认参数(如borderMode、borderValue)看似一致,但输出结果却不相同,请问忽略了什么?
代码示例
import numpy as np import skimage.transform import cv2 import matplotlib.pyplot as plt img = np.random.rand(16,16) angle = np.deg2rad(45) cos_a, sin_a = np.cos(angle), np.sin(angle) R = np.array([[cos_a, sin_a, -11 * (cos_a + sin_a - 1)], [-sin_a, cos_a, -11 * (cos_a - sin_a - 1)], [0, 0, 1]]) skimage_rotated = skimage.transform.warp(img, R, clip=False) cv2_rotated = cv2.warpPerspective(img, R, dsize=skimage_rotated.shape) print(np.count_nonzero(np.where(np.abs(skimage_rotated - cv2_rotated) > 1e-1))) # 输出356 plt.imshow(np.abs(skimage_rotated - cv2_rotated)) plt.show()
结果差异可视化

原因与解决方案
二者结果差异主要来自三个容易忽略的核心区别:
变换矩阵的映射方向相反
skimage的transform.warp采用反向映射逻辑:为输出图像的每个像素计算其对应输入图像的位置,传入的矩阵是用于从输出坐标反推输入坐标的逆变换矩阵。而OpenCV的warpPerspective采用正向映射逻辑:直接用传入的矩阵将输入像素坐标映射到输出坐标。因此给OpenCV传入的矩阵应为原矩阵的逆矩阵。输出尺寸的参数格式不同
OpenCV的dsize参数格式是(宽度, 高度)(对应图像列数、行数),而skimage输出图像的shape是(行数, 列数)。原代码直接传入skimage_rotated.shape会导致尺寸对应错误,需要交换维度顺序。插值计算的细节差异
即使修正上述两点,仍可能存在微小数值差异:skimage默认双线性插值的实现细节与OpenCV的INTER_LINEAR(默认插值方式)略有不同,但这种差异通常在1e-5量级,不会出现原代码中大于0.1的显著差异。
修正后的完整代码:
import numpy as np import skimage.transform import cv2 import matplotlib.pyplot as plt img = np.random.rand(16,16) angle = np.deg2rad(45) cos_a, sin_a = np.cos(angle), np.sin(angle) R = np.array([[cos_a, sin_a, -11 * (cos_a + sin_a - 1)], [-sin_a, cos_a, -11 * (cos_a - sin_a - 1)], [0, 0, 1]]) skimage_rotated = skimage.transform.warp(img, R, clip=False) # 修正矩阵和尺寸参数 R_inv = np.linalg.inv(R) cv2_rotated = cv2.warpPerspective(img, R_inv, dsize=(skimage_rotated.shape[1], skimage_rotated.shape[0]), borderMode=cv2.BORDER_CONSTANT, borderValue=0) print(np.count_nonzero(np.where(np.abs(skimage_rotated - cv2_rotated) > 1e-5))) # 差异像素数大幅减少 plt.imshow(np.abs(skimage_rotated - cv2_rotated)) plt.show()
内容的提问来源于stack exchange,提问作者Pazu
相关产品推荐
相关产品推荐

