py2ls 0.1.9.9__py3-none-any.whl → 0.1.10.0__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/batman.py ADDED
@@ -0,0 +1,183 @@
1
+ import smtplib
2
+ from email.mime.text import MIMEText
3
+ from email.mime.multipart import MIMEMultipart
4
+ from email.mime.base import MIMEBase
5
+ from email import encoders
6
+ import schedule
7
+ import time
8
+ from datetime import datetime
9
+ import os
10
+
11
+
12
+ signature_styles = [
13
+ "", # none
14
+ (
15
+ "------------------------------------------------------------------------------------------------\n"
16
+ "Jianfeng Liu, PhD\n"
17
+ "Institute of Medical Psychology and Behavioural Neurobiology\n"
18
+ "University of Tübingen\n"
19
+ "Otfried-Müller-Str. 25\n"
20
+ "72076 Tübingen\n\n"
21
+ ),
22
+ f"Pappelweg 8\n72076 Tübingen\n\n",
23
+ ]
24
+
25
+
26
+ def email_to(**kwargs):
27
+ """
28
+ usage:
29
+ email_to(who="example@gmail.com",
30
+ subject="test",
31
+ what="this is the body",
32
+ attachments="/Users/test.pdf")
33
+ Send an email with optional attachments.
34
+
35
+ :param who: Recipient email address
36
+ :param subject: Email subject
37
+ :param what: Email what
38
+ :param attachments: List of file paths to attach
39
+ """
40
+ who, what, subject = None, None, None
41
+ attachments = False
42
+ pause_sec = False # default 10 seconds pause
43
+ signature = signature_styles[0]
44
+
45
+ # params config
46
+ for k, v in kwargs.items():
47
+ if any(
48
+ [
49
+ "who" in k.lower(),
50
+ "whe" in k.lower(),
51
+ all(["@" in k.lower(), "." in k.lower()]),
52
+ ]
53
+ ): # 'who' or "where"
54
+ who = v
55
+ if any(["sub" in k.lower(), "hea" in k.lower()]): # 'subject', 'header'
56
+ subject = v
57
+ if any(
58
+ ["wha" in k.lower(), "con" in k.lower(), "bod" in k.lower()]
59
+ ): # 'what','content','body'
60
+ what = v
61
+ if any(["att" in k.lower(), "fil" in k.lower()]): # 'attachments', 'file'
62
+ attachments = v # optional
63
+ if any(
64
+ ["paus" in k.lower(), "tim" in k.lower(), "delay" in k.lower()]
65
+ ): # 'attachments', 'file'
66
+ pause_sec = v # optional
67
+ if any(["sig" in k.lower()]): # 'attachments', 'file'
68
+ signature = v # optional
69
+ if not isinstance(v, str):
70
+ signature = signature_styles[v]
71
+
72
+ # config sender
73
+ email_address = "andyandhope@gmail.com"
74
+ email_password = "myff ltls sfym wehe" # this is fake info
75
+
76
+ # Create email message
77
+ message = MIMEMultipart()
78
+ message["From"] = email_address
79
+ message["To"] = who
80
+ message["Subject"] = subject
81
+
82
+ # add signature
83
+ if signature:
84
+ what += f"\n\n{signature}\n"
85
+
86
+ # the eamil's body
87
+ message.attach(MIMEText(what, "plain"))
88
+
89
+ # attach files
90
+ if attachments:
91
+ if isinstance(attachments, str):
92
+ attachments = [attachments]
93
+ for file in attachments:
94
+ part = MIMEBase("application", "octet-stream")
95
+ try:
96
+ with open(file, "rb") as attachment:
97
+ part.set_payload(attachment.read())
98
+ encoders.encode_base64(part)
99
+
100
+ fname = os.path.basename(file)
101
+ print(fname)
102
+ part.add_header(
103
+ "Content-Disposition", f'attachment; filename= "{fname}"'
104
+ )
105
+ message.attach(part)
106
+ except FileNotFoundError:
107
+ print(f"File not found: {file}")
108
+ except Exception as e:
109
+ print(f"Error attaching file {file}: {e}")
110
+ if pause_sec:
111
+ time.sleep(pause_sec)
112
+ # Send the email
113
+ try:
114
+ with smtplib.SMTP("smtp.gmail.com", 587) as server:
115
+ server.starttls()
116
+ server.login(email_address, email_password)
117
+ server.sendmail(email_address, who, message.as_string())
118
+ print(f"Email successfully sent to {who}")
119
+ except Exception as e:
120
+ print(f"Failed to send email: {e}")
121
+
122
+
123
+ def email_to_every(who, subject, what, when, attachments=None):
124
+ """
125
+ Check the time and send an email when the time matches the when.
126
+
127
+ :param who: Recipient email address
128
+ :param subject: Email subject
129
+ :param what: Email what
130
+ :param when: Time to send the email in HH:MM format
131
+ :param attachments: List of file paths to attach
132
+ """
133
+ current_time = datetime.now().strftime("%H:%M")
134
+ if current_time == when:
135
+ email_to(
136
+ who=who,
137
+ subject=subject,
138
+ what=what,
139
+ attachments=attachments,
140
+ )
141
+
142
+
143
+ # Example usage
144
+ def example_job():
145
+ # Example email details
146
+ reminder_subject = "Reminder: Important Meeting Tomorrow"
147
+ reminder_what = (
148
+ "Don't forget about the meeting tomorrow at 10 AM in the conference room."
149
+ )
150
+ who = "Jianfeng.Liu0413@gmail.com"
151
+ when = "14:30" # Send time in 24-hour format
152
+
153
+ # Optional attachments
154
+ attachments = ["path/to/attachment1.pdf", "path/to/attachment2.jpg"]
155
+
156
+ # Schedule the email
157
+ email_to_every(who, reminder_subject, reminder_what, when, attachments)
158
+
159
+
160
+ if __name__ == "__main__":
161
+ # Schedule the job to run every minute
162
+ schedule.every(1).minutes.do(example_job)
163
+
164
+ while True:
165
+ schedule.run_pending()
166
+ time.sleep(1)
167
+
168
+ # example2:
169
+ email_to(
170
+ who="Jianfeng.Liu@medizin.uni-tuebingen.de",
171
+ subj="test",
172
+ wha="this is the body",
173
+ signat="\n\n Best, Jianfeng\n",
174
+ att="/Users/macjianfeng/Dropbox/Downloads/_*_doc-xlsx/20240822-preprints_full_20190101_20201031-2.xlsx",
175
+ )
176
+ # example3:
177
+ email_to(
178
+ who="Jianfeng.Liu@medizin.uni-tuebingen.de",
179
+ subj="test",
180
+ wha="this is the test",
181
+ signat=2,
182
+ att="/Users/macjianfeng/Dropbox/Downloads/_*_doc-xlsx/20240822-preprints_full_20190101_20201031-2.xlsx",
183
+ )
py2ls/ich2ls.py CHANGED
@@ -1,103 +1,212 @@
1
1
  import numpy as np
