使用Pillow (PIL)执行仿射图像变换时偏移方向错误的问题
嘿,我完全懂你现在的困惑!明明对着文档的公式设置了正的c值,想着能把图像往右移,结果反而往左跑了,这实在是容易绕晕人——其实问题出在你对Pillow的transform方法的变换逻辑理解反了!
你看到的文档里说的:
给定仿射参数
[a, b, c, d, e, f],像素的新位置是x_new, y_new = (a*x_old + b*y_old + c, d*x_old + e*y_old + f)
这是前向变换的逻辑:计算原图像的像素会移动到新图像的哪个位置。但Pillow的transform方法用的是逆变换的逻辑——它是反过来的:对于新图像里的每一个像素,它会用这个公式计算「我应该从原图像的哪个位置取像素来填充自己」。
举个直白的例子:
你想把图像右移85像素,意思是新图像里的第85个x坐标位置,应该放原图像第0个x坐标的像素(这样原图像的内容就整体靠右,左边空出来的地方用填充色补上)。那对应逆变换的公式,新图像的x_out对应的原图像x_in应该是x_in = x_out - 85。
而Pillow的仿射参数[a,b,c,d,e,f]对应的逆变换公式是:x_in = a * x_out + b * y_out + cy_in = d * x_out + e * y_out + f
所以代入a=1, b=0的情况,要满足x_in = x_out -85,c的值就必须是**-85**,而不是你原来用的+85。
你之前写的affine_params = [1, 0, 85, 0, 1, 0],按照逆变换逻辑,这意味着新图像的每个x_out像素,都从原图像的x_in = x_out +85位置取像素。比如新图像最左边的x_out=0,会取原图像x_in=85的像素,这样原图像的内容就会被拉到新图像的左侧,看起来就像是整体左移了,这正好和你遇到的现象一致!
把参数改成下面这样,就能得到你想要的右移85像素的效果:
from PIL import Image test_image = Image.open('Test image.png') # 把c改成-85,实现右移 affine_params = [1, 0, -85, 0, 1, 0] trans_image = test_image.transform(test_image.size, Image.AFFINE, affine_params, Image.BILINEAR, fillcolor = (150,150,150)) trans_image.save('Transformed image.png')
最后再给你划几个关键点:
- 记住Pillow的
transform用的是逆变换参数:从输出像素找输入源像素,和你直觉里的「原像素移到新位置」是反过来的 - 方向规则:要实现右移,
c设为负数;左移则设为正数;y方向同理,正的f会让图像上移,负的f会下移 - 不确定的时候可以先试小数值,比如
c=-10,快速验证方向是否正确
内容来源于stack exchange

