2 # Copyright 2020 Huawei Technologies Co., Ltd.
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
8 # http://www.apache.org/licenses/LICENSE-2.0
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.
18 from flask_sslify import SSLify
19 from flask import Flask, request, jsonify, Response
20 from flask_cors import CORS
21 from influxdb import InfluxDBClient
35 app.config['JSON_AS_ASCII'] = False
36 app.config['UPLOAD_PATH'] = '/usr/app/images_result/'
37 app.config['VIDEO_PATH'] = '/usr/app/test/resources/'
38 app.config['supports_credentials'] = True
39 app.config['CORS_SUPPORTS_CREDENTIALS'] = True
40 app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024
41 ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg'])
42 ALLOWED_VIDEO_EXTENSIONS = {'mp4'}
51 Store the data and manage multiple input video feeds
53 def __init__(self, status="Needs Filling", time=0):
54 self.type = "Shelf_INV1"
55 self.labels = "Bottles"
61 def setstatus(self, status):
67 def setcurrentCount(self, count):
68 self.currentCount = count
70 def getcurrentCount(self):
71 return self.currentCount
73 def setmaxCount(self, count):
76 def getmaxCount(self):
79 def setlabel(self, labels):
85 def settime(self, time):
92 # temporary copied capture_frame file to this due to docker issue for module
94 class VideoCamera(object):
96 opneCV to capture frame from a camera
98 def __init__(self, url):
99 self.video = cv2.VideoCapture(url)
106 get a frame from camera url
108 success, image = self.video.read()
109 return success, image
112 class VideoFile(object):
114 opneCV to capture frame from a video stream
116 def __init__(self, video_name):
117 self.video = cv2.VideoCapture(app.config['VIDEO_PATH'] + video_name)
124 get a frane from stream
126 success, image = self.video.read()
127 return success, image
130 def shelf_inventory(video_capture, camera_info, true=None):
138 count_val = 'ObjCount'
139 process_this_frame = 0
141 url = config.detection_url + "detect"
142 url_get = config.detection_url + "image"
145 success, frame = video_capture.get_frame()
147 print('read frame from file is failed')
156 if process_this_frame == 0:
157 imencoded = cv2.imencode(".jpg", frame)[1]
159 'image.jpg', imencoded.tostring(), 'image/jpeg',
161 res = requests.post(url, files=file)
162 data = json.loads(res.text)
165 response = requests.get(url_get)
167 file = open(app.config['UPLOAD_PATH'] + "sample_image.jpg", "wb")
168 file.write(response.content)
171 inven_info = inventory_info()
172 current_count = data[count_val]
173 if (current_count >= 3):
174 status = "Mostly Filled"
175 elif (current_count == 2):
176 status = "Partially Filled"
178 status = "Needs Filling"
180 inven_info.setlabel(labels)
181 inven_info.setstatus(status)
182 inven_info.setcurrentCount(current_count)
183 time_sec = time.time()
184 local_time = time.ctime(time_sec)
185 inven_info.time = local_time
186 store_info_db(inven_info)
190 def db_drop_table(inven_info):
192 cleanup measrurment before new trigger
194 :param inven_info: inven_info object
198 db_client.drop_measurement(inven_info.type)
201 def store_info_db(inven_info):
203 Send "shelf" data to InfluxDB
205 :param inven_info: Inventry object
211 "measurement": inven_info.type,
216 "time": inven_info.time,
217 "status": inven_info.status,
218 "currentCount": inven_info.currentCount,
219 "maxCount": inven_info.maxCount,
222 db_client.write_points(json_body)
225 def retrive_info_db():
227 Send "shelf" data to InfluxDB
229 :param inven_info: Inventry object
234 # get data last n data points from DB
235 result = db_client.query('select * from Shelf_INV1 order by desc limit '
238 # Get points and iterate over each record
239 points = result.get_points(tags={"object": "bottles"})
245 # iterate points and fill the records and insert to list
247 print("status: %s,Time: %s" % (point['status'], point['time']))
248 newdict = {"shelfName": 'Shelf_INV1', "ObjType": "bottles",
249 "status": point['status'],
250 "currentCount": point['currentCount'],
251 "maxCount": point['maxCount'],
252 "time": point['time']}
253 listOfMsgs.insert(0, newdict)
256 def create_database():
258 Connect to InfluxDB and create the database
263 proxy = {"http": "http://{}:{}".format(config.IPADDRESS, config.PORT)}
264 db_client = InfluxDBClient(host=config.IPADDRESS, port=config.PORT,
265 proxies=proxy, database=config.DATABASE_NAME)
266 db_client.create_database(config.DATABASE_NAME)
269 @app.route('/v1/inventry/table', methods=['GET'])
270 def inventry_table():
272 return inventry table
274 :return: inventry table
277 table = {"InventryData": listOfMsgs}
278 return jsonify(table)
281 @app.route('/v1/inventry/image', methods=['GET'])
282 def detected_image():
284 detect images with imposed
286 :return: result image
288 detected_image = app.config['UPLOAD_PATH'] + 'sample_image.jpg'
289 print('file exits:', str(path.exists(detected_image)))
290 status = str(path.exists(detected_image))
293 with open(detected_image, "rb") as img_file:
294 jpeg_bin = base64.b64encode(img_file.read())
296 response = {'image': jpeg_bin}
297 return jsonify(response)
299 response = {'image': 'null'}
300 print('file not exist')
301 return jsonify(response)
304 def allowed_videofile(filename):
306 File types to upload:mp4
309 return '.' in filename and \
310 filename.rsplit('.', 1)[1].lower() in ALLOWED_VIDEO_EXTENSIONS
313 @app.route('/v1/monitor/video', methods=['POST'])
315 app.logger.info("Received message from ClientIP [" + request.remote_addr
316 + "] Operation [" + request.method + "]" +
317 " Resource [" + request.url + "]")
318 print("videpath:" + app.config['VIDEO_PATH'])
319 if 'file' in request.files:
320 files = request.files.getlist("file")
322 if allowed_videofile(file.filename):
323 file.save(os.path.join(app.config['VIDEO_PATH'],
325 print('file path is:', app.config['VIDEO_PATH']
328 raise IOError('video format error')
329 msg = {"responce": "failure"}
331 msg = {"responce": "success"}
335 def hash_func(camera_info):
336 hash_string = camera_info["cameraNumber"] + \
337 camera_info["cameraLocation"] + \
338 camera_info["rtspUrl"]
339 # readable_hash = hashlib.sha256(str(hash_string).encode(
340 # 'utf-8')).hexdigest()
341 readable_hash = hash(hash_string)
342 if readable_hash < 0:
343 readable_hash += sys.maxsize
348 @app.route('/v1/monitor/cameras', methods=['POST'])
350 camera_detail = request.json
351 app.logger.info("Received message from ClientIP [" + request.remote_addr
352 + "] Operation [" + request.method + "]" +
353 " Resource [" + request.url + "]")
354 camera_id = hash_func(camera_detail)
355 camera_id = str(camera_id)
356 for camera_info in listOfCameras:
357 if camera_id == camera_info["cameraID"]:
358 msg = {"responce": "failure"}
361 camera_info = {"cameraID": camera_id,
362 "cameraNumber": camera_detail["cameraNumber"],
363 "rtspUrl": camera_detail["rtspUrl"],
364 "cameraLocation": camera_detail["cameraLocation"]}
365 listOfCameras.append(camera_info)
366 msg = {"responce": "success"}
370 @app.route('/v1/monitor/cameras/<cameraID>', methods=['GET'])
371 def get_camera(cameraID):
373 register camera with location
375 app.logger.info("Received message from ClientIP [" + request.remote_addr
376 + "] Operation [" + request.method + "]" +
377 " Resource [" + request.url + "]")
379 for camera_info in listOfCameras:
380 # cameraID = int(cameraID)
381 if cameraID == camera_info["cameraID"]:
386 app.logger.info("camera ID is not valid")
387 msg = {"responce": "failure"}
390 if "mp4" in camera_info["rtspUrl"]:
391 video_file = VideoFile(camera_info["rtspUrl"])
392 video_dict = {camera_info["cameraNumber"]: video_file}
393 listOfVideos.append(video_dict)
394 # return Response(shelf_inventory(video_file, camera_info[
396 # mimetype='multipart/x-mixed-replace; boundary=frame')
397 shelf_inventory(video_file, camera_info["cameraNumber"])
398 app.logger.info("get_camera: Added json")
399 msg = {"responce": "success"}
403 video_file = VideoCamera(camera_info["rtspUrl"])
404 video_dict = {camera_info["cameraNumber"]: video_file}
405 listOfVideos.append(video_dict)
406 return Response(shelf_inventory(video_file,
407 camera_info["cameraNumber"]),
408 mimetype='multipart/x-mixed-replace; boundary=frame')
411 @app.route('/v1/monitor/cameras/<camera_name>', methods=['DELETE'])
412 def delete_camera(camera_name):
413 app.logger.info("Received message from ClientIP [" + request.remote_addr
414 + "] Operation [" + request.method + "]" +
415 " Resource [" + request.url + "]")
416 for video1 in listOfVideos:
417 if camera_name in video1:
418 video_obj = video1[camera_name]
420 for camera in listOfCameras:
421 if camera_name == camera["cameraNumber"]:
422 listOfCameras.remove(camera)
423 return Response("success")
426 @app.route('/v1/monitor/cameras')
428 app.logger.info("Received message from ClientIP [" + request.remote_addr
429 + "] Operation [" + request.method + "]" +
430 " Resource [" + request.url + "]")
431 camera_info = {"roboCamera": listOfCameras}
432 return jsonify(camera_info)
435 @app.route('/', methods=['GET'])
437 app.logger.info("Received message from ClientIP [" + request.remote_addr
438 + "] Operation [" + request.method + "]" +
439 " Resource [" + request.url + "]")
440 return Response("Hello MEC Developer")
443 def start_server(handler):
444 app.logger.addHandler(handler)
446 if config.ssl_enabled:
447 context = (config.ssl_certfilepath, config.ssl_keyfilepath)
448 app.run(host=config.server_address, debug=True, ssl_context=context,
449 threaded=True, port=config.server_port)
451 app.run(host=config.server_address, debug=True, threaded=True,
452 port=config.server_port)