zea.displayΒΆ
Display functionality, including scan conversion frustrum conversion, etc.
Functions
|
Convert a Cartesian image matrix to a polar coordinate representation. |
|
Precompute coordinates for 2d scan conversion from polar coordinates. |
|
Precompute coordinates for 3d scan conversion from polar coordinates |
|
Convert coordinates from (rho, theta) space to (X,Z) space using the frustum coordinate conversion. |
|
Convert coordinates from (rho, theta, phi) space to (X,Y,Z) space using the frustum coordinate conversion. |
|
Convert coordinates from (X,Y,Z) space to (rho, theta, phi) space using the frustum coordinate conversion. |
|
Convert coordinates from (X,Z) space to (rho, theta) space using the frustum coordinate conversion. |
|
Match the histogram of an image to a reference image, for fair visual comparison. |
|
Convert a Cartesian-format ultrasound image to a polar representation. |
|
map_coordinates using keras.ops or scipy.ndimage when order > 1. |
|
Overlay segmentation masks on top of an image using PIL. |
|
(rho, theta) sampling grid that pins a polar cone's apex at pixel |
|
Resample a polar image onto a fixed Cartesian canvas with the apex at a chosen pixel. |
|
Scan convert image based on number of dimensions. |
|
Perform scan conversion on a 2D ultrasound image from polar coordinates (rho, theta) to Cartesian coordinates (x, z). |
|
Perform scan conversion on a 3D ultrasound image from polar coordinates (rho, theta, phi) to Cartesian coordinates (z, x, y). |
|
Convert image to 8 bit image [0, 255]. |
- zea.display.cartesian_to_polar_matrix(cartesian_matrix, fill_value=0.0, polar_shape=None, tip=None, r_max=None, theta_range=None, interpolation_order=1)[source]ΒΆ
Convert a Cartesian image matrix to a polar coordinate representation.
- Parameters:
cartesian_matrix (tensor) β Input 2D image array in Cartesian coordinates.
fill_value (float) β Value to use for points sampled outside the input image.
polar_shape (tuple, optional) β Desired shape of the polar output (rows, cols). Defaults to the shape of the input image.
tip (tuple, optional) β (x, y) coordinates of the origin for the polar transformation (typically the probe tip). Defaults to the center-top of the image.
r_max (float, optional) β Maximum radius to consider in the polar transform. Defaults to the height of the input image.
theta_range (tuple, optional) β
(theta_min, theta_max)angular extent of the polar grid in radians, allowing asymmetric cones. Use this when the left and right cone boundaries do not have equal half-angles. Defaults to (-45, 45) degrees.interpolation_order (int) β Order of interpolation to use (0 = nearest-neighbor, 1 = linear, 2+ = spline). Matches the convention of scipy.ndimage.map_coordinates.
- Returns:
- The image re-sampled in polar coordinates with shape
polar_shape.
- coordinates (Array): The Cartesian coordinates corresponding to each pixel in
the polar output.
- Return type:
polar_matrix (Array)
- zea.display.compute_scan_convert_2d_coordinates(image_shape, rho_range, theta_range, resolution=None, dtype='float32', distance_to_apex=0.0)[source]ΒΆ
Precompute coordinates for 2d scan conversion from polar coordinates.
rhois measured from the apex of the polar grid.distance_to_apexsays how far the transducer sits in front of that apex, and is used only to reportz_limas a depth below the transducer (matchingextent). It must not enter the sampling grid: the returned coordinates index the polar image, so they stay in the apex frame.
- zea.display.compute_scan_convert_3d_coordinates(image_shape, rho_range, theta_range, phi_range, resolution=None, dtype='float32')[source]ΒΆ
Precompute coordinates for 3d scan conversion from polar coordinates
- zea.display.frustum_convert_rt2xz(rho, theta)[source]ΒΆ
Convert coordinates from (rho, theta) space to (X,Z) space using the frustum coordinate conversion.
Angles are defined in radians.
- Parameters:
rho (ndarray) β Radial coordinates of the points to convert.
theta (ndarray) β Theta coordinates of the points to convert.
- Returns:
X coordinates of the converted points. z (ndarray): Z coordinates of the converted points.
- Return type:
x (ndarray)
- zea.display.frustum_convert_rtp2xyz(rho, theta, phi)[source]ΒΆ
Convert coordinates from (rho, theta, phi) space to (X,Y,Z) space using the frustum coordinate conversion.
Angles are defined in radians.
- Parameters:
rho (ndarray) β Radial coordinates of the points to convert.
theta (ndarray) β Theta coordinates of the points to convert.
phi (ndarray) β Phi coordinates of the points to convert.
- Returns:
X coordinates of the converted points. y (ndarray): Y coordinates of the converted points. z (ndarray): Z coordinates of the converted points.
- Return type:
x (ndarray)
- zea.display.frustum_convert_xyz2rtp(x, y, z, theta_limits, phi_limits)[source]ΒΆ
Convert coordinates from (X,Y,Z) space to (rho, theta, phi) space using the frustum coordinate conversion.
Angles are defined in radians.
- Parameters:
x (ndarray) β X coordinates of the points to convert.
y (ndarray) β Y coordinates of the points to convert.
z (ndarray) β Z coordinates of the points to convert.
tlimits β Theta and phi limits, respectively, of the original volume. Any point that resides outside of these limits is potentially undefined, and therefore, the radial value for these points is made to be -1.
plimits β Theta and phi limits, respectively, of the original volume. Any point that resides outside of these limits is potentially undefined, and therefore, the radial value for these points is made to be -1.
- Returns:
Radial coordinates of the converted points. theta (ndarray): Theta coordinates of the converted points. phi (ndarray): Phi coordinates of the converted points.
- Return type:
rho (ndarray)
- zea.display.frustum_convert_xz2rt(x, z, theta_limits)[source]ΒΆ
Convert coordinates from (X,Z) space to (rho, theta) space using the frustum coordinate conversion.
Angles are defined in radians.
- Parameters:
x (ndarray) β X coordinates of the points to convert.
z (ndarray) β Z coordinates of the points to convert.
theta_limits (list) β Theta limits of the original volume. Any point that resides outside of these limits is potentially undefined, and therefore, the radial value for these points is made to be -1.
- Returns:
Radial coordinates of the converted points. theta (ndarray): Theta coordinates of the converted points.
- Return type:
rho (ndarray)
- zea.display.histogram_match(image, reference, mode='full', n_bins=256, roi=None, allow_unequal_shapes=False, exclude_below=-300.0)[source]ΒΆ
Match the histogram of an image to a reference image, for fair visual comparison.
Image formation methods apply different dynamic range transformations, which biases visual as well as quantitative comparison. Matching the histogram of an image to a reference (typically a conventional B-mode image) puts the two on a common scale.
Reference
N. Bottenus, B. C. Byram, and D. Hyun, βHistogram Matching for Visual Ultrasound Image Comparison,β IEEE Transactions on Ultrasonics, Ferroelectrics, and Frequency Control, vol. 68, no. 5, pp. 1487β1495, 2021. doi.org/10.1109/TUFFC.2020.3035965
Their MATLAB implementation, referred to above as the reference implementation: https://github.com/nbottenus/histogram_matching/blob/main/histmatch.m
- Parameters:
image (ndarray) β Image to transform, typically log-compressed (dB).
reference (ndarray) β Image to match to. Has to be of the shape of
image, unlessallow_unequal_shapessays otherwise.mode (
str) βClass of transform to match with. Defaults to
"full"."partial": affine match (Sec. III.A), the scale and offset that match mean and variance. It leaves the shape of the imageβs own distribution intact, so pick it when that shape is the thing under comparison, when the fitted region contains structure rather than plain speckle, or when the CNR must survive the matching."full": any monotone mapping (Sec. III.B), the one that carries the histogram of the image onto that of the reference, estimated onn_binsbins. It matches the shape of the distribution too, hence undoes non-linear compression, so pick it to compare methods whose transformations differ in more than scale and offset, or are unknown (βblack boxβ images, Sec. III.C.2). Together with a speckleroi, the paperβs expected common use (Sec. V).
n_bins (
Union[int,str]) β Number of bins the mapping of a"full"match is estimated on; ignored by"partial". Defaults to 256, the number of bins used in the paper, which it found enough for consistent results. Pass"all"for one bin per fitted pixel, the limit of the binning process (Sec. III.C.1): it reproduces the reference distribution down to its outliers and tails, which replicates them in the matched image. This is what skimage.exposure.match_histograms does.roi (ndarray, optional) β Boolean mask, of the shape of both images, selecting a homogeneous speckle region (Sec. III.C.3, the paperβs expected common use). The mapping is fit inside the mask and applied to the whole image, extended linearly outside the fitted range. Defaults to None (fit on the whole image).
allow_unequal_shapes (
bool) β Whetherreferencemay be of a shape other than that ofimage. Only the two distributions are compared, so a match is well defined either way, but images of different shapes are more often a mistake (a stray transpose, the wrong frame of a sequence) than an intent. Defaults to False. Pass True to match against a reference deliberately not of the shape of the image, e.g. a region cut out of a larger acquisition. Anroihas to index both images regardless, so it cannot be combined with unequal shapes.exclude_below (
Optional[float]) β Value at or below which a pixel of either image is kept out of the fit and the transform. Defaults to -300.0, which catches zeaβslog(0)sentinel and nothing a log-compressed B-mode measures. Pass None to exclude nothing but the non-finite pixels.
- Returns:
Transformed image (float64), unclipped: clipping to a display range is left to the caller (to_8bit, or
vmin/vmax).- Return type:
ndarray
Note
Which image is matched to which is a choice (Sec. V): matching to B-mode is natural for a reader used to B-mode, but features outside its dynamic range are lost in the process, and matching in the other direction then shows them off better.
Example
>>> import numpy as np >>> from zea.display import histogram_match >>> rng = np.random.default_rng(0) >>> image = 20 * np.log10(rng.rayleigh(0.1, (64, 64))) >>> reference = 20 * np.log10(rng.rayleigh(1.0, (64, 64))) >>> round(image.mean() - reference.mean()) # the image is 20 dB darker -20 >>> matched = histogram_match(image, reference) >>> round(matched.mean() - reference.mean()) 0
- zea.display.inverse_scan_convert_2d(cartesian_image, fill_value=0.0, theta_range=None, output_size=None, interpolation_order=1, find_scan_cone=True, image_range=None)[source]ΒΆ
Convert a Cartesian-format ultrasound image to a polar representation.
This function can be used to recover a sector-shaped scan (polar format) from a Cartesian representation of an image. Optionally, it can detect and crop around the scan cone before conversion.
- Parameters:
cartesian_image (tensor) β 2D image array in Cartesian coordinates of type float.
fill_value (float) β Value used to fill regions outside the original image during interpolation.
theta_range (tuple, optional) β
(theta_min, theta_max)angular extent of the polar grid in radians, allowing asymmetric cones. Defaults to (-45, 45) degrees.output_size (tuple, optional) β Shape (rows, cols) of the resulting polar image. If None, the shape of the input image is used.
interpolation_order (int) β Order of interpolation used in resampling (0 = nearest-neighbor, 1 = linear, etc.).
find_scan_cone (bool) β If True, automatically detects and crops around the scan cone in the Cartesian image before polar conversion, ensuring that the scan cone is centered without padding. Can be set to False if the image is already cropped and centered.
image_range (
tuple|None) β Tuple (vmin, vmax) for display scaling when detecting the scan cone.
- Returns:
2D image in polar coordinates (sector-shaped scan).
- Return type:
polar_image (Array)
- zea.display.map_coordinates(inputs, coordinates, order, fill_mode='constant', fill_value=0)[source]ΒΆ
map_coordinates using keras.ops or scipy.ndimage when order > 1.
- zea.display.overlay_masks(image, masks, alpha=0.5, colors=None)[source]ΒΆ
Overlay segmentation masks on top of an image using PIL.
- Parameters:
image (PIL.Image or ndarray) β Base image. If grayscale, it is converted to RGB. If ndarray, it is converted to a PIL Image first.
masks (list of PIL.Image or ndarray) β Segmentation masks to overlay. Each mask should be an 8-bit single-channel image where non-zero pixels indicate the masked region.
alpha (
float) β Opacity of the mask overlays in [0, 1]. Defaults to 0.5.colors (list of tuple, optional) β RGB colors for each mask. If None, a default palette is used. If provided, must contain at least as many entries as masks (extra entries are ignored).
- Returns:
RGB image with masks overlaid.
- Return type:
PIL.Image
- zea.display.polar_to_cartesian_coordinates(cartesian_shape, n_rho, n_theta, tip=None, r_max=None, theta_range=None, pitch=1.0, dtype='float32')[source]ΒΆ
(rho, theta) sampling grid that pins a polar coneβs apex at pixel
tip.Shared core of
polar_to_cartesian_matrix(): builds the fractional index grid that resamples an(n_rho, n_theta)polar image onto acartesian_shapecanvas, with the apex at pixeltipandpitchunits per pixel. Pass the result ascoordinatestoscan_convert_2d()(or theScanConvertoperation) to run the same resampling inside a pipeline. Unlikecompute_scan_convert_2d_coordinates(), this uses thearctan2mapping in_polar_sampling_coordinates(), so it covers a full circle rather than only a narrow (|theta| < pi/2) sector.- Parameters:
cartesian_shape (
Tuple[int,int]) β Output(rows, cols)=(n_z, n_x).n_rho (
int) β Radial samples of the polar image the indices address.n_theta (
int) β Angular samples of the polar image the indices address.tip (
Optional[Tuple[float,float]]) β(col, row)pixel location of the cone apex in the output. Defaults to the centre-top(cols / 2, 0).r_max (
Optional[float]) β Radius spanned by the polar image, in the same units aspitch(pixels by default). Defaults torows.theta_range (
Optional[Tuple[float,float]]) β angular extent in radians; the order must match the column order of the polar image. Defaults to (45, -45) degrees.pitch (
float) β Output units per pixel (radial units ofr_max). Defaults to 1.0, i.e.tipandr_maxare in pixels.dtype (
str) β Compute dtype for the axes. Defaults to"float32".
- Returns:
(2, cols, rows)stack of[rho_idx, theta_idx]sampling indices.- Return type:
coords (Array)
- zea.display.polar_to_cartesian_matrix(polar_matrix, cartesian_shape, tip=None, r_max=None, theta_range=None, pitch=1.0, fill_value=0.0, order=1)[source]ΒΆ
Resample a polar image onto a fixed Cartesian canvas with the apex at a chosen pixel.
Faithful inverse of
cartesian_to_polar_matrix(). Wherescan_convert_2d()fits the cone bounding box into the output (losing absolute position and scale), this pins the cone apex at pixeltipon a canvas of shapecartesian_shapeand samples atpitchunits per pixel, so a forward/inverse round-trip reproduces the original frame. Both share the_polar_sampling_coordinates()core; they differ only in how the output grid is built.- Parameters:
polar_matrix (tensor) β Input polar image of shape
(n_rho, n_theta), float type.cartesian_shape (
Tuple[int,int]) β Output(rows, cols)=(n_z, n_x).tip (
Optional[Tuple[float,float]]) β(col, row)pixel location of the cone apex in the output. Defaults to the centre-top(cols / 2, 0).r_max (
Optional[float]) β Radius spanned by the polar image, in the same units aspitch(pixels by default). Defaults torows.theta_range (
Optional[Tuple[float,float]]) β angular extent in radians. The order is significant: it must match the column order ofpolar_matrix.cartesian_to_polar_matrix()lays its columns out from the larger to the smaller angle, so to invert it pass the range reversed, i.e.(theta_max, theta_min)β which is exactly whatpolar_geometry_from_coords_for_interp()returns. Defaults to (45, -45) degrees.pitch (
float) β Output units per pixel (radial units ofr_max). Defaults to 1.0, i.e.tipandr_maxare in pixels.fill_value (
float) β Value for pixels outside the polar domain.order (
int) β Spline interpolation order. Defaults to 1.
- Returns:
- The polar image resampled onto the Cartesian canvas, with
shape
cartesian_shape.
- Return type:
cartesian_matrix (Array)
- zea.display.scan_convert(image, rho_range=None, theta_range=None, phi_range=None, resolution=None, coordinates=None, fill_value=0.0, order=1, with_batch_dim=False, distance_to_apex=0.0)[source]ΒΆ
Scan convert image based on number of dimensions.
- zea.display.scan_convert_2d(image, rho_range=None, theta_range=None, resolution=None, coordinates=None, fill_value=0.0, order=1, distance_to_apex=0.0, **kwargs)[source]ΒΆ
Perform scan conversion on a 2D ultrasound image from polar coordinates (rho, theta) to Cartesian coordinates (x, z).
- Parameters:
image (ndarray) β The input 2D ultrasound image in polar coordinates. Has dimensions (n_rho, n_theta) with optional batch.
rho_range (
Optional[Tuple[float,float]]) β A tuple specifying the range of rho values (min_rho, max_rho). Defined in mm.theta_range (
Optional[Tuple[float,float]]) β A tuple specifying the range of theta values (min_theta, max_theta). Defined in radians.resolution (
Optional[float]) β The resolution for the Cartesian grid. If None, it is calculated based on the input image. In mm / pixel.coordinates (
Optional[ndarray]) β Precomputed coordinates for scan conversion. If provided, it will be used instead of computing new coordinates based on the input image shape and ranges.fill_value (
float) β The value to fill in for coordinates outside the input image ranges. Defaults to 0.0. When set to NaN, no interpolation at the edges will happen.order (
int) β The order of the spline interpolation. Defaults to 1.distance_to_apex (
float) β Distance from the apexrhois measured from to the transducer surface. Only shifts the reportedz_limso it reads as a depth below the transducer; the image itself is unchanged. Defaults to 0.0.
- Returns:
- The scan-converted 2D ultrasound image in Cartesian coordinates.
Has dimensions (grid_size_z, grid_size_x). Coordinates outside the input image ranges are filled with NaNs.
- parameters (dict): A dictionary containing information about the scan conversion.
Contains the resolution, x, and z limits, rho and theta ranges.
- Return type:
ndarray
Note
Polar grid is inferred from the input image shape and the supplied rho and theta ranges. Cartesian grid is computed based on polar grid with resolutions specified by resolution parameter.
- zea.display.scan_convert_3d(image, rho_range=None, theta_range=None, phi_range=None, resolution=None, coordinates=None, fill_value=0.0, order=1)[source]ΒΆ
Perform scan conversion on a 3D ultrasound image from polar coordinates (rho, theta, phi) to Cartesian coordinates (z, x, y).
- Parameters:
image (ndarray) β The input 3D ultrasound image in polar coordinates. Has dimensions (n_rho, n_theta, n_phi) with optional batch.
rho_range (
Optional[Tuple[float,float]]) β A tuple specifying the range of rho values (min_rho, max_rho). Defined in mm.theta_range (
Optional[Tuple[float,float]]) β A tuple specifying the range of theta values (min_theta, max_theta). Defined in radians.phi_range (
Optional[Tuple[float,float]]) β A tuple specifying the range of phi values (min_phi, max_phi). Defined in radians.resolution (
Optional[float]) β The resolution for the Cartesian grid. If None, it is calculated based on the input image. In mm / pixel.coodinates (ndarray, optional) β Precomputed coordinates for scan conversion. If provided, it will be used instead of computing new coordinates based on the input image shape and ranges.
fill_value (
float) β The value to fill in for coordinates outside the input image ranges. Defaults to 0.0. When set to NaN, no interpolation at the edges will happen.order (
int) β The order of the spline interpolation. Defaults to 1.
- Returns:
- The scan-converted 3D ultrasound image in Cartesian coordinates.
Has dimensions (grid_size_z, grid_size_x, n_y). Coordinates outside the input image ranges are filled with NaNs.
- parameters (dict): A dictionary containing information about the scan conversion.
Contains the resolution, x, y, and z limits, rho, theta, and phi ranges.
- Return type:
ndarray
Note
Polar grid is inferred from the input image shape and the supplied rho, theta and phi ranges. Cartesian grid is computed based on polar grid with resolutions specified by resolution parameter.
- zea.display.to_8bit(image, dynamic_range=None, pillow=True)[source]ΒΆ
Convert image to 8 bit image [0, 255]. Clip between dynamic range.
- Parameters:
image (ndarray) β Input image(s). Should be in between dynamic range.
dynamic_range (
Optional[tuple]) β Dynamic range of input image(s).pillow (
bool) β Whether to return PIL image. Defaults to True.
- Returns:
Output 8 bit image(s) [0, 255].
- Return type:
image (ndarray)
Note
If dynamic_range is None, it is assumed that the input image is already in the range [-60, 0] dB, which is a common range for ultrasound images.
Note
NaN values in the input image are replaced with the minimum value of the dynamic range before scaling, which ensures that they are represented as black (0) in the output image. +/- inf values are replaced with the min and max values of the dynamic range.
Example
>>> import numpy as np >>> import zea >>> file_path = ( ... "hf://zeahub/camus-sample/val/patient0401/patient0401_4CH_half_sequence.hdf5" ... ) >>> with zea.File(file_path, mode="r") as file: ... data = file.data.image.values[0] >>> image, _ = zea.display.scan_convert( ... data, ... rho_range=(0, 1), ... theta_range=(-0.78, 0.78), ... fill_value=np.nan, ... ) >>> image = zea.display.to_8bit(image, dynamic_range=(-60, 0)) >>> image.save("image.png")