From 94d21ed0a2aabf37219c4fe3750e62fb9f67d2d8 Mon Sep 17 00:00:00 2001 From: Michael Sandrof Date: Fri, 28 Sep 2018 18:13:50 -0700 Subject: [PATCH] Added max_sensitivity at the region and global levels which puts a cap on detections that can trigger an event. Added detection threshold that requires a minimum number of detections before triggering an event. --- definitions/en_CA.json | 16 +++++++ languages/en_CA.json | 2 + libs/detector.js | 78 ++++++++++++++++++++++++++++++-- web/libs/js/main.dash2.js | 20 +++++++- web/pages/blocks/monitoredit.ejs | 10 ++++ web/pages/blocks/region.ejs | 16 ++++++- 6 files changed, 135 insertions(+), 7 deletions(-) diff --git a/definitions/en_CA.json b/definitions/en_CA.json index 37b9494f..1fc0735a 100644 --- a/definitions/en_CA.json +++ b/definitions/en_CA.json @@ -877,6 +877,22 @@ "example": "10", "possible": "" }, + { + "name": "detail=detector_max_sensitivity", + "field": "Max Indifference", + "description": "An upperbound to indifference. Any value over this amount will be ignored.", + "default": "", + "example": "75", + "possible": "Any number." + }, + { + "name": "detail=detector_threshold", + "field": "Trigger Threshold", + "description": "Minimum number of detections to fire a motion event. Detections must be within the detector the threshold divided by detector fps seconds. For example, if detector fps is 2 and trigger threshold is 3, then three detections must occur within 1.5 seconds to trigger a motion event. This threshold is per detection region.", + "default": "1", + "example": "3", + "possible": "Any non-negative integer." + }, { "name": "detail=detector_webhook", "field": "Webhook", diff --git a/languages/en_CA.json b/languages/en_CA.json index a487faf6..5b10bbbd 100644 --- a/languages/en_CA.json +++ b/languages/en_CA.json @@ -184,6 +184,8 @@ "RegionNote": "Points are only saved when you press Save on the Monitor Settings window.", "Points": "Points When adding points click on the edge of the polygon.", "Indifference": "Indifference", + "Max Indifference": "Max Indifference", + "Trigger Threshold": "Trigger Threshold", "Region Name": "Region Name", "Regions": "Regions", "Again": "Again", diff --git a/libs/detector.js b/libs/detector.js index 3cc03553..a8e4c2f5 100644 --- a/libs/detector.js +++ b/libs/detector.js @@ -18,6 +18,13 @@ module.exports = function(s,config){ }else{ globalSensitivity = parseInt(e.details.detector_sensitivity) } + + // + globalMaxSensitivity = parseInt(e.details.detector_max_sensitivity) || undefined + + globalThreshold = parseInt(e.details.detector_threshold) || 0 + // + if(e.details.detector_frame==='1'){ fullFrame={ name:'FULL_FRAME', @@ -30,7 +37,19 @@ module.exports = function(s,config){ ] }; } - var regions = s.createPamDiffRegionArray(s.group[e.ke].mon_conf[e.id].details.cords,globalSensitivity,fullFrame); + + // + let regionJson + try{ + regionJson = JSON.parse(s.group[e.ke].mon_conf[e.id].details.cords) + }catch(err){ + regionJson = s.group[e.ke].mon_conf[e.id].details.cords + } + e.triggerTimer = {} + + var regions = s.createPamDiffRegionArray(regionJson,globalSensitivity,fullFrame) + // + if(!s.group[e.ke].mon[e.id].noiseFilterArray)s.group[e.ke].mon[e.id].noiseFilterArray = {} var noiseFilterArray = s.group[e.ke].mon[e.id].noiseFilterArray Object.keys(regions.notForPam).forEach(function(name){ @@ -44,6 +63,7 @@ module.exports = function(s,config){ id:e.id, ke:e.ke, name:trigger.name, + full_name:e.id + ':' + trigger.name, // details:{ plug:'built-in', name:trigger.name, @@ -54,8 +74,12 @@ module.exports = function(s,config){ imgHeight:height, imgWidth:width } - detectorObject.doObjectDetection = (s.ocv && e.details.detector_use_detect_object === '1') - s.triggerEvent(detectorObject) + // + s.detectorWrapper(e, regionJson, detectorObject, function() { + detectorObject.doObjectDetection = (s.ocv && e.details.detector_use_detect_object === '1') + s.triggerEvent(detectorObject) + }) + // } var filterTheNoise = function(trigger){ if(noiseFilterArray[trigger.name].length > 2){ @@ -126,4 +150,52 @@ module.exports = function(s,config){ if(pamDiffCompliantArray.length===0){pamDiffCompliantArray = null} return {forPam:pamDiffCompliantArray,notForPam:arrayForOtherStuff}; } + + // + s.detectorWrapper = function(monitor, regionJson, detectorObject, doRecord) { + if (regionJson === undefined || regionJson.length == 0) { + s.debugLog("No regions defined, ignoring trigger event") + return + } + const region = Object.values(regionJson).find(x => x.name == detectorObject.name) + let maxSensitivity = parseInt(region.max_sensitivity) || globalMaxSensitivity + let threshold = parseInt(region.threshold) || globalThreshold + + if (maxSensitivity===undefined || detectorObject.details.confidence <= maxSensitivity) { + if (threshold <= 1) { + s.debugLog('Detector threshold is ' + threshold + ', motion record started: ' + detectorObject.full_name) + doRecord() + } else { + s.debugLog('Trigger=' + detectorObject.full_name + ', confidence='+detectorObject.details.confidence) + if (monitor.triggerTimer[detectorObject.name] === undefined) { + monitor.triggerTimer[detectorObject.name] = { + count : threshold, + timeout : null + } + } + if (--monitor.triggerTimer[detectorObject.name].count == 0) { + s.debugLog('Trigger threshold ' + threshold + ' hit, motion record started: ' + detectorObject.full_name) + doRecord() + clearTimeout(monitor.triggerTimer[detectorObject.name].timeout) + monitor.triggerTimer[detectorObject.name] = undefined + } else { + const fps = parseFloat(monitor.details.detector_fps) || 2 + if (monitor.triggerTimer[detectorObject.name].timeout !== null) + clearTimeout(monitor.triggerTimer[detectorObject.name].timeout) + monitor.triggerTimer[detectorObject.name].timeout = setTimeout(function() { + s.debugLog('Trigger threshold timeout: ' + detectorObject.full_name) + monitor.triggerTimer[detectorObject.name] = undefined + }, ((threshold+0.5) * 1000) / fps) + } + } + } else { + s.debugLog('Trigger ' + detectorObject.full_name + ', confidence='+detectorObject.details.confidence + ' (over maxSensitivity)') + if (monitor.triggerTimer[detectorObject.name] !== undefined) { + clearTimeout(monitor.triggerTimer[detectorObject.name].timeout) + monitor.triggerTimer[detectorObject.name] = undefined + } + } + } + // + } diff --git a/web/libs/js/main.dash2.js b/web/libs/js/main.dash2.js index fc642834..57d5b9ec 100644 --- a/web/libs/js/main.dash2.js +++ b/web/libs/js/main.dash2.js @@ -2954,6 +2954,8 @@ $.zO.initCanvas=function(){ if(!e.val){ $.zO.f.find('[name="name"]').val('') $.zO.f.find('[name="sensitivity"]').val('') + $.zO.f.find('[name="max_sensitivity"]').val('') + $.zO.f.find('[name="threshold"]').val('') $.zO.rp.empty() }else{ e.cord=$.zO.regionViewerDetails.cords[e.val]; @@ -2967,6 +2969,8 @@ $.zO.initCanvas=function(){ $.zO.f.find('[name="name"]').val(e.val) $.zO.e.find('.cord_name').text(e.val) $.zO.f.find('[name="sensitivity"]').val(e.cord.sensitivity) + $.zO.f.find('[name="max_sensitivity"]').val(e.cord.max_sensitivity) + $.zO.f.find('[name="threshold"]').val(e.cord.threshold) $.zO.e.find('.canvas_holder canvas').remove(); $.zO.initLiveStream() @@ -2986,6 +2990,16 @@ $.zO.e.on('change','[name="sensitivity"]',function(e){ $.zO.regionViewerDetails.cords[$.zO.rl.val()].sensitivity=e.val; $.zO.saveCoords() }) +$.zO.e.on('change','[name="max_sensitivity"]',function(e){ + e.val=$(this).val(); + $.zO.regionViewerDetails.cords[$.zO.rl.val()].max_sensitivity=e.val; + $.zO.saveCoords() +}) +$.zO.e.on('change','[name="threshold"]',function(e){ + e.val=$(this).val(); + $.zO.regionViewerDetails.cords[$.zO.rl.val()].threshold=e.val; + $.zO.saveCoords() +}) $.zO.e.on('change','[name="name"]',function(e){ e.old=$.zO.rl.val(); e.new=$.zO.name.val(); @@ -3069,7 +3083,7 @@ $.zO.e.on('click','.add',function(e){ } }) $.zO.regionViewerDetails.cords=e.save; - $.zO.regionViewerDetails.cords[e.gid]={name:e.gid,sensitivity:0.0005,points:[[0,0],[0,100],[100,0]]}; + $.zO.regionViewerDetails.cords[e.gid]={name:e.gid,sensitivity:0.0005,max_sensitivity:'',threshold:1,points:[[0,0],[0,100],[100,0]]}; $.zO.rl.append(''); $.zO.rl.val(e.gid) $.zO.rl.change(); @@ -3521,6 +3535,8 @@ $.aM.generateDefaultMonitorSettings=function(){ "detector_use_detect_object": "0", "detector_frame": "0", "detector_sensitivity": "", + "detector_max_sensitivity": "", + "detector_threshold": "1", "cords": "[]", "detector_buffer_vcodec": "auto", "detector_buffer_fps": "", @@ -5622,7 +5638,7 @@ $('body') } if(!e.d.cords||e.d.cords===''){ e.d.cords={ - red:{ name:"red",sensitivity:0.0005, points:[[0,0],[0,100],[100,0]] }, + red:{ name:"red",sensitivity:0.0005, max_sensitivity:"",points:[[0,0],[0,100],[100,0]] }, } } $.zO.regionViewerDetails=e.d; diff --git a/web/pages/blocks/monitoredit.ejs b/web/pages/blocks/monitoredit.ejs index 1fb1660b..ed9a907a 100644 --- a/web/pages/blocks/monitoredit.ejs +++ b/web/pages/blocks/monitoredit.ejs @@ -1058,6 +1058,16 @@
+
+ +
+
+ +
+
+ +
+
+ +
@@ -64,4 +76,4 @@
- \ No newline at end of file +