@webarkit/jsfeat-next
Version:
Typescript version of jsfeat for WebARKit
227 lines (190 loc) • 9.05 kB
HTML
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="description" content="A JavaScript Computer Vision Library">
<title>JSFeatNext - JavaScript Computer Vision Library.</title>
<link rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Droid+Sans:regular,bold|Inconsolata|PT+Sans:400,700">
<link rel="stylesheet" href="css/bootstrap.css">
<link rel="stylesheet" href="css/jsfeat.css">
</head>
<body>
<video id="webcam" width="640" height="480" style="display:none;"></video>
<div style=" width:640px;height:480px;margin: 10px auto;">
<canvas id="canvas" width="640" height="480"></canvas>
<div id="no_rtc" class="alert alert-error" style="display:none;"></div>
<div id="log" class="alert alert-info"></div>
</div>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="../dist/jsfeatNext.js"></script>
<script type="text/javascript" src="js/compatibility.js"></script>
<script type="text/javascript" src="js/profiler.js"></script>
<script type="text/javascript" src="js/dat.gui.min.js"></script>
<script type="text/javascript">
$(window).on('load', function () {
"use strict";
// lets do some fun
var video = document.getElementById('webcam');
var canvas = document.getElementById('canvas');
var jsfeat = jsfeatNext.jsfeatNext;
var imgproc = new jsfeat.imgproc();
var optical_flow_lk = new jsfeat.optical_flow_lk();
try {
var attempts = 0;
var readyListener = function (event) {
findVideoSize();
};
var findVideoSize = function () {
if (video.videoWidth > 0 && video.videoHeight > 0) {
video.removeEventListener('loadeddata', readyListener);
onDimensionsReady(video.videoWidth, video.videoHeight);
} else {
if (attempts < 10) {
attempts++;
setTimeout(findVideoSize, 200);
} else {
onDimensionsReady(640, 480);
}
}
};
var onDimensionsReady = function (width, height) {
demo_app(width, height);
compatibility.requestAnimationFrame(tick);
};
video.addEventListener('loadeddata', readyListener);
compatibility.getUserMedia({ video: true }, function (stream) {
if (video.srcObject !== undefined) {
video.srcObject = stream
} else {
try {
video.src = compatibility.URL.createObjectURL(stream);
} catch (error) {
video.src = stream;
}
}
setTimeout(function () {
video.play();
}, 500);
}, function (error) {
$('#canvas').hide();
$('#log').hide();
$('#no_rtc').html('<h4>WebRTC not available.</h4>');
$('#no_rtc').show();
});
} catch (error) {
$('#canvas').hide();
$('#log').hide();
$('#no_rtc').html('<h4>Something goes wrong...</h4>');
$('#no_rtc').show();
}
var stat = new profiler();
var gui, options, ctx, canvasWidth, canvasHeight;
var curr_img_pyr, prev_img_pyr, point_count, point_status, prev_xy, curr_xy;
var demo_opt = function () {
this.win_size = 20;
this.max_iterations = 30;
this.epsilon = 0.01;
this.min_eigen = 0.001;
}
function demo_app(videoWidth, videoHeight) {
canvasWidth = canvas.width;
canvasHeight = canvas.height;
ctx = canvas.getContext('2d', {"willReadFrequently": true});
ctx.fillStyle = "rgb(0,255,0)";
ctx.strokeStyle = "rgb(0,255,0)";
curr_img_pyr = new jsfeat.pyramid_t(3);
prev_img_pyr = new jsfeat.pyramid_t(3);
curr_img_pyr.allocate(640, 480, jsfeat.U8_t | jsfeat.C1_t);
prev_img_pyr.allocate(640, 480, jsfeat.U8_t | jsfeat.C1_t);
point_count = 0;
point_status = new Uint8Array(100);
prev_xy = new Float32Array(100 * 2);
curr_xy = new Float32Array(100 * 2);
options = new demo_opt();
gui = new dat.GUI();
gui.add(options, 'win_size', 7, 30).step(1);
gui.add(options, 'max_iterations', 3, 30).step(1);
gui.add(options, 'epsilon', 0.001, 0.1).step(0.0025);
gui.add(options, 'min_eigen', 0.001, 0.01).step(0.0025);
stat.add("grayscale");
stat.add("build image pyramid");
stat.add("optical flow lk");
}
function tick() {
compatibility.requestAnimationFrame(tick);
stat.new_frame();
if (video.readyState === video.HAVE_ENOUGH_DATA) {
ctx.drawImage(video, 0, 0, 640, 480);
var imageData = ctx.getImageData(0, 0, 640, 480);
// swap flow data
var _pt_xy = prev_xy;
prev_xy = curr_xy;
curr_xy = _pt_xy;
var _pyr = prev_img_pyr;
prev_img_pyr = curr_img_pyr;
curr_img_pyr = _pyr;
stat.start("grayscale");
imgproc.grayscale(imageData.data, 640, 480, curr_img_pyr.data[0]);
stat.stop("grayscale");
stat.start("build image pyramid");
curr_img_pyr.build(curr_img_pyr.data[0], true);
stat.stop("build image pyramid");
stat.start("optical flow lk");
optical_flow_lk.track(prev_img_pyr, curr_img_pyr, prev_xy, curr_xy, point_count, options.win_size | 0, options.max_iterations | 0, point_status, options.epsilon, options.min_eigen);
stat.stop("optical flow lk");
prune_oflow_points(ctx);
$('#log').html(stat.log() + '<br/>click to add tracking points: ' + point_count);
}
}
function on_canvas_click(e) {
var coords = canvas.relMouseCoords(e);
if (coords.x > 0 & coords.y > 0 & coords.x < canvasWidth & coords.y < canvasHeight) {
curr_xy[point_count << 1] = coords.x;
curr_xy[(point_count << 1) + 1] = coords.y;
point_count++;
}
}
canvas.addEventListener('click', on_canvas_click, false);
function draw_circle(ctx, x, y) {
ctx.beginPath();
ctx.arc(x, y, 4, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
}
function prune_oflow_points(ctx) {
var n = point_count;
var i = 0, j = 0;
for (; i < n; ++i) {
if (point_status[i] == 1) {
if (j < i) {
curr_xy[j << 1] = curr_xy[i << 1];
curr_xy[(j << 1) + 1] = curr_xy[(i << 1) + 1];
}
draw_circle(ctx, curr_xy[j << 1], curr_xy[(j << 1) + 1]);
++j;
}
}
point_count = j;
}
function relMouseCoords(event) {
var totalOffsetX = 0, totalOffsetY = 0, canvasX = 0, canvasY = 0;
var currentElement = this;
do {
totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft;
totalOffsetY += currentElement.offsetTop - currentElement.scrollTop;
} while (currentElement = currentElement.offsetParent)
canvasX = event.pageX - totalOffsetX;
canvasY = event.pageY - totalOffsetY;
return { x: canvasX, y: canvasY }
}
HTMLCanvasElement.prototype.relMouseCoords = relMouseCoords;
$(window).on('unload', function () {
video.pause();
video.src = null;
});
});
</script>
</body>
</html>