How to use torchvision transform shearing for x and y direction?

In TensorFlow, one can define shearing in x and y direction independently, such as:

image = tf.contrib.image.transform(image, [1., level, 0., 0., 1., 0., 0., 0.]) #x direction 
image = tf.contrib.image.transform(image, [1., 0., 0., level, 1., 0., 0., 0.]) #y direction

However, in Pytorch, there is only 1 option, such as:

import torchvision.transforms.functional as TF
image = TF.affine(image,degrees=0,translate=None,scale=None,shear=level)

How to do it appropriately with Pytorch? Thank you

I think this functionality could be added in _get_inverse_affine_matrix by providing the shear argument as a list or tuple.
These would probably be the necessary changes:

def _get_inverse_affine_matrix(center, angle, translate, scale, shear):
    # Helper method to compute inverse matrix for affine transformation

    # As it is explained in PIL.Image.rotate
    # We need compute INVERSE of affine transformation matrix: M = T * C * RSS * C^-1
    # where T is translation matrix: [1, 0, tx | 0, 1, ty | 0, 0, 1]
    #       C is translation matrix to keep center: [1, 0, cx | 0, 1, cy | 0, 0, 1]
    #       RSS is rotation with scale and shear matrix
    #       RSS(a, scale, shear) = [ cos(a)*scale    -sin(a + shear)*scale     0]
    #                              [ sin(a)*scale    cos(a + shear)*scale     0]
    #                              [     0                  0          1]
    # Thus, the inverse is M^-1 = C * RSS^-1 * C^-1 * T^-1

    if isinstance(shear, (tuple, list)) and len(shear) == 2:
        shear[0] = math.radians(shear[0])
        shear[1] = math.radians(shear[1])
    else:
        shear = math.radians(shear)    
        shear = [shear, shear]

    angle = math.radians(angle)
    scale = 1.0 / scale

    # Inverted rotation matrix with scale and shear
    d = math.cos(angle + shear[0]) * math.cos(angle + shear[1]) + math.sin(angle + shear[0]) * math.sin(angle + shear[1])
    matrix = [
        math.cos(angle + shear[0]), math.sin(angle + shear[0]), 0,
        -math.sin(angle + shear[1]), math.cos(angle + shear[1]), 0
    ]
    matrix = [scale / d * m for m in matrix]

    # Apply inverse of translation and of center translation: RSS^-1 * C^-1 * T^-1
    matrix[2] += matrix[0] * (-center[0] - translate[0]) + matrix[1] * (-center[1] - translate[1])
    matrix[5] += matrix[3] * (-center[0] - translate[0]) + matrix[4] * (-center[1] - translate[1])

    # Apply center translation: C * RSS^-1 * C^-1 * T^-1
    matrix[2] += center[0]
    matrix[5] += center[1]
    return matrix

CC @fmassa
Let me know, if that looks good and I could create a PR for it.

This seems good to me at first, could you open a PR in torchvision and we can discuss further?

1 Like

@Chuong98 the PR is merged so you could build torchvision from master to enable shear parallel to the x- and y-axis.

2 Likes

many thanks for your prompt reply