Skip to content

Commit 4c2d862

Browse files
authored
Merge pull request #147 from masouduut94/master
Handled some errors in web server
2 parents 3df3923 + d443714 commit 4c2d862

File tree

7 files changed

+111
-42
lines changed

7 files changed

+111
-42
lines changed

webserver/.env

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
project_root="/home/user/codes/MSD/ZQ_pedestrian/"
2-
py_dir="/home/user/anaconda3/envs/pedestrian_detection_environment/bin/python"
1+
project_root="C:\Users\ZQ_deep_sort_pytorch"
32
model_type="yolov3"
43
output_dir="public/"
54
json_output="json_output/" # ignored for the moment in ped_det_online_server.py

webserver/config/config.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55

66
class BaseConfig:
77
SECRET_KEY = os.environ.get('SECRET_KEY') or 'Sm9obiBTY2hyb20ga2lja3MgYXNz'
8-
SERVER_NAME = '111.222.333.444:8888'
9-
# PORT = 8888
8+
SERVER_NAME = '127.0.0.1:8888'
109

1110

1211
class DevelopmentConfig(BaseConfig):

webserver/images/Thumbs.db

8.5 KB
Binary file not shown.

webserver/images/request.png

25.4 KB
Loading

webserver/readme.md

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,37 @@
99
- pytorch
1010
- dotenv
1111

12+
Please note that you need to install redis on your system.
1213

1314
### The architecture.
1415

1516
![web server architecture](images/arc.png)
1617

1718
1 - `RealTimeTracking` reads frames from rtsp link using threads
18-
(threads make it robust against network packet loss)
19+
(Using threads make the web server robust against network packet loss)
1920

2021
2 - In `RealTimeTracking.run` function in each iteration frame is stored in redis cache on server.
2122

2223
3 - Now we can serve the frames on redis to clients.
2324

2425
4 - To start the pedestrian detection, after running
25-
`rtsp_webserver.py`, go to `111.222.333.444:8888/start`
26-
on browser(which is configured in `config/config.py` as
27-
base url) to start the pedestrian_detection service.
26+
`rtsp_webserver.py`, send a GET request on `127.0.0.1:8888/run`
27+
with setting these GET method parameters
2828

29-
5 - watch pedestrian detection stream in `111.222.333.444:8888`
29+
| Param | Value | Description |
30+
| :-------------: | :-------------: | :-------------: |
31+
| run | 1/0 | to start the tracking set 1/ to stop tracking service set it as 0|
32+
| camera_stream | 'rtsp://ip:port/admin...' | provide it with valid rtsp link |
3033

31-
6 - To stop the service open browser and go to
32-
`111.222.333.444:8888/stop`.
34+
for example:
3335

36+
(to start the service) 127.0.0.1:8888/run?run=1
37+
(to stop the service) 127.0.0.1:8888/run?run=0
38+
(to change the camera)
39+
1- 127.0.0.1:8888/run?run=0 (first stop the current service)
40+
2- 127.0.0.1:8888/run?run=0&camera_stream=rtsp://ip:port/admin... (then start it with another rtsp link)
41+
42+
![web server architecture](images/request.png)
43+
44+
45+
5 - get pedestrian detection stream in `127.0.0.1:8888`

webserver/rtsp_threaded_tracker.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import warnings
12
from os import getenv
23
import sys
34
from os.path import dirname, abspath
@@ -12,7 +13,7 @@
1213
from concurrent.futures import ThreadPoolExecutor
1314
from redis import Redis
1415

15-
redis_cache = Redis('111.222.333.444')
16+
redis_cache = Redis('127.0.0.1')
1617

1718

1819
class RealTimeTracking(object):
@@ -34,7 +35,7 @@ def __init__(self, cfg, args):
3435
use_cuda = self.args.use_cuda and torch.cuda.is_available()
3536

3637
if not use_cuda:
37-
raise UserWarning("Running in cpu mode!")
38+
warnings.warn(UserWarning("Running in cpu mode!"))
3839

3940
self.detector = build_detector(cfg, use_cuda=use_cuda)
4041
self.deepsort = build_tracker(cfg, use_cuda=use_cuda)
@@ -50,22 +51,24 @@ def __init__(self, cfg, args):
5051

5152
self.thread = ThreadPoolExecutor(max_workers=1)
5253
self.thread.submit(self.update)
53-
print('streaming started ...')
5454

5555
def update(self):
5656
while True:
5757
if self.vdo.isOpened():
5858
(self.status, self.frame) = self.vdo.read()
5959

6060
def run(self):
61-
while getenv('tracking') != 'off':
61+
print('streaming started ...')
62+
while getenv('in_progress') != 'off':
6263
try:
6364
frame = self.frame.copy()
6465
self.detection(frame=frame)
6566
frame_to_bytes = cv2.imencode('.jpg', frame)[1].tobytes()
6667
redis_cache.set('frame', frame_to_bytes)
6768
except AttributeError:
6869
pass
70+
print('streaming stopped ...')
71+
6972

7073
def detection(self, frame):
7174
im = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

webserver/rtsp_webserver.py