2
+ import pandas as pd
2
3
  import matplotlib.pyplot as plt
3
4
  from scipy.stats import pearsonr
4
5
  from PIL import Image
5
6
  from skimage import filters, morphology, measure, color
6
7
 
8
+ # 用来处理ich图像的初级工具包
7
9
 
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
10
 
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).
11
+ def open_img(dir_img, convert="gray", plot=False):
12
+ # Step 1: Load the image
13
+ image = Image.open(dir_img)
17
14
 
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
15
+ if convert == "gray" or convert == "grey":
69
16
  gray_image = image.convert("L")
70
17
  image_array = np.array(gray_image)
18
+ else:
19
+ image_array = np.array(image)
20
+ if plot:
21
+ _, axs = plt.subplots(1, 2)
22
+ axs[0].imshow(image)
23
+ axs[1].imshow(image_array)
24
+ axs[0].set_title("img_raw")
25
+ axs[1].set_title(f"img_{convert}")
26
+ return image, image_array
27
+
28
+
29
+ from skimage import filters, morphology
30
+
31
+
32
+ def clean_img(
33
+ img,
34
+ method=["threshold_otsu", "objects", "holes"],
35
+ obj_min=50,
36
+ hole_min=50,
37
+ filter=None,
38
+ plot=False,
39
+ cmap="grey",
40
+ ):
41
+ if isinstance(method, str):
42
+ if method == "all":
43
+ method = ["threshold_otsu", "objects", "holes"]
44
+ else:
45
+ method = [method]
46
+ if any("thr" in met or "ot" in met for met in method) and filter is None:
47
+ thr_otsu = filters.threshold_otsu(img)
48
+ img_update = img > thr_otsu
49
+ if any("obj" in met for met in method):
50
+ img_update = morphology.remove_small_objects(img_update, min_size=obj_min)
51
+ if any("hol" in met for met in method):
52
+ img_update = morphology.remove_small_holes(img_update, area_threshold=hole_min)
53
+ if ("thr" in met for met in method) and filter: # threshold
54
+ mask = (img >= filter[0]) & (img <= filter[1])
55
+ img_update = np.where(mask, img, 0)
56
+
57
+ if plot:
58
+ plt.imshow(img_update, cmap=cmap)
59
+ return img_update
60
+
61
+
62
+ from skimage import filters, segmentation
63
+
64
+
65
+ def segment_img(
66
+ img,
67
+ filter=[30, 150],
68
+ plot=False,
69
+ mode="reflect", # 'reflect' or 'constant'
70
+ method="region", # 'region' or 'edge', 'threshold'
71
+ area_min=50,
72
+ cmap="jet",
73
+ connectivity=1,
74
+ output="segmentation",
75
+ ):
76
+ if "reg" in method: # region method
77
+ # 1. find an elevation map using the Sobel gradient of the image
78
+ elevation_map = filters.sobel(img, mode=mode)
79
+ # 2. find markers of the background and the coins based on the extreme parts of the histogram of gray values.
80
+ markers = np.zeros_like(img)
81
+ # Apply filtering based on provided filter values
82
+ if filter is not None:
83
+ markers[img < filter[0]] = 1
84
+ markers[img > filter[1]] = 2
85
+ else:
86
+ # If no filter is provided, set markers across the whole range of the image
87
+ markers[img == img.min()] = 1
88
+ markers[img == img.max()] = 2
89
+ # 3. watershed transform to fill regions of the elevation map starting from the markers
90
+ img_segmentation = segmentation.watershed(
91
+ elevation_map, markers=markers, connectivity=connectivity
92
+ )
93
+ if plot:
94
+ _, axs = plt.subplots(2, 2)
95
+ for i, ax in enumerate(axs.flatten().tolist()):
96
+ if i == 0:
97
+ ax.imshow(img)
98
+ ax.set_title("image")
99
+ elif i == 1:
100
+ ax.imshow(elevation_map, cmap=cmap)
101
+ ax.set_title("elevation map")
102
+ elif i == 2:
103
+ ax.imshow(markers, cmap=cmap)
104
+ ax.set_title("markers")
105
+ elif i == 3:
106
+ ax.imshow(img_segmentation, cmap=cmap)
107
+ ax.set_title("segmentation")
108
+ ax.set_axis_off()
109
+ if "el" in output:
110
+ return elevation_map
111
+ elif "mar" in output:
112
+ return markers
113
+ elif "seg" in output:
114
+ return img_segmentation
115
+ else:
116
+ return img_segmentation
117
+ elif "ed" in method: # edge
118
+ edges = cal_edges(img)
119
+ fills = fill_holes(edges)
120
+ img_segmentation = remove_holes(fills, area_min)
121
+ if plot:
122
+ _, axs = plt.subplots(2, 2)
123
+ for i, ax in enumerate(axs.flatten().tolist()):
124
+ if i == 0:
125
+ ax.imshow(img)
126
+ ax.set_title("image")
127
+ elif i == 1:
128
+ ax.imshow(edges, cmap=cmap)
129
+ ax.set_title("edges map")
130
+ elif i == 2:
131
+ ax.imshow(fills, cmap=cmap)
132
+ ax.set_title("fills")
133
+ elif i == 3:
134
+ ax.imshow(img_segmentation, cmap=cmap)
135
+ ax.set_title("segmentation")
136
+ ax.set_axis_off()
137
+ if "seg" in output:
138
+ return img_segmentation
139
+ elif "ed" in output:
140
+ return edges
141
+ elif "fill" in output:
142
+ return fills
143
+ else:
144
+ return img_segmentation
145
+ elif "thr" in method: # threshold
146
+ if filter:
147
+ mask = (img >= filter[0]) & (img <= filter[1])
148
+ img_threshold = np.where(mask, img, 0)
149
+ if plot:
150
+ plt.imshow(img_threshold, cmap=cmap)
151
+ return img_threshold
152
+ else:
153
+ return None
154
+
155
+
156
+ from skimage import measure
157
+
158
+
159
+ def label_img(img, plot=False):
160
+ img_label = measure.label(img)
161
+ if plot:
162
+ plt.imshow(img_label)
163
+ return img_label
164
+
165
+
166
+ def img_process(img, **kwargs):
167
+ convert = "gray"
168
+ method_clean_img = ["threshold_otsu", "objects", "holes"]
169
+ obj_min_clean_img = 50
170
+ hole_min_clean_img = 50
171
+ plot = True
172
+ for k, v in kwargs.items():
173
+ if "convert" in k.lower():
174
+ convert = v
175
+ if "met" in k.lower() and any(
176
+ ["clean" in k.lower(), "rem" in k.lower(), "rm" in k.lower()]
177
+ ):
178
+ method_clean_img = v
179
+ if "obj" in k.lower() and any(
180
+ ["clean" in k.lower(), "rem" in k.lower(), "rm" in k.lower()]
181
+ ):
182
+ obj_min_clean_img = v
183
+ if "hol" in k.lower() and any(
184
+ ["clean" in k.lower(), "rem" in k.lower(), "rm" in k.lower()]
185
+ ):
186
+ hole_min_clean_img = v
187
+ if "plot" in k.lower():
188
+ plot = v
189
+
190
+ if isinstance(img, str):
191
+ image, image_array = open_img(img, convert=convert)
71
192
  normalized_image = image_array / 255.0
