From c0aa299b8ce20a024860e9b56e20deecd3e0258a Mon Sep 17 00:00:00 2001 From: Auro Varat Patnaik Date: Fri, 25 Oct 2024 12:00:21 +0100 Subject: [PATCH 1/4] Optimized Area thresholding, works much faster for images with large dimensions --- topostats/grains.py | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/topostats/grains.py b/topostats/grains.py index 7429c1e38bf..498e887567a 100644 --- a/topostats/grains.py +++ b/topostats/grains.py @@ -360,22 +360,34 @@ def area_thresholding(self, image: npt.NDArray, area_thresholds: tuple) -> npt.N if lower_size_limit is None: lower_size_limit = 0 # Get array of grain numbers (discounting zero) - uniq = np.delete(np.unique(image), 0) - grain_count = 0 + # uniq = np.delete(np.unique(image), 0) + # grain_count = 0 LOGGER.debug( f"[{self.filename}] : Area thresholding grains | Thresholds: L: {(lower_size_limit / self.pixel_to_nm_scaling**2):.2f}," f"U: {(upper_size_limit / self.pixel_to_nm_scaling**2):.2f} px^2, L: {lower_size_limit:.2f}, U: {upper_size_limit:.2f} nm^2." ) - for grain_no in uniq: # Calculate grian area in nm^2 - grain_area = np.sum(image_cp == grain_no) * (self.pixel_to_nm_scaling**2) - # Compare area in nm^2 to area thresholds - if grain_area > upper_size_limit or grain_area < lower_size_limit: - image_cp[image_cp == grain_no] = 0 - else: - grain_count += 1 - image_cp[image_cp == grain_no] = grain_count - return image_cp + + grain_counts = np.bincount(image_cp.ravel()) + grain_counts = grain_counts[1:] + # Calculate areas in nm^2 + grain_areas = grain_counts * (self.pixel_to_nm_scaling**2) + + # Create a mask for valid grains + valid_grains = (grain_areas > lower_size_limit) & (grain_areas < upper_size_limit) + + # Create a new mapping for valid grain numbers + new_indices = np.arange(1, valid_grains.sum() + 1) # New indices for valid grains + valid_grain_numbers = np.where(valid_grains)[0]+1 # Original grain numbers that are valid + + # Step 1: Create a boolean mask for valid grains + valid_mask = np.isin(image_cp, valid_grain_numbers) + # Step 2: Set invalid values to 0 + image_cp[~valid_mask] = 0 # Invert the mask to find invalid values + # Map old grain numbers to new ones + for new_idx, old_idx in enumerate(valid_grain_numbers): + image_cp[image_cp == old_idx] = new_indices[new_idx] + return image_cp def colour_regions(self, image: npt.NDArray, **kwargs) -> npt.NDArray: """ Colour the regions. From d58a4842bf6577cea257843411c07b26af58cbe3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 11:04:12 +0000 Subject: [PATCH 2/4] [pre-commit.ci] Fixing issues with pre-commit --- topostats/grains.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/topostats/grains.py b/topostats/grains.py index 498e887567a..6f928b5d25e 100644 --- a/topostats/grains.py +++ b/topostats/grains.py @@ -366,7 +366,7 @@ def area_thresholding(self, image: npt.NDArray, area_thresholds: tuple) -> npt.N f"[{self.filename}] : Area thresholding grains | Thresholds: L: {(lower_size_limit / self.pixel_to_nm_scaling**2):.2f}," f"U: {(upper_size_limit / self.pixel_to_nm_scaling**2):.2f} px^2, L: {lower_size_limit:.2f}, U: {upper_size_limit:.2f} nm^2." ) - + grain_counts = np.bincount(image_cp.ravel()) grain_counts = grain_counts[1:] # Calculate areas in nm^2 @@ -377,8 +377,8 @@ def area_thresholding(self, image: npt.NDArray, area_thresholds: tuple) -> npt.N # Create a new mapping for valid grain numbers new_indices = np.arange(1, valid_grains.sum() + 1) # New indices for valid grains - valid_grain_numbers = np.where(valid_grains)[0]+1 # Original grain numbers that are valid - + valid_grain_numbers = np.where(valid_grains)[0] + 1 # Original grain numbers that are valid + # Step 1: Create a boolean mask for valid grains valid_mask = np.isin(image_cp, valid_grain_numbers) # Step 2: Set invalid values to 0 @@ -388,6 +388,7 @@ def area_thresholding(self, image: npt.NDArray, area_thresholds: tuple) -> npt.N image_cp[image_cp == old_idx] = new_indices[new_idx] return image_cp + def colour_regions(self, image: npt.NDArray, **kwargs) -> npt.NDArray: """ Colour the regions. From b030637ea5e36e4a73666373a58fb499f766c42f Mon Sep 17 00:00:00 2001 From: Auro Varat Patnaik Date: Mon, 3 Feb 2025 16:00:34 +0000 Subject: [PATCH 3/4] test commit --- topostats/grains.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/topostats/grains.py b/topostats/grains.py index 836ca3b34a6..843bbf5c627 100644 --- a/topostats/grains.py +++ b/topostats/grains.py @@ -372,14 +372,11 @@ def area_thresholding(self, image: npt.NDArray, area_thresholds: tuple) -> npt.N """ image_cp = image.copy() lower_size_limit, upper_size_limit = area_thresholds - # if one value is None adjust for comparison + # if one value is None adjust for comparison, nothing has changed except this. if upper_size_limit is None: upper_size_limit = image.size * self.pixel_to_nm_scaling**2 if lower_size_limit is None: lower_size_limit = 0 - # Get array of grain numbers (discounting zero) - # uniq = np.delete(np.unique(image), 0) - # grain_count = 0 LOGGER.debug( f"[{self.filename}] : Area thresholding grains | Thresholds: L: {(lower_size_limit / self.pixel_to_nm_scaling**2):.2f}," f"U: {(upper_size_limit / self.pixel_to_nm_scaling**2):.2f} px^2, L: {lower_size_limit:.2f}, U: {upper_size_limit:.2f} nm^2." From cba853c58a29285dd1f36af263355ad153877098 Mon Sep 17 00:00:00 2001 From: Auro Varat Patnaik Date: Mon, 3 Feb 2025 16:07:40 +0000 Subject: [PATCH 4/4] Fixed Failing Checks --- topostats/grains.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/topostats/grains.py b/topostats/grains.py index 843bbf5c627..4ee03fd1797 100644 --- a/topostats/grains.py +++ b/topostats/grains.py @@ -372,7 +372,7 @@ def area_thresholding(self, image: npt.NDArray, area_thresholds: tuple) -> npt.N """ image_cp = image.copy() lower_size_limit, upper_size_limit = area_thresholds - # if one value is None adjust for comparison, nothing has changed except this. + # if one value is None adjust for comparison if upper_size_limit is None: upper_size_limit = image.size * self.pixel_to_nm_scaling**2 if lower_size_limit is None: @@ -388,7 +388,7 @@ def area_thresholding(self, image: npt.NDArray, area_thresholds: tuple) -> npt.N grain_areas = grain_counts * (self.pixel_to_nm_scaling**2) # Create a mask for valid grains - valid_grains = (grain_areas > lower_size_limit) & (grain_areas < upper_size_limit) + valid_grains = (grain_areas >= lower_size_limit) & (grain_areas <= upper_size_limit) # Create a new mapping for valid grain numbers new_indices = np.arange(1, valid_grains.sum() + 1) # New indices for valid grains