From: Calin Crisan Date: Wed, 6 Apr 2016 19:57:56 +0000 (+0300) Subject: initial work on mask support X-Git-Url: http://www.vanbest.org/gitweb/?a=commitdiff_plain;h=4556c2426f7ed23edb9c5ceee76e9539d6a2b84e;p=motioneye-debian initial work on mask support --- diff --git a/motioneye/config.py b/motioneye/config.py index 97b8a9c..0b9ec4d 100644 --- a/motioneye/config.py +++ b/motioneye/config.py @@ -57,7 +57,8 @@ _KNOWN_MOTION_OPTIONS = set([ 'quality', 'rotate', 'saturation', 'snapshot_filename', 'snapshot_interval', 'stream_auth_method', 'stream_authentication', 'stream_localhost', 'stream_maxrate', 'stream_motion', 'stream_port', 'stream_quality', 'target_dir', 'text_changes', 'text_double', 'text_left', 'text_right', 'threshold', 'videodevice', 'width', 'webcam_localhost', 'webcam_port', 'webcam_maxrate', 'webcam_quality', 'webcam_motion', 'ffmpeg_cap_new', 'output_normal', 'output_motion', 'jpeg_filename', 'output_all', - 'gap', 'locate', 'netcam_url', 'netcam_userpass', 'netcam_http', 'netcam_tolerant_check', 'netcam_keepalive', 'rtsp_uses_tcp' + 'gap', 'locate', 'netcam_url', 'netcam_userpass', 'netcam_http', 'netcam_tolerant_check', 'netcam_keepalive', 'rtsp_uses_tcp', + 'mask_file', 'smart_mask_speed' ]) @@ -687,6 +688,8 @@ def motion_camera_ui_to_dict(ui, old_config=None): 'pre_capture': int(ui['pre_capture']), 'post_capture': int(ui['post_capture']), 'minimum_motion_frames': int(ui['minimum_motion_frames']), + 'smart_mask_speed': 0, + 'mask_file': '', # working schedule '@working_schedule': '', @@ -849,7 +852,18 @@ def motion_camera_ui_to_dict(ui, old_config=None): max_val = min(max_val, 9999999) data['ffmpeg_bps'] = int(int(ui['movie_quality']) * max_val / 100) - + + # motion detection + if ui['mask']: + if ui['mask_type'] == 'smart': + data['smart_mask_speed'] = 10 - int(ui['smart_mask_slugginess']) + + elif ui['mask_type'] == 'editable': + data['mask_file'] = utils.build_editable_mask_file(ui['editable_mask']) + + else: + data['mask_file'] = ui['mask_file'] + # working schedule if ui['working_schedule']: data['@working_schedule'] = ( @@ -1027,6 +1041,11 @@ def motion_camera_dict_to_ui(data): 'pre_capture': int(data['pre_capture']), 'post_capture': int(data['post_capture']), 'minimum_motion_frames': int(data['minimum_motion_frames']), + 'mask': False, + 'mask_type': 'smart', + 'smart_mask_slugginess': 5, + 'mask_file': '', + 'editable_mask': '', # motion notifications 'email_notifications_enabled': False, @@ -1210,6 +1229,23 @@ def motion_camera_dict_to_ui(data): max_val = min(max_val, 9999999) ui['movie_quality'] = min(100, int(round(ffmpeg_bps * 100.0 / max_val))) + + # motion detection + if data['smart_mask_speed'] or data['mask_file']: + ui['mask'] = True + if data['smart_mask_speed']: + ui['mask_type'] = 'smart' + ui['smart_mask_slugginess'] = 10 - int(data['smart_mask_speed']) + + else: + editable_mask = utils.parse_editable_mask_file(data['mask_file']) + if editable_mask: + ui['mask_type'] = 'editable' + ui['editable_mask'] = editable_mask + + else: + ui['mask_type'] = 'file' + ui['mask_file'] = data['mask_file'] # working schedule working_schedule = data['@working_schedule'] @@ -1759,6 +1795,8 @@ def _set_default_motion_camera(camera_id, data): data.setdefault('noise_level', 32) data.setdefault('lightswitch', 0) data.setdefault('minimum_motion_frames', 20) + data.setdefault('smart_mask_speed', 0) + data.setdefault('mask_file', '') data.setdefault('pre_capture', 1) data.setdefault('post_capture', 1) diff --git a/motioneye/static/js/main.js b/motioneye/static/js/main.js index 2d7da7c..a0ba788 100644 --- a/motioneye/static/js/main.js +++ b/motioneye/static/js/main.js @@ -1545,6 +1545,10 @@ function cameraUi2Dict() { 'pre_capture': $('#preCaptureEntry').val(), 'post_capture': $('#postCaptureEntry').val(), 'minimum_motion_frames': $('#minimumMotionFramesEntry').val(), + 'mask': $('#maskSwitch')[0].checked, + 'mask_type': $('#maskTypeSelect').val(), + 'smart_mask_slugginess': $('#smartMaskSlugginessSlider').val(), + 'mask_file': $('#maskFileEntry').val(), /* motion notifications */ 'email_notifications_enabled': $('#emailNotificationsEnabledSwitch')[0].checked, @@ -1882,6 +1886,10 @@ function dict2CameraUi(dict) { $('#preCaptureEntry').val(dict['pre_capture']); markHideIfNull('pre_capture', 'preCaptureEntry'); $('#postCaptureEntry').val(dict['post_capture']); markHideIfNull('post_capture', 'postCaptureEntry'); $('#minimumMotionFramesEntry').val(dict['minimum_motion_frames']); markHideIfNull('minimum_motion_frames', 'minimumMotionFramesEntry'); + $('#maskSwitch')[0].checked = dict['mask']; markHideIfNull('mask', 'maskSwitch'); + $('#maskTypeSelect').val(dict['mask_type']); markHideIfNull('mask_type', 'maskTypeSelect'); + $('#smartMaskSlugginessSlider').val(dict['smart_mask_slugginess']); markHideIfNull('smart_mask_slugginess', 'smartMaskSlugginessSlider'); + $('#maskFileEntry').val(dict['mask_file']); markHideIfNull('mask_file', 'maskFileEntry'); /* motion notifications */ $('#emailNotificationsEnabledSwitch')[0].checked = dict['email_notifications_enabled']; markHideIfNull('email_notifications_enabled', 'emailNotificationsEnabledSwitch'); diff --git a/motioneye/templates/main.html b/motioneye/templates/main.html index c994a81..1c00f99 100644 --- a/motioneye/templates/main.html +++ b/motioneye/templates/main.html @@ -112,7 +112,7 @@ Fit Frames Vertically - ? + ? Frame Rate Dimmer @@ -778,6 +778,35 @@ frames ? + +
+ + + Mask + + ? + + + Mask Type + + + + ? + + + Smart Mask Slugginess + + ? + + + Mask File + + ? + {% for config in camera_sections.get('motion-detection', {}).get('configs', []) %} {{config_item(config)}} {% endfor %} diff --git a/motioneye/utils.py b/motioneye/utils.py index 212379f..d3f0765 100644 --- a/motioneye/utils.py +++ b/motioneye/utils.py @@ -23,10 +23,13 @@ import logging import os import re import socket +import struct import time import urllib import urlparse +from PIL import Image, ImageDraw + from tornado.httpclient import AsyncHTTPClient, HTTPRequest from tornado.iostream import IOStream from tornado.ioloop import IOLoop @@ -714,3 +717,50 @@ def build_digest_header(method, url, username, password, state): state['nonce_count'] = nonce_count return 'Digest %s' % (base) + + +def build_editable_mask_file(editable_mask): + width = editable_mask[0] + height = editable_mask[1] + nx = editable_mask[2] + ny = editable_mask[3] + lines = editable_mask[4:] + + data = struct.pack('