Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
parkpow
GitHub Repository: parkpow/deep-license-plate-recognition
Path: blob/master/docker/platerec_installer/stream_config.py
1091 views
1
import logging
2
from pathlib import Path
3
4
import requests
5
from configobj import ConfigObj, flatten_errors
6
from validate import ValidateError, Validator
7
8
DEFAULT_CONFIG = """# Instructions:
9
# https://app.platerecognizer.com/stream-docs
10
11
# List of TZ names on https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
12
timezone = UTC
13
14
[cameras]
15
# Full list of regions: http://docs.platerecognizer.com/#countries
16
# regions = fr, gb
17
18
# Sample 1 out of X frames. A high number will result in less compute.
19
# A low number is preferred for a stream with fast moving vehicles
20
# sample = 2
21
22
# Maximum delay in seconds before a prediction is returned
23
# max_prediction_delay = 6
24
25
# Maximum time in seconds that a result stays in memory
26
# memory_decay = 300
27
28
# Enable make, model and color prediction. Your account must have that option.
29
# mmc = true
30
31
# Image file name, you can use any format codes from https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes
32
image_format = $(camera)_screenshots/%y-%m-%d/%H-%M-%S.%f.jpg
33
34
# Webhook image type. Use "vehicle" to send only the vehicle image or "original" to
35
# send the full-size image. This setting can be used at the camera level too.
36
webhook_image_type = vehicle
37
38
# When a webhook is sent, the request will time out after n seconds and retry later.
39
# webhook_request_timeout = 30
40
41
# Only accept the results that exactly match the templates of the specified regions.
42
# region_config = strict
43
44
# Only accept license plates when a vehicle is also detected.
45
# detection_rule = strict
46
47
# Beta - Detect vehicles without a license plate. One of: plate, vehicle
48
# detection_mode = plate
49
50
# Advanced - Number of steps used to merge unique vehicles. A low number will increase compute.
51
# If set to -1, it is automatically picked (default).
52
# merge_buffer = -1
53
54
[[camera-1]]
55
active = yes
56
url = rtsp://192.168.0.108:8080/video/h264
57
58
# Output methods. Uncomment/comment line to enable/disable.
59
# - Save to CSV file. The corresponding frame is stored as an image in the same directory.
60
csv_file = $(camera)_%y-%m-%d.csv
61
62
# - Send to Webhook. The recognition data and vehicle image are encoded in
63
# multipart/form-data and sent to webhook_target.
64
# webhook_targets = http://webhook.site/
65
# webhook_image = yes
66
# webhook_caching = yes
67
68
# - Send to ParkPow. See https://app.parkpow.com/accounts/token/
69
# - Save to file in JSONLines format. https://jsonlines.org/
70
# jsonlines_file = $(camera)_%y-%m-%d.jsonl
71
72
"""
73
74
75
def send_request(section):
76
if not section.get("webhook_target") or not section.get("webhook_header"):
77
return
78
if "/api/v1/webhook-receiver" not in section["webhook_target"]:
79
return
80
headers = {
81
"Authorization": f"Token {section['webhook_header'].split('Token ')[-1]}"
82
}
83
url = section["webhook_target"].replace("webhook-receiver", "parking-list")
84
try:
85
response = requests.get(url, headers=headers, timeout=10)
86
except (requests.Timeout, requests.ConnectionError) as exc:
87
raise ValidateError(
88
"[STR0019] The value in webhook_target in the config.ini file is incorrect. "
89
"Please check the webhook_target value and try again. "
90
"Go here for additional help "
91
"https://guides.platerecognizer.com/docs/stream/configuration#webhook-parameters."
92
) from exc
93
if response.status_code != 200:
94
raise ValidateError(
95
"[STR0020] The Token in webhook_header in the config.ini file is incorrect. "
96
"Please check the webhook_header value and try again. "
97
"Go here for additional help "
98
"https://guides.platerecognizer.com/docs/stream/configuration#webhook-parameters."
99
)
100
101
102
def check_token(config):
103
send_request(config)
104
for camera in config.sections:
105
if config[camera]["active"]:
106
send_request(config[camera])
107
108
109
def camera_spec():
110
camera_global = dict(
111
regions="force_list(default=list())",
112
webhook_target='string(default="")',
113
webhook_targets="force_list(default=list())",
114
webhook_header='string(default="")',
115
webhook_image="boolean(default=yes)",
116
webhook_caching="boolean(default=yes)",
117
webhook_image_type='option("vehicle", "original", default="vehicle")',
118
webhook_request_timeout="float(default=30)",
119
max_prediction_delay="float(default=6)",
120
memory_decay="float(default=300)",
121
image_format='string(default="$(camera)_screenshots/%y-%m-%d/%H-%M-%S.%f.jpg")',
122
sample="integer(default=2)",
123
total="integer(default=-1)",
124
mmc="boolean(default=no)",
125
csv_file='string(default="")',
126
jsonlines_file='string(default="")',
127
region_config='option("normal", "strict", default="normal")',
128
detection_rule='option("normal", "strict", default="normal")',
129
detection_mode='option("plate", "vehicle", default="plate")',
130
merge_buffer="integer(default=-1)",
131
)
132
133
camera = dict(
134
url="string",
135
active="boolean(default=yes)",
136
# Overridable
137
regions="force_list(default=None)",
138
webhook_target="string(default=None)",
139
webhook_targets="force_list(default=None)",
140
webhook_header="string(default=None)",
141
webhook_image="boolean(default=None)",
142
webhook_caching="boolean(default=None)",
143
webhook_image_type='option("vehicle", "original", default=None)',
144
webhook_request_timeout="float(default=None)",
145
max_prediction_delay="float(default=None)",
146
memory_decay="float(default=None)",
147
image_format="string(default=None)",
148
sample="integer(default=None)",
149
total="integer(default=None)",
150
mmc="boolean(default=None)",
151
csv_file="string(default=None)",
152
jsonlines_file="string(default=None)",
153
region_config='option("normal", "strict", default=None)',
154
detection_rule='option("normal", "strict", default=None)',
155
detection_mode='option("plate", "vehicle", default=None)',
156
merge_buffer="integer(default=None)",
157
)
158
assert set(camera_global.keys()) <= set(camera.keys())
159
return dict(__many__=camera, **camera_global)
160
161
162
def base_config(config_path: Path, config=None):
163
spec = ConfigObj()
164
spec["timezone"] = 'string(default="UTC")'
165
spec["version"] = "integer(default=2)"
166
spec["cameras"] = camera_spec()
167
if not config_path.exists():
168
with open(config_path, "w") as fp:
169
fp.write(DEFAULT_CONFIG.replace("\n", "\r\n"))
170
try:
171
config = ConfigObj(
172
config.split("\n") if config else str(config_path),
173
configspec=spec,
174
raise_errors=True,
175
indent_type=" ",
176
)
177
config.newlines = "\r\n" # For Windows
178
except Exception as e:
179
return None, str(e)
180
result = config.validate(Validator(), preserve_errors=True)
181
errors = flatten_errors(config, result)
182
if errors:
183
error_message = "[STR0021] The config.ini file does not seem to be formatted correctly. \n [Error details] \n"
184
for section_list, key, error in errors:
185
if error is False:
186
error = f"key {key} is missing."
187
elif key is not None:
188
section_list.append(key)
189
section_string = "/".join(section_list)
190
logging.error("%s: %s", section_string, error)
191
error = f"{section_string}, param: {key}, message: {error}"
192
error_message += f"\n{error}"
193
return (
194
None,
195
error_message
196
+ "\n Go here for additional help https://guides.platerecognizer.com/docs/stream/configuration",
197
)
198
try:
199
check_token(config["cameras"])
200
except Exception as e:
201
return None, str(e)
202
return config, None
203
204