|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| import numpy as np
|
|
|
|
|
| def get_masked_data(label_data, image_data, labels):
|
| """
|
| Extracts and returns the image data corresponding to specified labels within a 3D volume.
|
|
|
| This function efficiently masks the `image_data` array based on the provided `labels` in the `label_data` array.
|
| The function handles cases with both a large and small number of labels, optimizing performance accordingly.
|
|
|
| Args:
|
| label_data (np.ndarray): A NumPy array containing label data, representing different anatomical
|
| regions or classes in a 3D medical image.
|
| image_data (np.ndarray): A NumPy array containing the image data from which the relevant regions
|
| will be extracted.
|
| labels (list of int): A list of integers representing the label values to be used for masking.
|
|
|
| Returns:
|
| np.ndarray: A NumPy array containing the elements of `image_data` that correspond to the specified
|
| labels in `label_data`. If no labels are provided, an empty array is returned.
|
|
|
| Raises:
|
| ValueError: If `image_data` and `label_data` do not have the same shape.
|
|
|
| Example:
|
| label_int_dict = {"liver": [1], "kidney": [5, 14]}
|
| masked_data = get_masked_data(label_data, image_data, label_int_dict["kidney"])
|
| """
|
|
|
|
|
| if image_data.shape != label_data.shape:
|
| raise ValueError(
|
| f"Shape mismatch: image_data has shape {image_data.shape}, "
|
| f"but label_data has shape {label_data.shape}. They must be the same."
|
| )
|
|
|
| if not labels:
|
| return np.array([])
|
|
|
| labels = list(set(labels))
|
|
|
|
|
| num_label_acceleration_thresh = 3
|
| if len(labels) >= num_label_acceleration_thresh:
|
|
|
| mask = np.isin(label_data, labels)
|
| else:
|
|
|
| mask = np.zeros_like(label_data, dtype=bool)
|
| for label in labels:
|
| mask = np.logical_or(mask, label_data == label)
|
|
|
|
|
| masked_data = image_data[mask.astype(bool)]
|
|
|
| return masked_data
|
|
|
|
|
| def is_outlier(statistics, image_data, label_data, label_int_dict):
|
| """
|
| Perform a quality check on the generated image by comparing its statistics with precomputed thresholds.
|
|
|
| Args:
|
| statistics (dict): Dictionary containing precomputed statistics including mean +/- 3sigma ranges.
|
| image_data (np.ndarray): The image data to be checked, typically a 3D NumPy array.
|
| label_data (np.ndarray): The label data corresponding to the image, used for masking regions of interest.
|
| label_int_dict (dict): Dictionary mapping label names to their corresponding integer lists.
|
| e.g., label_int_dict = {"liver": [1], "kidney": [5, 14]}
|
|
|
| Returns:
|
| dict: A dictionary with labels as keys, each containing the quality check result,
|
| including whether it's an outlier, the median value, and the thresholds used.
|
| If no data is found for a label, the median value will be `None` and `is_outlier` will be `False`.
|
|
|
| Example:
|
| # Example input data
|
| statistics = {
|
| "liver": {
|
| "sigma_6_low": -21.596463547885904,
|
| "sigma_6_high": 156.27881534763367
|
| },
|
| "kidney": {
|
| "sigma_6_low": -15.0,
|
| "sigma_6_high": 120.0
|
| }
|
| }
|
| label_int_dict = {
|
| "liver": [1],
|
| "kidney": [5, 14]
|
| }
|
| image_data = np.random.rand(100, 100, 100) # Replace with actual image data
|
| label_data = np.zeros((100, 100, 100)) # Replace with actual label data
|
| label_data[40:60, 40:60, 40:60] = 1 # Example region for liver
|
| label_data[70:90, 70:90, 70:90] = 5 # Example region for kidney
|
| result = is_outlier(statistics, image_data, label_data, label_int_dict)
|
| """
|
| outlier_results = {}
|
|
|
| for label_name, stats in statistics.items():
|
|
|
| low_thresh = min(stats["sigma_6_low"], stats["percentile_0_5"])
|
| high_thresh = max(stats["sigma_6_high"], stats["percentile_99_5"])
|
|
|
| if label_name == "bone":
|
| high_thresh = 1000.0
|
|
|
|
|
| labels = label_int_dict.get(label_name, [])
|
| masked_data = get_masked_data(label_data, image_data, labels)
|
| masked_data = masked_data[~np.isnan(masked_data)]
|
|
|
| if len(masked_data) == 0 or masked_data.size == 0:
|
| outlier_results[label_name] = {
|
| "is_outlier": False,
|
| "median_value": None,
|
| "low_thresh": low_thresh,
|
| "high_thresh": high_thresh,
|
| }
|
| continue
|
|
|
|
|
| median_value = np.nanmedian(masked_data)
|
|
|
| if np.isnan(median_value):
|
| median_value = None
|
| is_outlier = False
|
| else:
|
|
|
| is_outlier = median_value < low_thresh or median_value > high_thresh
|
|
|
| outlier_results[label_name] = {
|
| "is_outlier": is_outlier,
|
| "median_value": median_value,
|
| "low_thresh": low_thresh,
|
| "high_thresh": high_thresh,
|
| }
|
|
|
| return outlier_results
|
|
|