Repository: Project-MONAI/MONAI

Issue:
Inquiry Regarding Functionality of CropForeground in MONAI Library
I have been using the CropForeground function to perform background segmentation for extracting foreground information. However, after the cropping operation, I've noticed that the original bounding box coordinates for the background are lost. I am inquiring whether there is a solution within MONAI to perform padding on the cropped background to a specific size while preserving the original background information.

In essence, I aim to pad the cropped background to a predetermined size based on the cropping operation, ensuring retention of the original background information. I would greatly appreciate your guidance or insights regarding any methods or alternative functions within MONAI that could address this requirement.

Thank you for your time and consideration in addressing this query.
`lazy` ignored in `SpatialPadd`
Since lazy is always overridden by the parent class, specifying `lazy=true` in the `SpatialPadd` constructor does not work. Similar issue in `BorderPadd` and `DivisiblePadd`.
https://github.com/Project-MONAI/MONAI/blob/b1c8b42d03bf3c1daabd6c39a35fcbdadb57e8b0/monai/transforms/croppad/dictionary.py#L279
https://github.com/Project-MONAI/MONAI/blob/b1c8b42d03bf3c1daabd6c39a35fcbdadb57e8b0/monai/transforms/croppad/dictionary.py#L129

_Originally posted by @77QiZhang in https://github.com/Project-MONAI/MONAI/issues/7314#issuecomment-1853177113_


Discussion:
the following code snippet related to my issue

import logging
import sys
import torch
import matplotlib.pyplot as plt
import json

from monai.config import print_config
from monai.data import Dataset
from monai.transforms import (
    Compose,
    LoadImaged,
    EnsureChannelFirstd,
    EnsureTyped,
    CropForegroundd,
    SpatialPadd,
)


logging.basicConfig(stream=sys.stdout, level=logging.INFO)
print_config()
![version](https://github.com/Project-MONAI/MONAI/assets/113111417/10e1fffd-5d4b-4351-bf05-a7a681fa731a)

train_json_path = 'my_data_path.json'

train_transforms = Compose([
    LoadImaged(keys=["image", "label"]),
    EnsureChannelFirstd(keys=["image", "label"]),
    EnsureTyped(keys=["image"], dtype=torch.float32),
    CropForegroundd(keys=["image"], source_key="label", lazy=True),
    SpatialPadd(keys=["image"], spatial_size=(128,96,32), mode='median', lazy=True),
])

train_data = json.load(open(train_json_path))
train_ds = Dataset(
        data=train_data,
        transform=train_transforms,
    )   
for data in train_ds:
    image = data['image']
    plt.imshow(image[0,0,:,:], cmap='gray')
    plt.show()
    break

![plt_show](https://github.com/Project-MONAI/MONAI/assets/113111417/43733a46-09fc-4b73-902e-cad495b915d8)



Resolving patch:
diff --git a/monai/transforms/croppad/dictionary.py b/monai/transforms/croppad/dictionary.py
--- a/monai/transforms/croppad/dictionary.py
+++ b/monai/transforms/croppad/dictionary.py
@@ -221,9 +221,8 @@ def __init__(
                 note that `np.pad` treats channel dimension as the first dimension.
 
         """
-        LazyTransform.__init__(self, lazy)
         padder = SpatialPad(spatial_size, method, lazy=lazy, **kwargs)
-        Padd.__init__(self, keys, padder=padder, mode=mode, allow_missing_keys=allow_missing_keys)
+        Padd.__init__(self, keys, padder=padder, mode=mode, allow_missing_keys=allow_missing_keys, lazy=lazy)
 
 
 class BorderPadd(Padd):
@@ -274,9 +273,8 @@ def __init__(
                 note that `np.pad` treats channel dimension as the first dimension.
 
         """
-        LazyTransform.__init__(self, lazy)
         padder = BorderPad(spatial_border=spatial_border, lazy=lazy, **kwargs)
-        Padd.__init__(self, keys, padder=padder, mode=mode, allow_missing_keys=allow_missing_keys)
+        Padd.__init__(self, keys, padder=padder, mode=mode, allow_missing_keys=allow_missing_keys, lazy=lazy)
 
 
 class DivisiblePadd(Padd):
@@ -324,9 +322,8 @@ def __init__(
         See also :py:class:`monai.transforms.SpatialPad`
 
         """
-        LazyTransform.__init__(self, lazy)
         padder = DivisiblePad(k=k, method=method, lazy=lazy, **kwargs)
-        Padd.__init__(self, keys, padder=padder, mode=mode, allow_missing_keys=allow_missing_keys)
+        Padd.__init__(self, keys, padder=padder, mode=mode, allow_missing_keys=allow_missing_keys, lazy=lazy)
 
 
 class Cropd(MapTransform, InvertibleTransform, LazyTransform):


Test patch:
diff --git a/tests/padders.py b/tests/padders.py
--- a/tests/padders.py
+++ b/tests/padders.py
@@ -136,6 +136,9 @@ def pad_test_pending_ops(self, input_param, input_shape):
             # TODO: mode="bilinear" may report error
             overrides = {"mode": "nearest", "padding_mode": mode[1], "align_corners": False}
             result = apply_pending(pending_result, overrides=overrides)[0]
+            # lazy in constructor
+            pad_fn_lazy = self.Padder(mode=mode[0], lazy=True, **input_param)
+            self.assertTrue(pad_fn_lazy.lazy)
             # compare
             assert_allclose(result, expected, rtol=1e-5)
             if isinstance(result, MetaTensor) and not isinstance(pad_fn, MapTransform):