Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
parkpow
GitHub Repository: parkpow/deep-license-plate-recognition
Path: blob/master/blur/main.py
641 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
105
if args.api_key:
106
headers = {"Authorization": f"Token {args.api_key}"}
107
else:
108
headers = None
109
110
response = requests.post(
111
args.blur_url,
112
headers=headers,
113
files={"logo": logo, "upload": fp},
114
data=data,
115
stream=True,
116
)
117
lgr.debug(f"Response: {response}")
118
if response.status_code < 200 or response.status_code > 300:
119
logging.error(response.text)
120
if response.status_code == 400:
121
msg = response.json().get("error")
122
else:
123
msg = response.text
124
raise BlurError(f"Error performing blur: {msg}")
125
126
blur_data = response.json().get("blur")
127
if blur_data is None:
128
raise BlurError(
129
"Error - ensure blurring on server is enabled - "
130
"https://guides.platerecognizer.com/docs/blur/api-reference#post-parameters"
131
)
132
else:
133
base64_encoded_data = blur_data["base64"]
134
decoded_bytes = base64.b64decode(base64_encoded_data)
135
with open(output, "wb") as f:
136
f.write(decoded_bytes)
137
138
139
def process_dir(input_dir: Path, args, output_dir: Path, rename_file, resume):
140
"""
141
Recursively Process Images in a directory
142
143
:return:
144
"""
145
logo_bytes = None
146
if args.logo:
147
with open(args.logo, "rb") as fp:
148
logo_bytes = fp.read()
149
150
for path in input_dir.glob("**/*"):
151
if path.is_file() and not path.name.startswith("blur-"):
152
lgr.info(f"Processing file: {path}")
153
# Skip files that are not images
154
if imghdr.what(path) is None:
155
lgr.debug(f"Skipped not an image: {path}")
156
continue
157
158
output_path = get_output_path(output_dir, path, rename_file)
159
if resume and output_path.is_file():
160
continue
161
process(args, path, output_path, logo_bytes)
162
163
164
def main():
165
parser = argparse.ArgumentParser(
166
description="Blur plates and faces in a folder recursively",
167
epilog="""Examples:
168
Process images from a folder:
169
python main.py -b=http://localhost:8001/v1/blur --images=/path/to/images
170
Specify engine config and/or two regions:
171
python main.py -b=http://localhost:8001/v1/blur --config='{"region":"strict"}' -r us-ca -r th-37 --images=/path/to/images""",
172
formatter_class=argparse.RawTextHelpFormatter,
173
)
174
parser.add_argument("-a", "--api-key", help="Your API key.", required=False)
175
parser.add_argument(
176
"-b",
177
"--blur-url",
178
help="Url to blur SDK. Example http://localhost:5000",
179
default="https://blur.platerecognizer.com/v1/blur",
180
)
181
parser.add_argument(
182
"--images",
183
type=Path,
184
required=True,
185
help="Folder containing images to process.",
186
)
187
parser.add_argument("--logo", type=Path, required=False, help="Logo file path.")
188
parser.add_argument(
189
"--plates", type=int, default="10", help="Plate blur intensity."
190
)
191
parser.add_argument("--faces", type=int, default="10", help="Face blur intensity.")
192
parser.add_argument(
193
"--camera_id", required=False, help="Camera ID forward to Snapshot"
194
)
195
parser.add_argument(
196
"--config", required=False, help="Extra engine config forward to Snapshot"
197
)
198
parser.add_argument(
199
"--et", type=float, required=False, default=0.0, help="Exclusion margin top."
200
)
201
parser.add_argument(
202
"--el", type=float, required=False, default=0.0, help="Exclusion margin left."
203
)
204
parser.add_argument(
205
"--eb", type=float, required=False, default=0.0, help="Exclusion margin bottom."
206
)
207
parser.add_argument(
208
"--er", type=float, required=False, default=0.0, help="Exclusion margin right."
209
)
210
parser.add_argument(
211
"--xmin", type=int, required=False, help="Exclusion xmin.", nargs="*"
212
)
213
parser.add_argument(
214
"--ymin", type=int, required=False, help="Exclusion ymin.", nargs="*"
215
)
216
parser.add_argument(
217
"--xmax", type=int, required=False, help="Exclusion xmax.", nargs="*"
218
)
219
parser.add_argument(
220
"--ymax", type=int, required=False, help="Exclusion ymax.", nargs="*"
221
)
222
parser.add_argument(
223
"--split",
224
type=int,
225
required=False,
226
help="Split large images into horizontal chunks to increase predictions.",
227
)
228
parser.add_argument(
229
"--overlap",
230
type=int,
231
required=False,
232
help="Percentage of overlap when splitting.",
233
)
234
parser.add_argument("--output", type=Path, required=False, help="Output directory.")
235
parser.add_argument(
236
"--resume",
237
action="store_true",
238
help="Skip already blurred images.",
239
default=False,
240
)
241
parser.add_argument(
242
"--copy-metadata",
243
action="store_true",
244
help="Copy original image metadata(EXIF and XMP) into blurred images.",
245
default=False,
246
)
247
parser.add_argument(
248
"-r",
249
"--regions",
250
help="Match the license plate pattern of a specific region",
251
required=False,
252
action="append",
253
)
254
args = parser.parse_args()
255
if not args.images.is_dir():
256
raise BlurError(
257
f"Images directory is missing or invalid. Ensure path exists: {args.images}"
258
)
259
260
if args.output is not None:
261
if args.output.is_dir():
262
output_dir = args.output
263
if output_dir == args.images:
264
lgr.info(
265
"--output ignored, Files are renamed when outputting to same directory."
266
)
267
rename_file = False
268
else:
269
raise BlurError(
270
f"Output directory is missing or invalid. Ensure path exists: {args.output}"
271
)
272
else:
273
output_dir = args.images
274
rename_file = True
275
276
start = time.time()
277
process_dir(args.images, args, output_dir, rename_file, args.resume)
278
end = time.time()
279
tt = end - start
280
lgr.debug(f"Processing complete. Time taken: {tt}")
281
282
283
if __name__ == "__main__":
284
try:
285
main()
286
except BlurError as e:
287
lgr.error(str(e))
288
289