Use `skimage.morphology.remove_small_objects` to remove small objects from images. See: https://scikit-image.org/docs/dev/api/skimage.morphology.html#remove-small-objects. Data should be one-hotted. Args: img: image to process. Expected shape: C, H,W,[D]. Expected to only
(
img: NdarrayTensor,
min_size: int = 64,
connectivity: int = 1,
independent_channels: bool = True,
by_measure: bool = False,
pixdim: Sequence[float] | float | np.ndarray | None = None,
)
| 1419 | |
| 1420 | |
| 1421 | def remove_small_objects( |
| 1422 | img: NdarrayTensor, |
| 1423 | min_size: int = 64, |
| 1424 | connectivity: int = 1, |
| 1425 | independent_channels: bool = True, |
| 1426 | by_measure: bool = False, |
| 1427 | pixdim: Sequence[float] | float | np.ndarray | None = None, |
| 1428 | ) -> NdarrayTensor: |
| 1429 | """ |
| 1430 | Use `skimage.morphology.remove_small_objects` to remove small objects from images. |
| 1431 | See: https://scikit-image.org/docs/dev/api/skimage.morphology.html#remove-small-objects. |
| 1432 | |
| 1433 | Data should be one-hotted. |
| 1434 | |
| 1435 | Args: |
| 1436 | img: image to process. Expected shape: C, H,W,[D]. Expected to only have singleton channel dimension, |
| 1437 | i.e., not be one-hotted. Converted to type int. |
| 1438 | min_size: objects smaller than this size are removed. |
| 1439 | connectivity: Maximum number of orthogonal hops to consider a pixel/voxel as a neighbor. |
| 1440 | Accepted values are ranging from 1 to input.ndim. If ``None``, a full |
| 1441 | connectivity of ``input.ndim`` is used. For more details refer to linked scikit-image |
| 1442 | documentation. |
| 1443 | independent_channels: Whether to consider each channel independently. |
| 1444 | by_measure: Whether the specified min_size is in number of voxels. if this is True then min_size |
| 1445 | represents a surface area or volume value of whatever units your image is in (mm^3, cm^2, etc.) |
| 1446 | default is False. |
| 1447 | pixdim: the pixdim of the input image. if a single number, this is used for all axes. |
| 1448 | If a sequence of numbers, the length of the sequence must be equal to the image dimensions. |
| 1449 | """ |
| 1450 | # if all equal to one value, no need to call skimage |
| 1451 | if len(unique(img)) == 1: |
| 1452 | return img |
| 1453 | |
| 1454 | if not has_morphology: |
| 1455 | raise RuntimeError("Skimage required.") |
| 1456 | |
| 1457 | if by_measure: |
| 1458 | sr = len(img.shape[1:]) |
| 1459 | if isinstance(img, monai.data.MetaTensor): |
| 1460 | _pixdim = img.pixdim |
| 1461 | elif pixdim is not None: |
| 1462 | _pixdim = ensure_tuple_rep(pixdim, sr) |
| 1463 | else: |
| 1464 | warnings.warn("`img` is not of type MetaTensor and `pixdim` is None, assuming affine to be identity.") |
| 1465 | _pixdim = (1.0,) * sr |
| 1466 | voxel_volume = np.prod(np.array(_pixdim)) |
| 1467 | if voxel_volume == 0: |
| 1468 | warnings.warn("Invalid `pixdim` value detected, set it to 1. Please verify the pixdim settings.") |
| 1469 | voxel_volume = 1 |
| 1470 | min_size = np.ceil(min_size / voxel_volume) |
| 1471 | elif pixdim is not None: |
| 1472 | warnings.warn("`pixdim` is specified but not in use when computing the volume.") |
| 1473 | |
| 1474 | img_np: np.ndarray |
| 1475 | img_np, *_ = convert_data_type(img, np.ndarray) |
| 1476 | |
| 1477 | # morphology.remove_small_objects assumes them to be independent by default |
| 1478 | # else, convert to foreground vs background, remove small objects, then convert |
no test coverage detected
searching dependent graphs…