Repository: Project-MONAI/MONAI

Issue:
Add multi-threads support to samples crop
**Is your feature request related to a problem? Please describe.**
Currently, there are 4 crop transforms can generate a list of samples, and we crop the images in a for loop.
After some testing, I found that if executing in multi-threads, it can be much faster.
So it would be useful to add `num_workers` support to these transforms, similar to the `CacheDataset`.


Discussion:

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
@@ -1096,8 +1096,8 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> List[Dict[Hashable, n
         d = dict(data)
         label = d[self.label_key]
         image = d[self.image_key] if self.image_key else None
-        fg_indices = d.get(self.fg_indices_key) if self.fg_indices_key is not None else None
-        bg_indices = d.get(self.bg_indices_key) if self.bg_indices_key is not None else None
+        fg_indices = d.pop(self.fg_indices_key, None) if self.fg_indices_key is not None else None
+        bg_indices = d.pop(self.bg_indices_key, None) if self.bg_indices_key is not None else None
 
         self.randomize(label, fg_indices, bg_indices, image)
         if not isinstance(self.spatial_size, tuple):
@@ -1106,12 +1106,12 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> List[Dict[Hashable, n
             raise ValueError("no available ROI centers to crop.")
 
         # initialize returned list with shallow copy to preserve key ordering
-        results: List[Dict[Hashable, np.ndarray]] = [dict(data) for _ in range(self.num_samples)]
+        results: List[Dict[Hashable, np.ndarray]] = [dict(d) for _ in range(self.num_samples)]
 
         for i, center in enumerate(self.centers):
             # fill in the extra keys with unmodified data
-            for key in set(data.keys()).difference(set(self.keys)):
-                results[i][key] = deepcopy(data[key])
+            for key in set(d.keys()).difference(set(self.keys)):
+                results[i][key] = deepcopy(d[key])
             for key in self.key_iterator(d):
                 img = d[key]
                 cropper = SpatialCrop(roi_center=tuple(center), roi_size=self.spatial_size)  # type: ignore
@@ -1276,7 +1276,7 @@ def __call__(self, data: Mapping[Hashable, Any]) -> List[Dict[Hashable, np.ndarr
         d = dict(data)
         label = d[self.label_key]
         image = d[self.image_key] if self.image_key else None
-        indices = d.get(self.indices_key) if self.indices_key is not None else None
+        indices = d.pop(self.indices_key, None) if self.indices_key is not None else None
 
         self.randomize(label, indices, image)
         if not isinstance(self.spatial_size, tuple):
@@ -1285,12 +1285,12 @@ def __call__(self, data: Mapping[Hashable, Any]) -> List[Dict[Hashable, np.ndarr
             raise ValueError("no available ROI centers to crop.")
 
         # initialize returned list with shallow copy to preserve key ordering
-        results: List[Dict[Hashable, np.ndarray]] = [dict(data) for _ in range(self.num_samples)]
+        results: List[Dict[Hashable, np.ndarray]] = [dict(d) for _ in range(self.num_samples)]
 
         for i, center in enumerate(self.centers):
             # fill in the extra keys with unmodified data
-            for key in set(data.keys()).difference(set(self.keys)):
-                results[i][key] = deepcopy(data[key])
+            for key in set(d.keys()).difference(set(self.keys)):
+                results[i][key] = deepcopy(d[key])
             for key in self.key_iterator(d):
                 img = d[key]
                 cropper = SpatialCrop(roi_center=tuple(center), roi_size=self.spatial_size)  # type: ignore


Test patch: