From 94d9b4954150dacf71e4206e3eabac1bd336d6d4 Mon Sep 17 00:00:00 2001 From: mollybuckley Date: Fri, 2 Aug 2024 14:13:51 +0100 Subject: [PATCH 1/4] Replace find_phantom_center method with get_mask_image --- hazenlib/tasks/acr_slice_thickness.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hazenlib/tasks/acr_slice_thickness.py b/hazenlib/tasks/acr_slice_thickness.py index a1ab075b..05ed7821 100644 --- a/hazenlib/tasks/acr_slice_thickness.py +++ b/hazenlib/tasks/acr_slice_thickness.py @@ -188,7 +188,7 @@ def get_slice_thickness(self, dcm): float: measured slice thickness. """ img = dcm.pixel_array - cxy, _ = self.ACR_obj.find_phantom_center(img, self.ACR_obj.dx, self.ACR_obj.dy) + mask = self.ACR_obj.get_mask_image(img) x_pts, y_pts = self.find_ramps(img, cxy) interp_factor = 1 / 5 From 33c31d3118014137817220445e186750b537f9a2 Mon Sep 17 00:00:00 2001 From: mollybuckley Date: Fri, 2 Aug 2024 14:26:42 +0100 Subject: [PATCH 2/4] get centre coordinates of detected circle --- hazenlib/tasks/acr_slice_thickness.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hazenlib/tasks/acr_slice_thickness.py b/hazenlib/tasks/acr_slice_thickness.py index 05ed7821..40a0120f 100644 --- a/hazenlib/tasks/acr_slice_thickness.py +++ b/hazenlib/tasks/acr_slice_thickness.py @@ -189,6 +189,8 @@ def get_slice_thickness(self, dcm): """ img = dcm.pixel_array mask = self.ACR_obj.get_mask_image(img) + cx, cy = mask.shape[1] // 2, mask.shape[0] // 2 + cxy=(cx,cy) x_pts, y_pts = self.find_ramps(img, cxy) interp_factor = 1 / 5 From a5b566c83d571328f1ed3c0df6124fdd4bed02d2 Mon Sep 17 00:00:00 2001 From: mollybuckley Date: Fri, 2 Aug 2024 14:28:42 +0100 Subject: [PATCH 3/4] testing a larger vertical range of different line profiles --- hazenlib/tasks/acr_slice_thickness.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hazenlib/tasks/acr_slice_thickness.py b/hazenlib/tasks/acr_slice_thickness.py index 40a0120f..318068da 100644 --- a/hazenlib/tasks/acr_slice_thickness.py +++ b/hazenlib/tasks/acr_slice_thickness.py @@ -197,8 +197,8 @@ def get_slice_thickness(self, dcm): interp_factor_dx = interp_factor * self.ACR_obj.dx sample = np.arange(1, x_pts[1] - x_pts[0] + 2) new_sample = np.arange(1, x_pts[1] - x_pts[0] + interp_factor, interp_factor) - offsets = np.arange(-3, 4) - ramp_length = np.zeros((2, 7)) + offsets = np.arange(-10, 11) + ramp_length = np.zeros((2, 21)) line_store = [] fwhm_store = [] From dfb1abe15ebae7a4569f2f2e7f35a7ff6f361a77 Mon Sep 17 00:00:00 2001 From: mollybuckley Date: Wed, 11 Sep 2024 16:12:21 +0100 Subject: [PATCH 4/4] Calculation update --- hazenlib/tasks/acr_slice_thickness.py | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/hazenlib/tasks/acr_slice_thickness.py b/hazenlib/tasks/acr_slice_thickness.py index 318068da..e3e8aee0 100644 --- a/hazenlib/tasks/acr_slice_thickness.py +++ b/hazenlib/tasks/acr_slice_thickness.py @@ -122,6 +122,18 @@ def find_ramps(self, img, centre): y = np.round([np.max(y_locs) - 0.25 * height, np.min(y_locs) + 0.25 * height]) + y_profiles = [skimage.measure.profile_line(img, (1, x_coord), (img.shape[0], x_coord), mode="constant")for x_coord in x] + + # Calculate the angle of the ramps + angles = [] + for profile in y_profiles: + profile_diff = np.diff(profile) + ramp_indices = np.where(profile_diff != 0)[0] # Simplistic approach to find ramps + if len(ramp_indices) >= 2: + y_diff = ramp_indices[-1] - ramp_indices[0] + x_diff = np.diff(x)[0] # The difference between x coordinates + angle = np.arctan2(y_diff, x_diff) + angles.append(np.degrees(angle)) return x, y def FWHM(self, data): @@ -229,9 +241,16 @@ def get_slice_thickness(self, dcm): line_store.append(interp_lines) fwhm_store.append(fwhm) - - with np.errstate(divide="ignore", invalid="ignore"): - dz = 0.2 * (np.prod(ramp_length, axis=0)) / np.sum(ramp_length, axis=0) + expected_ramp_length = 10 * 5 / self.ACR_obj.dx + tol_20percent = expected_ramp_length * 0.2 #trying to only include results where the line profile is actually over the ramp ie. filtering out completely unrealistic results - is this approach valid? + upper_tol = expected_ramp_length + tol_20percent + lower_tol = expected_ramp_length - tol_20percent + ramp_length_filtered_top = ramp_length[0][(ramp_length[0] >= lower_tol) & (ramp_length[0] <= upper_tol)] + ramp_length_filtered_bottom = ramp_length[1][(ramp_length[1] >= lower_tol) & (ramp_length[1] <= upper_tol)] + ramp_length_filtered_top_median = np.median(ramp_length_filtered_top) + ramp_length_filtered_bottom_median = np.median(ramp_length_filtered_bottom) + #calculation from ACR guidance: + dz = 0.2 * (ramp_length_filtered_top_median * ramp_length_filtered_bottom_median) / (ramp_length_filtered_top_median + ramp_length_filtered_bottom_median) dz = dz[~np.isnan(dz)] # TODO check this - if it's taking the value closest to the DICOM slice thickness this is potentially not accurate?