Repository: kornia/kornia

Issue:
[Bug] RandomCrop returns padded image when p=0
## 🐛 Bug

`RandomCrop` returns the padded image when p=0, Probably `RandomCrop3D` is also affected.



Discussion:
They are the same logic. So, the same error I think.

I am not sure how to fix this one since torch does not support ragged tensor. We cannot partially pad a tensor there. What solution are you suggesting?
I got one idea for this. I would suggest having some sort of ```unpad_if_nessary``` to remove the padding in the end.
```python
def forward(self, input):
    shape = input.shape
    input = self.pad_if_nessary(input)
    input = crop(input)
    input = self.unpad_if_nessary(input, shape)
    return input
```
or `crop_and_pad` with `keepshape` or `keepdim` flag
This also opens the question of the need for a more  specific image padding function like `make_border`
https://stackoverflow.com/questions/43391205/add-padding-to-images-to-get-them-into-the-same-shape
is this still relevant ?
> is this still relevant ?

Hasn't been fixed yet. 

Resolving patch:
diff --git a/kornia/augmentation/augmentation.py b/kornia/augmentation/augmentation.py
--- a/kornia/augmentation/augmentation.py
+++ b/kornia/augmentation/augmentation.py
@@ -786,12 +786,21 @@ def apply_transform(self, input: torch.Tensor, params: Dict[str, torch.Tensor])
     def forward(self, input: Union[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]],
                 params: Optional[Dict[str, torch.Tensor]] = None, return_transform: Optional[bool] = None
                 ) -> Union[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]]:
-        if type(input) == tuple:
-            input = (self.precrop_padding(input[0]), input[1])
+        if isinstance(input, (tuple, list)):
+            _input = (self.precrop_padding(input[0]), input[1])
         else:
-            input = cast(torch.Tensor, input)
-            input = self.precrop_padding(input)
-        return super().forward(input, params, return_transform)
+            input = cast(torch.Tensor, input)  # TODO: weird that cast is not working under this context.
+            _input = self.precrop_padding(input)  # type: ignore
+        out = super().forward(_input, params, return_transform)
+        if not self._params['batch_prob'].all():
+            # undo the pre-crop if nothing happened.
+            if isinstance(out, tuple) and isinstance(input, tuple):
+                return input[0], out[1]
+            elif isinstance(out, tuple) and not isinstance(input, tuple):
+                return input, out[1]
+            else:
+                return input
+        return out
 
 
 class RandomResizedCrop(AugmentationBase2D):
diff --git a/kornia/augmentation/base.py b/kornia/augmentation/base.py
--- a/kornia/augmentation/base.py
+++ b/kornia/augmentation/base.py
@@ -40,7 +40,7 @@ def __init__(self, p: float = 0.5, p_batch: float = 1., same_on_batch: bool = Fa
         self.p_batch = p_batch
         self.same_on_batch = same_on_batch
         self.keepdim = keepdim
-        self._params = None  # type: Union[None,Dict[str, torch.Tensor]]
+        self._params: Dict[str, torch.Tensor] = {}
         if p != 0. or p != 1.:
             self._p_gen = Bernoulli(self.p)
         if p_batch != 0. or p_batch != 1.:


Test patch:
diff --git a/test/augmentation/test_augmentation.py b/test/augmentation/test_augmentation.py
--- a/test/augmentation/test_augmentation.py
+++ b/test/augmentation/test_augmentation.py
@@ -2056,6 +2056,36 @@ def test_padding_batch_3(self, device, dtype):
 
         assert_allclose(out, expected, atol=1e-4, rtol=1e-4)
 
+    def test_padding_no_forward(self, device, dtype):
+        torch.manual_seed(0)
+        inp = torch.tensor([[[
+            [3., 4., 5.],
+            [6., 7., 8.]
+        ]]], device=device, dtype=dtype)
+        trans = torch.tensor([[
+            [1., 2., 3.],
+            [3., 4., 5.],
+            [6., 7., 8.]
+        ]], device=device, dtype=dtype)
+        # Not return transform
+        rc = RandomCrop(size=(2, 3), padding=(0, 1, 2, 3), fill=9, align_corners=True, p=0.)
+
+        out = rc(inp)
+        assert_allclose(out, inp, atol=1e-4, rtol=1e-4)
+
+        out = rc((inp, trans))
+        assert_allclose(out[0], inp, atol=1e-4, rtol=1e-4)
+        assert_allclose(out[1], trans, atol=1e-4, rtol=1e-4)
+
+        # with return transform
+        rc = RandomCrop(size=(2, 3), padding=(0, 1, 2, 3), fill=9, align_corners=True, p=0., return_transform=True)
+        out = rc(inp)
+        assert_allclose(out[0], inp, atol=1e-4, rtol=1e-4)
+
+        out = rc((inp, trans))
+        assert_allclose(out[0], inp, atol=1e-4, rtol=1e-4)
+        assert_allclose(out[1], trans, atol=1e-4, rtol=1e-4)
+
     def test_pad_if_needed(self, device, dtype):
         torch.manual_seed(0)
         batch_size = 2