Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
"""Using a brute force search of the images, find the median HU linearity slice.
This method walks through all the images and takes a collapsed circle profile where the HU
linearity ROIs are. If the profile contains both low (<800) and high (>800) HU values and most values are the same
(i.e. it's not an artifact), then
it can be assumed it is an HU linearity slice. The median of all applicable slices is the
center of the HU slice.
Returns
-------
int
The middle slice of the HU linearity module.
"""
hu_slices = []
for image_number in range(0, self.num_images, 2):
slice = Slice(self, image_number, combine=False)
#print(image_number)
# slice.image.plot()
try:
center = slice.phan_center
except ValueError: # a slice without the phantom in view
pass
else:
circle_prof = CollapsedCircleProfile(center, radius=self.localization_radius/self.mm_per_pixel, image_array=slice.image, width_ratio=0.05, num_profiles=5)
prof = circle_prof.values
# determine if the profile contains both low and high values and that most values are the same
low_end, high_end = np.percentile(prof, [2, 98])
median = np.median(prof)
middle_variation = np.percentile(prof, 80) - np.percentile(prof, 20)
variation_limit = max(100, self.dicom_stack.metadata.SliceThickness*-100+300)
if (low_end < median - 400) and (high_end > median + 400) and (middle_variation < variation_limit):
hu_slices.append(image_number)
This algorithm uses the two air bubbles in the HU slice and the resulting angle between them.
Returns
-------
float : the angle of the phantom in **degrees**.
"""
def is_right_area(region):
thresh = np.pi * ((self.air_bubble_radius_mm / self.mm_per_pixel) ** 2)
return thresh * 2 > region.filled_area > thresh / 2
def is_right_eccentricity(region):
return region.eccentricity < 0.5
# get edges and make ROIs from it
slice = Slice(self, self.origin_slice)
larr, regions, _ = get_regions(slice)
# find appropriate ROIs and grab the two most centrally positioned ones
hu_bubbles = [r for r in regions if (is_right_area(r) and is_right_eccentricity(r))]
central_bubbles = sorted(hu_bubbles, key=lambda x: abs(x.centroid[1] - slice.phan_center.x))[:2]
sorted_bubbles = sorted(central_bubbles, key=lambda x: x.centroid[0]) # top, bottom
y_dist = sorted_bubbles[1].centroid[0] - sorted_bubbles[0].centroid[0]
x_dist = sorted_bubbles[1].centroid[1] - sorted_bubbles[0].centroid[1]
phan_roll = np.arctan2(y_dist, x_dist)
anglroll = np.rad2deg(phan_roll) - 90
return anglroll
# convert the slice to binary and label ROIs
edges = filters.scharr(self.image.as_type(np.float))
if np.max(edges) < 0.1:
raise ValueError("Unable to locate Catphan")
larr, regionprops, num_roi = get_regions(self, fill_holes=True, threshold='mean')
# check that there is at least 1 ROI
if num_roi < 1 or num_roi is None:
raise ValueError("Unable to locate the CatPhan")
catphan_region = sorted(regionprops, key=lambda x: np.abs(x.filled_area - self.catphan_size))[0]
if (self.catphan_size * 1.2 < catphan_region.filled_area) or (catphan_region.filled_area < self.catphan_size / 1.2):
raise ValueError("Unable to locate Catphan")
center_pixel = catphan_region.centroid
return Point(center_pixel[1], center_pixel[0])
class CatPhanModule(Slice):
"""Base class for a CTP module.
"""
combine_method = 'mean'
num_slices = 0
roi_settings = {}
background_roi_settings = {}
roi_dist_mm = float
roi_radius_mm = float
rois = {} # dicts of HUDiskROIs
background_rois = {} # dict of HUDiskROIs; possibly empty
def __init__(self, catphan, tolerance, offset=0):
"""
Parameters
----------
catphan : `~pylinac.cbct.CatPhanBase` instance.
Parameters
----------
catphan : `~pylinac.cbct.CatPhanBase` instance.
tolerance : float
offset : int, float
"""
self.model = ''
self._offset = offset
self.origin_slice = catphan.origin_slice
self.tolerance = tolerance
self.slice_thickness = catphan.dicom_stack.metadata.SliceThickness
self.catphan_roll = catphan.catphan_roll
self.mm_per_pixel = catphan.mm_per_pixel
self.rois = {} # dicts of HUDiskROIs
self.background_rois = {} # dict of HUDiskROIs; possibly empty
Slice.__init__(self, catphan, combine_method=self.combine_method, num_slices=self.num_slices)
self._convert_units_in_settings()
self.preprocess(catphan)
self._setup_rois()