Source code for ultrasound_metrics.utils.phantom_utils
"""
Phantom utilities for ultrasound image analysis.
This module provides functions for loading and positioning digital phantoms
for use in ultrasound image registration and analysis.
"""
from pathlib import Path
from typing import Optional
import cv2
import numpy as np
from numpy.typing import NDArray
from skimage.transform import resize
# Pixel sizes below were determined empiricallly by aligning with US images
[docs]
PHANTOMJPG_X_PX_SZE_MM = 0.102
[docs]
PHANTOMJPG_Y_PX_SZE_MM = 0.105
def get_phantom_jpg(px_sze_mm: Optional[float] = None) -> tuple[NDArray[np.floating], dict[str, int]]:
"""
Get digital phantom stored as jpg image.
Parameters
----------
px_sze_mm
Desired pixel size in mm.
Returns
-------
tuple
Tuple of (phantom_image, dimensions_dict).
"""
phantom_path = Path(__file__).parent / ".." / "assets"
img = cv2.imread(str(phantom_path / "ATS359.jpg"), cv2.IMREAD_GRAYSCALE)
phantom = np.array(img)
nX = len(phantom[0])
nY = len(phantom)
if px_sze_mm is not None:
resize_ratio_x = PHANTOMJPG_X_PX_SZE_MM / px_sze_mm
resize_ratio_y = PHANTOMJPG_Y_PX_SZE_MM / px_sze_mm
print(f"Resize ratio: {resize_ratio_x},{resize_ratio_y}")
new_nX = int(nX * resize_ratio_x)
new_nY = int(nY * resize_ratio_y)
resized_phantom = resize(phantom, output_shape=(new_nY, new_nX))
else:
resized_phantom = phantom
new_nX = nX
new_nY = nY
return resized_phantom, {"x": new_nX, "y": new_nY}
def find_position(
us_image: NDArray[np.floating], phantom: NDArray[np.floating]
) -> tuple[NDArray[np.floating], dict[str, np.integer]]:
"""
Find position of the targets in the US image on the digital phantom.
Parameters
----------
us_image
Ultrasound image array.
phantom
Phantom image array.
Returns
-------
tuple
Tuple of (correlation_map, position_dict).
"""
us_image = np.array(us_image)
phantom = np.array(phantom)
us_im_sze = (len(us_image[0]), len(us_image))
corr = np.array(cv2.filter2D(phantom, ddepth=-1, kernel=us_image), dtype=float)
max_lin_idx = np.argmax(corr)
y, x = np.unravel_index(max_lin_idx, corr.shape)
xpos = x - round(us_im_sze[0] / 2)
ypos = y - round(us_im_sze[1] / 2)
return corr, {"x": xpos, "y": ypos}