Repository: kornia/kornia (Python)

Issue:
Affine shear matrix not properly computed around center point
This fix in this pull request: https://github.com/kornia/kornia/pull/612 isn't quite right. There's a negative sign missing in m23 when calculating the shear_mat. It should be:
```
shear_mat = torch.stack(
    [ones, -sx_tan, sx_tan * y, -sy_tan, ones + sx_tan * sy_tan, sy_tan * (x - sx_tan * y)], dim=-1  # type: ignore
).view(-1, 2, 3)
```

_Originally posted by @grosssoftware in https://github.com/kornia/kornia/issues/612#issuecomment-1117798930_


Discussion:
@grosssoftware could you file a PR with the fix ? and provide a test to verify



Patch:
diff --git a/kornia/augmentation/_2d/geometric/shear.py b/kornia/augmentation/_2d/geometric/shear.py
index f10e9e1572..802442c704 100644
--- a/kornia/augmentation/_2d/geometric/shear.py
+++ b/kornia/augmentation/_2d/geometric/shear.py
@@ -40,15 +40,15 @@ class RandomShear(GeometricAugmentationBase2D):
         >>> aug = RandomShear((-5., 2., 5., 10.), p=1.)
         >>> out = aug(input)
         >>> out, aug.transform_matrix
-        (tensor([[[[0.4420, 0.7598, 0.1536],
-                  [0.1740, 0.3095, 0.6121],
-                  [0.4450, 0.8892, 0.4045]]]]), tensor([[[ 1.0000,  0.0100, -0.0100],
-                 [-0.1183,  0.9988,  0.1171],
+        (tensor([[[[0.4403, 0.7614, 0.1516],
+                  [0.1753, 0.3074, 0.6127],
+                  [0.4438, 0.8924, 0.4061]]]]), tensor([[[ 1.0000,  0.0100, -0.0100],
+                 [-0.1183,  0.9988,  0.1194],
                  [ 0.0000,  0.0000,  1.0000]]]))
         >>> aug.inverse(out)
-        tensor([[[[0.4068, 0.7549, 0.1404],
-                  [0.2051, 0.3111, 0.5562],
-                  [0.3985, 0.8816, 0.4257]]]])
+        tensor([[[[0.4045, 0.7577, 0.1393],
+                  [0.2071, 0.3074, 0.5582],
+                  [0.3958, 0.8868, 0.4265]]]])
 
     To apply the exact augmenation again, you may take the advantage of the previous parameter state:
         >>> input = torch.randn(1, 3, 32, 32)
diff --git a/kornia/geometry/transform/imgwarp.py b/kornia/geometry/transform/imgwarp.py
index 20fb76ec29..e54ef0ac74 100644
--- a/kornia/geometry/transform/imgwarp.py
+++ b/kornia/geometry/transform/imgwarp.py
@@ -660,9 +660,9 @@ def get_shear_matrix2d(center: Tensor, sx: Optional[Tensor] = None, sy: Optional
     sx_tan = torch.tan(sx)
     sy_tan = torch.tan(sy)
     ones = torch.ones_like(sx)
-    shear_mat = stack([ones, -sx_tan, sx_tan * y, -sy_tan, ones + sx_tan * sy_tan, sy_tan * (sx_tan * y + x)], -1).view(
-        -1, 2, 3
-    )
+    shear_mat = stack(
+        [ones, -sx_tan, sx_tan * y, -sy_tan, ones + sx_tan * sy_tan, sy_tan * (x - sx_tan * y)], dim=-1
+    ).view(-1, 2, 3)
 
     shear_mat = convert_affinematrix_to_homography(shear_mat)
     return shear_mat


Test patch:
diff --git a/test/geometry/transform/test_affine.py b/test/geometry/transform/test_affine.py
index 8c4e11a0aa..0a52f4e7e0 100644
--- a/test/geometry/transform/test_affine.py
+++ b/test/geometry/transform/test_affine.py
@@ -698,7 +698,7 @@ def test_compose_affine_matrix_3x3(self, device, dtype):
         batch_size, _, height, width = 1, 1, 96, 96
         angle, translations = 6.971339922894188, (0.0, -4.0)
         scale, shear = [0.7785685905190581, 0.7785685905190581], [11.8235607082617, 7.06797949691645]
-        matrix_expected = T([[1.27536969, 4.26828945e-01, -3.2876e01], [2.18297196e-03, 1.29424165e00, -1.1717e01]])
+        matrix_expected = T([[1.27536969, 4.26828945e-01, -3.2349e01], [2.18297196e-03, 1.29424165e00, -9.1996e00]])
         center = T([float(width), float(height)]).view(1, 2) / 2.0 + 0.5
         center = center.expand(batch_size, -1)
         matrix_kornia = kornia.geometry.transform.get_affine_matrix2d(
@@ -731,3 +731,21 @@ def test_smoke(self, device, dtype):
 
         out = kornia.geometry.transform.warp_affine(img, affine_mat[:, :2], (H, W))
         assert_close(out, expected)
+
+
+class TestGetShearMatrix:
+    def test_get_shear_matrix2d_with_controlled_values(self, device, dtype):
+        # Define controlled values for shear angles and center
+        sx = torch.tensor([0.5], device=device, dtype=dtype)
+        sy = torch.tensor([0.25], device=device, dtype=dtype)
+        center = torch.tensor([[0.0, 0.0]], device=device, dtype=dtype)
+
+        # Calculate the shear matrix using your function
+        out = kornia.geometry.transform.get_shear_matrix2d(center, sx=sx, sy=sy)
+
+        # Define the expected shear matrix with controlled numbers
+        expected = torch.tensor(
+            [[[1.0, -0.5463, 0.0], [-0.2553, 1.1395, 0.0], [0.0, 0.0, 1.0]]], device=device, dtype=dtype
+        )
+
+        assert_close(out, expected, atol=1e-4, rtol=1e-4)