/*jshint esversion:6*/ $(function () { const video = $("video")[0]; var model; var cameraMode = "environment"; // or "user" const startVideoStreamPromise = navigator.mediaDevices .getUserMedia({ audio: false, video: { facingMode: cameraMode } }) .then(function (stream) { return new Promise(function (resolve) { video.srcObject = stream; video.onloadeddata = function () { video.play(); resolve(); }; }); }); var publishable_key = "rf_X52J0UfF21bwMQb3LeDUh1ZJjSi1"; var toLoad = { model: "beverage-containers-3atxb", version: 3 }; const loadModelPromise = new Promise(function (resolve, reject) { roboflow .auth({ publishable_key: publishable_key }) .load(toLoad) .then(function (m) { model = m; resolve(); }); }); Promise.all([startVideoStreamPromise, loadModelPromise]).then(function () { $("body").removeClass("loading"); resizeCanvas(); detectFrame(); }); var canvas, ctx; const font = "16px sans-serif"; function videoDimensions(video) { // Ratio of the video's intrisic dimensions var videoRatio = video.videoWidth / video.videoHeight; // The width and height of the video element var width = video.offsetWidth, height = video.offsetHeight; // The ratio of the element's width to its height var elementRatio = width / height; // If the video element is short and wide if (elementRatio > videoRatio) { width = height * videoRatio; } else { // It must be tall and thin, or exactly equal to the original ratio height = width / videoRatio; } return { width: width, height: height }; } $(window).resize(function () { resizeCanvas(); }); const resizeCanvas = function () { $("canvas").remove(); canvas = $(""); ctx = canvas[0].getContext("2d"); var dimensions = videoDimensions(video); console.log( video.videoWidth, video.videoHeight, video.offsetWidth, video.offsetHeight, dimensions ); canvas[0].width = video.videoWidth; canvas[0].height = video.videoHeight; canvas.css({ width: dimensions.width, height: dimensions.height, left: ($(window).width() - dimensions.width) / 2, top: ($(window).height() - dimensions.height) / 2 }); $("body").append(canvas); }; const renderPredictions = function (predictions) { var dimensions = videoDimensions(video); var scale = 1; ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); predictions.forEach(function (prediction) { const x = prediction.bbox.x; const y = prediction.bbox.y; const width = prediction.bbox.width; const height = prediction.bbox.height; // Draw the bounding box. ctx.strokeStyle = prediction.color; ctx.lineWidth = 4; ctx.strokeRect( (x - width / 2) / scale, (y - height / 2) / scale, width / scale, height / scale ); // Draw the label background. ctx.fillStyle = prediction.color; const textWidth = ctx.measureText(prediction.class).width; const textHeight = parseInt(font, 10); // base 10 ctx.fillRect( (x - width / 2) / scale, (y - height / 2) / scale, textWidth + 8, textHeight + 4 ); }); predictions.forEach(function (prediction) { const x = prediction.bbox.x; const y = prediction.bbox.y; const width = prediction.bbox.width; const height = prediction.bbox.height; // Draw the text last to ensure it's on top. ctx.font = font; ctx.textBaseline = "top"; ctx.fillStyle = "#000000"; ctx.fillText( prediction.class, (x - width / 2) / scale + 4, (y - height / 2) / scale + 1 ); }); }; var prevTime; var pastFrameTimes = []; const detectFrame = function () { if (!model) return requestAnimationFrame(detectFrame); model .detect(video) .then(function (predictions) { requestAnimationFrame(detectFrame); renderPredictions(predictions); if (prevTime) { pastFrameTimes.push(Date.now() - prevTime); if (pastFrameTimes.length > 30) pastFrameTimes.shift(); var total = 0; _.each(pastFrameTimes, function (t) { total += t / 1000; }); var fps = pastFrameTimes.length / total; $("#fps").text(Math.round(fps)); } prevTime = Date.now(); }) .catch(function (e) { console.log("CAUGHT", e); requestAnimationFrame(detectFrame); }); }; });