I have downloaded sample web app project.
The projects webcam is full screen and by measuring video and canvas size it creates bounding boxes which fits perfectly on screen.
I tried changing my webcam size to 60 % of full screen after which boxes misaligned.Even on some intances i came close but still it worked on some and not on others.
html, body {
background-color: black;
color: white;
font-family: -apple-system,BlinkMacSystemFont,“Segoe UI”,Roboto,“Helvetica Neue”,Arial,“Noto Sans”,sans-serif,“Apple Color Emoji”,“Segoe UI Emoji”,“Segoe UI Symbol”,“Noto Color Emoji”;
}
body video {
transition: filter 250ms linear;
}
body.loading video {
filter: grayscale(1) brightness(0.25);
}
body.loading:before {
content: “Loading Model…”;
color: white;
text-align: center;
width: 100%;
position: absolute;
top: 20px;
font-size: 3em;
font-weight: bold;
z-index: 100;
}
html, body, video, canvas {
width: 80%;
height: 80%;
margin: 0;
padding: 0;
}
video, canvas {
position: fixed;
top: 0;
left: 0;
}
body:after {
content: “”;
position: fixed;
bottom: 20px;
right: 20px;
width: 350px;
height: 150px;
z-index: 1;
background-image: url(“https://uploads-ssl.webflow.com/5eca8e43c4dfff837f0f6392/5ecad58e650fb5ec53e8b811_roboflow_assets_logo_white.png”);
background-size: contain;
background-repeat: no-repeat;
background-position: bottom right;
}
#fps {
position: fixed;
bottom: 10px;
left: 10px;
}
#fps:empty {
display: none;
}
#fps:after {
content: " fps";
}
changed video and canvas width and height to 80% but bounding box gets misaligned.
Js for project after reverting back to original script.
/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 = "XXXXXXXXXXXXXXXXXXXXX";
var toLoad = {
model: "ABC",
version: 2
};
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 = $("<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);
});
};
});
How to fix alignment when webcam size is changed to 60% of full screen.