Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
parkpow
GitHub Repository: parkpow/deep-license-plate-recognition
Path: blob/master/blur/main.py
1091 views
1
import argparse
2
import base64
3
import imghdr
4
import logging
5
import os
6
import sys
7
import time
8
from pathlib import Path
9
10
import requests
11
12
LOG_LEVEL = os.environ.get("LOGGING", "INFO").upper()
13
14
logging.basicConfig(
15
stream=sys.stdout,
16
level=LOG_LEVEL,
17
datefmt="%Y-%m-%d %H:%M:%S",
18
format="%(levelname)-5s [%(name)s.%(lineno)d] => %(message)s",
19
)
20
21
lgr = logging.getLogger("blur")
22
23
24
class BlurError(Exception):
25
pass
26
27
28
def merge_paths(path1: Path, path2: Path):
29
"""
30
This is path computation, No filesystem access
31
32
path1 = Path('/images/')
33
path2 = Path('/images/dir1/dir2/file4.jpg')
34
print(merge_paths(path1, path2))
35
# Output: /images/dir1/dir2/file4.jpg
36
37
path1 = Path('/tmp/output/test_skip_resume3-output/')
38
path2 = Path('/tmp/output/test_skip_resume3/dir1/dir2/file4.jpg')
39
print(merge_paths(path1, path2))
40
# Output: /tmp/output/test_skip_resume3-output/test_skip_resume3/dir1/dir2/file4.jpg
41
42
path1 = Path('/output/test_skip_resume3-output/')
43
path2 = Path('/images/test_skip_resume3/dir1/dir2/file4.jpg')
44
print(merge_paths(path1, path2))
45
# Output: /output/test_skip_resume3-output/test_skip_resume3/dir1/dir2/file4.jpg
46
47
:param path1: dir
48
:param path2: file
49
:return:
50
"""
51
common_prefix = os.path.commonpath([path1, path2])
52
if common_prefix == "/":
53
# Custom output dir, exclude the first (/images/) prefix
54
lgr.debug(f"path1: {path1}")
55
lgr.debug(f"path2: {path2}")
56
path3 = Path(path1) / Path(*path2.parts[2:])
57
else:
58
real_path = os.path.relpath(path2, common_prefix)
59
lgr.debug(f"common_prefix: {common_prefix}")
60
lgr.debug(f"real_path: {real_path}")
61
path3 = path1 / Path(real_path)
62
63
return path3
64
65
66
def get_output_path(output_dir, path, rename_file):
67
lgr.debug(f"get_output_path({output_dir}, {path}, {rename_file})")
68
if rename_file:
69
output = path.with_name(f"blur-{path.name}")
70
else:
71
output = merge_paths(output_dir, path)
72
73
lgr.debug(f"Output: {output}")
74
# Create output dirs if not exist
75
output.parent.mkdir(parents=True, exist_ok=True)
76
return output
77
78
79
def process(args, path: Path, output: Path, logo=None):
80
"""
81
Process An Image
82
"""
83
lgr.debug(f"output path: {output}")
84
with open(path, "rb") as fp:
85
data = {
86
"camera_id": args.camera_id,
87
"config": args.config,
88
"et": args.et,
89
"el": args.el,
90
"eb": args.eb,
91
"er": args.er,
92
"xmin": args.xmin,
93
"ymin": args.ymin,
94
"xmax": args.xmax,
95
"ymax": args.ymax,
96
"split": args.split,
97
"overlap": args.overlap,
98
"faces": args.faces,
99
"plates": args.plates,
100
"regions": args.regions,
101
}
102
if args.copy_metadata:
103
data["copy_metadata"] = "true"
104
headers = {"Authorization": f"Token {args.api_key}"} if args.api_key else None
105
106
response = requests.post(
107
args.blur_url,
108
headers=headers,
109
files={"logo": logo, "upload": fp},
110
data=data,
111
stream=True,
112
)
113
lgr.debug(f"Response: {response}")
114
if response.status_code < 200 or response.status_code > 300:
115
logging.error(response.text)
116
if response.status_code == 400:
117
msg = response.json().get("error")
118
else:
119
msg = response.text
120
raise BlurError(f"Error performing blur: {msg}")
121
122
blur_data = response.json().get("blur")
123
if blur_data is None:
124
raise BlurError(
125
"Error - ensure blurring on server is enabled - "
126
"https://guides.platerecognizer.com/docs/blur/api-reference#post-parameters"
127
)
128
else:
129
base64_encoded_data = blur_data["base64"]
130
decoded_bytes = base64.b64decode(base64_encoded_data)
131
with open(output, "wb") as f:
132
f.write(decoded_bytes)
133
134
135
def process_dir(input_dir: Path, args, output_dir: Path, rename_file, resume):
136
"""
137
Recursively Process Images in a directory
138
139
:return:
140
"""
141
logo_bytes = None
142
if args.logo:
143
with open(args.logo, "rb") as fp:
144
logo_bytes = fp.read()
145
146
for path in input_dir.glob("**/*"):
147
if path.is_file() and not path.name.startswith("blur-"):
148
lgr.info(f"Processing file: {path}")
149
# Skip files that are not images
150
if imghdr.what(path) is None:
151
lgr.debug(f"Skipped not an image: {path}")
152
continue
153
154
output_path = get_output_path(output_dir, path, rename_file)
155
if resume and output_path.is_file():
156
continue
157
process(args, path, output_path, logo_bytes)
158
159
160
def main():
161
parser = argparse.ArgumentParser(
162
description="Blur plates and faces in a folder recursively",
163
epilog="""Examples:
164
Process images from a folder:
165
python main.py -b=http://localhost:8001/v1/blur --images=/path/to/images
166
Specify engine config and/or two regions:
167
python main.py -b=http://localhost:8001/v1/blur --config='{"region":"strict"}' -r us-ca -r th-37 --images=/path/to/images""",
168
formatter_class=argparse.RawTextHelpFormatter,
169
)
170
parser.add_argument("-a", "--api-key", help="Your API key.", required=False)
171
parser.add_argument(
172
"-b",
173
"--blur-url",
174
help="Url to blur SDK. Example http://localhost:5000",
175
default="https://blur.platerecognizer.com/v1/blur",
176
)
177
parser.add_argument(
178
"--images",
179
type=Path,
180
required=True,
181
help="Folder containing images to process.",
182
)
183
parser.add_argument("--logo", type=Path, required=False, help="Logo file path.")
184
parser.add_argument(
185
"--plates", type=int, default="10", help="Plate blur intensity."
186
)
187
parser.add_argument("--faces", type=int, default="10", help="Face blur intensity.")
188
parser.add_argument(
189
"--camera_id", required=False, help="Camera ID forward to Snapshot"
190
)
191
parser.add_argument(
192
"--config", required=False, help="Extra engine config forward to Snapshot"
193
)
194
parser.add_argument(
195
"--et", type=float, required=False, default=0.0, help="Exclusion margin top."
196
)
197
parser.add_argument(
198
"--el", type=float, required=False, default=0.0, help="Exclusion margin left."
199
)
200
parser.add_argument(
201
"--eb", type=float, required=False, default=0.0, help="Exclusion margin bottom."
202
)
203
parser.add_argument(
204
"--er", type=float, required=False, default=0.0, help="Exclusion margin right."
205
)
206
parser.add_argument(
207
"--xmin", type=int, required=False, help="Exclusion xmin.", nargs="*"
208
)
209
parser.add_argument(
210
"--ymin", type=int, required=False, help="Exclusion ymin.", nargs="*"
211
)
212
parser.add_argument(
213
"--xmax", type=int, required=False, help="Exclusion xmax.", nargs="*"
214
)
215
parser.add_argument(
216
"--ymax", type=int, required=False, help="Exclusion ymax.", nargs="*"
217
)
218
parser.add_argument(
219
"--split",
220
type=int,
221
required=False,
222
help="Split large images into horizontal chunks to increase predictions.",
223
)
224
parser.add_argument(
225
"--overlap",
226
type=int,
227
required=False,
228
help="Percentage of overlap when splitting.",
229
)
230
parser.add_argument("--output", type=Path, required=False, help="Output directory.")
231
parser.add_argument(
232
"--resume",
233
action="store_true",
234
help="Skip already blurred images.",
235
default=False,
236
)
237
parser.add_argument(
238
"--copy-metadata",
239
action="store_true",
240
help="Copy original image metadata(EXIF and XMP) into blurred images.",
241
default=False,
242
)
243
parser.add_argument(
244
"-r",
245
"--regions",
246
help="Match the license plate pattern of a specific region",
247
required=False,
248
action="append",
249
)
250
args = parser.parse_args()
251
if not args.images.is_dir():
252
raise BlurError(
253
f"Images directory is missing or invalid. Ensure path exists: {args.images}"
254
)
255
256
if args.output is not None:
257
if args.output.is_dir():
258
output_dir = args.output
259
if output_dir == args.images:
260
lgr.info(
261
"--output ignored, Files are renamed when outputting to same directory."
262
)
263
rename_file = False
264
else:
265
raise BlurError(
266
f"Output directory is missing or invalid. Ensure path exists: {args.output}"
267
)
268
else:
269
output_dir = args.images
270
rename_file = True
271
272
start = time.time()
273
process_dir(args.images, args, output_dir, rename_file, args.resume)
274
end = time.time()
275
tt = end - start
276
lgr.debug(f"Processing complete. Time taken: {tt}")
277
278
279
if __name__ == "__main__":
280
try:
281
main()
282
except BlurError as e:
283
lgr.error(str(e))
284
285