hls 스트리밍 및 추론 병합을 위한 테스트 및 코드 작성, config 파일들의 디렉토리 및 명명 리펙토링, ITS api 코드 가독성을 위한 변수 이름 및 잘못 하드코딩되어 있는 (도로 타입 변수 지정 불가) 부분 수정.
@9ac7555e925f75ee14efd0e1d1b68faf7e239c09
--- ITS/api.py
+++ ITS/api.py
... | ... | @@ -8,13 +8,13 @@ |
8 | 8 |
from dotenv import load_dotenv |
9 | 9 |
|
10 | 10 |
|
11 |
-def create_url(apiKey, type, cctvType, minX, maxX, minY, maxY, getType="json", |
|
11 |
+def create_url(apiKey, roadType, cctvType, minX, maxX, minY, maxY, getType="json", |
|
12 | 12 |
baseurl="https://openapi.its.go.kr:9443/cctvInfo"): |
13 | 13 |
''' |
14 |
- 국가교통정보센터 예제 실행 |
|
14 |
+ 국가교통정보센터 api 예제 실행 코드, 더 자세한 내용은 |
|
15 | 15 |
https://www.its.go.kr/opendata/openApiEx?service=cctv 참고 |
16 | 16 |
:param apiKey: ``str`` 국가교통정보센터에서 발급받은 api 키 |
17 |
- :param type: ``str`` 도로 유형 ('ex' : 고속도로, 'its' : 국도) |
|
17 |
+ :param roadType: ``str`` 도로 유형 ('ex' : 고속도로, 'its' : 국도) |
|
18 | 18 |
:param cctvType: ``int`` CCTV 유형 (1. 실시간 스트리밍(HLS) / 2. 동영상 파일(m3u8) / 3. 정지 영상(JPEG)) |
19 | 19 |
:param minX: 최소 경도 영역 |
20 | 20 |
:param maxX: 최대 경도 영역 |
... | ... | @@ -23,20 +23,34 @@ |
23 | 23 |
:param getType: 출력 결과 형식 ("xml" or "json") |
24 | 24 |
:return: api 요청 url |
25 | 25 |
''' |
26 |
- assert type != "ex" or "its", 'Error! type should be either "ex" or "its"' |
|
26 |
+ assert roadType != "ex" or "its", 'Error! roadType should be either "ex" or "its"' |
|
27 | 27 |
assert cctvType != 1 or 2 or 3, 'Error! cctvType should be one of 1, 2, 3!' |
28 | 28 |
assert getType != "json" or "xml", 'Error! gettype should be either "json" or "xml"!' |
29 | 29 |
|
30 | 30 |
return ( |
31 | 31 |
f"{baseurl}?" |
32 | 32 |
f"apiKey={apiKey}&" |
33 |
- f"type={type}&" |
|
33 |
+ f"roadType={roadType}&" |
|
34 | 34 |
f"cctvType={cctvType}&" |
35 | 35 |
f"minX={minX}&maxX={maxX}&minY={minY}&maxY={maxY}&" |
36 | 36 |
f"getType={getType}" |
37 | 37 |
) |
38 | 38 |
|
39 |
-def gather_cctv_list(xmin, xmax, ymin, ymax, intervals, cctvtype): |
|
39 |
+def gather_cctv_list(xmin, xmax, ymin, ymax, intervals, roadType, cctvType): |
|
40 |
+ ''' |
|
41 |
+ :param minX: 최소 경도 영역 |
|
42 |
+ :param maxX: 최대 경도 영역 |
|
43 |
+ :param minY: 최소 위도 영역 |
|
44 |
+ :param maxY: 최대 경도 영역 |
|
45 |
+ :param intervals: api를 통해서 cctv 목록을 불러올때 위경도 격자 간격 |
|
46 |
+ :param roadType: ``str`` 도로 유형 ('ex' : 고속도로, 'its' : 국도) |
|
47 |
+ :param cctvType: ``int`` CCTV 유형 (1. 실시간 스트리밍(HLS) / 2. 동영상 파일(m3u8) / 3. 정지 영상(JPEG)) |
|
48 |
+ :return: pandas DataFrame 형태로 반환 |
|
49 |
+ 주요 컬럼은 다음과 같음 |
|
50 |
+ coordx coordy cctvtype cctvformat cctvname cctvurl |
|
51 |
+ |
|
52 |
+ |
|
53 |
+ ''' |
|
40 | 54 |
dotenv = load_dotenv() |
41 | 55 |
apiKey= os.getenv("ITS_API") |
42 | 56 |
x_values = np.linspace(xmin, xmax, intervals+1) |
... | ... | @@ -52,7 +66,7 @@ |
52 | 66 |
x_next = x_values[i + 1] |
53 | 67 |
y_next = y_values[j + 1] |
54 | 68 |
|
55 |
- url = create_url(apiKey, 'its', cctvtype, |
|
69 |
+ url = create_url(apiKey, roadType, cctvType, |
|
56 | 70 |
x, x_next, y, y_next) |
57 | 71 |
response = requests.get(url) |
58 | 72 |
response_json = json.loads(response.text) |
... | ... | @@ -66,7 +80,7 @@ |
66 | 80 |
# df.to_csv(f"result/pohang/listofcctv_포항_{x}_{y}.csv", index=False) |
67 | 81 |
time.sleep(1) |
68 | 82 |
print(f"{i}, {j}") |
69 |
- all_data_df.to_csv(f"result/{xmin}_{xmax}_y{ymin}_{ymax}.csv") |
|
83 |
+ # all_data_df.to_csv(f"result/{xmin}_{xmax}_y{ymin}_{ymax}.csv") |
|
70 | 84 |
return all_data_df |
71 | 85 |
|
72 | 86 |
def get_jpeg(url): |
+++ ITS_api_test.py
... | ... | @@ -0,0 +1,19 @@ |
1 | +import os | |
2 | +import pandas as pd | |
3 | +from ITS.api import gather_cctv_list | |
4 | + | |
5 | +df = pd.read_csv("result/129.2_129.3_y35.9_36.07.csv") | |
6 | + | |
7 | +name_of_original = df.loc[0]["cctvname"] | |
8 | +lat = df.loc[0]["coordx"] | |
9 | +lon = df.loc[0]["coordy"] | |
10 | +apiKey = os.getenv("ITS_API") | |
11 | +lat_lon_interval = 0.000001 | |
12 | +api_result = gather_cctv_list(xmin=lat-lat_lon_interval, ymin=lon-lat_lon_interval, xmax=lat+lat_lon_interval, ymax=lon+lat_lon_interval, intervals=1, roadType=1) | |
13 | + | |
14 | +name_of_requested = api_result.loc[0]["cctvname"] | |
15 | + | |
16 | +if name_of_original == name_of_requested: | |
17 | + print("success") | |
18 | + print(name_of_original) | |
19 | + |
+++ config/cctv_lists.csv
... | ... | @@ -0,0 +1,0 @@ |
+++ config/hls_streaming_config.py
... | ... | @@ -0,0 +1,0 @@ |
--- config.py
+++ config/yolo_config.py
No changes |
--- yoloseg/config/classes.txt
+++ config/yolo_config.txt
No changes |
--- hls_streaming/hls.py
+++ hls_streaming/hls.py
... | ... | @@ -1,3 +1,4 @@ |
1 |
+import parser |
|
1 | 2 |
import time |
2 | 3 |
import av |
3 | 4 |
import cv2 |
... | ... | @@ -72,7 +73,7 @@ |
72 | 73 |
img_binary = cv2.imencode('.png', self.current_frame) |
73 | 74 |
img_binary = img_binary[1].tobytes() |
74 | 75 |
self.send_image_to_server(img_binary, self.endpoint) |
75 |
- # cv2.imwrite(f'hls_streaming/captured_frame_/{datetime.now()}_{frame_name}', img) |
|
76 |
+ cv2.imwrite(f'hls_streaming/captured_frame_/{datetime.now()}_{frame_name}', self.current_frame) |
|
76 | 77 |
self.last_capture_time = current_time |
77 | 78 |
print(f"Captured {frame_name} at time: {current_time - self.start_time:.2f}s") |
78 | 79 |
self.captured_frame_count +=1 |
... | ... | @@ -122,7 +123,7 @@ |
122 | 123 |
if __name__ == "__main__": |
123 | 124 |
capturer = FrameCapturer( |
124 | 125 |
'http://cctvsec.ktict.co.kr/5545/LFkDslDT81tcSYh3G4306+mcGlLb3yShF9rx2vcPfltwUL4+I950kcBlD15uWm6K0cKCtAMlxsIptMkCDo5lGQiLlARP+SyUloz8vIMNB18=', |
125 |
- 101, 10 |
|
126 |
+ 101, 10, 5 |
|
126 | 127 |
) |
127 | 128 |
t1 = time.time() |
128 | 129 |
try: |
+++ hls_streaming/streaming_process.py
... | ... | @@ -0,0 +1,14 @@ |
1 | +from ITS.api import gather_cctv_list | |
2 | +from hls_streaming.hls import FrameCapturer | |
3 | + | |
4 | +def refresh_hls_address(lat, lon, lat_lon_interval=0.000001): | |
5 | + api_result = gather_cctv_list(xmin=lat-lat_lon_interval, ymin=lon-lat_lon_interval, xmax=lat+lat_lon_interval, ymax=lon+lat_lon_interval, intervals=1, roadType=1) | |
6 | + return api_result.loc[0]["cctvurl"] | |
7 | + | |
8 | +if __name__ == "__main__": | |
9 | + import argparse | |
10 | + args = argparse.ArgumentParser | |
11 | + args.add_argument("cctv_num", help="index number of cctv, see cctv_list.csv") | |
12 | + args = args.parse_args() | |
13 | + | |
14 | + cctv_ind = args.cctv_num |
+++ inference_endpoint.py
... | ... | @@ -0,0 +1,79 @@ |
1 | +from flask import Flask, request | |
2 | +from flask_restx import Api, Resource, fields | |
3 | +import os | |
4 | +from datetime import datetime | |
5 | +from yoloseg.inference_ import Inference, overlay_mask | |
6 | +import cv2 | |
7 | +import time | |
8 | + | |
9 | +app = Flask(__name__) | |
10 | +api = Api(app, version='1.0', title='CCTV Image Upload API', | |
11 | + description='A simple API for receiving CCTV images') | |
12 | + | |
13 | +# Namespace definition | |
14 | +ns = api.namespace('cctv', description='CCTV operations') | |
15 | + | |
16 | +model_path = 'yoloseg/weight/best.onnx' | |
17 | +classes_txt_file = 'config/yolo_config.txt' | |
18 | +image_path = 'yoloseg/img3.jpg' | |
19 | + | |
20 | +model_input_shape = (640, 640) | |
21 | +inference_engine = Inference( | |
22 | + onnx_model_path=model_path, | |
23 | + model_input_shape=model_input_shape, | |
24 | + classes_txt_file=classes_txt_file, | |
25 | + run_with_cuda=True | |
26 | +) | |
27 | + | |
28 | +# Define the expected model for incoming data | |
29 | +image_upload_model = api.model('ImageUpload', { | |
30 | + 'image': fields.String(required=True, description='Image file', dt='File'), | |
31 | + 'x-cctv-info': fields.String(required=False, description='CCTV identifier'), | |
32 | + 'x-time-sent': fields.String(required=False, description='Time image was sent'), | |
33 | + 'x-cctv-latitude': fields.String(required=False, description='Latitude of CCTV'), | |
34 | + 'x-cctv-longitude': fields.String(required=False, description='Longitude of CCTV') | |
35 | +}) | |
36 | + | |
37 | +# Define the directory where images will be saved | |
38 | +IMAGE_DIR = "network_test" | |
39 | +if not os.path.exists(IMAGE_DIR): | |
40 | + os.makedirs(IMAGE_DIR) | |
41 | + | |
42 | [email protected]('/infer', ) | |
43 | +class ImageUpload(Resource): | |
44 | + # @ns.expect(image_upload_model, validate=True) | |
45 | + @ns.response(200, 'Success') | |
46 | + @ns.response(400, 'Validation Error') | |
47 | + def post(self): | |
48 | + if 'file' not in request.files: | |
49 | + ns.abort(400, 'No image part in the request') | |
50 | + image = request.files['file'] | |
51 | + cctv_info = request.headers.get('x-cctv-info', '') | |
52 | + time_sent = request.headers.get('x-time-sent', '') | |
53 | + cctv_latitude = request.headers.get('x-cctv-latitude', 'Not provided') | |
54 | + cctv_longitude = request.headers.get('x-cctv-longitude', 'Not provided') | |
55 | + | |
56 | + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
57 | + image = cv2.imdecode(image) | |
58 | + filename = f"{timestamp}_{cctv_info}.png" | |
59 | + | |
60 | + t1 = time.time() | |
61 | + detections, mask_maps = inference_engine.run_inference(image) | |
62 | + t2 = time.time() | |
63 | + | |
64 | + if mask_maps is not None: | |
65 | + seg_image = overlay_mask(image, mask_maps[0], color=(0, 255, 0), alpha=0.3) | |
66 | + | |
67 | + if image.filename == '': | |
68 | + ns.abort(400, 'No selected image') | |
69 | + | |
70 | + # Use current timestamp to avoid filename conflicts | |
71 | + # image_path = os.path.join(IMAGE_DIR, filename) | |
72 | + # image.save(image_path) | |
73 | + | |
74 | + return {"message": f"Image {filename} uploaded successfully!"} | |
75 | + | |
76 | + def send_result(self): | |
77 | + pass | |
78 | +if __name__ == '__main__': | |
79 | + app.run(debug=True, port=12345) |
+++ run_image_anal_backend.sh
... | ... | @@ -0,0 +1,29 @@ |
1 | +#!/bin/bash | |
2 | + | |
3 | +# Array to hold the process IDs | |
4 | +declare -a pids | |
5 | + | |
6 | +# Start multiple Python processes in the background | |
7 | +python hls_streaming/hls.py & | |
8 | +pids+=($!) | |
9 | +python hls_streaming/hls.py & | |
10 | +pids+=($!) | |
11 | + | |
12 | +# Function to kill all processes | |
13 | +cleanup() { | |
14 | + echo "Terminating all processes..." | |
15 | + for pid in "${pids[@]}"; do | |
16 | + kill -9 $pid | |
17 | + done | |
18 | +} | |
19 | + | |
20 | +# Trap keyboard interrupt and call cleanup | |
21 | +trap cleanup SIGINT | |
22 | + | |
23 | +# Print message | |
24 | +echo "Running... Press Ctrl+C to stop." | |
25 | + | |
26 | +# Wait forever until Ctrl+C is pressed | |
27 | +while true; do | |
28 | + sleep 1 | |
29 | +done |
--- test.py
+++ test.py
... | ... | @@ -2,6 +2,7 @@ |
2 | 2 |
from flask_restx import Api, Resource, fields |
3 | 3 |
import os |
4 | 4 |
from datetime import datetime |
5 |
+from yoloseg.inference_ import Inference |
|
5 | 6 |
|
6 | 7 |
app = Flask(__name__) |
7 | 8 |
api = Api(app, version='1.0', title='CCTV Image Upload API', |
... | ... | @@ -20,7 +21,7 @@ |
20 | 21 |
}) |
21 | 22 |
|
22 | 23 |
# Define the directory where images will be saved |
23 |
-IMAGE_DIR = "received_images" |
|
24 |
+IMAGE_DIR = "network_test" |
|
24 | 25 |
if not os.path.exists(IMAGE_DIR): |
25 | 26 |
os.makedirs(IMAGE_DIR) |
26 | 27 |
|
--- yoloseg/inference_.py
+++ yoloseg/inference_.py
... | ... | @@ -188,7 +188,7 @@ |
188 | 188 |
|
189 | 189 |
# Path to your ONNX model and classes text file |
190 | 190 |
model_path = 'yoloseg/weight/best.onnx' |
191 |
- classes_txt_file = 'yoloseg/config/classes.txt' |
|
191 |
+ classes_txt_file = 'yoloseg/config/yolo_config.txt' |
|
192 | 192 |
image_path = 'yoloseg/img3.jpg' |
193 | 193 |
|
194 | 194 |
model_input_shape = (640, 640) |
... | ... | @@ -241,7 +241,7 @@ |
241 | 241 |
|
242 | 242 |
# Path to your ONNX model and classes text file |
243 | 243 |
model_path = 'yoloseg/weight/best.onnx' |
244 |
- classes_txt_file = 'yoloseg/config/classes.txt' |
|
244 |
+ classes_txt_file = 'yoloseg/config/yolo_config.txt' |
|
245 | 245 |
|
246 | 246 |
model_input_shape = (640, 640) |
247 | 247 |
inference_engine = Inference( |
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?