example app backend code
[ealt-edge.git] / example-apps / ROBO / retail_app / inventry / retail_app.py
1 #
2 # Copyright 2020 Huawei Technologies Co., Ltd.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 #
16
17 import config
18 from flask_sslify import SSLify
19 from flask import Flask, request, jsonify, Response
20 from flask_cors import CORS
21 # from camera_driver.capture_frame import VideoCamera, VideoFile
22 # from capture_frame import VideoCamera, VideoFile
23 # from influxdb import InfluxDBClient
24 import json
25 import time
26 import requests
27 import os
28 import cv2
29
30
31 app = Flask(__name__)
32 CORS(app)
33 sslify = SSLify(app)
34 app.config['JSON_AS_ASCII'] = False
35 app.config['UPLOAD_PATH'] = '/usr/app/images/'
36 app.config['supports_credentials'] = True
37 app.config['CORS_SUPPORTS_CREDENTIALS'] = True
38 app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024
39 ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg'])
40 ALLOWED_VIDEO_EXTENSIONS = {'mp4'}
41 count = 0
42 listOfMsgs = []
43 listOfCameras = []
44 listOfVideos = []
45 mock_func = 1
46
47
48 class inventory_info:
49     """
50     Store the data and manage multiple input video feeds
51     """
52     def __init__(self, current_count=0, total_count=0, time=0):
53         self.type = "Shelf_INV1"
54         self.labels = "Bottles"
55         self.current_count = current_count
56         self.total_count = total_count
57         self.time = time
58
59     def setcurrentcount(self, current_count):
60         self.current_count = current_count
61
62     def settotalcount(self, total_count):
63         self.total_count = total_count
64
65     def getcurrentcount(self):
66         return self.current_count
67
68     def gettotalcount(self):
69         return self.total_count
70
71     def setlabel(self, labels):
72         self.labels = labels
73
74     def getlabel(self):
75         return self.labels
76
77     def settime(self, time):
78         self.labels = time
79
80     def gettime(self):
81         return self.time
82
83
84 # temporary copied capture_frame file to this due to docker issue for module
85 # import
86
87 class VideoCamera(object):
88     """
89     opneCV to capture frame from a camera
90     """
91     def __init__(self, url):
92         self.video = cv2.VideoCapture(url)
93
94     def delete(self):
95         self.video.release()
96
97     def get_frame(self):
98         """
99         get a frame from camera url
100         """
101         success, image = self.video.read()
102         return success, image
103
104
105 class VideoFile(object):
106     """
107     opneCV to capture frame from a video stream
108     """
109     def __init__(self, video_name):
110         self.video = cv2.VideoCapture("./test/resources/" + video_name)
111
112     def delete(self):
113         self.video.release()
114
115     def get_frame(self):
116         """
117         get a frane from stream
118         """
119         success, image = self.video.read()
120         return success, image
121
122
123 def store_data(inventory_info):
124     """
125     store time series data in influx db
126     """
127     # TODO config, schema table, DB, fill data set
128     create_database()
129     store_info_db(inventory_info)
130
131
132 def mock_table(inven_info):
133     current_count = 3
134     labels = "Bottles"
135     total_count = 6
136     inven_info.setcurrentcount(current_count)
137     inven_info.settotalcount(total_count)
138     inven_info.setlabel(labels)
139     inven_info.utime = time.time()
140     # store_data(inven_info)
141     local_store(inven_info)
142
143
144 def shelf_inventory(video_capture, camera_info, true=None):
145     """
146     shelf_inventory
147     """
148     global count
149     global mock_func
150
151     labels = "bottles"
152     process_this_frame = 0
153     if mock_func == 1:
154         inven_info = inventory_info()
155         mock_table(inven_info)
156     else:
157         while True:
158             success, frame = video_capture.get_frame()
159             if not success:
160                 break
161             if process_this_frame == 0:
162                 url = config.detection_url + "/v1/obj_detection/detect"
163                 # info1 = cv2.imencode(".jpg", rgb_small_frame)[1].tobytes()
164                 data = json.loads(requests.post
165                                   (url, data=frame,
166                                    verify=config.ssl_cacertpath).text)
167         inven_info = inventory_info()
168         current_count = data[count]
169         labels = data[labels]
170         total_count = inven_info.current_count + inven_info.total_count
171         inven_info.setcurrentcount(current_count)
172         inven_info.settotalcount(total_count)
173         inven_info.setlabel(labels)
174         inven_info.utime = time.time()
175         # store_data(inven_info)
176         local_store(inven_info)
177
178
179 def local_store(inven_info):
180     """
181     store "shelf" data to array
182
183     :param inven_info: Inventry object
184     :return: None
185     """
186     if len(listOfMsgs) >= 100:
187         listOfMsgs.pop()
188     newdict = {"shelfName": inven_info.type, "ObjType": inven_info.labels,
189                "currentCount": inven_info.current_count,
190                "totalCount": inven_info.total_count,
191                "time": time.time()}
192     listOfMsgs.insert(0, newdict)
193
194
195 def store_info_db(inven_info):
196     """
197     Send "shelf" data to InfluxDB
198
199     :param inven_info: Inventry object
200     :return: None
201     """
202     global db_client
203     json_body = [
204         {
205             "measurement": inven_info.type,
206             "tags": {
207                 "object": "bottles",
208             },
209             "fields": {
210                 "time": inven_info.time,
211                 "Current Count": inven_info.current_count,
212                 "Total Count": inven_info.total_count,
213             }
214         }]
215     db_client.write_points(json_body)
216
217
218 def create_database():
219     """
220     Connect to InfluxDB and create the database
221
222     :return: None
223     """
224     global db_client
225 #    proxy = {"http": "http://{}:{}".format(config.IPADDRESS, config.PORT)}
226 #    db_client = InfluxDBClient(host=config.IPADDRESS, port=config.PORT,
227 #    proxies=proxy, database=config.DATABASE_NAME)
228 #    db_client.create_database(config.DATABASE_NAME)
229
230
231 @app.route('/v1/inventry/table', methods=['GET'])
232 def inventry_table():
233     """
234     return inventry table
235
236     :return: inventry table
237     """
238     return jsonify(listOfMsgs)
239
240
241 @app.route('/v1/inventry/image', methods=['GET'])
242 def detected_image():
243     """
244     return inventry table
245
246     :return: inventry table
247     """
248     return jsonify(listOfMsgs)
249
250
251 def allowed_videofile(filename):
252     """
253     File types to upload:mp4
254     param: filename:
255     """
256     return '.' in filename and \
257            filename.rsplit('.', 1)[1].lower() in ALLOWED_VIDEO_EXTENSIONS
258
259
260 @app.route('/v1/monitor/video', methods=['POST'])
261 def upload_video():
262     app.logger.info("Received message from ClientIP [" + request.remote_addr
263                     + "] Operation [" + request.method + "]" +
264                     " Resource [" + request.url + "]")
265     if 'file' in request.files:
266         files = request.files.getlist("file")
267         for file in files:
268             if allowed_videofile(file.filename):
269                 file.save(os.path.join(app.config['VIDEO_PATH'],
270                                        file.filename))
271             else:
272                 raise IOError('video format error')
273     return Response("success")
274
275
276 @app.route('/v1/monitor/cameras', methods=['POST'])
277 def add_camera():
278     camera_info = request.json
279     app.logger.info("Received message from ClientIP [" + request.remote_addr
280                     + "] Operation [" + request.method + "]" +
281                     " Resource [" + request.url + "]")
282     camera_info = {"name": camera_info["name"],
283                    "rtspurl": camera_info["rtspurl"],
284                    "location": camera_info["location"]}
285     listOfCameras.append(camera_info)
286     return Response("success")
287
288
289 @app.route('/v1/monitor/cameras/<name>/<rtspurl>/<location>', methods=['GET'])
290 def get_camera(name, rtspurl, location):
291     """
292     register camera with location
293     """
294     app.logger.info("Received message from ClientIP [" + request.remote_addr
295                     + "] Operation [" + request.method + "]" +
296                     " Resource [" + request.url + "]")
297     camera_info = {"name": name, "rtspurl": rtspurl, "location": location}
298     if "mp4" in camera_info["rtspurl"]:
299         video_file = VideoFile(camera_info["rtspurl"])
300         video_dict = {camera_info["name"]: video_file}
301         listOfVideos.append(video_dict)
302         return Response(shelf_inventory(video_file, camera_info["name"]),
303                         mimetype='multipart/x-mixed-replace; boundary=frame')
304     else:
305         video_file = VideoCamera(camera_info["rtspurl"])
306         video_dict = {camera_info["name"]: video_file}
307         listOfVideos.append(video_dict)
308         return Response(shelf_inventory(video_file, camera_info["name"]),
309                         mimetype='multipart/x-mixed-replace; boundary=frame')
310
311
312 @app.route('/v1/monitor/cameras/<camera_name>', methods=['DELETE'])
313 def delete_camera(camera_name):
314     app.logger.info("Received message from ClientIP [" + request.remote_addr
315                     + "] Operation [" + request.method + "]" +
316                     " Resource [" + request.url + "]")
317     for video1 in listOfVideos:
318         if camera_name in video1:
319             video_obj = video1[camera_name]
320             video_obj.delete()
321     for camera in listOfCameras:
322         if camera_name == camera["name"]:
323             listOfCameras.remove(camera)
324     for msg in listOfMsgs:
325         if camera_name in msg["msg"]:
326             listOfMsgs.remove(msg)
327     return Response("success")
328
329
330 @app.route('/v1/monitor/cameras')
331 def query_cameras():
332     app.logger.info("Received message from ClientIP [" + request.remote_addr
333                     + "] Operation [" + request.method + "]" +
334                     " Resource [" + request.url + "]")
335     return jsonify(listOfCameras)
336
337
338 @app.route('/', methods=['GET'])
339 def hello_world():
340     app.logger.info("Received message from ClientIP [" + request.remote_addr
341                     + "] Operation [" + request.method + "]" +
342                     " Resource [" + request.url + "]")
343     return Response("Hello MEC Developer")
344
345
346 def start_server(handler):
347     app.logger.addHandler(handler)
348     if config.ssl_enabled:
349         context = (config.ssl_certfilepath, config.ssl_keyfilepath)
350         app.run(host=config.server_address, debug=True, ssl_context=context,
351                 threaded=True, port=config.server_port)
352     else:
353         app.run(host=config.server_address, debug=True, threaded=True,
354                 port=config.server_port)