--- inference_endpoint.py
+++ inference_endpoint.py
... | ... | @@ -52,11 +52,12 @@ |
52 | 52 |
self.time_sent = None |
53 | 53 |
self.cctv_latitude = None |
54 | 54 |
self.cctv_longitude = None |
55 |
- self.cctv_info = None |
|
55 |
+ self.cctv_name = None |
|
56 | 56 |
self.mask = None |
57 | 57 |
self.mask_blob = None |
58 | 58 |
self.image = None |
59 | 59 |
self.image_type = None |
60 |
+ self.seg_image = None |
|
60 | 61 |
self.area_percent = 0 |
61 | 62 |
|
62 | 63 |
@ns.response(200, 'Success') |
... | ... | @@ -66,7 +67,7 @@ |
66 | 67 |
ns.abort(400, 'No image part in the request') |
67 | 68 |
self.image = request.files['file'] |
68 | 69 |
self.image_type = request.headers.get('Content-Type') |
69 |
- self.cctv_info = base64.b64decode(request.headers.get('x-cctv-name', '')).decode('UTF-8') |
|
70 |
+ self.cctv_name = base64.b64decode(request.headers.get('x-cctv-name', '')).decode('UTF-8') |
|
70 | 71 |
self.time_sent = request.headers.get('x-time-sent', '') |
71 | 72 |
self.cctv_latitude = request.headers.get('x-cctv-latitude', 'Not provided') |
72 | 73 |
self.cctv_longitude = request.headers.get('x-cctv-longitude', 'Not provided') |
... | ... | @@ -75,7 +76,7 @@ |
75 | 76 |
image = self.image.read() |
76 | 77 |
image = np.frombuffer(image, np.uint8) |
77 | 78 |
image = cv2.imdecode(image, cv2.IMREAD_COLOR) |
78 |
- # filename = f"{timestamp}_{self.cctv_info}.png" |
|
79 |
+ # filename = f"{timestamp}_{self.cctv_name}.png" |
|
79 | 80 |
|
80 | 81 |
t1 = time.time() |
81 | 82 |
detections, self.mask = inference_engine.run_inference(cv2.resize(image, model_input_shape)) |
... | ... | @@ -89,7 +90,7 @@ |
89 | 90 |
print(t2 - t1) |
90 | 91 |
|
91 | 92 |
if len(self.mask) != 0: |
92 |
- seg_image = overlay_mask(image, self.mask[0], color=(0, 255, 0), alpha=0.3) |
|
93 |
+ self.seg_image = overlay_mask(image, self.mask[0], color=(0, 255, 0), alpha=0.3) |
|
93 | 94 |
self.area_percent = 0 |
94 | 95 |
else : |
95 | 96 |
self.area_percent = np.sum(self.mask) / image.shape[0] * image.shape[1] |
... | ... | @@ -103,7 +104,7 @@ |
103 | 104 |
header = { |
104 | 105 |
'Content-Type': f'{self.image_type}', |
105 | 106 |
'x-time-sent': time_sent, |
106 |
- 'x-cctv-name': base64.b64encode(str(self.cctv_info).encode('utf-8')).decode('ascii'), |
|
107 |
+ 'x-cctv-name': base64.b64encode(str(self.cctv_name).encode('utf-8')).decode('ascii'), |
|
107 | 108 |
'x-cctv-latitude': str(self.cctv_latitude), |
108 | 109 |
'x-cctv-longitude': str(self.cctv_longitude), |
109 | 110 |
'x-area-percentage' : str(self.area_percent), |
... | ... | @@ -114,13 +115,18 @@ |
114 | 115 |
multipart_data = MultipartEncoder( |
115 | 116 |
fields={ |
116 | 117 |
'image': ( |
117 |
- f'frame_{self.cctv_info}.{self.image_type}', |
|
118 |
+ f'frame_{self.cctv_name}.{self.image_type}', |
|
118 | 119 |
self.image, |
119 | 120 |
f'image/{self.image_type}' |
120 | 121 |
), |
121 | 122 |
'mask' : ( |
122 |
- f'frame_mask_{self.cctv_info}.{self.image_type}', |
|
123 |
+ f'frame_mask_{self.cctv_name}.{self.image_type}', |
|
123 | 124 |
self.mask_blob, |
125 |
+ f'image/{self.image_type}' |
|
126 |
+ ), |
|
127 |
+ 'seg_mask' : ( |
|
128 |
+ f'frame_seg_{self.cctv_name}.{self.image_type}', |
|
129 |
+ self.seg_image, |
|
124 | 130 |
f'image/{self.image_type}' |
125 | 131 |
) |
126 | 132 |
} |
... | ... | @@ -130,7 +136,7 @@ |
130 | 136 |
|
131 | 137 |
except Exception as e: |
132 | 138 |
print(e) |
133 |
- print("Can not connect to the analyzer server. Check the endpoint address or connection.\n" |
|
139 |
+ print("Can not connect to the postprocessing server. Check the endpoint address or connection.\n" |
|
134 | 140 |
f"Can not connect to : {self.endpoint}") |
135 | 141 |
|
136 | 142 |
|
--- postprocess_draft.py
+++ postprocess_draft.py
... | ... | @@ -1,7 +1,29 @@ |
1 |
-class StreamSources: |
|
1 |
+import numpy as np |
|
2 |
+from flask import Flask, request |
|
3 |
+from flask_restx import Api, Resource, fields |
|
4 |
+import os |
|
5 |
+from datetime import datetime |
|
6 |
+from yoloseg.inference_ import Inference, overlay_mask |
|
7 |
+import cv2 |
|
8 |
+import time |
|
9 |
+import base64 |
|
10 |
+import requests |
|
11 |
+import typing |
|
12 |
+from requests_toolbelt import MultipartEncoder |
|
13 |
+ |
|
14 |
+# from config_files import API_ENDPOINT_MAIN |
|
15 |
+ |
|
16 |
+app = Flask(__name__) |
|
17 |
+api = Api(app, version='1.0', title='CCTV Image Upload API', |
|
18 |
+ description='A postprocessing and adaptive rate mainserver pusher') |
|
19 |
+ |
|
20 |
+# Namespace definition |
|
21 |
+ns = api.namespace('cctv', description='CCTV operations') |
|
22 |
+ |
|
23 |
+class StreamSources(): |
|
2 | 24 |
def __init__(self, buffer_size, normal_send_interval, failure_mode_thres, failure_mode_check_past_n, normal_mode_thres, normal_mode_check_past_n): |
3 |
- assert failure_mode_thres <= failure_mode_check_past_n, f"failure_mode checker condition is invaild!, failure_mode needs {failure_mode_thres} fails in {failure_mode_check_past_n}, which is not possible!" |
|
4 |
- assert failure_mode_thres <= failure_mode_check_past_n, f"normal_mode checker condition is invaild!, normal_mode needs {failure_mode_thres} fails in {normal_mode_check_past_n}, which is not possible!" |
|
25 |
+ assert failure_mode_thres <= failure_mode_check_past_n, f"failure_mode checker condition is invaild!, failure_mode needs {failure_mode_thres} fails in {failure_mode_check_past_n}, which is not possible!" |
|
26 |
+ assert normal_mode_thres <= normal_mode_check_past_n, f"normal_mode checker condition is invaild!, normal_mode needs {normal_mode_thres} fails in {normal_mode_check_past_n}, which is not possible!" |
|
5 | 27 |
assert buffer_size < failure_mode_check_past_n, f"'buffer_size' is smaller then failure_mode_thres! This is not possible! This will cause program to never enter failure mode!! \nPrinting relevent args and shutting down!\n buffer_size : {buffer_size}\n failure_mode_thres : {failure_mode_thres}" |
6 | 28 |
assert buffer_size < normal_mode_thres, f"'buffer_size' is smaller then normal_mode_thres! This is will cause the program to never revert back to normal mode!! \nPrinting relevent args and shutting down!\n buffer_size : {buffer_size}\n normal_mode_thres : {normal_mode_thres}" |
7 | 29 |
|
... | ... | @@ -15,34 +37,39 @@ |
15 | 37 |
self.switching_fail_consecutive_mode = False |
16 | 38 |
if normal_mode_thres == normal_mode_check_past_n: |
17 | 39 |
self.switching_normal_consecutive_mode = True |
18 |
- else |
|
40 |
+ else: |
|
19 | 41 |
self.switching_normal_consecutive_mode = False |
20 | 42 |
|
21 | 43 |
self.failure_mode_thres = failure_mode_thres |
22 | 44 |
self.failure_mode_check_past_n = failure_mode_check_past_n |
23 | 45 |
self.normal_mode_thres = normal_mode_thres |
24 | 46 |
|
25 |
- def __setitem__(self, key): |
|
47 |
+ def __setitem__(self, key, value): |
|
26 | 48 |
if key not in self.sources: |
27 | 49 |
self.sources[key] = { |
28 | 50 |
"status_counts": [], |
29 | 51 |
"ok_counts": 0, |
30 |
- "force_send_mode": False |
|
52 |
+ "force_send_mode": False, |
|
53 |
+ "most_recent_image" : None, |
|
54 |
+ "most_recent_mask" : None, |
|
55 |
+ "most_recent_seg_iamge" : None, |
|
56 |
+ "cctv_name" : value, |
|
31 | 57 |
} |
32 | 58 |
else : |
33 |
- raise "Error! Attempting to access that has no key!" |
|
59 |
+ raise KeyError(f"Error! Source {key} already initialized.") |
|
34 | 60 |
# Update logic here if needed |
35 | 61 |
|
36 | 62 |
def __getitem__(self, key): |
37 | 63 |
return self.sources[key] |
38 | 64 |
|
39 | 65 |
def add_status(self, source, status): |
40 |
- assert status == "OK" or status == "FAIL" , f"Invalid status was given!, status must be one of 'OK' or 'FAIL', but given '{status}'!" |
|
66 |
+ assert status in ["OK", "FAIL"], f"Invalid status was given!, status must be one of 'OK' or 'FAIL', but given '{status}'!" |
|
41 | 67 |
|
42 | 68 |
if source not in self.sources: |
43 |
- self[source] = {} # Initializes source if not existing |
|
69 |
+ raise f"No key found for source. Did you forgot to add it? \n source : {source}" |
|
70 |
+ |
|
44 | 71 |
self.sources[source]["status_counts"].append(status) |
45 |
- if len(self.sources[source]["status_counts"]) > self.buffer_size): |
|
72 |
+ if len(self.sources[source]["status_counts"]) > self.buffer_size: |
|
46 | 73 |
self.sources[source]["status_counts"].pop(0) |
47 | 74 |
|
48 | 75 |
# Your existing logic for updating counts and checking statuses |
... | ... | @@ -50,14 +77,15 @@ |
50 | 77 |
self.sources[source]["ok_counts"] += 1 |
51 | 78 |
if self.sources[source]["force_send_mode"] and self.sources[source]["ok_counts"] >= self.normal_mode_thres: |
52 | 79 |
self.sources[source]["force_send_mode"] = False |
53 |
- self.send_message(source, "OK SEND") |
|
80 |
+ self.send_message(source, "NORMAL SEND") |
|
54 | 81 |
else: |
55 | 82 |
self.sources[source]["ok_counts"] = 0 # Reset on FAIL |
56 | 83 |
self.check_failures(source) |
57 | 84 |
|
58 | 85 |
def check_failures(self, source): |
59 | 86 |
if self.switching_fail_consecutive_mode: |
60 |
- if len(self.sources[source]["status_counts"]) >= failure_mode_thres and all(status == 'FAIL' for status in self.sources[source]["status_counts"][-failure_mode_thres:]): |
|
87 |
+ if (len(self.sources[source]["status_counts"]) >= self.failure_mode_thres |
|
88 |
+ and all(status == 'FAIL' for status in self.sources[source]["status_counts"][-self.failure_mode_thres:])): |
|
61 | 89 |
print(f"Source {source} has 5 consecutive FAILs!") |
62 | 90 |
self.sources[source]["force_send_mode"] = True |
63 | 91 |
self.send_message(source, "FORCE SEND") |
... | ... | @@ -69,3 +97,57 @@ |
69 | 97 |
# Reset the count after sending message |
70 | 98 |
self.sources[source]["ok_counts"] = 0 |
71 | 99 |
|
100 |
+ |
|
101 |
[email protected]('/postprocess', ) |
|
102 |
+class PostProcesser(Resource): |
|
103 |
+ def __init__(self, *args, **kargs): |
|
104 |
+ super().__init__(*args, **kargs) |
|
105 |
+ self.time_sent = None |
|
106 |
+ self.cctv_latitude = None |
|
107 |
+ self.cctv_longitude = None |
|
108 |
+ self.cctv_name = None |
|
109 |
+ self.cctv_info = None |
|
110 |
+ self.mask = None |
|
111 |
+ self.mask_blob = None |
|
112 |
+ self.image = None |
|
113 |
+ self.image_type = None |
|
114 |
+ self.seg_image = None |
|
115 |
+ self.area_percent = 0 |
|
116 |
+ self.memory = StreamSources( |
|
117 |
+ buffer_size=15, |
|
118 |
+ normal_send_interval=10, |
|
119 |
+ failure_mode_thres=8, |
|
120 |
+ failure_mode_check_past_n=12, |
|
121 |
+ normal_mode_thres=8, |
|
122 |
+ normal_mode_check_past_n=12, |
|
123 |
+ ) |
|
124 |
+ pass |
|
125 |
+ |
|
126 |
+ @ns.response(200, 'Success') |
|
127 |
+ @ns.response(400, 'Validation Error') |
|
128 |
+ def post(self): |
|
129 |
+ self.image_type = request.headers.get('Content-Type') |
|
130 |
+ self.cctv_name = base64.b64decode(request.headers.get('x-cctv-name', '')).decode('UTF-8') |
|
131 |
+ self.time_sent = request.headers.get('x-time-sent', '') |
|
132 |
+ self.cctv_latitude = request.headers.get('x-cctv-latitude', 'Not provided') |
|
133 |
+ self.cctv_longitude = request.headers.get('x-cctv-longitude', 'Not provided') |
|
134 |
+ self.area_percent = request.headers.get('x-area-percentage') |
|
135 |
+ |
|
136 |
+ self.cctv_info = { |
|
137 |
+ 'cctv_name' : self.cctv_name, |
|
138 |
+ 'cctv_latitude' : self.cctv_latitude, |
|
139 |
+ 'cctv_longitude' : self.cctv_longitude, |
|
140 |
+ } |
|
141 |
+ self.memory[self.cctv_info['cctv_name']] = self.cctv_info |
|
142 |
+ pass_fail = self.pass_fail() |
|
143 |
+ self.memory.add_status(self.cctv_name, pass_fail) |
|
144 |
+ pass |
|
145 |
+ |
|
146 |
+ def pass_fail(self): |
|
147 |
+ thres = 0.1 |
|
148 |
+ #TODO temporal pass_fail threshold |
|
149 |
+ if self.area_percent > thres: |
|
150 |
+ ret = 'Fail' |
|
151 |
+ else: |
|
152 |
+ ret = 'OK' |
|
153 |
+ return ret(파일 끝에 줄바꿈 문자 없음) |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?