Skip to content

Visualizer

visualizer #

3DSliceImages: Efficiently generate and store 2D slices from a 3D SimpleITK image.

Functions:

Name Description
view_multiple_SliceImage3DObjects

This is a grand view to help when you want to view multiple

SliceImage3D dataclass #

SliceImage3D(
    image: SimpleITK.Image,
    mask: SimpleITK.Image | None = None,
    alpha: float = 0.2,
    disable_progress: bool = False,
)

Generates 2D slices from a 3D SimpleITK image and optionally overlays a mask.

Methods:

Name Description
generate_dim_slices

Generate 2D slices along a given dimension, optionally overlaying the mask.

generate_dim_slices #

generate_dim_slices(
    dim: int, every_n: int = 5
) -> imgtools.vizualize.visualizer.SliceImage3D

Generate 2D slices along a given dimension, optionally overlaying the mask.

Parameters:

Name Type Description Default
dim #
int

The dimension along which to generate slices (0, 1, or 2).

required
every_n #
int

Generate a slice every every_n pixels, by default 5.

5
Source code in src/imgtools/vizualize/visualizer.py
def generate_dim_slices(
    self,
    dim: int,
    every_n: int = 5,
) -> SliceImage3D:
    """Generate 2D slices along a given dimension, optionally overlaying the mask.

    Parameters
    ----------
    dim : int
        The dimension along which to generate slices (0, 1, or 2).
    every_n : int, optional
        Generate a slice every `every_n` pixels, by default 5.
    """
    slices = self.image_slices(dim, every_n)
    mask_slices: list[np.ndarray] | None = self.mask_slices(dim, every_n)

    if mask_slices is None:
        mask_slices = [
            np.zeros_like(slices[0]) for _ in range(len(slices))
        ]
    logger.warning("Generating slices...")
    tasks = [
        (
            i,
            img,
            mask,
            self.alpha,
            self.vmax,
            self.vmin,
        )
        for i, (img, mask) in enumerate(
            zip(slices, mask_slices, strict=False)
        )
    ]
    start = time.time()
    results = [
        SliceImage3D._generate_slice(*task)
        for task in tqdm(tasks, disable=self.disable_progress)
    ]
    logger.info(f"Time taken: {time.time() - start:.2f}s")

    # Store slices in a dictionary
    images = [image for _, image in results]
    self.slices = ImageSlices(images)

    return self

view_multiple_SliceImage3DObjects #

view_multiple_SliceImage3DObjects(
    *args: tuple[
        str, imgtools.vizualize.visualizer.SliceImage3D
    ]
) -> None

This is a grand view to help when you want to view multiple

pass in all of them, with generate_dim_slices already called ALL of them MUST have the same number of slices this will then use a SINGLE slider, to view and iterate over all of them

Source code in src/imgtools/vizualize/visualizer.py
def view_multiple_SliceImage3DObjects(*args: tuple[str, SliceImage3D]) -> None:  # noqa
    """This is a grand view to help when you want to view multiple

    pass in all of them, with generate_dim_slices already called
    ALL of them MUST have the same number of slices
    this will then use a SINGLE slider, to view and iterate over all of them

    """

    # calculate some metadata for all the slices
    metadata_dict = {
        name: f"Shape : x={slice_image.image_array.shape[2]}, y={slice_image.image_array.shape[1]}"
        for name, slice_image in args
    }

    def display_slices(index: int) -> None:
        # Create a vertical box layout for each slice with a label
        vboxes = []
        for name, slice_image in args:
            # Convert the Pillow image to Base64
            buffer = BytesIO()
            slice_image.slices[index].save(buffer, format="PNG")
            base64_image = base64.b64encode(buffer.getvalue()).decode()

            metadata_str = metadata_dict[name]
            # Generate HTML content with Base64-encoded image
            html_content = f"""
            <div style="text-align: center;">
                <h3>{name}</h3>
                <p>{metadata_str}</p>
                <img src="data:image/png;base64,{base64_image}" 
                    style="width: 500px; height: auto;">
            </div>
            """
            vbox = widgets.VBox([widgets.HTML(html_content)])
            vboxes.append(vbox)

        # Create a horizontal box layout for all vboxes
        hbox = widgets.HBox(vboxes)
        display(hbox)

    if not args:
        raise ValueError("At least one SliceImage3D object must be provided")

    num_slices = len(args[0][1].slices)
    if not all(
        len(slice_image.slices) == num_slices for _, slice_image in args
    ):
        errmsg = (
            "All SliceImage3D objects must have the same number of slices!!"
            f" (expected {num_slices}) but got {[len(s.slices) for _, s in args]}"
        )
        raise ValueError(errmsg)

    max_slider = num_slices - 1
    widgets.interact(
        display_slices,
        index=widgets.IntSlider(
            min=0, max=max_slider, step=1, value=max_slider // 2
        ),
    )