6

I have problems with the im.transform method in PIL python library. I thought I figured out the logic of parameters, A to F, however, the resulting image gets rotated in the wrong direction and cut off although all four corners calculated by the bellow function have correct positive values.

Could anybody give me formulas to calculate affine parameters (A to F) from three identical points in both coordinate systems?

def tran (x_pic, y_pic, A, B, C, D, E, F):
  X = A * x_pic + B * y_pic + C
  Y = D * x_pic + E * y_pic + F
  return X, Y
Salvatore
  • 10,815
  • 4
  • 31
  • 69
Matej
  • 932
  • 4
  • 14
  • 22

2 Answers2

15

transform works fine for me. As an example we'll rotate an image around a center different from (0,0) with optional scaling and translation to a new center. Here is how to do it with transform:

def ScaleRotateTranslate(image, angle, center = None, new_center = None, scale = None,expand=False):
    if center is None:
        return image.rotate(angle)
    angle = -angle/180.0*math.pi
    nx,ny = x,y = center
    sx=sy=1.0
    if new_center:
        (nx,ny) = new_center
    if scale:
        (sx,sy) = scale
    cosine = math.cos(angle)
    sine = math.sin(angle)
    a = cosine/sx
    b = sine/sx
    c = x-nx*a-ny*b
    d = -sine/sy
    e = cosine/sy
    f = y-nx*d-ny*e
    return image.transform(image.size, Image.AFFINE, (a,b,c,d,e,f), resample=Image.BICUBIC)
bytefish
  • 3,697
  • 1
  • 29
  • 35
  • In the meantime, I figured it out. I'll also give your example a try. Thx – Matej Oct 08 '11 at 10:52
  • 1
    Expand is non-functional. If True, the first argument to the image.transform() call should be a scaled size, and the translation needs to be redone. I got the first part, but failed at the second. Can you help make expand=True work? – theoden Feb 05 '20 at 01:37
1

I think my version of is much more explicit and easy to understand.

def scale_rotate_translate(image, angle, sr_center=None, displacement=None, scale=None):
    if sr_center is None:
        sr_center = 0, 0
    if displacement is None:
        displacement = 0, 0
    if scale is None:
        scale = 1, 1

    angle = -angle / 180.0 * np.pi

    C = np.array([[1, 0, -sr_center[0]],
                  [0, 1, -sr_center[1]],
                  [0, 0, 1]])

    C_1 = np.linalg.inv(C)

    S = np.array([[scale[0], 0, 0],
                  [0, scale[1], 0],
                  [0,        0, 1]])

    R = np.array([[np.cos(angle), np.sin(angle), 0],
                  [-np.sin(angle), np.cos(angle), 0],
                  [0,                         0, 1]])

    D = np.array([[1, 0, displacement[0]],
                  [0, 1, displacement[1]],
                  [0, 0,            1]])

    Mt = np.dot(D, np.dot(C_1, np.dot(R, np.dot(S, C))))

    a, b, c = Mt[0]
    d, e, f = Mt[1]

    return image.transform(image.size, Image.AFFINE, (a, b, c, d, e, f), resample=Image.BICUBIC)
vish
  • 1,046
  • 9
  • 26
Marat Zakirov
  • 905
  • 1
  • 8
  • 13