72
193
  else:
73
- cleaned_image = dir_img
194
+ cleaned_image = img
74
195
  image_array = cleaned_image
75
196
  normalized_image = cleaned_image
76
197
  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
198
 
199
+ # Remove small objects and fill small holes
200
+ cleaned_image = clean_img(
201
+ img=image_array,
202
+ method=method_clean_img,
203
+ obj_min=obj_min_clean_img,
204
+ hole_min=hole_min_clean_img,
205
+ plot=False,
206
+ )
96
207
  # 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)
208
+ label_image = label_img(cleaned_image)
209
+ overlay_image = overlay_imgs(label_image, image=image_array)
101
210
  regions = measure.regionprops(label_image, intensity_image=image_array)
102
211
  region_props = measure.regionprops_table(
103
212
  label_image, intensity_image=image_array, properties=props_list
@@ -108,18 +217,137 @@ def img_preprocess(dir_img, subtract_background=True, size_obj=50, size_hole=50)
108
217
  "img": image,
109
218
  "img_array": image_array,
110
219
  "img_scale": normalized_image,
111
- "img_binary": binary_image,
112
220
  "img_clean": cleaned_image,
113
221
  "img_label": label_image,
114
222
  "img_overlay": overlay_image,
115
- "thr_val": thr_val,
116
223
  "regions": regions,
117
224
  "df_regions": df_regions,
118
225
  }
