py2ls 0.1.9.7__py3-none-any.whl → 0.1.9.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
py2ls/ich2ls.py ADDED
@@ -0,0 +1,136 @@
1
+ import numpy as np
2
+ import matplotlib.pyplot as plt
3
+ from scipy.stats import pearsonr
4
+ from PIL import Image
5
+ from skimage import filters, morphology, measure, color
6
+
7
+
8
+ def img_preprocess(dir_img, subtract_background=True, size_obj=50, size_hole=50):
9
+ """
10
+ Processes an image by performing thresholding, morphological operations,
11
+ and region labeling.
12
+
13
+ Parameters:
14
+ - dir_img: Path to the image file.
15
+ - size_obj: Minimum size of objects to keep (default: 50).
16
+ - size_hole: Maximum size of holes to fill (default: 50).
17
+
18
+ Returns:
19
+ - output: Dictionary containing the overlay image, threshold value, and regions.
20
+ """
21
+ props_list = [
22
+ "area", # Number of pixels in the region. Useful for determining the size of regions.
23
+ "area_bbox",
24
+ "area_convex",
25
+ "area_filled",
26
+ "axis_major_length", # Lengths of the major and minor axes of the ellipse that fits the region. Useful for understanding the shape's elongation and orientation.
27
+ "axis_minor_length",
28
+ "bbox", # Bounding box coordinates (min_row, min_col, max_row, max_col). Useful for spatial localization of regions.
29
+ "centroid", # Center of mass coordinates (centroid-0, centroid-1). Helps locate the center of each region.
30
+ "centroid_local",
31
+ "centroid_weighted",
32
+ "centroid_weighted_local",
33
+ "coords",
34
+ "eccentricity", # Measure of how elongated the region is. Values range from 0 (circular) to 1 (line). Useful for assessing the shape of regions.
35
+ "equivalent_diameter_area", # Diameter of a circle with the same area as the region. Provides a simple measure of size.
36
+ "euler_number",
37
+ "extent", # Ratio of the region's area to the area of its bounding box. Indicates how much of the bounding box is filled by the region.
38
+ "feret_diameter_max", # Maximum diameter of the region, providing another measure of size.
39
+ "image",
40
+ "image_convex",
41
+ "image_filled",
42
+ "image_intensity",
43
+ "inertia_tensor", # ensor describing the distribution of mass in the region, useful for more advanced shape analysis.
44
+ "inertia_tensor_eigvals",
45
+ "intensity_max", # Maximum intensity value within the region. Helps identify regions with high-intensity features.
46
+ "intensity_mean", # Average intensity value within the region. Useful for distinguishing between regions based on their brightness.
47
+ "intensity_min", # Minimum intensity value within the region. Useful for regions with varying intensity.
48
+ "intensity_std",
49
+ "label", # Unique identifier for each region.
50
+ "moments",
51
+ "moments_central",
52
+ "moments_hu", # Hu moments are a set of seven invariant features that describe the shape of the region. Useful for shape recognition and classification.
53
+ "moments_normalized",
54
+ "moments_weighted",
55
+ "moments_weighted_central",
56
+ "moments_weighted_hu",
57
+ "moments_weighted_normalized",
58
+ "orientation", # ngle of the major axis of the ellipse that fits the region. Useful for determining the orientation of elongated regions.
59
+ "perimeter", # Length of the boundary of the region. Useful for shape analysis.
60
+ "perimeter_crofton",
61
+ "slice",
62
+ "solidity", # Ratio of the area of the region to the area of its convex hull. Indicates how solid or compact a region is.
63
+ ]
64
+ if isinstance(dir_img, str):
65
+ # Step 1: Load the image
66
+ image = Image.open(dir_img)
67
+
68
+ # Step 2: Convert the image to grayscale and normalize
69
+ gray_image = image.convert("L")
70
+ image_array = np.array(gray_image)
71
+ normalized_image = image_array / 255.0
72
+ else:
73
+ cleaned_image = dir_img
74
+ image_array = cleaned_image
75
+ normalized_image = cleaned_image
76
+ image = cleaned_image
77
+ binary_image = cleaned_image
78
+ thr_val = None
79
+ if subtract_background:
80
+ # Step 3: Apply thresholding to segment the image
81
+ thr_val = filters.threshold_otsu(image_array)
82
+ print(f"Threshold value is: {thr_val}")
83
+
84
+ # Apply thresholds and generate binary images
85
+ binary_image = image_array > thr_val
86
+
87
+ # Step 4: Perform morphological operations to clean the image
88
+ # Remove small objects and fill small holes
89
+ cleaned_image_rm_min_obj = morphology.remove_small_objects(
90
+ binary_image, min_size=size_obj
91
+ )
92
+ cleaned_image = morphology.remove_small_holes(
93
+ cleaned_image_rm_min_obj, area_threshold=size_hole
94
+ )
95
+
96
+ # Label the regions
97
+ label_image = measure.label(cleaned_image)
98
+
99
+ # Optional: Overlay labels on the original image
100
+ overlay_image = color.label2rgb(label_image, image_array)
101
+ regions = measure.regionprops(label_image, intensity_image=image_array)
102
+ region_props = measure.regionprops_table(
103
+ label_image, intensity_image=image_array, properties=props_list
104
+ )
105
+ df_regions = pd.DataFrame(region_props)
106
+ # Pack the results into a single output variable (dictionary)
107
+ output = {
108
+ "img": image,
109
+ "img_array": image_array,
110
+ "img_scale": normalized_image,
111
+ "img_binary": binary_image,
112
+ "img_clean": cleaned_image,
113
+ "img_label": label_image,
114
+ "img_overlay": overlay_image,
115
+ "thr_val": thr_val,
116
+ "regions": regions,
117
+ "df_regions": df_regions,
118
+ }
119
+
120
+ return output
121
+
122
+
123
+ def cal_pearson(img1, img2):
124
+ """Compute Pearson correlation coefficient between two images."""
125
+ img1_flat = img1.flatten()
126
+ img2_flat = img2.flatten()
127
+ r, p = pearsonr(img1_flat, img2_flat)
128
+ return r, p
129
+
130
+
131
+ def cal_manders(img1, img2):
132
+ """Compute Manders' overlap coefficient between two binary images."""
133
+ img1_binary = img1 > filters.threshold_otsu(img1)
134
+ img2_binary = img2 > filters.threshold_otsu(img2)
135
+ overlap_coef = np.sum(img1_binary & img2_binary) / np.sum(img1_binary)
136
+ return overlap_coef