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

Chuong98: <p>In TensorFlow, one can define shearing in x and y direction independently, such as:</p>
<pre><code class="lang-auto">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
</code></pre>
<p>However, in Pytorch, there is only 1 option, such as:</p>
<pre><code class="lang-auto">import torchvision.transforms.functional as TF
image = TF.affine(image,degrees=0,translate=None,scale=None,shear=level)
</code></pre>
<p>How to do it appropriately with Pytorch? Thank you</p>

ptrblck: <p>I think this functionality could be added in <a href="https://github.com/pytorch/vision/blob/867e5b4e7835dbebcf0c501850a7b08e466496f1/torchvision/transforms/functional.py#L717" rel="nofollow noopener">_get_inverse_affine_matrix</a> by providing the <code>shear</code> argument as a <code>list</code> or <code>tuple</code>.<br>
These would probably be the necessary changes:</p>
<pre><code class="lang-python">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
</code></pre>
<p>CC <a class="mention" href="/u/fmassa">@fmassa</a><br>
Let me know, if that looks good and I could create a PR for it.</p>

fmassa: <p>This seems good to me at first, could you open a PR in torchvision and we can discuss further?</p>

ptrblck: <p><a class="mention" href="/u/chuong98">@Chuong98</a> the PR is <a href="https://github.com/pytorch/vision/pull/1070#pullrequestreview-257344528" rel="nofollow noopener">merged</a> so you could build <code>torchvision</code> from master to enable shear parallel to the x- and y-axis.</p>

Chuong98: <p>many thanks for your  prompt reply</p>