Python/PIL affine transformation

前端 未结 4 1923
庸人自扰
庸人自扰 2020-12-08 05:40

This is a basic transform question in PIL. I\'ve tried at least a couple of times in the past few years to implement this correctly and it seems there is something I don\'t

4条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2020-12-08 06:06

    OK! So I've been working on understanding this all weekend and I think I have an answer that satisfies me. Thank you all for your comments and suggestions!

    I start by looking at this:

    affine transform in PIL python?

    while I see that the author can make arbitrary similarity transformations it does not explain why my code was not working, nor does he explain the spatial layout of the image that we need to transform nor does he provide a linear algebraic solution to my problems.

    But I do see from his code I do see that he's dividing the rotation part of the matrix (a,b,d and e) into the scale which struck me as odd. I went back to read the PIL documentation which I quote:

    "im.transform(size, AFFINE, data, filter) => image

    Applies an affine transform to the image, and places the result in a new image with the given size.

    Data is a 6-tuple (a, b, c, d, e, f) which contain the first two rows from an affine transform matrix. For each pixel (x, y) in the output image, the new value is taken from a position (a x + b y + c, d x + e y + f) in the input image, rounded to nearest pixel.

    This function can be used to scale, translate, rotate, and shear the original image."

    so the parameters (a,b,c,d,e,f) are a transform matrix, but the one that maps (x,y) in the destination image to (a x + b y + c, d x + e y + f) in the source image. But not the parameters of the transform matrix you want to apply, but its inverse. That is:

    • weird
    • different than in Matlab
    • but now, fortunately, fully understood by me

    I'm attaching my code:

    import Image
    import math
    from numpy import matrix
    from numpy import linalg
    
    def rot_x(angle,ptx,pty):
        return math.cos(angle)*ptx + math.sin(angle)*pty
    
    def rot_y(angle,ptx,pty):
        return -math.sin(angle)*ptx + math.cos(angle)*pty
    
    angle = math.radians(45)
    im = Image.open('test.jpg')
    (x,y) = im.size
    xextremes = [rot_x(angle,0,0),rot_x(angle,0,y-1),rot_x(angle,x-1,0),rot_x(angle,x-1,y-1)]
    yextremes = [rot_y(angle,0,0),rot_y(angle,0,y-1),rot_y(angle,x-1,0),rot_y(angle,x-1,y-1)]
    mnx = min(xextremes)
    mxx = max(xextremes)
    mny = min(yextremes)
    mxy = max(yextremes)
    print mnx,mny
    T = matrix([[math.cos(angle),math.sin(angle),-mnx],[-math.sin(angle),math.cos(angle),-mny],[0,0,1]])
    Tinv = linalg.inv(T);
    print Tinv
    Tinvtuple = (Tinv[0,0],Tinv[0,1], Tinv[0,2], Tinv[1,0],Tinv[1,1],Tinv[1,2])
    print Tinvtuple
    im = im.transform((int(round(mxx-mnx)),int(round((mxy-mny)))),Image.AFFINE,Tinvtuple,resample=Image.BILINEAR)
    im.save('outputpython2.jpg')
    

    and the output from python:

    enter image description here

    Let me state the answer to this question again in a final summary:

    PIL requires the inverse of the affine transformation you want to apply.

提交回复
热议问题