如何用Python沿任意直线拉伸图像或绕任意点缩放?
图像沿指定方向相对于不变直线的仿射拉伸实现
问题背景
现有一张128x128的2D numpy.ndarray热力图,已知:
- 图像上一点
P = (x0, y0) - 方向向量
v = [v0, v1] - 直线
L:过点P且与v垂直 - 缩放因子
s(百分比形式)
需求是沿v方向、以比例s将图像远离直线L拉伸,直线L上的点变换后位置不变:
- s为正时,所有点远离L
- s为负时,所有点向L靠近
同时要求:
- 仅修改图像内容,保持128x128尺寸不变
- 变换前后直线L在图像中的位置不变(视野不变)
当L过原点时,这是简单的线性变换,但L不一定过原点,因此需要用仿射变换实现。
已尝试的方法及问题
cv2.resize:仅支持过原点的线性变换,且必须调整图像实际尺寸,不符合需求。
cv2.getAffineTransform + cv2.warpAffine:
尝试通过选取共线点生成变换矩阵,代码如下:def get_transformation_matrix(pt1 : tuple[float, float], pt2 : tuple[float, float], scale_factor : float) -> np.ndarray: """Returns the transformation matrix to scale an image along the line containing `pt1` and `pt2`, centered at their midpoint, by `scale_factor` (a percentage increase/decrease).""" # 从pt1到pt2的向量,除以2(即pt1到中点/中点到pt2的向量) slope_vector = np.array([pt2[0] - pt1[0], pt2[1] - pt1[1]]) / 2 # 两点的中点 center = np.array([(pt2[0] - pt1[0]) / 2 + pt1[0], (pt2[1] - pt1[1]) / 2 + pt1[1]]) # 变换后的新点:中点±缩放后的slope_vector new_pt1 = center - slope_vector * (1 + scale_factor / 100) new_pt2 = center + slope_vector * (1 + scale_factor / 100) initial_points = np.float32([pt1, center, pt2]) final_points = np.float32([new_pt1, center, new_pt2]) return cv2.getAffineTransform(initial_points, final_points) M = get_transformation_matrix([100, 100], [200, 100], 10) print(M) dst = cv2.warpAffine(data, M, data.shape)但得到的变换矩阵
M是全零矩阵[[0. 0. 0.] [0. 0. 0.]],输出图像dst全黑。推测是因为cv2.getAffineTransform需要三组不共线的点(构成三角形)来计算仿射矩阵,而选取的三个点共线导致无法生成有效矩阵。scipy.ndimage.affine_transform:看起来可行,但不清楚如何推导对应的变换矩阵和偏移量。
相关子问题
如果需求改为绕点P进行均匀缩放,是否和上述直线拉伸的逻辑类似,只是不需要区分L方向的单位向量?特此确认。
内容的提问来源于stack exchange,提问作者Nik3141
相关产品推荐
相关产品推荐