Lines changed: 83 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
11
"""
2-
Main flask application
3-
4-
# Reference for start/stop trick:
5-
https://stackoverflow.com/questions/49821707/starting-and-stopping-a-method-using-flask-routes-python
62
73
# TODO: Load ML model with redis and keep it for sometime.
84
1- detector/yolov3/detector.py |=> yolov3 weightfile -> redis cache
95
2- deepsort/deep/feature_extractor |=> model_path -> redis cache
106
3- Use tmpfs (Insert RAM as a virtual disk and store model state): https://pypi.org/project/memory-tempfile/
117
12-
# TODO: Automatic turn off or switch between the cameras in ML model part.
13-
# TODO: send rtsp url to the ML model part and run the model for that camera.
148
"""
159
from os.path import join
1610
from os import getenv, environ
@@ -19,16 +13,16 @@
1913
from threading import Thread
2014

2115
from redis import Redis
22-
from flask import Response, Flask, jsonify
16+
from flask import Response, Flask, jsonify, request, abort
2317

2418
from rtsp_threaded_tracker import RealTimeTracking
2519
from server_cfg import model, deep_sort_dict
2620
from config.config import DevelopmentConfig
2721
from utils.parser import get_config
2822

29-
redis_cache = Redis('111.222.333.444')
23+
redis_cache = Redis('127.0.0.1')
3024
app = Flask(__name__)
31-
environ['tracking'] = 'off'
25+
environ['in_progress'] = 'off'
3226

3327

3428
def parse_args():
@@ -59,39 +53,101 @@ def parse_args():
5953

6054

6155
def gen():
56+
"""
57+
58+
Returns: video frames from redis cache
59+
60+
"""
6261
while True:
6362
frame = redis_cache.get('frame')
6463
if frame is not None:
6564
yield b'--frame\r\n'b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n'
6665

66+
6767
def pedestrian_tracking(cfg, args):
68+
"""
69+
starts the pedestrian detection on rtsp link
70+
Args:
71+
cfg:
72+
args:
73+
74+
Returns:
75+
76+
"""
6877
tracker = RealTimeTracking(cfg, args)
6978
tracker.run()
7079

80+
7181
def trigger_process(cfg, args):
72-
t = Thread(target=pedestrian_tracking, args=(cfg, args))
73-
t.start()
74-
return jsonify({"msg": "Pedestrian detection started successfully"})
82+
"""
83+
triggers pedestrian_tracking process on rtsp link using a thread
84+
Args:
85+
cfg:
86+
args:
87+
88+
Returns:
89+
"""
90+
try:
91+
t = Thread(target=pedestrian_tracking, args=(cfg, args))
92+
t.start()
93+
return jsonify({"message": "Pedestrian detection started successfully"})
94+
except Exception:
95+
return jsonify({'message': "Unexpected exception occured in process"})
96+
97+
98+
@app.errorhandler(400)
99+
def bad_argument(error):
100+
return jsonify({'message': error.description['message']})
101+
75102

76103
# Routes
77-
@app.route('/')
78-
def video_feed():
104+
@app.route('/stream', methods=['GET'])
105+
def stream():
106+
"""
107+
Provides video frames on http link
108+
Returns:
109+
110+
"""
79111
return Response(gen(),
80112
mimetype='multipart/x-mixed-replace; boundary=frame')
81113

82-
@app.route("/start", methods=['GET'])
83-
def start_tracking():
84-
if environ['tracking'] != 'on':
85-
global cfg, args
86-
environ['tracking'] = 'on'
87-
return Response(trigger_process(cfg, args), mimetype="text/html")
88-
else:
89-
return jsonify({"msg": " Pedestrian detection is already in progress."})
90-
91-
@app.route("/stop", methods=['GET'])
92-
def stop_tracking():
93-
environ['tracking'] = 'off'
94-
return jsonify({"msg": "Pedestrian detection terminated!"})
114+
115+
@app.route("/run", methods=['GET'])
116+
def process_manager():
117+
"""
118+
request parameters:
119+
run (bool): 1 -> start the pedestrian tracking
120+
0 -> stop it
121+
camera_stream: str -> rtsp link to security camera
122+
123+
:return:
124+
"""
125+
# data = request.args
126+
data = request.args
127+
status = data['run']
128+
status = int(status) if status.isnumeric() else abort(400, {'message': f"bad argument for run {data['run']}"})
129+
if status == 1:
130+
# if pedestrian tracking is not running, start it off!
131+
try:
132+
if environ.get('in_progress', 'off') == 'off':
133+
global cfg, args
134+
vdo = data.get('camera_stream')
135+
if vdo is not None:
136+
args.input = int(vdo)
137+
environ['in_progress'] = 'on'
138+
return trigger_process(cfg, args)
139+
elif environ.get('in_progress') == 'on':
140+
# if pedestrian tracking is running, don't start another one (we are short of gpu resources)
141+
return jsonify({"message": " Pedestrian detection is already in progress."})
142+
except Exception:
143+
environ['in_progress'] = 'off'
144+
return abort(503)
145+
elif status == 0:
146+
if environ.get('in_progress', 'off') == 'off':
147+
return jsonify({"message": "pedestrian detection is already terminated!"})
148+
else:
149+
environ['in_progress'] = 'off'
150+
return jsonify({"message": "Pedestrian detection terminated!"})
95151

96152

97153
if __name__ == '__main__':

0 commit comments

Comments
 (0)