Generate the spatial bounding box of foreground in the image with start-end positions (inclusive). Users can define arbitrary function to select expected foreground from the whole image or specified channels. And it can also add margin to every dim of the bounding box. The output fo
(
img: NdarrayOrTensor,
select_fn: Callable = is_positive,
channel_indices: IndexSelection | None = None,
margin: Sequence[int] | int = 0,
allow_smaller: bool = False,
)
| 1084 | |
| 1085 | |
| 1086 | def generate_spatial_bounding_box( |
| 1087 | img: NdarrayOrTensor, |
| 1088 | select_fn: Callable = is_positive, |
| 1089 | channel_indices: IndexSelection | None = None, |
| 1090 | margin: Sequence[int] | int = 0, |
| 1091 | allow_smaller: bool = False, |
| 1092 | ) -> tuple[list[int], list[int]]: |
| 1093 | """ |
| 1094 | Generate the spatial bounding box of foreground in the image with start-end positions (inclusive). |
| 1095 | Users can define arbitrary function to select expected foreground from the whole image or specified channels. |
| 1096 | And it can also add margin to every dim of the bounding box. |
| 1097 | The output format of the coordinates is: |
| 1098 | |
| 1099 | [1st_spatial_dim_start, 2nd_spatial_dim_start, ..., Nth_spatial_dim_start], |
| 1100 | [1st_spatial_dim_end, 2nd_spatial_dim_end, ..., Nth_spatial_dim_end] |
| 1101 | |
| 1102 | This function returns [0, 0, ...], [0, 0, ...] if there's no positive intensity. |
| 1103 | |
| 1104 | Args: |
| 1105 | img: a "channel-first" image of shape (C, spatial_dim1[, spatial_dim2, ...]) to generate bounding box from. |
| 1106 | select_fn: function to select expected foreground, default is to select values > 0. |
| 1107 | channel_indices: if defined, select foreground only on the specified channels |
| 1108 | of image. if None, select foreground on the whole image. |
| 1109 | margin: add margin value to spatial dims of the bounding box, if only 1 value provided, use it for all dims. |
| 1110 | allow_smaller: when computing box size with `margin`, whether to allow the image edges to be smaller than the |
| 1111 | final box edges. If `True`, the bounding boxes edges are aligned with the input image edges, if `False`, |
| 1112 | the bounding boxes edges are aligned with the final box edges. Default to `False`. |
| 1113 | The default value is changed from `True` to `False` in v1.5.0. |
| 1114 | |
| 1115 | """ |
| 1116 | check_non_lazy_pending_ops(img, name="generate_spatial_bounding_box") |
| 1117 | spatial_size = img.shape[1:] |
| 1118 | data = img[list(ensure_tuple(channel_indices))] if channel_indices is not None else img |
| 1119 | data = select_fn(data).any(0) |
| 1120 | ndim = len(data.shape) |
| 1121 | margin = ensure_tuple_rep(margin, ndim) |
| 1122 | for m in margin: |
| 1123 | if m < 0: |
| 1124 | raise ValueError(f"margin value should not be negative number, got {margin}.") |
| 1125 | |
| 1126 | box_start = [0] * ndim |
| 1127 | box_end = [0] * ndim |
| 1128 | |
| 1129 | for di, ax in enumerate(itertools.combinations(reversed(range(ndim)), ndim - 1)): |
| 1130 | dt = data |
| 1131 | if len(ax) != 0: |
| 1132 | dt = any_np_pt(dt, ax) |
| 1133 | |
| 1134 | if not dt.any(): |
| 1135 | # if no foreground, return all zero bounding box coords |
| 1136 | return [0] * ndim, [0] * ndim |
| 1137 | |
| 1138 | arg_max = where(dt == dt.max())[0] |
| 1139 | min_d = arg_max[0] - margin[di] |
| 1140 | max_d = arg_max[-1] + margin[di] + 1 |
| 1141 | if allow_smaller: |
| 1142 | min_d = max(min_d, 0) |
| 1143 | max_d = min(max_d, spatial_size[di]) |
searching dependent graphs…