119
-
226
+ if plot:
227
+ imgs = []
228
+ [imgs.append(i) for i in list(output.keys()) if "img" in i]
229
+ for img_ in imgs:
230
+ plt.figure()
231
+ plt.imshow(output[img_])
232
+ plt.title(img_)
120
233
  return output
121
234
 
122
235
 
236
+ # def img_preprocess(dir_img, subtract_background=True, size_obj=50, size_hole=50,**kwargs):
237
+ # """
238
+ # Processes an image by performing thresholding, morphological operations,
239
+ # and region labeling.
240
+
241
+ # Parameters:
242
+ # - dir_img: Path to the image file.
243
+ # - size_obj: Minimum size of objects to keep (default: 50).
244
+ # - size_hole: Maximum size of holes to fill (default: 50).
245
+
246
+ # Returns:
247
+ # - output: Dictionary containing the overlay image, threshold value, and regions.
248
+ # """
249
+ # props_list = [
250
+ # "area", # Number of pixels in the region. Useful for determining the size of regions.
251
+ # "area_bbox",
252
+ # "area_convex",
253
+ # "area_filled",
254
+ # "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.
255
+ # "axis_minor_length",
256
+ # "bbox", # Bounding box coordinates (min_row, min_col, max_row, max_col). Useful for spatial localization of regions.
257
+ # "centroid", # Center of mass coordinates (centroid-0, centroid-1). Helps locate the center of each region.
258
+ # "centroid_local",
259
+ # "centroid_weighted",
260
+ # "centroid_weighted_local",
261
+ # "coords",
262
+ # "eccentricity", # Measure of how elongated the region is. Values range from 0 (circular) to 1 (line). Useful for assessing the shape of regions.
263
+ # "equivalent_diameter_area", # Diameter of a circle with the same area as the region. Provides a simple measure of size.
264
+ # "euler_number",
265
+ # "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.
266
+ # "feret_diameter_max", # Maximum diameter of the region, providing another measure of size.
267
+ # "image",
268
+ # "image_convex",
269
+ # "image_filled",
270
+ # "image_intensity",
271
+ # "inertia_tensor", # ensor describing the distribution of mass in the region, useful for more advanced shape analysis.
272
+ # "inertia_tensor_eigvals",
273
+ # "intensity_max", # Maximum intensity value within the region. Helps identify regions with high-intensity features.
274
+ # "intensity_mean", # Average intensity value within the region. Useful for distinguishing between regions based on their brightness.
275
+ # "intensity_min", # Minimum intensity value within the region. Useful for regions with varying intensity.
276
+ # "intensity_std",
277
+ # "label", # Unique identifier for each region.
278
+ # "moments",
279
+ # "moments_central",
280
+ # "moments_hu", # Hu moments are a set of seven invariant features that describe the shape of the region. Useful for shape recognition and classification.
281
+ # "moments_normalized",
282
+ # "moments_weighted",
283
+ # "moments_weighted_central",
284
+ # "moments_weighted_hu",
285
+ # "moments_weighted_normalized",
286
+ # "orientation", # ngle of the major axis of the ellipse that fits the region. Useful for determining the orientation of elongated regions.
287
+ # "perimeter", # Length of the boundary of the region. Useful for shape analysis.
288
+ # "perimeter_crofton",
289
+ # "slice",
290
+ # "solidity", # Ratio of the area of the region to the area of its convex hull. Indicates how solid or compact a region is.
291
+ # ]
292
+ # if isinstance(dir_img, str):
293
+ # # Step 1: Load the image
294
+ # image = Image.open(dir_img)
295
+
296
+ # # Step 2: Convert the image to grayscale and normalize
297
+ # gray_image = image.convert("L")
298
+ # image_array = np.array(gray_image)
299
+ # normalized_image = image_array / 255.0
300
+ # else:
301
+ # cleaned_image = dir_img
302
+ # image_array = cleaned_image
303
+ # normalized_image = cleaned_image
304
+ # image = cleaned_image
305
+ # binary_image = cleaned_image
306
+ # thr_val = None
307
+ # if subtract_background:
308
+ # # Step 3: Apply thresholding to segment the image
309
+ # thr_val = filters.threshold_otsu(image_array)
310
+ # print(f"Threshold value is: {thr_val}")
311
+
312
+ # # Apply thresholds and generate binary images
313
+ # binary_image = image_array > thr_val
314
+
315
+ # # Step 4: Perform morphological operations to clean the image
316
+ # # Remove small objects and fill small holes
317
+ # cleaned_image_rm_min_obj = morphology.remove_small_objects(
318
+ # binary_image, min_size=size_obj
319
+ # )
320
+ # cleaned_image = morphology.remove_small_holes(
321
+ # cleaned_image_rm_min_obj, area_threshold=size_hole
322
+ # )
323
+
324
+ # # Label the regions
325
+ # label_image = label_img(cleaned_image)
326
+
327
+ # # Optional: Overlay labels on the original image
328
+ # overlay_image = color.label2rgb(label_image, image_array)
329
+ # regions = measure.regionprops(label_image, intensity_image=image_array)
330
+ # region_props = measure.regionprops_table(
331
+ # label_image, intensity_image=image_array, properties=props_list
332
+ # )
333
+ # df_regions = pd.DataFrame(region_props)
334
+ # # Pack the results into a single output variable (dictionary)
335
+ # output = {
336
+ # "img": image,
337
+ # "img_array": image_array,
338
+ # "img_scale": normalized_image,
339
+ # "img_binary": binary_image,
340
+ # "img_clean": cleaned_image,
341
+ # "img_label": label_image,
342
+ # "img_overlay": overlay_image,
343
+ # "thr_val": thr_val,
344
+ # "regions": regions,
345
+ # "df_regions": df_regions,
346
+ # }
347
+
348
+ # return output
349
+
350
+
123
351
  def cal_pearson(img1, img2):
