Created
May 1, 2017 13:20
-
-
Save Keyes/3f75607f124d94d44b3ae4c991fb662b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Motion detection with nodeJS | |
* | |
* You'll need node-canvas: https://github.com/Automattic/node-canvas | |
*/ | |
var Canvas = require('canvas'), | |
Image = Canvas.Image, | |
canvas = new Canvas(640, 480), | |
diffCanvas = new Canvas(640, 480), | |
context = canvas.getContext('2d'), | |
diffContext = diffCanvas.getContext('2d'), | |
fs = require('fs'); | |
const canvasWidth = 640; | |
const canvasHeight = 480; | |
const pixelDiffThreshold = 50; | |
const diffWidth = 64; | |
const diffHeight = 48; | |
const scoreThreshold = 16; | |
const movementPadding = 10; | |
const motionThreshold = 10; | |
var currentImage = fs.readFileSync('last.jpg'); | |
var lastImage = fs.readFileSync('prelast.jpg'); | |
var img = new Image; | |
img.src = currentImage; | |
diffContext.drawImage(img, 0, 0, canvasWidth, canvasHeight); | |
img = new Image; | |
img.src = currentImage; | |
context.drawImage(img, 0, 0, canvasWidth, canvasHeight); | |
diffContext.globalCompositeOperation = 'difference'; | |
img = new Image; | |
img.src = lastImage; | |
diffContext.drawImage(img, 0, 0, canvasWidth, canvasHeight); | |
diffContext.globalCompositeOperation = 'source-on'; | |
// predefined no-motion-areas: in my case my TV and some reflections | |
diffContext.fillStyle = "black"; | |
diffContext.fillRect(canvasWidth * 0.68, canvasHeight * 0.52, canvasWidth * 0.29, canvasHeight * 0.32); // TV | |
diffContext.fillRect(canvasWidth * 0.05, canvasHeight * 0.25, canvasWidth * 0.05, canvasHeight * 0.15); // TV reflection | |
diffContext.fillRect(canvasWidth * 0.15, canvasHeight * 0.65, canvasWidth * 0.05, canvasHeight * 0.11); // TV reflection | |
var diff = processDiff(); | |
if (diff.motionBox) { | |
context.strokeStyle = 'green'; | |
context.lineWidth = 2; | |
context.strokeRect( | |
diff.motionBox.x[0] - movementPadding, | |
diff.motionBox.y[0] - movementPadding, | |
diff.motionBox.x[1] - diff.motionBox.x[0] + (movementPadding * 2), | |
diff.motionBox.y[1] - diff.motionBox.y[0] + (movementPadding * 2) | |
); | |
} | |
fs.writeFileSync('difference.png', diffCanvas.toBuffer()); | |
fs.writeFileSync('movement.png', canvas.toBuffer()); | |
console.log('processDiff', diff); | |
function processDiff() { | |
var imageData = diffContext.getImageData(0, 0, canvasWidth, canvasHeight); | |
var rgba = imageData.data; | |
// pixel adjustments are done by reference directly on diffImageData | |
var changedPixels = 0; | |
var motionPixels = []; | |
var motionBox = { x: [canvasWidth, 0], y: [canvasHeight, 0] }; | |
for (var i = 0; i < rgba.length; i += 4) { | |
var brightness = 0.34 * rgba[i] + 0.5 * rgba[i + 1] + 0.16 * rgba[i + 2]; | |
coords = { | |
x: (i / 4) % canvasWidth, | |
y: Math.floor((i / 4) / canvasWidth) | |
}; | |
if (brightness >= pixelDiffThreshold) { | |
changedPixels++; | |
rgba[i] = brightness; | |
rgba[i + 1] = brightness; | |
rgba[i + 2] = brightness; | |
if (coords.x < motionBox.x[0]) motionBox.x[0] = coords.x; | |
if (coords.y < motionBox.y[0]) motionBox.y[0] = coords.y; | |
if (coords.x > motionBox.x[1]) motionBox.x[1] = coords.x; | |
if (coords.y > motionBox.y[1]) motionBox.y[1] = coords.y; | |
} else { | |
rgba[i] = 0; | |
rgba[i + 1] = 0; | |
rgba[i + 2] = 0; | |
} | |
} | |
var motionBoxWidth = motionBox.x[1] - motionBox.x[0]; | |
var motionBoxHeight = motionBox.y[1] - motionBox.y[0]; | |
var score = Math.round((changedPixels / (motionBoxWidth * motionBoxHeight)) * 100000) / 1000; | |
var hasMovement = score > motionThreshold; | |
diffContext.putImageData(imageData, 0, 0); | |
return { | |
score: score, | |
hasMovement: hasMovement, | |
motionBox: hasMovement ? motionBox : false | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment