py2ls 0.1.10.0__py3-none-any.whl → 0.1.10.1__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/.git/COMMIT_EDITMSG +1 -1
- py2ls/.git/FETCH_HEAD +1 -1
- py2ls/.git/index +0 -0
- py2ls/.git/logs/HEAD +1 -0
- py2ls/.git/logs/refs/heads/main +1 -0
- py2ls/.git/logs/refs/remotes/origin/HEAD +1 -0
- py2ls/.git/logs/refs/remotes/origin/main +1 -0
- py2ls/.git/objects/27/aa6074f652bc6f7078f8647489d9ee8e24f0e2 +0 -0
- py2ls/.git/objects/28/c2969d785c1b892c2a96b3f00eba63a59811b3 +0 -0
- py2ls/.git/objects/2a/fdf45791a26d42ccead35ace76a8f0b2a56561 +0 -0
- py2ls/.git/objects/34/b6f3a2ee84f39bed4eee57f2c0e0afb994feb1 +0 -0
- py2ls/.git/objects/35/1a5f491ab97eee9d1ee699478d75a8bb5d3dc2 +0 -0
- py2ls/.git/objects/39/b13be65125556784e44c7a1d9821703c7ab67e +0 -0
- py2ls/.git/objects/3b/507acc7f23391644cc0b824b1e79fd2677a362 +0 -0
- py2ls/.git/objects/3d/9d10d27724657a436c65a6254bfd213d4b3562 +0 -0
- py2ls/.git/objects/47/6cbd5a7c5e35cddef2f8a38bdc4896d403b095 +0 -0
- py2ls/.git/objects/78/063f4c863fc371ec0313303c0a81283b35d9b6 +0 -0
- py2ls/.git/objects/82/70b319ce4046854fbe7dc41054b6c2d112dab2 +0 -0
- py2ls/.git/objects/85/aee46f478e9afdb84d50a05242c53b04ed2e21 +0 -0
- py2ls/.git/objects/86/e288b46f8fe179907e4413f665aeb5053fddb1 +0 -0
- py2ls/.git/objects/94/f7dbe88e80c4205a901b71eb8f181974376bba +0 -0
- py2ls/.git/objects/9b/ec5ee2236ee2d5532c36bfd132e23c58fdb69c +0 -0
- py2ls/.git/objects/b3/4f7f271c6d6105e35a6556ffda71d03afe8c96 +0 -0
- py2ls/.git/objects/b3/69579064bde9de9a19d114fc33e4e48cc8c0e4 +0 -0
- py2ls/.git/objects/bf/b54d65922ce1dfda1aaa014913a54e7172d0bc +0 -0
- py2ls/.git/objects/c1/397c6ed72c4e20ef6b9ab83163e9a6baba5b45 +0 -0
- py2ls/.git/objects/cc/45df1d317a2eb63ff1ff3a5f3b4a9f98fd92b5 +0 -0
- py2ls/.git/objects/d6/39e8af592cd75a318d8affddd1bcc70c2095f2 +0 -0
- py2ls/.git/objects/db/3f2cd643292057936230b95cf7ec3046affe11 +0 -0
- py2ls/.git/objects/de/214c626ac2dd2685bfaa0bc0fc20f528d014d7 +0 -0
- py2ls/.git/objects/e4/6c715352db9fe3c887a635f1916df4ca1f4ff9 +0 -0
- py2ls/.git/objects/e5/0580a0bd1e1b3d29f834382b80fceb61d5cf0c +0 -0
- py2ls/.git/objects/ec/d980279432b13f0374b90ca439a6329cdece0f +0 -0
- py2ls/.git/objects/ee/cee64eacaff022dcdc509c0c2b1da492f21060 +0 -0
- py2ls/.git/objects/f5/61c3c1bf1c9ea9c9d1f556a7be2869f71f3bdf +0 -0
- py2ls/.git/refs/heads/main +1 -1
- py2ls/.git/refs/remotes/origin/main +1 -1
- py2ls/batman.py +62 -47
- py2ls/ips.py +1 -1
- py2ls/netfinder.py +100 -1
- py2ls/ocr.py +557 -0
- py2ls/plot.py +24 -0
- {py2ls-0.1.10.0.dist-info → py2ls-0.1.10.1.dist-info}/METADATA +1 -1
- {py2ls-0.1.10.0.dist-info → py2ls-0.1.10.1.dist-info}/RECORD +45 -16
- {py2ls-0.1.10.0.dist-info → py2ls-0.1.10.1.dist-info}/WHEEL +0 -0
py2ls/.git/COMMIT_EDITMSG
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
reg_update
|
py2ls/.git/FETCH_HEAD
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
86e288b46f8fe179907e4413f665aeb5053fddb1 branch 'main' of https://github.com/Jianfengliu0413/py2ls
|
py2ls/.git/index
CHANGED
Binary file
|
py2ls/.git/logs/HEAD
CHANGED
@@ -19,3 +19,4 @@ d84688b54c0040a30976b3a6540bc47adf7ce680 32fd627b62fad7cf3b2f9e34ab9777126a0987a
|
|
19
19
|
1c3f92adda34344bcbbbf9d409c79855ae2aaea8 bf67907e337021ebff434e02b19b30a741c144af Jianfeng <Jianfeng.Liu0413@gmail.com> 1720948339 +0200 commit: update
|
20
20
|
bf67907e337021ebff434e02b19b30a741c144af a15389729850729fc7bd78a54f26fce77f30be12 Jianfeng <Jianfeng.Liu0413@gmail.com> 1721137352 +0200 commit: update ips
|
21
21
|
a15389729850729fc7bd78a54f26fce77f30be12 6dc2cdf4a84e538e5d4777486aeff87e42f41799 Jianfeng <Jianfeng.Liu0413@gmail.com> 1723527985 +0200 commit: update
|
22
|
+
6dc2cdf4a84e538e5d4777486aeff87e42f41799 86e288b46f8fe179907e4413f665aeb5053fddb1 Jianfeng <Jianfeng.Liu0413@gmail.com> 1725537214 +0200 commit: reg_update
|
py2ls/.git/logs/refs/heads/main
CHANGED
@@ -19,3 +19,4 @@ d84688b54c0040a30976b3a6540bc47adf7ce680 32fd627b62fad7cf3b2f9e34ab9777126a0987a
|
|
19
19
|
1c3f92adda34344bcbbbf9d409c79855ae2aaea8 bf67907e337021ebff434e02b19b30a741c144af Jianfeng <Jianfeng.Liu0413@gmail.com> 1720948339 +0200 commit: update
|
20
20
|
bf67907e337021ebff434e02b19b30a741c144af a15389729850729fc7bd78a54f26fce77f30be12 Jianfeng <Jianfeng.Liu0413@gmail.com> 1721137352 +0200 commit: update ips
|
21
21
|
a15389729850729fc7bd78a54f26fce77f30be12 6dc2cdf4a84e538e5d4777486aeff87e42f41799 Jianfeng <Jianfeng.Liu0413@gmail.com> 1723527985 +0200 commit: update
|
22
|
+
6dc2cdf4a84e538e5d4777486aeff87e42f41799 86e288b46f8fe179907e4413f665aeb5053fddb1 Jianfeng <Jianfeng.Liu0413@gmail.com> 1725537214 +0200 commit: reg_update
|
@@ -137,3 +137,4 @@ a15389729850729fc7bd78a54f26fce77f30be12 a15389729850729fc7bd78a54f26fce77f30be1
|
|
137
137
|
a15389729850729fc7bd78a54f26fce77f30be12 a15389729850729fc7bd78a54f26fce77f30be12 Jianfeng Liu <macjianfeng@JFLMBP.cin.medizin.uni-tuebingen.de> 1721326072 +0200 remote set-head
|
138
138
|
a15389729850729fc7bd78a54f26fce77f30be12 a15389729850729fc7bd78a54f26fce77f30be12 Jianfeng Liu <macjianfeng@jflmbp.speedport.ip> 1723527981 +0200 remote set-head
|
139
139
|
6dc2cdf4a84e538e5d4777486aeff87e42f41799 6dc2cdf4a84e538e5d4777486aeff87e42f41799 Jianfeng Liu <macjianfeng@jflmbp.speedport.ip> 1723527990 +0200 remote set-head
|
140
|
+
86e288b46f8fe179907e4413f665aeb5053fddb1 86e288b46f8fe179907e4413f665aeb5053fddb1 Jianfeng Liu <macjianfeng@JFLMBP.cin.medizin.uni-tuebingen.de> 1725537218 +0200 remote set-head
|
@@ -18,3 +18,4 @@ d84688b54c0040a30976b3a6540bc47adf7ce680 32fd627b62fad7cf3b2f9e34ab9777126a0987a
|
|
18
18
|
1c3f92adda34344bcbbbf9d409c79855ae2aaea8 bf67907e337021ebff434e02b19b30a741c144af Jianfeng <Jianfeng.Liu0413@gmail.com> 1720948342 +0200 update by push
|
19
19
|
bf67907e337021ebff434e02b19b30a741c144af a15389729850729fc7bd78a54f26fce77f30be12 Jianfeng <Jianfeng.Liu0413@gmail.com> 1721137354 +0200 update by push
|
20
20
|
a15389729850729fc7bd78a54f26fce77f30be12 6dc2cdf4a84e538e5d4777486aeff87e42f41799 Jianfeng <Jianfeng.Liu0413@gmail.com> 1723527989 +0200 update by push
|
21
|
+
6dc2cdf4a84e538e5d4777486aeff87e42f41799 86e288b46f8fe179907e4413f665aeb5053fddb1 Jianfeng <Jianfeng.Liu0413@gmail.com> 1725537218 +0200 update by push
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
py2ls/.git/refs/heads/main
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
86e288b46f8fe179907e4413f665aeb5053fddb1
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
86e288b46f8fe179907e4413f665aeb5053fddb1
|
py2ls/batman.py
CHANGED
@@ -7,20 +7,19 @@ import schedule
|
|
7
7
|
import time
|
8
8
|
from datetime import datetime
|
9
9
|
import os
|
10
|
+
from pprint import pp
|
11
|
+
import json
|
10
12
|
|
11
13
|
|
12
|
-
|
13
|
-
"",
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
),
|
22
|
-
f"Pappelweg 8\n72076 Tübingen\n\n",
|
23
|
-
]
|
14
|
+
def extract_kv(
|
15
|
+
dir_data="/Users/macjianfeng/Dropbox/github/python/py2ls/confidential_data/gmail_login.json",
|
16
|
+
idx=0,
|
17
|
+
): # select the index
|
18
|
+
with open(dir_data, "r") as file:
|
19
|
+
email_login = json.load(file)
|
20
|
+
for i, (user, pd) in enumerate(email_login.items()):
|
21
|
+
if i == idx:
|
22
|
+
return user, pd
|
24
23
|
|
25
24
|
|
26
25
|
def email_to(**kwargs):
|
@@ -40,7 +39,10 @@ def email_to(**kwargs):
|
|
40
39
|
who, what, subject = None, None, None
|
41
40
|
attachments = False
|
42
41
|
pause_sec = False # default 10 seconds pause
|
43
|
-
|
42
|
+
|
43
|
+
signature_styles = extract_kv(idx=1)[1] # signature list
|
44
|
+
signature = signature_styles[0] # default signature,None
|
45
|
+
verbose = True
|
44
46
|
|
45
47
|
# params config
|
46
48
|
for k, v in kwargs.items():
|
@@ -67,15 +69,14 @@ def email_to(**kwargs):
|
|
67
69
|
if any(["sig" in k.lower()]): # 'attachments', 'file'
|
68
70
|
signature = v # optional
|
69
71
|
if not isinstance(v, str):
|
72
|
+
print(signature_styles)
|
70
73
|
signature = signature_styles[v]
|
71
|
-
|
72
|
-
|
73
|
-
email_address = "andyandhope@gmail.com"
|
74
|
-
email_password = "myff ltls sfym wehe" # this is fake info
|
74
|
+
if any(["verb" in k.lower(), "show" in k.lower()]): # 'verbose', 'show'
|
75
|
+
verbose = v # verbose
|
75
76
|
|
76
77
|
# Create email message
|
77
78
|
message = MIMEMultipart()
|
78
|
-
message["From"] =
|
79
|
+
message["From"] = extract_kv()[0]
|
79
80
|
message["To"] = who
|
80
81
|
message["Subject"] = subject
|
81
82
|
|
@@ -97,10 +98,9 @@ def email_to(**kwargs):
|
|
97
98
|
part.set_payload(attachment.read())
|
98
99
|
encoders.encode_base64(part)
|
99
100
|
|
100
|
-
fname = os.path.basename(file)
|
101
|
-
print(fname)
|
102
101
|
part.add_header(
|
103
|
-
"Content-Disposition",
|
102
|
+
"Content-Disposition",
|
103
|
+
f'attachment; filename= "{os.path.basename(file)}"',
|
104
104
|
)
|
105
105
|
message.attach(part)
|
106
106
|
except FileNotFoundError:
|
@@ -109,13 +109,21 @@ def email_to(**kwargs):
|
|
109
109
|
print(f"Error attaching file {file}: {e}")
|
110
110
|
if pause_sec:
|
111
111
|
time.sleep(pause_sec)
|
112
|
+
|
112
113
|
# Send the email
|
113
114
|
try:
|
114
115
|
with smtplib.SMTP("smtp.gmail.com", 587) as server:
|
115
116
|
server.starttls()
|
116
|
-
server.login(
|
117
|
-
server.sendmail(
|
118
|
-
|
117
|
+
server.login(extract_kv()[0], extract_kv()[1])
|
118
|
+
server.sendmail(extract_kv()[0], who, message.as_string())
|
119
|
+
if verbose:
|
120
|
+
if attachments:
|
121
|
+
print(
|
122
|
+
f'\nEmail successfully sent to:\nto:"{who}"\nsubject:{subject}\nattached:'
|
123
|
+
)
|
124
|
+
pp(attachments)
|
125
|
+
else:
|
126
|
+
print(f'\nEmail successfully sent to:\nto:"{who}"\nsubject:{subject}')
|
119
127
|
except Exception as e:
|
120
128
|
print(f"Failed to send email: {e}")
|
121
129
|
|
@@ -158,26 +166,33 @@ def example_job():
|
|
158
166
|
|
159
167
|
|
160
168
|
if __name__ == "__main__":
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
#
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
169
|
+
pass
|
170
|
+
# # Schedule the job to run every minute
|
171
|
+
# schedule.every(1).minutes.do(example_job)
|
172
|
+
|
173
|
+
# while True:
|
174
|
+
# schedule.run_pending()
|
175
|
+
# time.sleep(1)
|
176
|
+
|
177
|
+
# # example2:
|
178
|
+
# email_to(
|
179
|
+
# who="Jianfeng.Liu@medizin.uni-tuebingen.de",
|
180
|
+
# subj="test",
|
181
|
+
# wha="this is the body",
|
182
|
+
# signat="\n\n Best, Jianfeng\n",
|
183
|
+
# att="/Users/macjianfeng/Dropbox/Downloads/_*_doc-xlsx/20240822-preprints_full_20190101_20201031-2.xlsx",
|
184
|
+
# )
|
185
|
+
|
186
|
+
# # example3:
|
187
|
+
# email_to(
|
188
|
+
# who="Jianfeng.Liu@medizin.uni-tuebingen.de",
|
189
|
+
# subj="test",
|
190
|
+
# wha="this is the test",
|
191
|
+
# signat=2,
|
192
|
+
# # att="/Users/macjianfeng/Dropbox/Downloads/_*_doc-xlsx/20240822-preprints_full_20190101_20201031-2.xlsx",
|
193
|
+
# )
|
194
|
+
|
195
|
+
# # example_4
|
196
|
+
# print(extract_kv(idx=0))
|
197
|
+
# print(extract_kv(idx=0)[0])
|
198
|
+
# print(extract_kv(idx=1))
|
py2ls/ips.py
CHANGED
@@ -295,7 +295,7 @@ def is_text(s):
|
|
295
295
|
return has_alpha and has_non_alpha
|
296
296
|
|
297
297
|
|
298
|
-
def strcmp(search_term, candidates, ignore_case=True, verbose=
|
298
|
+
def strcmp(search_term, candidates, ignore_case=True, verbose=False, scorer="WR"):
|
299
299
|
"""
|
300
300
|
Compares a search term with a list of candidate strings and finds the best match based on similarity score.
|
301
301
|
|
py2ls/netfinder.py
CHANGED
@@ -63,6 +63,36 @@ def user_agent(
|
|
63
63
|
return output_ua
|
64
64
|
|
65
65
|
|
66
|
+
def get_tags(content, ascending=True):
|
67
|
+
tag_names = set()
|
68
|
+
|
69
|
+
# Iterate through all tags in the parsed HTML
|
70
|
+
for tag in content.find_all(True): # `True` finds all tags
|
71
|
+
tag_names.add(tag.name) # Add the tag name to the set
|
72
|
+
|
73
|
+
# Convert set to a sorted list for easier reading (optional)
|
74
|
+
if ascending is None:
|
75
|
+
return tag_names
|
76
|
+
else:
|
77
|
+
if ascending:
|
78
|
+
return sorted(tag_names)
|
79
|
+
else:
|
80
|
+
return tag_names
|
81
|
+
|
82
|
+
|
83
|
+
def get_attr(content, where, attr):
|
84
|
+
all_tags = get_tags(content)
|
85
|
+
if all([where, attr]):
|
86
|
+
if where in all_tags:
|
87
|
+
element_ = content.find_all(where)
|
88
|
+
return [i[attr] for i in element_]
|
89
|
+
else:
|
90
|
+
print(
|
91
|
+
f"cannot find attr {attr} in tag_name{where}\n or possibly cannot find the tag_names:"
|
92
|
+
)
|
93
|
+
pp(all_tags)
|
94
|
+
|
95
|
+
|
66
96
|
def extract_text_from_content(
|
67
97
|
content, content_type="text/html", where=None, what=None, extend=True, **kwargs
|
68
98
|
):
|
@@ -128,7 +158,9 @@ def extract_text_from_content(
|
|
128
158
|
result_set = content.find_all(where, **search_kwargs)
|
129
159
|
else:
|
130
160
|
result_set = content.find_all(where, attrs=dict(**search_kwargs))
|
131
|
-
|
161
|
+
if "get" in kwargs:
|
162
|
+
attr = kwargs["get"]
|
163
|
+
return get_attr(content, where, attr)
|
132
164
|
if not result_set:
|
133
165
|
print("Failed: check the 'attrs' setting: attrs={'id':'xample'}")
|
134
166
|
if extend:
|
@@ -216,6 +248,60 @@ def get_cookies(url, login={"username": "your_username", "password": "your_passw
|
|
216
248
|
return cookies_dict
|
217
249
|
|
218
250
|
|
251
|
+
### 更加平滑地移动鼠标, 这样更容易反爬
|
252
|
+
def scroll_smth_steps(driver, scroll_pause=0.5, min_step=200, max_step=600):
|
253
|
+
"""Smoothly scrolls down the page to trigger lazy loading."""
|
254
|
+
current_scroll_position = 0
|
255
|
+
end_of_page = driver.execute_script("return document.body.scrollHeight")
|
256
|
+
|
257
|
+
while current_scroll_position < end_of_page:
|
258
|
+
step = random.randint(min_step, max_step)
|
259
|
+
driver.execute_script(f"window.scrollBy(0, {step});")
|
260
|
+
time.sleep(scroll_pause)
|
261
|
+
|
262
|
+
# Update the current scroll position
|
263
|
+
current_scroll_position += step
|
264
|
+
end_of_page = driver.execute_script("return document.body.scrollHeight")
|
265
|
+
|
266
|
+
|
267
|
+
def scroll_inf2end(driver, scroll_pause=1):
|
268
|
+
"""Continuously scrolls until the end of the page is reached."""
|
269
|
+
last_height = driver.execute_script("return document.body.scrollHeight")
|
270
|
+
|
271
|
+
while True:
|
272
|
+
# Scroll to the bottom
|
273
|
+
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
|
274
|
+
time.sleep(scroll_pause)
|
275
|
+
|
276
|
+
# Get the new height after scrolling
|
277
|
+
new_height = driver.execute_script("return document.body.scrollHeight")
|
278
|
+
if new_height == last_height:
|
279
|
+
break # Exit if no new content is loaded
|
280
|
+
last_height = new_height
|
281
|
+
|
282
|
+
|
283
|
+
def corr_by_kind(wait_until_kind):
|
284
|
+
"""
|
285
|
+
Map the 'wait_until_kind' string to the appropriate Selenium By strategy.
|
286
|
+
"""
|
287
|
+
if "tag" in wait_until_kind:
|
288
|
+
return By.TAG_NAME
|
289
|
+
elif "css" in wait_until_kind:
|
290
|
+
return By.CSS_SELECTOR
|
291
|
+
elif "id" in wait_until_kind:
|
292
|
+
return By.ID
|
293
|
+
elif "name" in wait_until_kind:
|
294
|
+
return By.NAME
|
295
|
+
elif "class" in wait_until_kind:
|
296
|
+
return By.CLASS_NAME
|
297
|
+
elif "path" in wait_until_kind:
|
298
|
+
return By.XPATH
|
299
|
+
elif "link" in wait_until_kind or "text" in wait_until_kind:
|
300
|
+
return By.LINK_TEXT
|
301
|
+
else:
|
302
|
+
raise ValueError(f"Unsupported wait_until_kind: {wait_until_kind}")
|
303
|
+
|
304
|
+
|
219
305
|
def fetch_all(
|
220
306
|
url,
|
221
307
|
parser="lxml",
|
@@ -224,6 +310,8 @@ def fetch_all(
|
|
224
310
|
timeout=10,
|
225
311
|
retry=2,
|
226
312
|
wait=0,
|
313
|
+
wait_until=None,
|
314
|
+
wait_until_kind=None,
|
227
315
|
scroll_try=3,
|
228
316
|
login_url=None,
|
229
317
|
username=None,
|
@@ -308,7 +396,10 @@ def fetch_all(
|
|
308
396
|
prefs = {"profile.managed_default_content_settings.images": 2}
|
309
397
|
chrome_options.add_experimental_option("prefs", prefs)
|
310
398
|
# chrome_options.page_load_strategy = capability
|
399
|
+
|
311
400
|
service = Service(ChromeDriverManager().install())
|
401
|
+
# driver_path='/Users/macjianfeng/.wdm/drivers/chromedriver/mac64/127.0.6533.119/chromedriver-mac-arm64/chromedriver'
|
402
|
+
# service=Service(executable_path=driver_path)
|
312
403
|
|
313
404
|
driver_ = webdriver.Chrome(service=service, options=chrome_options)
|
314
405
|
|
@@ -323,6 +414,11 @@ def fetch_all(
|
|
323
414
|
wait_ = 0
|
324
415
|
driver_.implicitly_wait(wait_)
|
325
416
|
|
417
|
+
if wait_until is not None and wait_until_kind is not None:
|
418
|
+
strategy = corr_by_kind(wait_until_kind)
|
419
|
+
WebDriverWait(driver_, timeout).until(
|
420
|
+
EC.presence_of_element_located((strategy, wait_until))
|
421
|
+
)
|
326
422
|
if login_url and login_dict:
|
327
423
|
cookies = get_cookies(url=login_url, login=login_dict)
|
328
424
|
driver_.get(url)
|
@@ -358,6 +454,9 @@ def fetch_all(
|
|
358
454
|
# EC.presence_of_element_located((by, where))
|
359
455
|
# )
|
360
456
|
|
457
|
+
# # scroll down the page by a certain number of pixels
|
458
|
+
scroll_smth_steps(driver_)
|
459
|
+
|
361
460
|
# 设置轮询
|
362
461
|
for attempt in range(scroll_try):
|
363
462
|
page_source = driver_.page_source
|
py2ls/ocr.py
ADDED
@@ -0,0 +1,557 @@
|
|
1
|
+
import easyocr
|
2
|
+
import cv2
|
3
|
+
import numpy as np
|
4
|
+
import matplotlib.pyplot as plt
|
5
|
+
from py2ls.ips import (
|
6
|
+
strcmp,
|
7
|
+
detect_angle,
|
8
|
+
) # Ensure this function is defined in your 'ips' module
|
9
|
+
from spellchecker import SpellChecker
|
10
|
+
import re
|
11
|
+
|
12
|
+
from PIL import Image, ImageDraw, ImageFont
|
13
|
+
import PIL.PngImagePlugin
|
14
|
+
|
15
|
+
"""
|
16
|
+
Optical Character Recognition (OCR)
|
17
|
+
"""
|
18
|
+
|
19
|
+
# Valid language codes
|
20
|
+
lang_valid = {
|
21
|
+
"english": "en",
|
22
|
+
"thai": "th",
|
23
|
+
"chinese_traditional": "ch_tra",
|
24
|
+
"chinese": "ch_sim",
|
25
|
+
"japanese": "ja",
|
26
|
+
"korean": "ko",
|
27
|
+
"tamil": "ta",
|
28
|
+
"telugu": "te",
|
29
|
+
"kannada": "kn",
|
30
|
+
"german": "de",
|
31
|
+
}
|
32
|
+
|
33
|
+
|
34
|
+
def lang_auto_detect(lang):
|
35
|
+
res_lang = []
|
36
|
+
if isinstance(lang, str):
|
37
|
+
lang = [lang]
|
38
|
+
for i in lang:
|
39
|
+
res_lang.append(lang_valid[strcmp(i, list(lang_valid.keys()))[0]])
|
40
|
+
return res_lang
|
41
|
+
|
42
|
+
|
43
|
+
def determine_src_points(image):
|
44
|
+
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
45
|
+
_, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
|
46
|
+
contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
47
|
+
|
48
|
+
# Sort contours by area and pick the largest one
|
49
|
+
contours = sorted(contours, key=cv2.contourArea, reverse=True)[:5]
|
50
|
+
src_points = None
|
51
|
+
|
52
|
+
for contour in contours:
|
53
|
+
epsilon = 0.02 * cv2.arcLength(contour, True)
|
54
|
+
approx = cv2.approxPolyDP(contour, epsilon, True)
|
55
|
+
if len(approx) == 4: # We need a quadrilateral
|
56
|
+
src_points = np.array(approx, dtype="float32")
|
57
|
+
break
|
58
|
+
|
59
|
+
if src_points is not None:
|
60
|
+
# Order points in a specific order (top-left, top-right, bottom-right, bottom-left)
|
61
|
+
src_points = src_points.reshape(4, 2)
|
62
|
+
rect = np.zeros((4, 2), dtype="float32")
|
63
|
+
s = src_points.sum(axis=1)
|
64
|
+
diff = np.diff(src_points, axis=1)
|
65
|
+
rect[0] = src_points[np.argmin(s)]
|
66
|
+
rect[2] = src_points[np.argmax(s)]
|
67
|
+
rect[1] = src_points[np.argmin(diff)]
|
68
|
+
rect[3] = src_points[np.argmax(diff)]
|
69
|
+
src_points = rect
|
70
|
+
else:
|
71
|
+
# If no rectangle is detected, fallback to a default or user-defined points
|
72
|
+
height, width = image.shape[:2]
|
73
|
+
src_points = np.array(
|
74
|
+
[[0, 0], [width - 1, 0], [width - 1, height - 1], [0, height - 1]],
|
75
|
+
dtype="float32",
|
76
|
+
)
|
77
|
+
return src_points
|
78
|
+
|
79
|
+
|
80
|
+
def get_default_camera_matrix(image_shape):
|
81
|
+
height, width = image_shape[:2]
|
82
|
+
focal_length = width
|
83
|
+
center = (width / 2, height / 2)
|
84
|
+
camera_matrix = np.array(
|
85
|
+
[[focal_length, 0, center[0]], [0, focal_length, center[1]], [0, 0, 1]],
|
86
|
+
dtype="float32",
|
87
|
+
)
|
88
|
+
dist_coeffs = np.zeros((4, 1)) # Assuming no distortion
|
89
|
+
return camera_matrix, dist_coeffs
|
90
|
+
|
91
|
+
|
92
|
+
def correct_perspective(image, src_points):
|
93
|
+
# Define the destination points for the perspective transform
|
94
|
+
width, height = 1000, 1000 # Adjust size as needed
|
95
|
+
dst_points = np.array(
|
96
|
+
[[0, 0], [width - 1, 0], [width - 1, height - 1], [0, height - 1]],
|
97
|
+
dtype="float32",
|
98
|
+
)
|
99
|
+
|
100
|
+
# Calculate the perspective transform matrix
|
101
|
+
M = cv2.getPerspectiveTransform(src_points, dst_points)
|
102
|
+
# Apply the perspective transform
|
103
|
+
corrected_image = cv2.warpPerspective(image, M, (width, height))
|
104
|
+
return corrected_image
|
105
|
+
|
106
|
+
|
107
|
+
def detect_text_orientation(image):
|
108
|
+
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
109
|
+
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
|
110
|
+
lines = cv2.HoughLines(edges, 1, np.pi / 180, 200)
|
111
|
+
|
112
|
+
if lines is None:
|
113
|
+
return 0
|
114
|
+
|
115
|
+
angles = []
|
116
|
+
for rho, theta in lines[:, 0]:
|
117
|
+
angle = theta * 180 / np.pi
|
118
|
+
if angle > 90:
|
119
|
+
angle -= 180
|
120
|
+
angles.append(angle)
|
121
|
+
|
122
|
+
median_angle = np.median(angles)
|
123
|
+
return median_angle
|
124
|
+
|
125
|
+
|
126
|
+
def rotate_image(image, angle):
|
127
|
+
center = (image.shape[1] // 2, image.shape[0] // 2)
|
128
|
+
rot_mat = cv2.getRotationMatrix2D(center, angle, 1.0)
|
129
|
+
rotated_image = cv2.warpAffine(
|
130
|
+
image, rot_mat, (image.shape[1], image.shape[0]), flags=cv2.INTER_LINEAR
|
131
|
+
)
|
132
|
+
return rotated_image
|
133
|
+
|
134
|
+
|
135
|
+
def correct_skew(image):
|
136
|
+
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
137
|
+
coords = np.column_stack(np.where(gray > 0))
|
138
|
+
angle = cv2.minAreaRect(coords)[-1]
|
139
|
+
if angle < -45:
|
140
|
+
angle = -(90 + angle)
|
141
|
+
else:
|
142
|
+
angle = -angle
|
143
|
+
return rotate_image(image, angle)
|
144
|
+
|
145
|
+
|
146
|
+
def undistort_image(image, camera_matrix, dist_coeffs):
|
147
|
+
return cv2.undistort(image, camera_matrix, dist_coeffs)
|
148
|
+
|
149
|
+
|
150
|
+
def add_text_pil(image, text, position, font_size=10, color=(255, 0, 0)):
|
151
|
+
# Convert the image to PIL format
|
152
|
+
pil_image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
|
153
|
+
# Create a drawing context
|
154
|
+
draw = ImageDraw.Draw(pil_image)
|
155
|
+
# Define the font (make sure to use a font that supports Chinese characters)
|
156
|
+
try:
|
157
|
+
font = ImageFont.truetype(
|
158
|
+
"/System/Library/Fonts/Supplemental/Songti.ttc", font_size
|
159
|
+
)
|
160
|
+
except IOError:
|
161
|
+
font = ImageFont.load_default()
|
162
|
+
|
163
|
+
# cal top_left position
|
164
|
+
# Measure text size using textbbox
|
165
|
+
text_bbox = draw.textbbox((0, 0), text, font=font)
|
166
|
+
text_width = text_bbox[2] - text_bbox[0]
|
167
|
+
text_height = text_bbox[3] - text_bbox[1]
|
168
|
+
# Calculate 5% of the text height for upward adjustment
|
169
|
+
offset = int(0.5 * text_height) # 上移动 50%
|
170
|
+
# Adjust position to match OpenCV's bottom-left alignment
|
171
|
+
adjusted_position = (position[0], position[1] - text_height - offset)
|
172
|
+
|
173
|
+
# Add text to the image
|
174
|
+
draw.text(adjusted_position, text, font=font, fill=color)
|
175
|
+
# Convert the image back to OpenCV format
|
176
|
+
image = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR)
|
177
|
+
return image
|
178
|
+
|
179
|
+
|
180
|
+
def preprocess_img(
|
181
|
+
image,
|
182
|
+
grayscale=True,
|
183
|
+
threshold=True,
|
184
|
+
threshold_method="adaptive",
|
185
|
+
rotate="auto",
|
186
|
+
skew=True,
|
187
|
+
denoise=True,
|
188
|
+
blur_ksize=(5, 5),
|
189
|
+
morph=True,
|
190
|
+
morph_op="open",
|
191
|
+
morph_kernel_size=(3, 3),
|
192
|
+
enhance_contrast=True,
|
193
|
+
clahe_clip=2.0,
|
194
|
+
clahe_grid_size=(8, 8),
|
195
|
+
edge_detection=False,
|
196
|
+
):
|
197
|
+
"""
|
198
|
+
预处理步骤:
|
199
|
+
|
200
|
+
转换为灰度图像: 如果 grayscale 为 True,将图像转换为灰度图像。
|
201
|
+
二值化处理: 根据 threshold 和 threshold_method 参数,对图像进行二值化处理。
|
202
|
+
降噪处理: 使用高斯模糊对图像进行降噪。
|
203
|
+
形态学处理: 根据 morph_op 参数选择不同的形态学操作(开运算、闭运算、膨胀、腐蚀),用于去除噪声或填补孔洞。
|
204
|
+
对比度增强: 使用 CLAHE 技术增强图像对比度。
|
205
|
+
边缘检测: 如果 edge_detection 为 True,使用 Canny 边缘检测算法。
|
206
|
+
|
207
|
+
预处理图像以提高 OCR 识别准确性。
|
208
|
+
参数:
|
209
|
+
image: 输入的图像路径或图像数据。
|
210
|
+
grayscale: 是否将图像转换为灰度图像。
|
211
|
+
threshold: 是否对图像进行二值化处理。
|
212
|
+
threshold_method: 二值化方法,可以是 'global' 或 'adaptive'。
|
213
|
+
denoise: 是否对图像进行降噪处理。
|
214
|
+
blur_ksize: 高斯模糊的核大小。
|
215
|
+
morph: 是否进行形态学处理。
|
216
|
+
morph_op: 形态学操作的类型,包括 'open'(开运算)、'close'(闭运算)、'dilate'(膨胀)、'erode'(腐蚀)。
|
217
|
+
morph_kernel_size: 形态学操作的内核大小。
|
218
|
+
enhance_contrast: 是否增强图像对比度。
|
219
|
+
clahe_clip: CLAHE(对比度受限的自适应直方图均衡)的剪裁限制。
|
220
|
+
clahe_grid_size: CLAHE 的网格大小。
|
221
|
+
edge_detection: 是否进行边缘检测。
|
222
|
+
"""
|
223
|
+
if isinstance(image, PIL.PngImagePlugin.PngImageFile):
|
224
|
+
image = np.array(image)
|
225
|
+
if isinstance(image, str):
|
226
|
+
image = cv2.imread(image)
|
227
|
+
if not isinstance(image, np.ndarray):
|
228
|
+
image = np.array(image)
|
229
|
+
if image.shape[1] == 4: # Check if it has an alpha channel
|
230
|
+
# Drop the alpha channel (if needed), or handle it as required
|
231
|
+
image = cv2.cvtColor(image, cv2.COLOR_RGBA2RGB)
|
232
|
+
else:
|
233
|
+
# Convert RGB to BGR for OpenCV compatibility
|
234
|
+
image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
|
235
|
+
|
236
|
+
# Rotate image
|
237
|
+
if rotate == "auto":
|
238
|
+
angle = detect_angle(image, by="fft")
|
239
|
+
img_preprocessed = rotate_image(image, angle)
|
240
|
+
else:
|
241
|
+
img_preprocessed = image
|
242
|
+
|
243
|
+
# # Correct skew
|
244
|
+
# if skew:
|
245
|
+
# img_preprocessed = correct_skew(image)
|
246
|
+
|
247
|
+
# Convert to grayscale
|
248
|
+
if grayscale:
|
249
|
+
img_preprocessed = cv2.cvtColor(img_preprocessed, cv2.COLOR_BGR2GRAY)
|
250
|
+
|
251
|
+
# Thresholding
|
252
|
+
if threshold:
|
253
|
+
if threshold_method == "adaptive":
|
254
|
+
image = cv2.adaptiveThreshold(
|
255
|
+
img_preprocessed,
|
256
|
+
255,
|
257
|
+
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
|
258
|
+
cv2.THRESH_BINARY,
|
259
|
+
11,
|
260
|
+
2,
|
261
|
+
)
|
262
|
+
elif threshold_method == "global":
|
263
|
+
_, img_preprocessed = cv2.threshold(
|
264
|
+
img_preprocessed, 127, 255, cv2.THRESH_BINARY
|
265
|
+
)
|
266
|
+
|
267
|
+
# Denoise
|
268
|
+
if denoise:
|
269
|
+
img_preprocessed = cv2.GaussianBlur(img_preprocessed, blur_ksize, 0)
|
270
|
+
|
271
|
+
# 形态学处理
|
272
|
+
if morph:
|
273
|
+
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, morph_kernel_size)
|
274
|
+
if morph_op == "close": # 闭运算
|
275
|
+
# 目的: 闭运算用于填补前景物体中的小孔或间隙,同时保留其形状和大小。
|
276
|
+
# 工作原理: 闭运算先进行膨胀,然后进行腐蚀。膨胀步骤填补小孔或间隙,腐蚀步骤恢复较大物体的形状。
|
277
|
+
# 效果:
|
278
|
+
# 填补前景物体中的小孔和间隙。
|
279
|
+
# 平滑较大物体的边缘。
|
280
|
+
# 示例用途: 填补物体中的小孔或间隙。
|
281
|
+
img_preprocessed = cv2.morphologyEx(
|
282
|
+
img_preprocessed, cv2.MORPH_CLOSE, kernel
|
283
|
+
)
|
284
|
+
elif morph_op == "open": # 开运算
|
285
|
+
# 目的: 开运算用于去除背景中的小物体或噪声,同时保留较大物体的形状和大小。
|
286
|
+
# 工作原理: 开运算先进行腐蚀,然后进行膨胀。腐蚀步骤去除小规模的噪声,膨胀步骤恢复剩余物体的大小。
|
287
|
+
# 效果:
|
288
|
+
# 去除前景中的小物体。
|
289
|
+
# 平滑较大物体的轮廓。
|
290
|
+
# 示例用途: 去除小噪声或伪影,同时保持较大物体完整。
|
291
|
+
img_preprocessed = cv2.morphologyEx(
|
292
|
+
img_preprocessed, cv2.MORPH_OPEN, kernel
|
293
|
+
)
|
294
|
+
elif morph_op == "dilate": # 膨胀
|
295
|
+
# 目的: 膨胀操作在物体边界上添加像素。它可以用来填补物体中的小孔或连接相邻的物体。
|
296
|
+
# 工作原理: 内核在图像上移动,每个位置上的像素值被设置为内核覆盖区域中的最大值。
|
297
|
+
# 效果:
|
298
|
+
# 物体变大。
|
299
|
+
# 填补物体中的小孔或间隙。
|
300
|
+
# 示例用途: 填补物体中的小孔或连接断裂的物体部分。
|
301
|
+
img_preprocessed = cv2.dilate(img_preprocessed, kernel)
|
302
|
+
elif morph_op == "erode": # 腐蚀
|
303
|
+
# 目的: 腐蚀操作用于去除物体边界上的像素。它可以用来去除小规模的噪声,并将靠近的物体分开。
|
304
|
+
# 工作原理: 内核(结构元素)在图像上移动,每个位置上的像素值被设置为内核覆盖区域中的最小值。
|
305
|
+
# 效果:
|
306
|
+
# 物体变小。
|
307
|
+
# 去除图像中的小白点(在白色前景/黑色背景的图像中)。
|
308
|
+
# 示例用途: 去除二值图像中的小噪声或分离相互接触的物体
|
309
|
+
img_preprocessed = cv2.erode(img_preprocessed, kernel)
|
310
|
+
|
311
|
+
# 对比度增强
|
312
|
+
if enhance_contrast:
|
313
|
+
clahe = cv2.createCLAHE(clipLimit=clahe_clip, tileGridSize=clahe_grid_size)
|
314
|
+
img_preprocessed = clahe.apply(img_preprocessed)
|
315
|
+
|
316
|
+
# 边缘检测
|
317
|
+
if edge_detection:
|
318
|
+
img_preprocessed = cv2.Canny(img_preprocessed, 100, 200)
|
319
|
+
|
320
|
+
return img_preprocessed
|
321
|
+
|
322
|
+
|
323
|
+
def text_postprocess(
|
324
|
+
text,
|
325
|
+
spell_check=True,
|
326
|
+
clean=True,
|
327
|
+
filter=dict(min_length=2),
|
328
|
+
pattern=None,
|
329
|
+
merge=True,
|
330
|
+
):
|
331
|
+
|
332
|
+
def correct_spelling(text_list):
|
333
|
+
spell = SpellChecker()
|
334
|
+
corrected_text = [spell.candidates(word) for word in text_list]
|
335
|
+
return corrected_text
|
336
|
+
|
337
|
+
def clean_text(text_list):
|
338
|
+
cleaned_text = [re.sub(r"[^\w\s]", "", text) for text in text_list]
|
339
|
+
return cleaned_text
|
340
|
+
|
341
|
+
def filter_text(text_list, min_length=2):
|
342
|
+
filtered_text = [text for text in text_list if len(text) >= min_length]
|
343
|
+
return filtered_text
|
344
|
+
|
345
|
+
def extract_patterns(text_list, pattern):
|
346
|
+
pattern = re.compile(pattern)
|
347
|
+
matched_text = [text for text in text_list if pattern.search(text)]
|
348
|
+
return matched_text
|
349
|
+
|
350
|
+
def merge_fragments(text_list):
|
351
|
+
merged_text = " ".join(text_list)
|
352
|
+
return merged_text
|
353
|
+
|
354
|
+
results = text
|
355
|
+
print(results)
|
356
|
+
if spell_check:
|
357
|
+
results = correct_spelling(results)
|
358
|
+
if clean:
|
359
|
+
results = clean_text(results)
|
360
|
+
if filter:
|
361
|
+
results = filter_text(
|
362
|
+
results, min_length=postprocess["filter"].get("min_length", 2)
|
363
|
+
)
|
364
|
+
if pattern:
|
365
|
+
results = extract_patterns(results, postprocess["pattern"])
|
366
|
+
if merge:
|
367
|
+
results = merge_fragments(results)
|
368
|
+
|
369
|
+
|
370
|
+
# https://www.jaided.ai/easyocr/documentation/
|
371
|
+
# extract text from an image with EasyOCR
|
372
|
+
def get_text(
|
373
|
+
image,
|
374
|
+
lang=["ch_sim", "en"],
|
375
|
+
thr=0.25,
|
376
|
+
gpu=True,
|
377
|
+
decoder="wordbeamsearch", #'greedy', 'beamsearch' and 'wordbeamsearch'(hightly accurate)
|
378
|
+
output="all",
|
379
|
+
preprocess=None,
|
380
|
+
postprocess="not ready",
|
381
|
+
show=True,
|
382
|
+
ax=None,
|
383
|
+
cmap=cv2.COLOR_BGR2RGB, # draw_box
|
384
|
+
font=cv2.FONT_HERSHEY_SIMPLEX,
|
385
|
+
fontScale=0.8,
|
386
|
+
thickness_text=2, # Line thickness of 2 px
|
387
|
+
color_box=(0, 255, 0), # draw_box
|
388
|
+
color_text=(0, 0, 255), # draw_box
|
389
|
+
**kwargs,
|
390
|
+
):
|
391
|
+
"""
|
392
|
+
功能: 该函数使用 EasyOCR 进行文本识别,并允许自定义图像预处理步骤和结果展示。
|
393
|
+
参数:
|
394
|
+
image: 输入的图像路径或图像数据。
|
395
|
+
lang: OCR 语言列表。
|
396
|
+
thr: 置信度阈值,低于此阈值的检测结果将被过滤。
|
397
|
+
gpu: 是否使用 GPU。
|
398
|
+
output: 输出类型,可以是 'all'(返回所有检测结果)、'text'(返回文本)、'score'(返回置信度分数)、'box'(返回边界框)。
|
399
|
+
preprocess: 预处理参数字典,传递给 preprocess_img 函数。
|
400
|
+
show: 是否显示结果图像。
|
401
|
+
ax: 用于显示图像的 Matplotlib 子图。
|
402
|
+
cmap: 用于显示图像的颜色映射。
|
403
|
+
color_box: 边界框的颜色。
|
404
|
+
color_text: 文本的颜色。
|
405
|
+
kwargs: 传递给 EasyOCR readtext 函数的其他参数。
|
406
|
+
|
407
|
+
# Uage
|
408
|
+
image_path = 'car_plate.jpg' # 替换为你的图像路径
|
409
|
+
results = get_text(
|
410
|
+
image_path,
|
411
|
+
lang=["en"],
|
412
|
+
gpu=False,
|
413
|
+
output="text",
|
414
|
+
preprocess={
|
415
|
+
"grayscale": True,
|
416
|
+
"threshold": True,
|
417
|
+
"threshold_method": 'adaptive',
|
418
|
+
"denoise": True,
|
419
|
+
"blur_ksize": (5, 5),
|
420
|
+
"morph": True,
|
421
|
+
"morph_op": 'close',
|
422
|
+
"morph_kernel_size": (3, 3),
|
423
|
+
"enhance_contrast": True,
|
424
|
+
"clahe_clip": 2.0,
|
425
|
+
"clahe_grid_size": (8, 8),
|
426
|
+
"edge_detection": False
|
427
|
+
},
|
428
|
+
adjust_contrast=0.7
|
429
|
+
)
|
430
|
+
"""
|
431
|
+
lang = lang_auto_detect(lang)
|
432
|
+
print(f"detecting language(s):{lang}")
|
433
|
+
if isinstance(image, str):
|
434
|
+
image = cv2.imread(image)
|
435
|
+
|
436
|
+
# Ensure lang is always a list
|
437
|
+
if isinstance(lang, str):
|
438
|
+
lang = [lang]
|
439
|
+
|
440
|
+
# ! preprocessing img
|
441
|
+
if preprocess is None:
|
442
|
+
preprocess = {}
|
443
|
+
image_process = preprocess_img(image, **preprocess)
|
444
|
+
|
445
|
+
# Perform OCR on the image
|
446
|
+
reader = easyocr.Reader(lang, gpu=gpu)
|
447
|
+
detections = reader.readtext(image_process, decoder=decoder, **kwargs)
|
448
|
+
if postprocess is None:
|
449
|
+
postprocess = dict(
|
450
|
+
spell_check=True,
|
451
|
+
clean=True,
|
452
|
+
filter=dict(min_length=2),
|
453
|
+
pattern=None,
|
454
|
+
merge=True,
|
455
|
+
)
|
456
|
+
text_corr = []
|
457
|
+
for _, text, _ in detections:
|
458
|
+
text_corr.extend(text_postprocess(text, **postprocess))
|
459
|
+
if show:
|
460
|
+
if ax is None:
|
461
|
+
ax = plt.gca()
|
462
|
+
for bbox, text, score in detections:
|
463
|
+
if score > thr:
|
464
|
+
top_left = tuple(map(int, bbox[0]))
|
465
|
+
bottom_right = tuple(map(int, bbox[2]))
|
466
|
+
image = cv2.rectangle(image, top_left, bottom_right, color_box, 2)
|
467
|
+
# image = cv2.putText(
|
468
|
+
# image, text, top_left, font, fontScale, color_text, thickness_text
|
469
|
+
# )
|
470
|
+
image = add_text_pil(
|
471
|
+
image, text, top_left, font_size=fontScale * 32, color=color_text
|
472
|
+
)
|
473
|
+
|
474
|
+
img_cmp = cv2.cvtColor(image, cmap)
|
475
|
+
ax.imshow(img_cmp)
|
476
|
+
ax.axis("off")
|
477
|
+
# plt.show()
|
478
|
+
# 根据输出类型返回相应的结果
|
479
|
+
if output == "all":
|
480
|
+
return ax, detections
|
481
|
+
elif "t" in output.lower() and "x" in output.lower():
|
482
|
+
# 提取文本,过滤低置信度的结果
|
483
|
+
text = [text_ for _, text_, score_ in detections if score_ >= thr]
|
484
|
+
if postprocess:
|
485
|
+
return ax, text
|
486
|
+
else:
|
487
|
+
return text_corr
|
488
|
+
elif "score" in output.lower() or "prob" in output.lower():
|
489
|
+
# 提取分数
|
490
|
+
scores = [score_ for _, _, score_ in detections]
|
491
|
+
return ax, scores
|
492
|
+
elif "box" in output.lower():
|
493
|
+
# 提取边界框,过滤低置信度的结果
|
494
|
+
bboxes = [bbox_ for bbox_, _, score_ in detections if score_ >= thr]
|
495
|
+
return ax, bboxes
|
496
|
+
else:
|
497
|
+
# 默认返回所有检测信息
|
498
|
+
return ax, detections
|
499
|
+
else:
|
500
|
+
# 根据输出类型返回相应的结果
|
501
|
+
if output == "all":
|
502
|
+
return detections
|
503
|
+
elif "t" in output.lower() and "x" in output.lower():
|
504
|
+
# 提取文本,过滤低置信度的结果
|
505
|
+
text = [text_ for _, text_, score_ in detections if score_ >= thr]
|
506
|
+
return text
|
507
|
+
elif "score" in output.lower() or "prob" in output.lower():
|
508
|
+
# 提取分数
|
509
|
+
scores = [score_ for _, _, score_ in detections]
|
510
|
+
return scores
|
511
|
+
elif "box" in output.lower():
|
512
|
+
# 提取边界框,过滤低置信度的结果
|
513
|
+
bboxes = [bbox_ for bbox_, _, score_ in detections if score_ >= thr]
|
514
|
+
return bboxes
|
515
|
+
else:
|
516
|
+
# 默认返回所有检测信息
|
517
|
+
return detections
|
518
|
+
|
519
|
+
|
520
|
+
def draw_box(
|
521
|
+
image,
|
522
|
+
detections=None,
|
523
|
+
thr=0.25,
|
524
|
+
cmap=cv2.COLOR_BGR2RGB,
|
525
|
+
color_box=(0, 255, 0), # draw_box
|
526
|
+
color_text=(0, 0, 255), # draw_box
|
527
|
+
font_scale=0.8,
|
528
|
+
show=True,
|
529
|
+
ax=None,
|
530
|
+
**kwargs,
|
531
|
+
):
|
532
|
+
|
533
|
+
if ax is None:
|
534
|
+
ax = plt.gca()
|
535
|
+
if isinstance(image, str):
|
536
|
+
image = cv2.imread(image)
|
537
|
+
if detections is None:
|
538
|
+
detections = get_text(image=image, show=0, output="all", **kwargs)
|
539
|
+
|
540
|
+
for bbox, text, score in detections:
|
541
|
+
if score > thr:
|
542
|
+
top_left = tuple(map(int, bbox[0]))
|
543
|
+
bottom_right = tuple(map(int, bbox[2]))
|
544
|
+
image = cv2.rectangle(image, top_left, bottom_right, color_box, 2)
|
545
|
+
# image = cv2.putText(
|
546
|
+
# image, text, top_left, font, fontScale, color_text, thickness_text
|
547
|
+
# )
|
548
|
+
image = add_text_pil(
|
549
|
+
image, text, top_left, font_size=font_scale * 32, color=color_text
|
550
|
+
)
|
551
|
+
|
552
|
+
img_cmp = cv2.cvtColor(image, cmap)
|
553
|
+
if show:
|
554
|
+
ax.imshow(img_cmp)
|
555
|
+
ax.axis("off")
|
556
|
+
# plt.show()
|
557
|
+
return img_cmp
|
py2ls/plot.py
CHANGED
@@ -1637,6 +1637,30 @@ def figsets(*args, **kwargs):
|
|
1637
1637
|
ax.tick_params(
|
1638
1638
|
labelsize=val
|
1639
1639
|
) # float, distance in points between tick and label
|
1640
|
+
if "text" in key.lower():
|
1641
|
+
if isinstance(value, dict):
|
1642
|
+
ax.text(**value)
|
1643
|
+
elif isinstance(value, list):
|
1644
|
+
if all([isinstance(i, dict) for i in value]):
|
1645
|
+
[ax.text(**value_) for value_ in value]
|
1646
|
+
# e.g.,
|
1647
|
+
# figsets(ax=ax,
|
1648
|
+
# text=[
|
1649
|
+
# dict(
|
1650
|
+
# x=1,
|
1651
|
+
# y=1.3,
|
1652
|
+
# s="Wake",
|
1653
|
+
# c="k",
|
1654
|
+
# bbox=dict(facecolor="0.8", edgecolor="none", boxstyle="round,pad=0.1"),
|
1655
|
+
# ),
|
1656
|
+
# dict(
|
1657
|
+
# x=1,
|
1658
|
+
# y=0.4,
|
1659
|
+
# s="Sleep",
|
1660
|
+
# c="k",
|
1661
|
+
# bbox=dict(facecolor="0.8", edgecolor="none", boxstyle="round,pad=0.05"),
|
1662
|
+
# ),
|
1663
|
+
# ])
|
1640
1664
|
|
1641
1665
|
if "mi" in key.lower() and "tic" in key.lower(): # minor_ticks
|
1642
1666
|
if "x" in value.lower() or "x" in key.lower():
|
@@ -1,6 +1,6 @@
|
|
1
1
|
py2ls/.DS_Store,sha256=BloZZz2vlFVfF-I3X7ZsqXusvqOawJMx7erKcnIP-b0,6148
|
2
|
-
py2ls/.git/COMMIT_EDITMSG,sha256=
|
3
|
-
py2ls/.git/FETCH_HEAD,sha256=
|
2
|
+
py2ls/.git/COMMIT_EDITMSG,sha256=AdtqRHle5Ej2EBNPJY79v-SB454v5UK4wuPCPFELiFQ,11
|
3
|
+
py2ls/.git/FETCH_HEAD,sha256=VM-2Jiw6iPaGu0ftg9xwq76OyNPWV0iT1nL0VWiL1zI,100
|
4
4
|
py2ls/.git/HEAD,sha256=KNJb-Cr0wOK3L1CVmyvrhZ4-YLljCl6MYD2tTdsrboA,21
|
5
5
|
py2ls/.git/config,sha256=CL7WR7jU8VRchJwRooCBkXUMvuRoPdf3FWIBAOlap1c,378
|
6
6
|
py2ls/.git/description,sha256=ZzMxc0Ca26m45Twn1DDnOHqin5VHEZ9uOTBrScIXSjE,16
|
@@ -17,12 +17,12 @@ py2ls/.git/hooks/pre-receive.sample,sha256=pMPSuce7P9jRRBwxvU7nGlldZrRPz0ndsxAlI
|
|
17
17
|
py2ls/.git/hooks/prepare-commit-msg.sample,sha256=6d3KpBif3dJe2X_Ix4nsp7bKFjkLI5KuMnbwyOGqRhk,1492
|
18
18
|
py2ls/.git/hooks/push-to-checkout.sample,sha256=pT0HQXmLKHxt16-mSu5HPzBeZdP0lGO7nXQI7DsSv18,2783
|
19
19
|
py2ls/.git/hooks/update.sample,sha256=jV8vqD4QPPCLV-qmdSHfkZT0XL28s32lKtWGCXoU0QY,3650
|
20
|
-
py2ls/.git/index,sha256=
|
20
|
+
py2ls/.git/index,sha256=YCofugnXLz17aY5kqXGtUpV8FzXPdgQdEwcjQ8bHDfg,4232
|
21
21
|
py2ls/.git/info/exclude,sha256=ZnH-g7egfIky7okWTR8nk7IxgFjri5jcXAbuClo7DsE,240
|
22
|
-
py2ls/.git/logs/HEAD,sha256=
|
23
|
-
py2ls/.git/logs/refs/heads/main,sha256=
|
24
|
-
py2ls/.git/logs/refs/remotes/origin/HEAD,sha256=
|
25
|
-
py2ls/.git/logs/refs/remotes/origin/main,sha256=
|
22
|
+
py2ls/.git/logs/HEAD,sha256=8ID7WuAe_TlO9g-ARxhIJYdgdL3u3m7-1qrOanaIUlA,3535
|
23
|
+
py2ls/.git/logs/refs/heads/main,sha256=8ID7WuAe_TlO9g-ARxhIJYdgdL3u3m7-1qrOanaIUlA,3535
|
24
|
+
py2ls/.git/logs/refs/remotes/origin/HEAD,sha256=58xXc_oi3Gt_mWRW_ZF3IES40amGtFS1N_I8J7E85Cw,23540
|
25
|
+
py2ls/.git/logs/refs/remotes/origin/main,sha256=9ohHV9XT1dBowBZUVo52U9205_o513hmvCvtW9rS4Fk,3192
|
26
26
|
py2ls/.git/objects/01/d5bd8065e6860c0bd23ff9fa57161806a099e1,sha256=hEQ8nqJnGsfFsuV5wc4cZas58rehXvT0v5ANx1zmMAY,584
|
27
27
|
py2ls/.git/objects/09/08da26de58c114225ad81f484b80bf5d351b34,sha256=NOyYvrJxATpK3aDdP1_stwkqOQRDwJn7DSy6isyKImE,925
|
28
28
|
py2ls/.git/objects/0b/409e1bc918277010f5679b402d1d1dda53e15c,sha256=y5S1XaGxJz1NXi-SPWjPC_NKIqqSbZv9oOg74MzBihY,156
|
@@ -36,20 +36,29 @@ py2ls/.git/objects/1d/fe9d9633b24ea560354f4f93d39c6e5f163ea0,sha256=mV_84wLqIitn
|
|
36
36
|
py2ls/.git/objects/20/72c28e83f4347959d29f7b3a6c1fc3e4ee6b59,sha256=85riTUsfNmOwOoolBNgC0HegJ6LajYl5vFDl_l3W19Y,9947
|
37
37
|
py2ls/.git/objects/24/6b368b986f758630c46dc02b7fa512b53422f7,sha256=sw7ERFCFu7m6fnURAqQfQ4GWShaARr-Vc6GRnlOPkxU,8512
|
38
38
|
py2ls/.git/objects/25/b796accd261b9135fd32a2c00785f68edf6c46,sha256=4ic5vOwEdfbGL8oARSVEeAnSoDs14-gggGZEL-61nYE,564
|
39
|
+
py2ls/.git/objects/27/aa6074f652bc6f7078f8647489d9ee8e24f0e2,sha256=yrhSezJgUP0qjNid0oPA2Hkqpr7x89LCgw6l_FbgIqM,6057
|
40
|
+
py2ls/.git/objects/28/c2969d785c1b892c2a96b3f00eba63a59811b3,sha256=MHJ8giN9LRzVgeWEi5BhmUiCJKUc3V4JkkwcR-8NoGo,1071
|
39
41
|
py2ls/.git/objects/2a/ae95d517d213b660bf4f65a4e0cfae7bb893eb,sha256=V0MJF1QXVSLDntEWS1n3_lErS_faBLwlP67fXv_Bysk,776
|
42
|
+
py2ls/.git/objects/2a/fdf45791a26d42ccead35ace76a8f0b2a56561,sha256=jDm8bBdAgNEDk0XteXGVrEItc1mRaaFWP6hz62UZQnU,267
|
40
43
|
py2ls/.git/objects/30/a2f8da47ee947811dc8d993f5a06a45de374f4,sha256=u5W33_qNtTs1-U8Fardx-zB_udqKvuCm5kiw1mQGdsU,3218
|
41
44
|
py2ls/.git/objects/32/fd627b62fad7cf3b2f9e34ab9777126a0987ad,sha256=_QlClFT2799H_igDlGPr6Uz3SqoPN5v-hehesdIj18U,164
|
42
45
|
py2ls/.git/objects/34/9e31b6a3634cea102ce5588b98c11cc1738605,sha256=drNtu4yQrw0rWqk6SmHnsW0ZA3Jtvut8WG9S15gyTwk,1219
|
46
|
+
py2ls/.git/objects/34/b6f3a2ee84f39bed4eee57f2c0e0afb994feb1,sha256=HdtFToCoX-g2trQ8m46yvEjeitUYmGlyZ3rqQIEHNwg,17992
|
47
|
+
py2ls/.git/objects/35/1a5f491ab97eee9d1ee699478d75a8bb5d3dc2,sha256=80vRDvQZlx4WfCSgJBgR-MNYmt1fCq5N4-3By_7hGrM,63106
|
43
48
|
py2ls/.git/objects/36/b4a1b7403abc6c360f8fe2cb656ab945254971,sha256=X18sHo17gQTxusNptoILoWxSfU0ulrsZvbETlBtV5aY,2327
|
44
49
|
py2ls/.git/objects/36/e56a361f526eafa59c5235a5c990bf288b5f9c,sha256=7L1L-iqVvuufrlfEE2myD0-QnAPueFMySKetu08W-Pc,34216
|
45
50
|
py2ls/.git/objects/36/ef43e50009e59db11812c258846d9e38718173,sha256=0nwCwQSuQAdGyD2NfEK-_L12ydE9nGVKBXOfFq_Lndc,169
|
46
51
|
py2ls/.git/objects/39/7ead045fbbcfb17c62019eb18fe21ed05dbee5,sha256=3zM2AAtKWPfDVSy-prLogf1Z_RjkA6DwBBvN_M7pZqs,10409
|
52
|
+
py2ls/.git/objects/39/b13be65125556784e44c7a1d9821703c7ab67e,sha256=Jm8jhOfT8XB6DRkEynhEa1QMDHl-HIKW0Zr-goqSV8E,822
|
53
|
+
py2ls/.git/objects/3b/507acc7f23391644cc0b824b1e79fd2677a362,sha256=p-F6SaVzlGTr4u44DaqxAqVF-doxhEpiM8nXwqdMUp0,53351
|
47
54
|
py2ls/.git/objects/3b/bd972aa7ad680858f8dfbd0f7fcd97756f0d6f,sha256=MQWEzML3wbb4GixiHDCHrxgbXLQitrYDstT1plhmQSU,169
|
48
55
|
py2ls/.git/objects/3c/bbe5f4173d165127b9ad96119f1ec24c306ffc,sha256=S1BXemROYtzRaj5WXLPYnTmPTBQDKovMEN0GRLul-I4,33489
|
56
|
+
py2ls/.git/objects/3d/9d10d27724657a436c65a6254bfd213d4b3562,sha256=k70wNeQBm9RHdMlSQa-4HU2Gi50k0Fpa3O_3n0wmp_A,1063
|
49
57
|
py2ls/.git/objects/3f/d6561300938afbb3d11976cf9c8f29549280d9,sha256=91oqbTWfUE1d_hT_1ptYmRUb5pOQ1X4oxQxpF6NXjKU,8501
|
50
58
|
py2ls/.git/objects/41/dcf4b3bf0460946b2da93776cf9e836d62178f,sha256=jdsIHuNTgeely4JL072ktLgpDHB-97GDL7unti8TLrw,93
|
51
59
|
py2ls/.git/objects/43/dbd49b2ee367c5434dd545e3b5795434f2ef0b,sha256=DAzt0dWp2KsuuImCKp7N9ia7KaCDNqwB-tYIx3Wf_c0,565
|
52
60
|
py2ls/.git/objects/45/b1b6178bacbfc997811a998b5cc60c1ea7fac8,sha256=7Oea5ZA0nNs6-jQV0yCSr4ZSCcm7m_z3UYVLNmDBj2w,167
|
61
|
+
py2ls/.git/objects/47/6cbd5a7c5e35cddef2f8a38bdc4896d403b095,sha256=Egdg9CCOcB_IWt3CBaIpmdZzBGK4woUYY5v5X275trc,207
|
53
62
|
py2ls/.git/objects/48/a88fc5806305d0bb0755ee6801161b79696972,sha256=f3JStE39k_hPGE-WRwqZtDTjQkfOmBVb_6-ELBbScjI,203
|
54
63
|
py2ls/.git/objects/4f/7afb40dff2153d857fc85748c2eecb85125042,sha256=QnSXlNWzKLoMzDHNAiwe06vqJEQj9xu0q-9PvCUbtbM,39680
|
55
64
|
py2ls/.git/objects/50/08ddfcf53c02e82d7eee2e57c38e5672ef89f6,sha256=p0M2WLqiTe6X2FI_k5Aj0IEsE85jqLa58sVdmV8x1vU,255
|
@@ -79,17 +88,23 @@ py2ls/.git/objects/6d/ee29dbdcc84edeeacede105110446f3ccac963,sha256=-4Bi-tw0O-Eb
|
|
79
88
|
py2ls/.git/objects/71/36b2074a2754be8b58127d82250e5b37e3c373,sha256=cbVFQaBx0Q5QkZ1wQle-iIxNx14JxGSx3G8aQ7EbbAA,586
|
80
89
|
py2ls/.git/objects/72/245a05b0966011cb381e6b32b0465000e969ab,sha256=Jph97UOQ6ZXwAEIZHkd037rPpoj_hbs74kMIj1nmIVc,14013
|
81
90
|
py2ls/.git/objects/72/e4179337639859678ddaecf38b16f33aaec8e1,sha256=bdgg9rmPgKP3UH1-QDqIrCgzmrFVRgdByrgYuQkzVJg,436
|
91
|
+
py2ls/.git/objects/78/063f4c863fc371ec0313303c0a81283b35d9b6,sha256=ow4MGqzfJbPrW9ggXw2Eh4JwCjteFWNscgR_SuyMUR4,2280
|
82
92
|
py2ls/.git/objects/78/3d4167bc95c9d2175e0df03ef1c1c880ba75ab,sha256=SK2QDjDBiDhVMG1I5p19g4RbEm2Rax7mYnxawmVZYxs,15523
|
83
93
|
py2ls/.git/objects/79/7ae089b2212a937840e215276005ce76881307,sha256=lQOKF2pb1JvipI3eT79X0-TuMGWsy1A-Yw4BCgKZNOM,33472
|
84
94
|
py2ls/.git/objects/7e/5956c806b5edc344d46dab599dec337891ba1f,sha256=sfqJBiSNj-gyJo4D7xkmRAo76mC2ztjqeZZsl4ifULA,162
|
85
95
|
py2ls/.git/objects/81/8f26b7bf042269729020cf944fc362d66ba27e,sha256=mg6FGEyv6EcOgurR8CEvHGovaWrUgMUxTtACAy7-ei4,34960
|
96
|
+
py2ls/.git/objects/82/70b319ce4046854fbe7dc41054b6c2d112dab2,sha256=uXFGUHmm5K4cACXpWG_hQN4xV__3WxFyeKipRpvXAxo,27520
|
86
97
|
py2ls/.git/objects/84/59071b722a255b774a80b27746033f8141ab39,sha256=0pYGJOXFfp4MSu4n5MzE1XN--t0lSs7wcdqboADWMx0,9792
|
98
|
+
py2ls/.git/objects/85/aee46f478e9afdb84d50a05242c53b04ed2e21,sha256=R1IE6mh9ANSTSzouKl5BclPeIR_ubjFnXBI4xPRvGRo,23087
|
99
|
+
py2ls/.git/objects/86/e288b46f8fe179907e4413f665aeb5053fddb1,sha256=uIVROSpqiSyImHBLh0X9bSpKl6zveGGoJSzO8W799QE,160
|
87
100
|
py2ls/.git/objects/87/ef1fc3f7f1ddc4d0ab9b3e65381ce9f3388621,sha256=OFrpW6lu31qGBvD3ijPUBSG9JrdU1_mKzeYBzidn9VM,3748
|
88
101
|
py2ls/.git/objects/8b/84f56978e1de8f2ae82abce5f8b3e182d365cd,sha256=a8XequnUMBSv9zIQJdcdgDvMQ7PLGdIrgZ-MqQGF87c,573
|
89
102
|
py2ls/.git/objects/8e/55a7d2b96184030211f20c9b9af201eefcac82,sha256=yW-jVYeCTWR-nX3JJgA1g9YLPjzNsKlDmEOH290Ywx0,1221
|
90
103
|
py2ls/.git/objects/91/c69ad88fe0ba94aa7859fb5f7edac5e6f1a3f7,sha256=Kk2MWCO1OcShYuABGzp2O9LiWGDfDkcZtd0oy4nY6RU,9529
|
91
104
|
py2ls/.git/objects/94/74152b4b463d70ae5ad07f0c658be3e296026b,sha256=jmA6qTuUVldsyjg5Z0WddbnSm7GrqWug3USa16jifo4,3733
|
105
|
+
py2ls/.git/objects/94/f7dbe88e80c4205a901b71eb8f181974376bba,sha256=eqJuPAKPX35xx17vtfrw_MtLgRwbV5q_txWBZAwPZRY,377
|
92
106
|
py2ls/.git/objects/97/1aef09ea939f46b60b9646f8d524c78a9220f4,sha256=lWu9FuqxnDT-H_jZGYlA0Tbx6NdH7bScu5EVl3BoAxU,2532
|
107
|
+
py2ls/.git/objects/9b/ec5ee2236ee2d5532c36bfd132e23c58fdb69c,sha256=r3oCOgc2gGRPNuTEB8PkqGt6YNZtGfbwwutxzqAQN5k,20191
|
93
108
|
py2ls/.git/objects/9d/0df52899fe95279059286d9c0ec42287edc168,sha256=67nV3TLo-fwe4lt0wwvxoDnVNHc1IpapRyAY2STP3iI,564
|
94
109
|
py2ls/.git/objects/a1/5389729850729fc7bd78a54f26fce77f30be12,sha256=iNB4jWPKwQfHJSwbGiXz7UgC5J-LbLZu19ylWNr2COs,159
|
95
110
|
py2ls/.git/objects/a1/906da89d1174f74867800c74c43af36253bd5e,sha256=vKUcX4zLVSvZ2Z_FXP-1czZF9MkVMsFidtg43CEhxkQ,780
|
@@ -99,52 +114,65 @@ py2ls/.git/objects/a7/3e13eafee65c5b8d73ad2d3ea46d0eee82f0d3,sha256=iv3uTzna5XBz
|
|
99
114
|
py2ls/.git/objects/b0/56be4be89ba6b76949dd641df45bb7036050c8,sha256=8Y7z30eNceBd5QIx09QfMp5cYBbrgUllmats0kvJEJ4,132
|
100
115
|
py2ls/.git/objects/b0/9cd7856d58590578ee1a4f3ad45d1310a97f87,sha256=82dx4hIdMpdcB64e5PU1s2gZFVkTvrj1cPwwJ_kasNU,4444
|
101
116
|
py2ls/.git/objects/b2/18e6a0f0f1c4df8cdefa9852058348abc713b7,sha256=hOQfdyzDZctjoge0-pAcEDel5XHVPNfOtrMNyFPUOIE,564
|
117
|
+
py2ls/.git/objects/b3/4f7f271c6d6105e35a6556ffda71d03afe8c96,sha256=dpXOxJ_H0pMun5XcAenyvzwEeeRh0FluxyIHYYBc1HI,1046
|
118
|
+
py2ls/.git/objects/b3/69579064bde9de9a19d114fc33e4e48cc8c0e4,sha256=nC24lde8O_cg64f6QjMazlPTHX9X4aSoEBwbdXWTh_Q,62664
|
102
119
|
py2ls/.git/objects/b5/61831c7dce8ea51e7ee6b6fa35745f14d8242d,sha256=wUqxlKjLN1vOUj2tkYStado64QewdcF3CHlSICds1ik,34415
|
103
120
|
py2ls/.git/objects/b7/2c9e75ab7d0afe594664650aa8f6c772f5ac64,sha256=dyeWYp22wgZSCE7D3F43N76ehCDTsbMJcSMJRW3VbDI,65
|
104
121
|
py2ls/.git/objects/bb/81ccc0513f18fc160b54a82861e9a80d23f4f6,sha256=WrBnpacpm4kOcVCYoWgPO8MqOAi0ZeHaxekPT3DxpCk,587
|
105
122
|
py2ls/.git/objects/bb/934eb33bc1a8b85630bf680caffd99560c1b8f,sha256=ggehjexUsWlskHJvHxW7u6U0otB0OCItmIZdT9O-3OU,9670
|
106
123
|
py2ls/.git/objects/bf/67907e337021ebff434e02b19b30a741c144af,sha256=4nCdIiXB2kZUL2n0U-cTeGCXlFrlI3uCr3QDytICFOE,157
|
124
|
+
py2ls/.git/objects/bf/b54d65922ce1dfda1aaa014913a54e7172d0bc,sha256=ng8_i6LZEhJTkpZxRThCVYr9Z41F-DJ286vC0CGQaFs,61371
|
107
125
|
py2ls/.git/objects/c1/20fc812b9ad311c34a3608512d6a9d976bb48e,sha256=q-WAKugB-_-g7w0Mlw6oyTBaXQ_Qd7BdLatrDiYN7Wc,156
|
126
|
+
py2ls/.git/objects/c1/397c6ed72c4e20ef6b9ab83163e9a6baba5b45,sha256=f55lzMy77ERzLOEUAYsrbxY9rUQCkuZrKo8UFayEdmQ,15861
|
108
127
|
py2ls/.git/objects/c4/cba65f1163661999ee4b8ed23342b63bc1300c,sha256=rwSdKt-C98nUQ_B-7imY4fYRYmn29MQc4SIu9wruHeo,566
|
109
128
|
py2ls/.git/objects/c6/7f17e5707313600efcb85e9a3fedea35dba591,sha256=TL7rDIWiaWlk8iIwqPst7St5Xr2otPs-vp17GPlET7o,565
|
110
129
|
py2ls/.git/objects/c6/f32aced880bd165a251cb52b26b0c1107e2141,sha256=ybarsWjoo-JCb8gnxsG6VKt6Sal2VwQiOEZYxQl8DcE,29556
|
130
|
+
py2ls/.git/objects/cc/45df1d317a2eb63ff1ff3a5f3b4a9f98fd92b5,sha256=GEEKOqrl6bLBn1z6B8uhjY7uGOWP6TELfBEmx41vdVE,1041
|
111
131
|
py2ls/.git/objects/cd/822b3574a88ebdd1ed82fd6983f37e626d52b4,sha256=MJbPJ-8vpfVTUMhzyzTp5qGmZYgsgrG-7nwwzDdODlQ,617
|
112
132
|
py2ls/.git/objects/cf/0c0d9c6fb09473aaeb7f7e2edbd770c3f2ef3d,sha256=T_nV0GrgpVu3mOJ4fYcCW98oCunzgqy0DnSX0luy04Q,183
|
113
133
|
py2ls/.git/objects/d2/992df305f4b56a466a2f221aeb182ddd20f418,sha256=6zInwArNx-uw1OzxOIhTAZiKpelI3cyhW7Z-dj-Ws2I,9546
|
134
|
+
py2ls/.git/objects/d6/39e8af592cd75a318d8affddd1bcc70c2095f2,sha256=WwoBGl56IGGKozgK1u046NjWMkrqebL2HKm3p9mpl9Y,1029
|
114
135
|
py2ls/.git/objects/d6/9ab1c4aadf279936dd778e8346ba60f74705b6,sha256=WcfdSMKqfiWT5TOWVUcDj0XDaD2hYxDnyIRNlYGutL8,34976
|
115
136
|
py2ls/.git/objects/d8/4688b54c0040a30976b3a6540bc47adf7ce680,sha256=1gJp1iTVAooc5PZZsiIj215-J1RtJ-_zy22_9jZ8jAY,160
|
116
137
|
py2ls/.git/objects/d9/005f2cc7fc4e65f14ed5518276007c08cf2fd0,sha256=IJIoz93V7pf9yx43U1JdN8gBq_LWtw8A9Z2YMPnq_B0,1450
|
117
138
|
py2ls/.git/objects/d9/c2403fd166ce791b4e9d0c6792ed8342c71fcd,sha256=uD7BsKdrmN-9FStTpwsRWh-XxVXeDsV4dGjFkaMIIs8,170
|
118
139
|
py2ls/.git/objects/d9/dfa5aee51e92a541b707e8e7baea6f06deff98,sha256=jMdhZ1i_L5q_UgjOtjLN15PCSCz3pE51FhD3z74ZUr8,163
|
119
140
|
py2ls/.git/objects/db/141dbaa93594df2a8156182f361ee4db829359,sha256=TpKTLvbDc4Blzrp1Pq9JijqDROJyBJ7sCQQBmIuYKZo,845984
|
141
|
+
py2ls/.git/objects/db/3f2cd643292057936230b95cf7ec3046affe11,sha256=EdzFq6kPwS2lvqY0OVBi9QV-O5LlhX7K11XZn58v4NQ,27259
|
120
142
|
py2ls/.git/objects/db/ffa8ea7bda721d0cee7b9e4ce5b2ef927733ff,sha256=GhDkvP6JYV26qVg5ETPys1ZEnGlsct9hiXCc24Ky4Xg,565
|
121
143
|
py2ls/.git/objects/dc/c2bdbafb3296e09d9ee4955cfa55d275825f94,sha256=EwQROBwhbTP2VbODehfMwXhSoDC1LknvxBtDkCOCTco,988
|
122
144
|
py2ls/.git/objects/dc/cdbd4266765d840be2ae35ab1752a0fa312c16,sha256=ABBvXL3TWBRyx_q5XQLgg-k0EU2rvMKv3HIXpk73I8c,12583
|
123
145
|
py2ls/.git/objects/dd/87fb5f606fe380d81e6fe3a2c98f9f99e3e09b,sha256=gBHzzOxwRhDCCwm6WWSyN51RSENJhwEojekygZj8qsc,1424
|
146
|
+
py2ls/.git/objects/de/214c626ac2dd2685bfaa0bc0fc20f528d014d7,sha256=NwSO-vjNC-cdecDSkfIobxW8Ap-L5QspDr_QnyVyBKI,1070
|
124
147
|
py2ls/.git/objects/df/e0770424b2a19faf507a501ebfc23be8f54e7b,sha256=vCdlxwEidekh8i-5TVMVgSLGk9DPZCZAbWqvGYSKQ9c,76
|
125
148
|
py2ls/.git/objects/e2/f2f8f4c25e62a297fc55f36acc6b01cfbab76f,sha256=OnyaP4aCH8kHPj2ZcRsBnUQOGYLmX0OOG8uYtDClmB8,113
|
126
149
|
py2ls/.git/objects/e3/1356f90ea6dd0577b5e0b40b206319adcbf085,sha256=I9_QNwmmtoqSwq29Ixdfv_PgF2x14u2M6sX1eQumwoY,161
|
127
150
|
py2ls/.git/objects/e3/5a4dafc50850cacac7bf76c56db2715cbda2c4,sha256=GAcBj3YSEbm6tm7fGD6al16uBo8LtEtjZ2Hi-UgIsUg,3290
|
151
|
+
py2ls/.git/objects/e4/6c715352db9fe3c887a635f1916df4ca1f4ff9,sha256=gH66Mpwns2PXEgZ0iqVgTYXGOuAnblKTVnWPsPntIug,825
|
152
|
+
py2ls/.git/objects/e5/0580a0bd1e1b3d29f834382b80fceb61d5cf0c,sha256=4QxUSgpyDtN4XeWOoFFAQ_c8FYbs3BJaOyr5ErXtZkM,434
|
128
153
|
py2ls/.git/objects/e9/391ffe371f1cc43b42ef09b705d9c767c2e14f,sha256=RWTy2n8L2XxZQknBFyPczA0Aa_4gSG_Ybcr8e8v4ccc,10264
|
129
154
|
py2ls/.git/objects/ea/3a18cc75e53792744ef754e05d3f4481768c13,sha256=p-Ny3qYi1akV2i58-Fxr0c0c8lhaEVrbr6ek7-v21jM,9369
|
130
155
|
py2ls/.git/objects/ec/40fd8bf8e4c342534a9fc020289e402ba6bc9d,sha256=ptkoZH3jOT5PLgsYhxSutkPvtJ4TUlcD5H5JVJIu_AA,28992
|
156
|
+
py2ls/.git/objects/ec/d980279432b13f0374b90ca439a6329cdece0f,sha256=l-PpV7ZbOPp1QVROl_R9UANx58pNevZTeX8hUoJUuU0,10313
|
157
|
+
py2ls/.git/objects/ee/cee64eacaff022dcdc509c0c2b1da492f21060,sha256=KfPSbfpy1b-1-93aEh27gddBCJ3GJMnTQeP78ZE97ok,51197
|
131
158
|
py2ls/.git/objects/f1/e50757fddc28b445545dc7e2759b54cdd0f42e,sha256=2NG4lzk2IPOZfJ4tRHvxla63yQTcY_YTOprG1tzK-IY,40554
|
132
159
|
py2ls/.git/objects/f4/b64d3107b39e3ad6f540c6607004ea34e6c024,sha256=0egAtqc0x8hc7U1z91tIjcRhSd_BT2a_gxZxo_7NTJA,564
|
133
160
|
py2ls/.git/objects/f4/ba7f815b886797b73fede071d86e0c134d2bc7,sha256=UispRfx4EvDFujmyICYgMz4gZHqZhO_dbNfiL3MFTNw,332
|
161
|
+
py2ls/.git/objects/f5/61c3c1bf1c9ea9c9d1f556a7be2869f71f3bdf,sha256=ceHjRx-BTwl4FdgHFykZTGT_hoertmCG1z0aY-9FEH8,29789
|
134
162
|
py2ls/.git/objects/f6/44a8ff56fa035105fc517cbb1ac46c3d8e349a,sha256=a_5p_uf5YsJVFzXNWAAQptZr8l7rGNLLxasotb9q0OU,777
|
135
163
|
py2ls/.git/objects/f7/c98ba5c2f903e603b1f5e63d49fbc8a43815cc,sha256=tYbi3A7irrIPB_11bwItuof0Vc9a0MDuLFMNAzRsG3A,33467
|
136
164
|
py2ls/.git/objects/f9/045a08e96eb76848fc4d68e3e3e687cca39a2d,sha256=u29Cwu3SL3HlagZIal5ueGZ3miqgZAtuDbtP8-fUVvE,141
|
137
165
|
py2ls/.git/objects/fa/147e6bb78a2e8db241d231295fd7f1ed061af8,sha256=G9pg5LXv7AdxnPIQsTm2AF3Un314dLRJQYwxmZem9rQ,574
|
138
166
|
py2ls/.git/objects/fc/292e793ecfd42240ac43be407023bd731fa9e7,sha256=hGIYoxKWNT3IPwk3DE4l3FLBbUYF-kXcHcx7KrH9uS0,1971
|
139
|
-
py2ls/.git/refs/heads/main,sha256=
|
167
|
+
py2ls/.git/refs/heads/main,sha256=vaWoJWq2YOJm04yq8v-ImmaNjjqq-OEhS8SdTKUuKw8,41
|
140
168
|
py2ls/.git/refs/remotes/origin/HEAD,sha256=K7aiSqD8bEhBAPXVGim7rYQc0sdV9dk_qiBOXbtOsrQ,30
|
141
|
-
py2ls/.git/refs/remotes/origin/main,sha256=
|
169
|
+
py2ls/.git/refs/remotes/origin/main,sha256=vaWoJWq2YOJm04yq8v-ImmaNjjqq-OEhS8SdTKUuKw8,41
|
142
170
|
py2ls/.gitattributes,sha256=Gh2-F2vCM7SZ01pX23UT8pQcmauXWfF3gwyRSb6ZAFs,66
|
143
171
|
py2ls/.gitignore,sha256=y7GvbD_zZkjPVVIue8AyiuFkDMuUbvMaV65Lgu89To8,2763
|
144
172
|
py2ls/LICENSE,sha256=UOZ1F5fFDe3XXvG4oNnkL1-Ecun7zpHzRxjp-XsMeAo,11324
|
145
173
|
py2ls/README.md,sha256=CwvJWAnSXnCnrVHlnEbrxxi6MbjbE_MT6DH2D53S818,11572
|
146
174
|
py2ls/__init__.py,sha256=Nn8jTIvySX7t7DMJ8VNRVctTStgXGjHldOIdZ35PdW8,165
|
147
|
-
py2ls/batman.py,sha256=
|
175
|
+
py2ls/batman.py,sha256=_DKFjLsX4s6F5wbWcogLbOykE0Xx79C2W8oAvisaPEg,6218
|
148
176
|
py2ls/brain_atlas.py,sha256=w1o5EelRjq89zuFJUNSz4Da8HnTCwAwDAZ4NU4a-bAY,5486
|
149
177
|
py2ls/chat.py,sha256=Yr22GoIvoWhpV3m4fdwV_I0Mn77La346_ymSinR-ORA,3793
|
150
178
|
py2ls/correlators.py,sha256=RbOaJIPLCHJtUm5SFi_4dCJ7VFUPWR0PErfK3K26ad4,18243
|
@@ -178,14 +206,15 @@ py2ls/doc.py,sha256=xN3g1OWfoaGUhikbJ0NqbN5eKy1VZVvWwRlhHMgyVEc,4243
|
|
178
206
|
py2ls/export_requirements.py,sha256=x2WgUF0jYKz9GfA1MVKN-MdsM-oQ8yUeC6Ua8oCymio,2325
|
179
207
|
py2ls/freqanalysis.py,sha256=F4218VSPbgL5tnngh6xNCYuNnfR-F_QjECUUxrPYZss,32594
|
180
208
|
py2ls/ich2ls.py,sha256=3E9R8oVpyYZXH5PiIQgT3CN5NxLe4Dwtm2LwaeacE6I,21381
|
181
|
-
py2ls/ips.py,sha256=
|
182
|
-
py2ls/netfinder.py,sha256=
|
183
|
-
py2ls/
|
209
|
+
py2ls/ips.py,sha256=DzUlb6LYFj6fC58cU1FaLCh5PkAC3VCijzXyhbPMcVA,105440
|
210
|
+
py2ls/netfinder.py,sha256=kJT78g9L0NWkcbPMsnY_2d7gQdwMKxfQ3ojfZm2-M00,54373
|
211
|
+
py2ls/ocr.py,sha256=qx1HjiWGpteHIV8SzDavAnxfG9AGAxJySo1IeNvNwrg,19765
|
212
|
+
py2ls/plot.py,sha256=J8hRKLpQXHQRG_xE_nmT0mQvc1IxCMJ21tJmKsUKFl4,96155
|
184
213
|
py2ls/setuptools-70.1.0-py3-none-any.whl,sha256=2bi3cUVal8ip86s0SOvgspteEF8SKLukECi-EWmFomc,882588
|
185
214
|
py2ls/sleep_events_detectors.py,sha256=bQA3HJqv5qnYKJJEIhCyhlDtkXQfIzqksnD0YRXso68,52145
|
186
215
|
py2ls/stats.py,sha256=fJmXQ9Lq460StOn-kfEljE97cySq7876HUPTnpB5hLs,38123
|
187
216
|
py2ls/translator.py,sha256=bc5FB-wqC4TtQz9gyCP1mE38HqNRJ_pmuRIgKnAlMzM,30581
|
188
217
|
py2ls/wb_detector.py,sha256=7y6TmBUj9exCZeIgBAJ_9hwuhkDh1x_-yg4dvNY1_GQ,6284
|
189
|
-
py2ls-0.1.10.
|
190
|
-
py2ls-0.1.10.
|
191
|
-
py2ls-0.1.10.
|
218
|
+
py2ls-0.1.10.1.dist-info/METADATA,sha256=BjfmIp8s1DEklNcXqKNCxp5lLV13iUKjZSzMc_WadrU,20018
|
219
|
+
py2ls-0.1.10.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
220
|
+
py2ls-0.1.10.1.dist-info/RECORD,,
|
File without changes
|