def main_handler(): # set up logging to syslog # construct the argument parse and parse the arguments ap = argparse.ArgumentParser() ap.add_argument('-c', '--config', help='config file with path') ap.add_argument('-e', '--eventid', help='event ID to retrieve') ap.add_argument('-p', '--eventpath', help='path to store object image file', default='') ap.add_argument('-m', '--monitorid', help='monitor id - needed for mask') ap.add_argument('-v', '--version', help='print version and quit', action='store_true') ap.add_argument('-o', '--output-path', help='internal testing use only - path for debug images to be written') ap.add_argument('-f', '--file', help='internal testing use only - skips event download') ap.add_argument('-r', '--reason', help='reason for event (notes field in ZM)') ap.add_argument('-n', '--notes', help='updates notes field in ZM with detections', action='store_true') ap.add_argument('-d', '--debug', help='enables debug on console', action='store_true') args, u = ap.parse_known_args() args = vars(args) if args.get('version'): print('hooks:{} pyzm:{}'.format(hooks_version, pyzm_version)) exit(0) if not args.get('config'): print ('--config required') exit(1) if not args.get('file')and not args.get('eventid'): print ('--eventid required') exit(1) utils.get_pyzm_config(args) if args.get('debug'): g.config['pyzm_overrides']['dump_console'] = True g.config['pyzm_overrides']['log_debug'] = True g.config['pyzm_overrides']['log_level_debug'] = 5 g.config['pyzm_overrides']['log_debug_target'] = None if args.get('monitorid'): log.init(name='zmesdetect_' + 'm' + args.get('monitorid'), override=g.config['pyzm_overrides']) else: log.init(name='zmesdetect',override=g.config['pyzm_overrides']) g.logger = log es_version='(?)' try: es_version=subprocess.check_output(['/usr/bin/zmeventnotification.pl', '--version']).decode('ascii') except: pass try: import cv2 except ImportError as e: g.logger.Fatal (f'{e}: You might not have installed OpenCV as per install instructions. Remember, it is NOT automatically installed') g.logger.Info('---------| pyzm version:{}, hook version:{}, ES version:{} , OpenCV version:{}|------------'.format(pyzm_version, hooks_version, es_version, cv2.__version__)) # load modules that depend on cv2 try: import zmes_hook_helpers.image_manip as img except Exception as e: g.logger.Error (f'{e}') exit(1) g.polygons = [] # process config file g.ctx = ssl.create_default_context() utils.process_config(args, g.ctx) # misc came later, so lets be safe if not os.path.exists(g.config['base_data_path'] + '/misc/'): try: os.makedirs(g.config['base_data_path'] + '/misc/') except FileExistsError: pass # if two detects run together with a race here if not g.config['ml_gateway']: g.logger.Info('Importing local classes for Object/Face') import pyzm.ml.object as object_detection else: g.logger.Info('Importing remote shim classes for Object/Face') from zmes_hook_helpers.apigw import ObjectRemote, FaceRemote, AlprRemote # now download image(s) start = datetime.datetime.now() obj_json = [] import pyzm.api as zmapi api_options = { 'apiurl': g.config['api_portal'], 'portalurl': g.config['portal'], 'user': g.config['user'], 'password': g.config['password'] , 'logger': g.logger, # use none if you don't want to log to ZM, #'disable_ssl_cert_check': True } g.logger.Info('Connecting with ZM APIs') zmapi = zmapi.ZMApi(options=api_options) stream = args.get('eventid') or args.get('file') ml_options = {} stream_options={} secrets = None if g.config['ml_sequence'] and g.config['use_sequence'] == 'yes': g.logger.Debug(2,'using ml_sequence') ml_options = g.config['ml_sequence'] secrets = pyzmutils.read_config(g.config['secrets']) ml_options = pyzmutils.template_fill(input_str=ml_options, config=None, secrets=secrets._sections.get('secrets')) ml_options = ast.literal_eval(ml_options) g.config['ml_sequence'] = ml_options else: g.logger.Debug(2,'mapping legacy ml data from config') ml_options = utils.convert_config_to_ml_sequence() if g.config['stream_sequence'] and g.config['use_sequence'] == 'yes': # new sequence g.logger.Debug(2,'using stream_sequence') stream_options = g.config['stream_sequence'] stream_options = ast.literal_eval(stream_options) g.config['stream_sequence'] = stream_options else: # legacy g.logger.Debug(2,'mapping legacy stream data from config') if g.config['detection_mode'] == 'all': g.config['detection_mode'] = 'most_models' frame_set = g.config['frame_id'] if g.config['frame_id'] == 'bestmatch': if g.config['bestmatch_order'] == 's,a': frame_set = 'snapshot,alarm' else: frame_set = 'alarm,snapshot' stream_options['resize'] =int(g.config['resize']) if g.config['resize'] != 'no' else None stream_options['strategy'] = g.config['detection_mode'] stream_options['frame_set'] = frame_set # These are stream options that need to be set outside of supplied configs stream_options['api'] = zmapi stream_options['polygons'] = g.polygons ''' stream_options = { 'api': zmapi, 'download': False, 'frame_set': frame_set, 'strategy': g.config['detection_mode'], 'polygons': g.polygons, 'resize': int(g.config['resize']) if g.config['resize'] != 'no' else None } ''' m = None matched_data = None all_data = None if not args['file'] and int(g.config['wait']) > 0: g.logger.Info('Sleeping for {} seconds before inferencing'.format( g.config['wait'])) time.sleep(g.config['wait']) if g.config['ml_gateway']: stream_options['api'] = None stream_options['monitorid'] = args.get('monitorid') start = datetime.datetime.now() try: matched_data,all_data = remote_detect(stream=stream, options=stream_options, api=zmapi) diff_time = (datetime.datetime.now() - start) g.logger.Debug(1,'Total remote detection detection took: {}'.format(diff_time)) except Exception as e: g.logger.Error ("Error with remote mlapi:{}".format(e)) g.logger.Debug(2,traceback.format_exc()) if g.config['ml_fallback_local'] == 'yes': g.logger.Debug (1, "Falling back to local detection") stream_options['api'] = zmapi from pyzm.ml.detect_sequence import DetectSequence m = DetectSequence(options=ml_options, logger=g.logger) matched_data,all_data = m.detect_stream(stream=stream, options=stream_options) else: from pyzm.ml.detect_sequence import DetectSequence m = DetectSequence(options=ml_options, logger=g.logger) matched_data,all_data = m.detect_stream(stream=stream, options=stream_options) #print(f'ALL FRAMES: {all_data}\n\n') #print (f"SELECTED FRAME {matched_data['frame_id']}, size {matched_data['image_dimensions']} with LABELS {matched_data['labels']} {matched_data['boxes']} {matched_data['confidences']}") #print (matched_data) ''' matched_data = { 'boxes': matched_b, 'labels': matched_l, 'confidences': matched_c, 'frame_id': matched_frame_id, 'image_dimensions': self.media.image_dimensions(), 'image': matched_frame_img } ''' # let's remove past detections first, if enabled if g.config['match_past_detections'] == 'yes' and args.get('monitorid'): # point detections to post processed data set g.logger.Info('Removing matches to past detections') bbox_t, label_t, conf_t = img.processPastDetection( matched_data['boxes'], matched_data['labels'], matched_data['confidences'], args.get('monitorid')) # save current objects for future comparisons g.logger.Debug(1, 'Saving detections for monitor {} for future match'.format( args.get('monitorid'))) try: mon_file = g.config['image_path'] + '/monitor-' + args.get( 'monitorid') + '-data.pkl' f = open(mon_file, "wb") pickle.dump(matched_data['boxes'], f) pickle.dump(matched_data['labels'], f) pickle.dump(matched_data['confidences'], f) f.close() except Exception as e: g.logger.Error(f'Error writing to {mon_file}, past detections not recorded:{e}') matched_data['boxes'] = bbox_t matched_data['labels'] = label_t matched_data['confidences'] = conf_t obj_json = { 'labels': matched_data['labels'], 'boxes': matched_data['boxes'], 'frame_id': matched_data['frame_id'], 'confidences': matched_data['confidences'], 'image_dimensions': matched_data['image_dimensions'] } # 'confidences': ["{:.2f}%".format(item * 100) for item in matched_data['confidences']], detections = [] seen = {} pred='' prefix = '' if matched_data['frame_id'] == 'snapshot': prefix = '[s] ' elif matched_data['frame_id'] == 'alarm': prefix = '[a] ' else: prefix = '[x] ' #g.logger.Debug (1,'CONFIDENCE ARRAY:{}'.format(conf)) for idx, l in enumerate(matched_data['labels']): if l not in seen: if g.config['show_percent'] == 'no': pred = pred + l + ',' else: pred = pred + l + ':{:.0%}'.format(matched_data['confidences'][idx]) + ' ' seen[l] = 1 if pred != '': pred = pred.rstrip(',') pred = prefix + 'detected:' + pred g.logger.Info('Prediction string:{}'.format(pred)) jos = json.dumps(obj_json) g.logger.Debug(1,'Prediction string JSON:{}'.format(jos)) print(pred + '--SPLIT--' + jos) if (matched_data['image'] is not None) and (g.config['write_image_to_zm'] == 'yes' or g.config['write_debug_image'] == 'yes'): debug_image = pyzmutils.draw_bbox(image=matched_data['image'],boxes=matched_data['boxes'], labels=matched_data['labels'], confidences=matched_data['confidences'], polygons=g.polygons, poly_thickness = g.config['poly_thickness']) if g.config['write_debug_image'] == 'yes': for _b in matched_data['error_boxes']: cv2.rectangle(debug_image, (_b[0], _b[1]), (_b[2], _b[3]), (0,0,255), 1) filename_debug = g.config['image_path']+'/'+os.path.basename(append_suffix(stream, '-{}-debug'.format(matched_data['frame_id']))) g.logger.Debug (1,'Writing bound boxes to debug image: {}'.format(filename_debug)) cv2.imwrite(filename_debug,debug_image) if g.config['write_image_to_zm'] == 'yes' and args.get('eventpath'): g.logger.Debug(1,'Writing detected image to {}/objdetect.jpg'.format( args.get('eventpath'))) cv2.imwrite(args.get('eventpath') + '/objdetect.jpg', debug_image) jf = args.get('eventpath')+ '/objects.json' g.logger.Debug(1,'Writing JSON output to {}'.format(jf)) try: with open(jf, 'w') as jo: json.dump(obj_json, jo) jo.close() except Exception as e: g.logger.Error(f'Error creating {jf}:{e}') if args.get('notes'): url = '{}/events/{}.json'.format(g.config['api_portal'], args['eventid']) try: ev = zmapi._make_request(url=url, type='get') except Exception as e: g.logger.Error ('Error during event notes retrieval: {}'.format(str(e))) g.logger.Debug(2,traceback.format_exc()) exit(0) # Let's continue with zmdetect new_notes = pred if ev.get('event',{}).get('Event',{}).get('Notes'): old_notes = ev['event']['Event']['Notes'] old_notes_split = old_notes.split('Motion:') old_d = old_notes_split[0] # old detection try: old_m = old_notes_split[1] except IndexError: old_m = '' new_notes = pred + 'Motion:'+ old_m g.logger.Debug (1,'Replacing old note:{} with new note:{}'.format(old_notes, new_notes)) payload = {} payload['Event[Notes]'] = new_notes try: ev = zmapi._make_request(url=url, payload=payload, type='put') except Exception as e: g.logger.Error ('Error during notes update: {}'.format(str(e))) g.logger.Debug(2,traceback.format_exc()) if g.config['create_animation'] == 'yes': if not args.get('eventid'): g.logger.Error ('Cannot create animation as you did not pass an event ID') else: g.logger.Debug(1,'animation: Creating burst...') try: img.createAnimation(matched_data['frame_id'], args.get('eventid'), args.get('eventpath')+'/objdetect', g.config['animation_types']) except Exception as e: g.logger.Error('Error creating animation:{}'.format(e)) g.logger.Error('animation: Traceback:{}'.format(traceback.format_exc()))
if len(sys.argv) == 1: eid = input('Enter event ID to analyze:') else: eid = sys.argv[1] ''' api_options = { 'apiurl': 'https://demo.zoneminder.com/zm/api', 'portalurl': 'https://demo.zoneminder.com/zm', 'user': '******', 'password': '******', 'logger': logger, # use none if you don't want to log to ZM, #'disable_ssl_cert_check': True } ''' conf = utils.read_config('/etc/zm/secrets.ini') api_options = { 'apiurl': utils.get(key='ZM_API_PORTAL', section='secrets', conf=conf), 'portalurl': utils.get(key='ZM_PORTAL', section='secrets', conf=conf), 'user': utils.get(key='ZM_USER', section='secrets', conf=conf), 'password': utils.get(key='ZM_PASSWORD', section='secrets', conf=conf), 'logger': logger, # use none if you don't want to log to ZM, #'disable_ssl_cert_check': True } zmapi = zmapi.ZMApi(options=api_options, logger=logger) ml_options = { 'general': { 'model_sequence': 'object,face,alpr', 'disable_locks': 'no' },
api = Api(app, prefix='/api/v1') app.config['UPLOAD_FOLDER'] = g.config['images_path'] app.config['MAX_CONTENT_LENGTH'] = g.MAX_FILE_SIZE_MB * 1024 * 1024 app.config['JWT_SECRET_KEY'] = g.config['mlapi_secret_key'] app.config['JWT_ACCESS_TOKEN_EXPIRES'] = g.ACCESS_TOKEN_EXPIRES app.config['PROPAGATE_EXCEPTIONS'] = True app.debug = False jwt = JWTManager(app) db = Database.Database() api.add_resource(Login, '/login') api.add_resource(Detect, '/detect/object') api.add_resource(Health, '/health') secrets_conf = pyzmutils.read_config(g.config['secrets']) api_options = { 'apiurl': pyzmutils.get(key='ZM_API_PORTAL', section='secrets', conf=secrets_conf), 'portalurl':pyzmutils.get(key='ZM_PORTAL', section='secrets', conf=secrets_conf), 'user': pyzmutils.get(key='ZM_USER', section='secrets', conf=secrets_conf), 'password': pyzmutils.get(key='ZM_PASSWORD', section='secrets', conf=secrets_conf), 'disable_ssl_cert_check':False if g.config['allow_self_signed']=='no' else True } g.log.set_level(5) if not api_options.get('apiurl') or not api_options.get('portalurl'): g.log.Fatal('Missing API and/or Portal URLs. Your secrets file probably doesn\'t have these values') zmapi = zmapi.ZMApi(options=api_options, logger=g.log)
# Desktop notifications of zm alarms using pyzm import pyzm, getpass, traceback, gi, time, playsound, argparse, os, datetime import pyzm.api as zmapi import pyzm.ZMMemory as zmmemory import pyzm.helpers.utils as utils from pyzm.helpers.Base import ConsoleLog from gi.repository import Notify zmPath = os.path.realpath(__file__).replace('/zmNotify.py', '') logFile = os.path.join(zmPath, "zmNotify.log") alertSoundFile = os.path.join(zmPath, 'alert.ogg') lastidFile = os.path.join(zmPath, 'lastid') logger = ConsoleLog() logger.set_level(1) # 2 will display each poll conf = utils.read_config(os.path.join(zmPath, 'secrets.ini')) Notify.init("zmNotifyMessage") api_options = { 'apiurl': utils.get(key='ZM_API_PORTAL', section='secrets', conf=conf), 'portalurl': utils.get(key='ZM_PORTAL', section='secrets', conf=conf), 'user': utils.get(key='ZM_USER', section='secrets', conf=conf), 'password': utils.get(key='ZM_PASSWORD', section='secrets', conf=conf), 'logger': logger } zmapi = zmapi.ZMApi(options=api_options) event_filter = { 'object_only': True, 'min_alarmed_frames': 2,
def process_config(args): # parse config file into a dictionary with defaults g.config = {} has_secrets = False secrets_file = None def _correct_type(val, t): if t == 'int': return int(val) elif t == 'eval' or t == 'dict': return ast.literal_eval(val) if val else None elif t == 'str_split': return str_split(val) if val else None elif t == 'string': return val elif t == 'float': return float(val) else: g.logger.Error( 'Unknown conversion type {} for config key:{}'.format( e['type'], e['key'])) return val def _set_config_val(k, v): # internal function to parse all keys val = config_file[v['section']].get(k, v['default']) if val and val[0] == '!': # its a secret token, so replace g.logger.Debug(1, 'Secret token found in config: {}'.format(val)) if not has_secrets: raise ValueError( 'Secret token found, but no secret file specified') if secrets_file.has_option('secrets', val[1:]): vn = secrets_file.get('secrets', val[1:]) #g.logger.Debug (1,'Replacing {} with {}'.format(val,vn)) val = vn else: raise ValueError( 'secret token {} not found in secrets file {}'.format( val, secrets_filename)) g.config[k] = _correct_type(val, v['type']) if k.find('password') == -1: dval = g.config[k] else: dval = '***********' #g.logger.Debug (1,'Config: setting {} to {}'.format(k,dval)) # main try: config_file = ConfigParser(interpolation=None, inline_comment_prefixes='#') config_file.read(args['config']) g.config['pyzm_overrides'] = {} if config_file.has_option('general', 'pyzm_overrides'): pyzm_overrides = config_file.get('general', 'pyzm_overrides') g.config['pyzm_overrides'] = ast.literal_eval( pyzm_overrides) if pyzm_overrides else {} if args.get('debug'): g.config['pyzm_overrides']['dump_console'] = True g.config['pyzm_overrides']['log_debug'] = True g.config['pyzm_overrides']['log_level_debug'] = 5 g.config['pyzm_overrides']['log_debug_target'] = None if config_file.has_option('general', 'use_zm_logs'): use_zm_logs = config_file.get('general', 'use_zm_logs') if use_zm_logs == 'yes': try: import pyzm.ZMLog as zmlog zmlog.init(name='zm_mlapi', override=g.config['pyzm_overrides']) except Exception as e: g.logger.Error( 'Not able to switch to ZM logs: {}'.format(e)) else: g.log = zmlog g.logger = g.log g.logger.Info('Switched to ZM logs') g.logger.Info('Reading config from: {}'.format( args.get('config'))) g.logger.Info('Reading config from: {}'.format(args.get('config'))) if config_file.has_option('general', 'secrets'): secrets_filename = config_file.get('general', 'secrets') g.config['secrets'] = secrets_filename g.logger.Info('Reading secrets from: {}'.format(secrets_filename)) has_secrets = True secrets_file = ConfigParser(interpolation=None, inline_comment_prefixes='#') try: with open(secrets_filename) as f: secrets_file.read_file(f) except: raise else: g.logger.Debug(1, 'No secrets file configured') # now read config values g.polygons = [] # first, fill in config with default values for k, v in g.config_vals.items(): val = v.get('default', None) g.config[k] = _correct_type(val, v['type']) #print ('{}={}'.format(k,g.config[k])) # now iterate the file for sec in config_file.sections(): if sec == 'secrets': continue # Move monitor specific stuff to a different structure if sec.lower().startswith('monitor-'): ts = sec.split('-') if len(ts) != 2: g.logger.Error( 'Skipping section:{} - could not derive monitor name. Expecting monitor-NUM format' ) continue mid = ts[1] g.logger.Debug( 2, 'Found monitor specific section for monitor: {}'.format( mid)) g.monitor_polygons[mid] = [] g.monitor_config[mid] = {} g.monitor_zone_patterns[mid] = {} # Copy the sequence into each monitor because when we do variable subs # later, we will use this for monitor specific work try: ml = config_file.get('ml', 'ml_sequence') g.monitor_config[mid]['ml_sequence'] = ml except: g.logger.Debug(2, 'ml sequence not found in globals') try: ss = config_file.get('ml', 'stream_sequence') g.monitor_config[mid]['stream_sequence'] = ss except: g.logger.Debug(2, 'stream sequence not found in globals') for item in config_file[sec].items(): k = item[0] v = item[1] if k.endswith('_zone_detection_pattern'): zone_name = k.split('_zone_detection_pattern')[0] g.logger.Debug( 2, 'found zone specific pattern:{} storing'.format( zone_name)) g.monitor_zone_patterns[mid][zone_name] = v continue else: if k in g.config_vals: # This means its a legit config key that needs to be overriden g.logger.Debug( 2, '[{}] overrides key:{} with value:{}'.format( sec, k, v)) g.monitor_config[mid][k] = _correct_type( v, g.config_vals[k]['type']) # g.monitor_config[mid].append({ 'key':k, 'value':_correct_type(v,g.config_vals[k]['type'])}) else: if k.startswith(('object_', 'face_', 'alpr_')): g.logger.Debug( 2, 'assuming {} is an ML sequence'.format(k)) g.monitor_config[mid][k] = v else: try: p = str2tuple( v ) # if not poly, exception will be thrown g.monitor_polygons[mid].append({ 'name': k, 'value': p, 'pattern': None }) g.logger.Debug( 2, 'adding polygon: {} [{}]'.format(k, v)) except Exception as e: g.logger.Debug( 2, '{} is not a polygon, adding it as unknown string key' .format(k)) g.monitor_config[mid][k] = v # TBD only_triggered_zones # Not monitor specific stuff else: for (k, v) in config_file.items(sec): if k in g.config_vals: _set_config_val(k, g.config_vals[k]) else: g.config[k] = v # Parameter substitution g.logger.Debug(2, 'Doing parameter substitution for globals') p = r'{{(\w+?)}}' for gk, gv in g.config.items(): #input ('Continue') gv = '{}'.format(gv) #if not isinstance(gv, str): # continue while True: matches = re.findall(p, gv) replaced = False for match_key in matches: if match_key in g.config: replaced = True new_val = g.config[gk].replace( '{{' + match_key + '}}', str(g.config[match_key])) g.config[gk] = new_val gv = new_val else: g.logger.Debug( 2, 'substitution key: {} not found'.format(match_key)) if not replaced: break g.logger.Debug( 2, 'Doing parameter substitution for monitor specific entities') p = r'{{(\w+?)}}' for mid in g.monitor_config: for key in g.monitor_config[mid]: #input ('Continue') gk = key gv = g.monitor_config[mid][key] gv = '{}'.format(gv) #if not isinstance(gv, str): # continue while True: matches = re.findall(p, gv) replaced = False for match_key in matches: if match_key in g.monitor_config[mid]: replaced = True new_val = gv.replace( '{{' + match_key + '}}', str(g.monitor_config[mid][match_key])) gv = new_val g.monitor_config[mid][key] = gv elif match_key in g.config: replaced = True new_val = gv.replace('{{' + match_key + '}}', str(g.config[match_key])) gv = new_val g.monitor_config[mid][key] = gv else: g.logger.Debug( 2, 'substitution key: {} not found'.format( match_key)) if not replaced: break secrets = pyzmutils.read_config(g.config['secrets']) #g.monitor_config[mid]['ml_sequence'] = pyzmutils.template_fill(input_str=g.monitor_config[mid]['ml_sequence'], config=None, secrets=secrets._sections.get('secrets')) #g.monitor_config[mid]['ml_sequence'] = ast.literal_eval(g.monitor_config[mid]['ml_sequence']) #g.monitor_config[mid]['stream_sequence'] = pyzmutils.template_fill(input_str=g.monitor_config[mid]['stream_sequence'], config=None, secrets=secrets._sections.get('secrets')) #g.monitor_config[mid]['stream_sequence'] = ast.literal_eval(g.monitor_config[mid]['stream_sequence']) #print ("GLOBALS={}".format(g.config)) #print ("\n\nMID_SPECIFIC={}".format(g.monitor_config)) #print ("\n\nMID POLYPATTERNS={}".format(g.monitor_polypatterns)) #print ('FINAL POLYS={}'.format(g.monitor_polygons)) #exit(0) except Exception as e: g.logger.Error('Error parsing config:{}'.format(args['config'])) g.logger.Error('Error was:{}'.format(e)) g.logger.Fatal('error: Traceback:{}'.format(traceback.format_exc())) exit(0)
def post(self): args = parse_args() req = request.get_json() fi = None stream_options = {} stream = None ml_overrides = {} config_copy = None poly_copy = None ml_options = None mid = None if not req: req = {} if req.get('mid') and str(req.get('mid')) in g.monitor_config: mid = str(req.get('mid')) g.logger.Debug( 1, 'Monitor ID {} provided & matching config found in mlapi, ignoring objectconfig.ini' .format(mid)) config_copy = copy.copy(g.config) poly_copy = copy.copy(g.polygons) g.polygons = copy.copy(g.monitor_polygons[mid]) for key in g.monitor_config[mid]: # This will also take care of copying over mid specific stream_options g.logger.Debug( 2, 'Overriding global {} with {}...'.format( key, g.monitor_config[mid][key][:30])) g.config[key] = g.monitor_config[mid][key] # stupid mlapi and zm_detect config incompatibility if not g.config.get('image_path') and g.config.get('images_path'): g.config['image_path'] = g.config['images_path'] # At this stage, polygons has a copy of that monitor polygon set # g.config has overriden values of config from the mid r = req.get('reason') if r and g.config['only_triggered_zm_zones'] == 'yes' and g.config[ 'import_zm_zones'] == 'yes': g.logger.Debug( 2, 'Only filtering polygon names that have {}'.format(r)) g.logger.Debug( 2, 'Original polygons being used: {}'.format(g.polygons)) g.polygons[:] = [ item for item in g.polygons if utils.findWholeWord(item['name'])(r) ] g.logger.Debug( 2, 'Final polygons being used: {}'.format(g.polygons)) if g.config['ml_sequence'] and g.config['use_sequence'] == 'yes': g.log.Debug(2, 'using ml_sequence') ml_options = g.config['ml_sequence'] secrets = pyzmutils.read_config(g.config['secrets']) ml_options = pyzmutils.template_fill( input_str=ml_options, config=None, secrets=secrets._sections.get('secrets')) ml_options = ast.literal_eval(ml_options) #print (ml_options) else: g.logger.Debug(2, 'mapping legacy ml data from config') ml_options = utils.convert_config_to_ml_sequence() g.logger.Debug(2, 'Overwriting ml_sequence of pre loaded model') m.set_ml_options(ml_options) else: g.logger.Debug( 1, 'Monitor ID not specified, or not found in mlapi config, using zm_detect overrides' ) ml_overrides = req.get('ml_overrides', {}) if g.config['ml_sequence'] and g.config['use_sequence'] == 'yes': g.log.Debug(2, 'using ml_sequence') ml_options = g.config['ml_sequence'] secrets = pyzmutils.read_config(g.config['secrets']) ml_options = pyzmutils.template_fill( input_str=ml_options, config=None, secrets=secrets._sections.get('secrets')) ml_options = ast.literal_eval(ml_options) #print (ml_options) else: g.logger.Debug(2, 'mapping legacy ml data from config') ml_options = utils.convert_config_to_ml_sequence() #print (ml_options) if g.config.get('stream_sequence'): g.logger.Debug( 2, 'Found stream_sequence in mlapi config, ignoring objectconfig.ini' ) stream_options = ast.literal_eval(g.config.get('stream_sequence')) else: stream_options = req.get('stream_options') if not stream_options: if config_copy: g.log.Debug(2, 'Restoring global config & ml_options') g.config = config_copy g.polygons = poly_copy abort(400, msg='No stream options found') stream_options['api'] = zmapi stream_options['polygons'] = g.polygons stream = req.get('stream') if args['type'] == 'face': g.log.Debug(1, 'Face Recognition requested') elif args['type'] == 'alpr': g.log.Debug(1, 'ALPR requested') elif args['type'] in [None, 'object']: g.log.Debug(1, 'Object Recognition requested') #m = ObjectDetect.Object() else: if config_copy: g.log.Debug(2, 'Restoring global config & ml_options') g.config = config_copy g.polygons = poly_copy abort(400, msg='Invalid Model:{}'.format(args['type'])) if not stream: g.log.Debug(1, 'Stream info not found, looking at args...') fip, ext = get_file(args) fi = fip + ext stream = fi #image = cv2.imread(fi) #bbox,label,conf = m.detect(image) stream_options['mid'] = mid if not stream_options.get('delay') and g.config.get('wait'): stream_options['delay'] = g.config.get('wait') g.log.Debug(1, 'Calling detect streams') matched_data, all_matches = m.detect_stream(stream=stream, options=stream_options, ml_overrides=ml_overrides) if matched_data['image_dimensions']: oldh = matched_data['image_dimensions']['original'][0] oldw = matched_data['image_dimensions']['original'][1] if config_copy: g.log.Debug(2, 'Restoring global config & ml_options') g.config = config_copy g.polygons = poly_copy matched_data['image'] = None if args.get('response_format') == 'zm_detect': resp_obj = { 'matched_data': matched_data, 'all_matches': all_matches, } g.log.Debug(1, 'Returning {}'.format(resp_obj)) return resp_obj # legacy format bbox = matched_data['boxes'] label = matched_data['labels'] conf = matched_data['confidences'] detections = [] for l, c, b in zip(label, conf, bbox): c = "{:.2f}%".format(c * 100) obj = {'type': 'object', 'label': l, 'confidence': c, 'box': b} detections.append(obj) if args['delete'] and fi: #pass os.remove(fi) return detections