Webcam Pixel Manipulation with HTML5 Canvas

march 29, 2021

I was fascinated by a web page at Manipulating video using canvas and so I decided to replicate it here:)

One difference is that here we'll use webcam as video input source. Yes, your webcam... so please click yes when your browser asks your permission to use your webcam.

Here's the flowchart / diagram for that: flowchart / diagram.

Demo

sorry but your browser doesn't support HTML5 canvas, please upgrade. sorry but your browser doesn't support HTML5 canvas, please upgrade.

HTML Structure

<div id="demo">
	<p></p>

	<form autocomplete="off">
		<input id="cb" type="checkbox" disabled>
		<label for="cb"></label>
	</form>

	<video>sorry but your browser doesn't support HTML5 video, please upgrade.</video>

	<canvas>sorry but your browser doesn't support HTML5 canvas, please upgrade.</canvas>

	<canvas>sorry but your browser doesn't support HTML5 canvas, please upgrade.</canvas>
</div>

<script src="clock.js"></script>
<script src="page.js"></script>

Javascript

You may get details of clock.js at smokingscript.com/pages/event-based-animation.

Following is the page.js source code:

'use strict';
+function(){
	//get elements
	var demo = document.getElementById('demo'),
		vid = demo.getElementsByTagName('video')[0],
		canvs = demo.getElementsByTagName('canvas'),
		cb = document.getElementById('cb'),
		msg = demo.getElementsByTagName('p')[0];
		
	//installl fps clock to demo element.
	var clock = new Clock(demo, 10);

	//whenever video is ready, adjust both source and target canvases dimension
	vid.addEventListener('canplay', function(){
		canvs[0].height = vid.videoHeight;
		canvs[0].width = vid.videoWidth;
		canvs[1].height = vid.videoHeight;
		canvs[1].width = vid.videoWidth;
	});
	
	//when user click on cb toggle clock on / off
	cb.addEventListener('change', function(){
		if(this.checked)
			clock.start();
		else
			clock.stop();
	});
	
	//listen to clock ticks
	demo.addEventListener('ticks', function(){
		
		//clear canvas source and screen capture video stream to it
		let ctx = canvs[0].getContext('2d');
		ctx.clearRect(0, 0, canvs[0].width, canvs[0].height);
		ctx.drawImage(vid, 0, 0, canvs[0].width, canvs[0].height);
		
		//get data from canvas source
		const IMGDAT = ctx.getImageData(0, 0, canvs[0].width, canvs[0].height);

		//calculate & manipulate data. in this demo make all pixels grayed.
		let grays = [],
			grayMin = 255, 
			grayMax = 0;
				
		for(let i = 0; i < IMGDAT.data.length; i += 4){
			let gray = (IMGDAT.data[i] + IMGDAT.data[i + 1] + IMGDAT.data[i + 2]) / 3;
			grays.push(gray);
			grayMin = Math.min(grayMin, gray);
			grayMax = Math.max(grayMax, gray);
		}
		
		let grayDelt = grayMax - grayMin;
		
		for(let i = 0, j = 0; i < IMGDAT.data.length; i += 4){
			let gray = Math.floor(255 * (grays[j] - grayMin) / grayDelt);
			IMGDAT.data[i] = gray;
			IMGDAT.data[i + 1] = gray;
			IMGDAT.data[i + 2] = gray;
			j++;
		}
		
		//put manipulated data to canvas target
		ctx = canvs[1].getContext('2d');
		ctx.putImageData(IMGDAT, 0, 0);
	});//end of canvs[0] ticks event listener
		
	//redirect camera stream to video
	if(!navigator.mediaDevices)
		msg.innerHTML = 'Sorry but camera access is allowed only over secure HTTPS protocol. ' +
			'Please edit this page URL in your browser address bar and instead of HTTP, make sure it is prefixed with HTTPS. ' +
			'Or click <a href="https://smokingscript.com/pages/webcam-manipulation-with-canvas/">here</a> to go straight there.';
	else
		navigator.mediaDevices.getUserMedia({
			video: true, 
			audio: false
		}).then(function(stream){
			vid.srcObject = stream;
			vid.play();//play video
			cb.disabled = false;//enable cb toggle clock on / off
		}).catch(function(err){
			msg.textContent = err;
		});
}();

Comments