124
352
  """Compute Pearson correlation coefficient between two images."""
125
353
  img1_flat = img1.flatten()
@@ -134,3 +362,229 @@ def cal_manders(img1, img2):
134
362
  img2_binary = img2 > filters.threshold_otsu(img2)
135
363
  overlap_coef = np.sum(img1_binary & img2_binary) / np.sum(img1_binary)
136
364
  return overlap_coef
365
+
366
+
367
+ def overlay_imgs(
368
+ *imgs,
369
+ image=None,
370
+ colors=None,
371
+ alpha=0.3,
372
+ bg_label=0,
373
+ bg_color=(0, 0, 0),
374
+ image_alpha=1,
375
+ kind="overlay",
376
+ saturation=0,
377
+ channel_axis=-1,
378
+ ):
379
+ # Ensure all input images have the same shape
380
+ print(
381
+ f'\nusage:\nich2ls.overlay_imgs(res_b["img_binary"], res_r["img_binary"], bg_label=0)'
382
+ )
383
+ shapes = [img.shape for img in imgs]
384
+ if not all(shape == shapes[0] for shape in shapes):
385
+ raise ValueError("All input images must have the same shape")
386
+
387
+ # If no image is provided, use the first input image as the base
388
+ if image is None:
389
+ image = imgs[0]
390
+
391
+ # Combine the images into a label, with unique multipliers for each image
392
+ label = sum((img.astype(np.uint) * (i + 1) for i, img in enumerate(imgs)))
393
+
394
+ # Create the overlay image
395
+ overlay_image = color.label2rgb(
396
+ label,
397
+ image=image,
398
+ bg_label=bg_label,
399
+ colors=colors,
400
+ alpha=alpha,
401
+ bg_color=bg_color,
402
+ image_alpha=image_alpha,
403
+ saturation=saturation,
404
+ kind=kind,
405
+ channel_axis=channel_axis, # Corrected from saturation to channel_axis
406
+ )
407
+
408
+ return overlay_image
409
+
410
+
411
+ from skimage import exposure
412
+
413
+
414
+ # Comparing edge-based and region-based segmentation
415
+ def draw_hist(img, ax=None, **kwargs):
416
+ """
417
+ _, axs = plt.subplots(1, 2)
418
+ draw_hist(image, c="r", ax=axs[1], lw=2, ls=":")
419
+ """
420
+ print(f"img type: {type(img)}")
421
+ if not isinstance(img, np.ndarray):
422
+ img = np.array(img)
423
+ hist, hist_centers = exposure.histogram(img)
424
+ if ax is None:
425
+ ax = plt.gca()
426
+ ax.plot(hist_centers, hist, **kwargs)
427
+
428
+
429
+ from skimage import feature
430
+
431
+
432
+ # delineate the contours of the coins using edge-based segmentation
433
+ def cal_edges(img, plot=False, cmap=plt.cm.gray):
434
+ edges = feature.canny(img)
435
+ if plot:
436
+ plt.imshow(edges, cmap=cmap)
437
+ return edges
438
+
439
+
440
+ from scipy import ndimage as ndi
441
+
442
+
443
+ # These contours are then filled using mathematical morphology.
444
+ def fill_holes(img, plot=False):
445
+ img_fill_holes = ndi.binary_fill_holes(img)
446
+ if plot:
447
+ plt.imshow(img_fill_holes, cmap=plt.cm.gray)
448
+ return img_fill_holes
449
+
450
+
451
+ from skimage import morphology
452
+
453
+
454
+ def remove_holes(img, size=50, plot=False):
455
+ img_rm_holes = morphology.remove_small_objects(img, size)
456
+ if plot:
457
+ plt.imshow(img_rm_holes, cmap=plt.cm.gray)
458
+ return img_rm_holes
459
+
460
+
461
+ import matplotlib.patches as mpatches
462
+ from skimage import measure, color
463
+
464
+
465
+ def draw_bbox(
466
+ img,
467
+ df=None,
468
+ img_label=None,
469
+ img_label2rgb=None,
470
+ show=True, # plot the image
471
+ bg_alpha=1, # the alpha of the bg image
472
+ area_min=1,
473
+ area_max=None,
474
+ fill=False,
475
+ edgecolor="red",
476
+ linewidth=2,
477
+ ax=None,
478
+ **kwargs,
479
+ ):
480
+ """
481
+ ich2ls.draw_bbox(
482
+ res["img_label"], fill=False, color="r", lw=1, edgecolor="w", alpha=0.4)
483
+ """
484
+ if ax is None:
485
+ ax = plt.gca()
486
+ if img_label is None:
487
+ img_label = measure.label(img)
488
+ if isinstance(show, bool):
489
+ if show:
490
+ if img_label2rgb is None:
491
+ img_label2rgb = color.label2rgb(img_label, image=img, bg_label=0)
492
+ ax.imshow(img_label2rgb, alpha=bg_alpha)
493
+ elif isinstance(show, str):
494
+ if "raw" in show:
495
+ ax.imshow(img, alpha=bg_alpha)
496
+ elif "label" in show:
497
+ ax.imshow(img_label, alpha=bg_alpha)
498
+ elif "rgb" in show:
499
+ if img_label2rgb is None:
500
+ img_label2rgb = color.label2rgb(img_label, image=img, bg_label=0)
501
+ ax.imshow(img_label2rgb, alpha=bg_alpha)
502
+ elif "no" in show.lower():
503
+ pass
504
+ num = 0
505
+ if df is None:
506
+ for region in measure.regionprops(img_label):
507
+ # take regions with large enough areas
508
+ if area_max is None:
509
+ area_max = np.inf
510
+ if area_min <= region.area <= area_max:
511
+ minr, minc, maxr, maxc = region.bbox
512
+ rect = mpatches.Rectangle(
513
+ (minc, minr),
514
+ maxc - minc,
515
+ maxr - minr,
516
+ fill=fill,
517
+ edgecolor=edgecolor,
518
+ linewidth=linewidth,
519
+ **kwargs,
520
+ )
521
+ ax.add_patch(rect)
522
+ num += 1
523
+ else:
524
+ # Iterate over each row in the DataFrame and draw the bounding boxes
525
+ for _, row in df.iterrows():
526
+ minr = row["bbox-0"]
527
+ minc = row["bbox-1"]
528
+ maxr = row["bbox-2"]
529
+ maxc = row["bbox-3"]
530
+
531
+ # Optionally filter by area if needed
532
+ area = (maxr - minr) * (maxc - minc)
533
+ if area >= area_min:
534
+ rect = mpatches.Rectangle(
535
+ (minc, minr),
536
+ maxc - minc,
537
+ maxr - minr,
538
+ fill=fill,
539
+ edgecolor=edgecolor,
540
+ linewidth=linewidth,
541
+ **kwargs,
542
+ )
543
+ ax.add_patch(rect)
544
+ num += 1
545
+ return num
546
+
547
+
548
+ props_list = [
549
+ "area", # Number of pixels in the region. Useful for determining the size of regions.
550
+ "area_bbox",
551
+ "area_convex",
552
+ "area_filled",
553
+ "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.
554
+ "axis_minor_length",
555
+ "bbox", # Bounding box coordinates (min_row, min_col, max_row, max_col). Useful for spatial localization of regions.
556
+ "centroid", # Center of mass coordinates (centroid-0, centroid-1). Helps locate the center of each region.
557
+ "centroid_local",
558
+ "centroid_weighted",
559
+ "centroid_weighted_local",
560
+ "coords",
561
+ "eccentricity", # Measure of how elongated the region is. Values range from 0 (circular) to 1 (line). Useful for assessing the shape of regions.
562
+ "equivalent_diameter_area", # Diameter of a circle with the same area as the region. Provides a simple measure of size.
563
+ "euler_number",
564
+ "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.
565
+ "feret_diameter_max", # Maximum diameter of the region, providing another measure of size.
566
+ "image",
567
+ "image_convex",
568
+ "image_filled",
569
+ "image_intensity",
570
+ "inertia_tensor", # ensor describing the distribution of mass in the region, useful for more advanced shape analysis.
571
+ "inertia_tensor_eigvals",
572
+ "intensity_max", # Maximum intensity value within the region. Helps identify regions with high-intensity features.
573
+ "intensity_mean", # Average intensity value within the region. Useful for distinguishing between regions based on their brightness.
574
+ "intensity_min", # Minimum intensity value within the region. Useful for regions with varying intensity.
575
+ "intensity_std",
576
+ "label", # Unique identifier for each region.
577
+ "moments",
578
+ "moments_central",
579
+ "moments_hu", # Hu moments are a set of seven invariant features that describe the shape of the region. Useful for shape recognition and classification.
580
+ "moments_normalized",
581
+ "moments_weighted",
582
+ "moments_weighted_central",
583
+ "moments_weighted_hu",
584
+ "moments_weighted_normalized",
585
+ "orientation", # ngle of the major axis of the ellipse that fits the region. Useful for determining the orientation of elongated regions.
586
+ "perimeter", # Length of the boundary of the region. Useful for shape analysis.
587
+ "perimeter_crofton",
588
+ "slice",
589
+ "solidity", # Ratio of the area of the region to the area of its convex hull. Indicates how solid or compact a region is.
590
+ ]
py2ls/netfinder.py CHANGED
@@ -671,8 +671,8 @@ def downloader(
671
671
  if dir_save:
672
672
  if rm_folder:
673
673
  ips.rm_folder(dir_save)
674
- if verbose:
675
- print(f"\n... attempting to download to local\n")
674
+ # if verbose:
675
+ # print(f"\n... attempting to download to local\n")
676
676
  fnames = [file_link.split("/")[-1] for file_link in file_links_all]
677
677
 
678
678
  for idx, file_link in enumerate(file_links_all):
@@ -688,6 +688,9 @@ def downloader(
688
688
  ext = next(
689
689
  (ftype for ftype in kind if ftype in file_link), None
690
690
  )
691
+ if ext is None:
692
+ ext = kind_
693
+ print("ehereerere", ext)
691
694
  if ext:
692
695
  corrected_fname = fname_corrector(fnames[idx], ext)
693
696
  corrected_fname = check_and_modify_filename(
py2ls/plot.py CHANGED
@@ -1823,15 +1823,43 @@ def get_color(
1823
1823
  cmap = "grey"
1824
1824
  # Determine color list based on cmap parameter
1825
1825
  if "aut" in cmap:
1826
- colorlist = [
1827
- "#474747",
1828
- "#FF2C00",
1829
- "#0C5DA5",
1830
- "#845B97",
1831
- "#58BBCC",
1832
- "#FF9500",
1833
- "#D57DBE",
1834
- ]
1826
+ if n == 1:
1827
+ colorlist = ["#3A4453"]
1828
+ elif n == 2:
1829
+ colorlist = ["#3A4453", "#DF5932"]
1830
+ elif n == 3:
1831
+ colorlist = ["#3A4453", "#DF5932", "#299D8F"]
1832
+ elif n == 4:
1833
+ # colorlist = ["#3A4453", "#DF5932", "#EBAA00", "#0B4083"]
1834
+ colorlist = ["#81C6BD", "#FBAF63", "#F2675B", "#72A1C9"]
1835
+ elif n == 5:
1836
+ colorlist = [
1837
+ "#3A4453",
1838
+ "#427AB2",
1839
+ "#F09148",
1840
+ "#DBDB8D",
1841
+ "#C59D94",
1842
+ "#AFC7E8",
1843
+ ]
1844
+ elif n == 6:
1845
+ colorlist = [
1846
+ "#3A4453",
1847
+ "#427AB2",
1848
+ "#F09148",
1849
+ "#DBDB8D",
1850
+ "#C59D94",
1851
+ "#E53528",
1852
+ ]
1853
+ else:
1854
+ colorlist = [
1855
+ "#474747",
1856
+ "#FF2C00",
1857
+ "#0C5DA5",
1858
+ "#845B97",
1859
+ "#58BBCC",
1860
+ "#FF9500",
1861
+ "#D57DBE",
1862
+ ]
1835
1863
  by = "start"
1836
1864
  elif any(["cub" in cmap.lower(), "sns" in cmap.lower()]):
1837
1865
  if kwargs:
@@ -1909,6 +1937,10 @@ import matplotlib.pyplot as plt
1909
1937
 
1910
1938
 
1911
1939
  def stdshade(ax=None, *args, **kwargs):
1940
+ """
1941
+ usage:
1942
+ plot.stdshade(data_array, c=clist[1], lw=2, ls="-.", alpha=0.2)
1943
+ """
1912
1944
  # Separate kws_line and kws_fill if necessary
1913
1945
  kws_line = kwargs.pop("kws_line", {})
1914
1946
  kws_fill = kwargs.pop("kws_fill", {})
@@ -1946,8 +1978,9 @@ def stdshade(ax=None, *args, **kwargs):
1946
1978
  ax = plt.gca()
1947
1979
  if ax is None:
1948
1980
  ax = plt.gca()
1949
- alpha = 0.5
1950
- acolor = "k"
1981
+ alpha = kwargs.get("alpha", 0.2)
1982
+ acolor = kwargs.get("color", "k")
1983
+ acolor = kwargs.get("c", "k")
1951
1984
  paraStdSem = "sem"
1952
1985
  plotStyle = "-"
1953
1986
  plotMarker = "none"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: py2ls
3
- Version: 0.1.9.9
3
+ Version: 0.1.10.0
4
4
  Summary: py(thon)2(too)ls
5
5
  Author: Jianfeng
6
6
  Author-email: Jianfeng.Liu0413@gmail.com
@@ -144,6 +144,7 @@ py2ls/.gitignore,sha256=y7GvbD_zZkjPVVIue8AyiuFkDMuUbvMaV65Lgu89To8,2763
144
144
  py2ls/LICENSE,sha256=UOZ1F5fFDe3XXvG4oNnkL1-Ecun7zpHzRxjp-XsMeAo,11324
145
145
  py2ls/README.md,sha256=CwvJWAnSXnCnrVHlnEbrxxi6MbjbE_MT6DH2D53S818,11572
146
146
  py2ls/__init__.py,sha256=Nn8jTIvySX7t7DMJ8VNRVctTStgXGjHldOIdZ35PdW8,165
147
+ py2ls/batman.py,sha256=CSM3PxXE4Qpt_yVfaAgMUAGZuJCG_PGkENjG_Mjev4k,5717
147
148
  py2ls/brain_atlas.py,sha256=w1o5EelRjq89zuFJUNSz4Da8HnTCwAwDAZ4NU4a-bAY,5486
148
149
  py2ls/chat.py,sha256=Yr22GoIvoWhpV3m4fdwV_I0Mn77La346_ymSinR-ORA,3793
149
150
  py2ls/correlators.py,sha256=RbOaJIPLCHJtUm5SFi_4dCJ7VFUPWR0PErfK3K26ad4,18243
@@ -176,15 +177,15 @@ py2ls/db2ls.py,sha256=MMfFX47aIPIyu7fU9aPvX9lbPRPYOpJ_VXwlnWk-8qo,13615
176
177
  py2ls/doc.py,sha256=xN3g1OWfoaGUhikbJ0NqbN5eKy1VZVvWwRlhHMgyVEc,4243
177
178
  py2ls/export_requirements.py,sha256=x2WgUF0jYKz9GfA1MVKN-MdsM-oQ8yUeC6Ua8oCymio,2325
178
179
  py2ls/freqanalysis.py,sha256=F4218VSPbgL5tnngh6xNCYuNnfR-F_QjECUUxrPYZss,32594
179
- py2ls/ich2ls.py,sha256=LYoMjU8fRJrtu_ZAnIAQkZVs2Vdoy7RvyUGA9Fq_Pt4,5995
180
+ py2ls/ich2ls.py,sha256=3E9R8oVpyYZXH5PiIQgT3CN5NxLe4Dwtm2LwaeacE6I,21381
180
181
  py2ls/ips.py,sha256=HbktFzKIszBHtB3DtyUCCM6xj9NJZAz38ZCcIomjBFs,105439
181
- py2ls/netfinder.py,sha256=oo8Nyqe9Oi3TON7YS9TCs2RBUjPY3KY7772DrsNPkyU,50679
182
- py2ls/plot.py,sha256=pMopJJSapyUwAFaoizwJMGSawGFVQFcAPDOh1vFM7N4,94253
182
+ py2ls/netfinder.py,sha256=xma9YoBxY4GcgoyG4YXEOU8oKPYByIt0uWqPyshHt8s,50812
183
+ py2ls/plot.py,sha256=9z0VPvMTFsuYKakuHjTGKK6UtiQylM3-WCxbNEKxTos,95283
183
184
  py2ls/setuptools-70.1.0-py3-none-any.whl,sha256=2bi3cUVal8ip86s0SOvgspteEF8SKLukECi-EWmFomc,882588
184
185
  py2ls/sleep_events_detectors.py,sha256=bQA3HJqv5qnYKJJEIhCyhlDtkXQfIzqksnD0YRXso68,52145
185
186
  py2ls/stats.py,sha256=fJmXQ9Lq460StOn-kfEljE97cySq7876HUPTnpB5hLs,38123
186
187
  py2ls/translator.py,sha256=bc5FB-wqC4TtQz9gyCP1mE38HqNRJ_pmuRIgKnAlMzM,30581
187
188
  py2ls/wb_detector.py,sha256=7y6TmBUj9exCZeIgBAJ_9hwuhkDh1x_-yg4dvNY1_GQ,6284
188
- py2ls-0.1.9.9.dist-info/METADATA,sha256=tRTwCfUkzWCGXAIkgA3xlBL4jUN7V6GI-4P4IcSg4Fc,20017
189
- py2ls-0.1.9.9.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
190
- py2ls-0.1.9.9.dist-info/RECORD,,
189
+ py2ls-0.1.10.0.dist-info/METADATA,sha256=76w1Clumy3D_fhABBpVwMaJV_49n-MJnOVRHW3wiaJY,20018
190
+ py2ls-0.1.10.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
191
+ py2ls-0.1.10.0.dist-info/RECORD,,