From: Calin Crisan Date: Tue, 4 Oct 2016 16:21:43 +0000 (+0300) Subject: mask file now uses the dimensions from the actual frame picture X-Git-Url: http://www.vanbest.org/gitweb/?a=commitdiff_plain;h=de6485ab582e4078f6f000b93fc56ca694f704bd;p=motioneye-debian mask file now uses the dimensions from the actual frame picture --- diff --git a/motioneye/config.py b/motioneye/config.py index f303736..03e5386 100644 --- a/motioneye/config.py +++ b/motioneye/config.py @@ -874,7 +874,7 @@ def motion_camera_ui_to_dict(ui, old_config=None): data['smart_mask_speed'] = 10 - int(ui['smart_mask_slugginess']) elif ui['mask_type'] == 'editable': - data['mask_file'] = utils.build_editable_mask_file(old_config['@id'], data.get('width'), data.get('height'), ui['mask_lines']) + data['mask_file'] = utils.build_editable_mask_file(old_config['@id'], ui['mask_lines'], data.get('width'), data.get('height')) # working schedule if ui['working_schedule']: diff --git a/motioneye/handlers.py b/motioneye/handlers.py index 40d51d4..85ea8d0 100644 --- a/motioneye/handlers.py +++ b/motioneye/handlers.py @@ -208,8 +208,7 @@ class MainHandler(BaseHandler): has_streaming_auth=motionctl.has_streaming_auth(), has_new_movie_format_support=motionctl.has_new_movie_format_support(), has_motion=bool(motionctl.find_motion()), - mask_width=utils.MASK_WIDTH, - mask_default_resolution=utils.MASK_DEFAULT_RESOLUTION) + mask_width=utils.MASK_WIDTH) class ConfigHandler(BaseHandler): diff --git a/motioneye/server.py b/motioneye/server.py index 3b65296..8f1aef1 100644 --- a/motioneye/server.py +++ b/motioneye/server.py @@ -331,7 +331,11 @@ def start_motion(): io_loop.add_timeout(datetime.timedelta(seconds=settings.MOTION_CHECK_INTERVAL), checker) - motionctl.start() + try: + motionctl.start() + + except Exception as e: + logging.error(str(e), exc_info=True) io_loop.add_timeout(datetime.timedelta(seconds=settings.MOTION_CHECK_INTERVAL), checker) diff --git a/motioneye/static/css/main.css b/motioneye/static/css/main.css index 4803417..4d448fa 100644 --- a/motioneye/static/css/main.css +++ b/motioneye/static/css/main.css @@ -241,7 +241,7 @@ div.hostname { div.settings { background-color: #313131; position: fixed; - z-index: 1; + z-index: 2; top: 50px; left: 0px; width: 0px; diff --git a/motioneye/static/js/main.js b/motioneye/static/js/main.js index c9871a9..b978106 100644 --- a/motioneye/static/js/main.js +++ b/motioneye/static/js/main.js @@ -895,27 +895,12 @@ function initUI() { /* mask editor buttons */ $('div#editMaskButton').click(function () { var cameraId = $('#cameraSelect').val(); - var resolution = $('#resolutionSelect').val(); - if (!cameraId) { - return; + var img = getCameraFrame(cameraId).find('img.camera')[0]; + if (!img.naturalWidth || !img.naturalHeight) { + return runAlertDialog('Cannot edit the mask without a valid camera image!'); } - - if (!resolution) { - /* - * motion requires the mask file to be the same size as the - * captured images; however for netcams we have no means to know in - * advance the size of the stream; therefore, for netcams, we impose - * here a standard fixed mask size, which WILL NOT WORK for netcam - * streams of a different resolution, unless motion is patched accordingly - */ - resolution = maskDefaultResolution; - } - - resolution = resolution.split('x'); - var width = resolution[0]; - var height = resolution[1]; - - enableMaskEdit(cameraId, width, height); + + enableMaskEdit(cameraId, img.naturalWidth, img.naturalHeight); }); $('div#saveMaskButton').click(function () { disableMaskEdit(); @@ -1099,6 +1084,9 @@ function enableMaskEdit(cameraId, width, height) { var maskLines = []; var bits, line; + maskLines.push(width); + maskLines.push(height); + for (y = 0; y < ny; y++) { bits = []; for (x = 0; x < nx; x++) { @@ -1135,10 +1123,10 @@ function enableMaskEdit(cameraId, width, height) { line |= 1 << (maskWidth - 1 - i); } }); + + maskLines.push(line); } - maskLines.push(line); - $('#maskLinesEntry').val(maskLines.join(',')).change(); } @@ -1219,7 +1207,8 @@ function enableMaskEdit(cameraId, width, height) { /* use mask lines to initialize the element matrix */ var line; var maskLines = $('#maskLinesEntry').val() ? $('#maskLinesEntry').val().split(',').map(function (v) {return parseInt(v);}) : []; - + maskLines = maskLines.slice(2); + for (y = 0; y < ny; y++) { line = maskLines[y]; for (x = 0; x < nx; x++) { diff --git a/motioneye/templates/main.html b/motioneye/templates/main.html index 924f14b..1f18022 100644 --- a/motioneye/templates/main.html +++ b/motioneye/templates/main.html @@ -71,7 +71,6 @@ var hasNetCamSupport = {% if has_motion %}true{% else %}false{% endif %}; {% if mask_width %} var maskWidth = {{mask_width}}; - var maskDefaultResolution = '{{mask_default_resolution[0]}}x{{mask_default_resolution[1]}}'; {% endif %} {% endblock %} diff --git a/motioneye/utils.py b/motioneye/utils.py index fbeb091..d6a7309 100644 --- a/motioneye/utils.py +++ b/motioneye/utils.py @@ -48,7 +48,6 @@ _SIGNATURE_REGEX = re.compile('[^a-zA-Z0-9/?_.=&{}\[\]":, _-]') _SPECIAL_COOKIE_NAMES = {'expires', 'domain', 'path', 'secure', 'httponly'} MASK_WIDTH = 32 -MASK_DEFAULT_RESOLUTION = (640, 480) DEV_NULL = open('/dev/null', 'w') @@ -787,13 +786,14 @@ def urlopen(*args, **kwargs): return urllib2.urlopen(*args, **kwargs) -def build_editable_mask_file(camera_id, width, height, mask_lines): +def build_editable_mask_file(camera_id, mask_lines, capture_width=None, capture_height=None): + width = mask_lines[0] + height = mask_lines[1] + mask_lines = mask_lines[2:] + logging.debug('building editable mask for camera with id %s (%sx%s)' % (camera_id, width, height)) - width = width or MASK_DEFAULT_RESOLUTION[0] - height = height or MASK_DEFAULT_RESOLUTION[1] - # horizontal rectangles nx = MASK_WIDTH # number of rectangles if width % nx: @@ -851,20 +851,54 @@ def build_editable_mask_file(camera_id, width, height, mask_lines): dr.rectangle((nx * rw, ny * rh, nx * rw + rx - 1, ny * rh + ry - 1), fill=0) file_name = os.path.join(settings.CONF_PATH, 'mask_%s.pgm' % camera_id) - im.save(file_name, 'ppm') + # resize the image if necessary + if capture_width and capture_height and im.size != (capture_width, capture_height): + logging.debug('editable mask needs resizing from %sx%s to %sx%s' % + (im.size[0], im.size[1], capture_width, capture_height)) + + im = im.resize((capture_width, capture_height)) + + im.save(file_name, 'ppm') + return file_name -def parse_editable_mask_file(camera_id, width, height): - logging.debug('parsing editable mask for camera with id %s (%sx%s)' % - (camera_id, width, height)) +def parse_editable_mask_file(camera_id, capture_width=None, capture_height=None): + # capture_width and capture_height arguments represent the current size + # of the camera image, as it might be different from that of the associated mask; + # they can be null (e.g. netcams) + + file_name = os.path.join(settings.CONF_PATH, 'mask_%s.pgm' % camera_id) + + logging.debug('parsing editable mask for camera with id %s: %s' % (camera_id, file_name)) + + # read the image file + try: + im = Image.open(file_name) + + except Exception as e: + logging.error('failed to read mask file %s: %s' % (file_name, e)) + + # empty mask + return [0] * (MASK_WIDTH * 10) + + if capture_width and capture_height: + # resize the image if necessary + if im.size != (capture_width, capture_height): + logging.debug('editable mask needs resizing from %sx%s to %sx%s' % + (im.size[0], im.size[1], capture_width, capture_height)) - # width and height arguments represent the current size of the camera image, - # as it might be different from that of the associated mask + im = im.resize((capture_width, capture_height)) + + width, height = capture_width, capture_height + + else: + logging.debug('using mask size from file: %sx%s' % (im.size[0], im.size[1])) - width = width or MASK_DEFAULT_RESOLUTION[0] - height = height or MASK_DEFAULT_RESOLUTION[1] + width, height = im.size + + pixels = list(im.getdata()) # horizontal rectangles nx = MASK_WIDTH # number of rectangles @@ -878,7 +912,7 @@ def parse_editable_mask_file(camera_id, width, height): rw = width / nx # rectangle width # vertical rectangles - ny = mask_height = height * MASK_WIDTH / width # number of rectangles + ny = height * MASK_WIDTH / width # number of rectangles if height % ny: ny -= 1 ry = height % ny # remainder @@ -888,29 +922,8 @@ def parse_editable_mask_file(camera_id, width, height): rh = height / ny # rectangle height - file_name = os.path.join(settings.CONF_PATH, 'mask_%s.pgm' % camera_id) - - # read the image file - try: - im = Image.open(file_name) - - except Exception as e: - logging.error('failed to read mask file %s: %s' % (file_name, e)) - - # empty mask - return [0] * mask_height - - # resize the image if necessary - if im.size != (width, height): - logging.debug('editable mask needs resizing from %sx%s to %sx%s' % - (im.size[0], im.size[1], width, height)) - - im = im.resize((width, height)) - - pixels = list(im.getdata()) - # parse the image contents and build the mask lines - mask_lines = [] + mask_lines = [width, height] for y in xrange(ny): bits = [] for x in xrange(nx):