Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: video crops when webcam resolution is not 480p #5

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.vscode
108 changes: 32 additions & 76 deletions script.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ if (window.matchMedia("(max-width: 500px)").matches) {
picture_canvas.width = width;
picture_canvas.height = height;
} else {
var width = 640;
var width = 640; // delete these if incoming video dimensions are overwriting them?
parth-agrawal marked this conversation as resolved.
Show resolved Hide resolved
var height = 480;
}

Expand Down Expand Up @@ -378,6 +378,11 @@ function webcamInference() {
.then(function (stream) {
// if video exists, show it
// create video element
const settings = stream.getVideoTracks()[0].getSettings()
width = settings.width // override width and height with incoming video width and height
height = settings.height
const videoAspectRatio = width / height

var video = document.createElement("video");
video.srcObject = stream;
video.id = "video1";
Expand All @@ -394,16 +399,27 @@ function webcamInference() {

ctx.scale(1, 1);


// setting the dimensions of video and canvas, doesn't need to be in video render loop
// sWidth, sHeight, dx, dy are unused, but must be reset here because they are global variables
var [sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight, scalingRatio] =
getCoordinates(video, videoAspectRatio);
canvas.width = dWidth;
canvas.style.width = dWidth + "px";
canvas.height = dHeight;
canvas.style.height = dHeight + "px";
setImageState(
LOADING_URL,
"video_canvas"
);

video.addEventListener(
"loadeddata",
function () {
var loopID = setInterval(function () {

var [sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight, scalingRatio] =
getCoordinates(video);
model.then(function (model) {
model.detect(video).then(function (predictions) {
ctx.drawImage(video, 0, 0, width, height, 0, 0, width, height);
ctx.drawImage(video, 0, 0, width, height, 0, 0, dWidth, dHeight);

ctx.beginPath();

Expand All @@ -427,36 +443,26 @@ function webcamInference() {
}
}

function getCoordinates(img) {
function getCoordinates(img, videoAspectRatio) {

var dx = 0;
var dy = 0;
var dWidth = 640;
var dHeight = 480;
var dWidth = 0; // we're going to dynamically set width based on video aspect ratio
var dHeight = 480; // assume fixed height of canvas

// sy and sx are the offset of the coordinates
var sy;
var sx;
var sWidth = 0;
var sWidth = img.width; // set to incoming image width
var sHeight = 0;

var imageWidth = img.width;
var imageHeight = img.height;
var sx = 0;
var sy = 0;

const canvasRatio = dWidth / dHeight;
const imageRatio = imageWidth / imageHeight;
dWidth = dHeight * videoAspectRatio

// scenario 1 - image is more vertical than canvas
if (canvasRatio >= imageRatio) {
var sx = 0;
var sWidth = imageWidth;
var sHeight = sWidth / canvasRatio;
var sy = (imageHeight - sHeight) / 2;
} else {
// scenario 2 - image is more horizontal than canvas
var sy = 0;
var sHeight = imageHeight;
var sWidth = sHeight * canvasRatio;
var sx = (imageWidth - sWidth) / 2;
}
// dWidth is width of the canvas we're drawing to
// sWidth is the width of the original image

var scalingRatio = dWidth / sWidth;

Expand All @@ -467,56 +473,6 @@ function getCoordinates(img) {
return [sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight, scalingRatio];
}

function getBase64Image(img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) {
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
var dataURL = canvas.toDataURL("image/jpeg");
return dataURL;
}

function imageInference(e) {
// replace canvas with image
document.getElementById("picture").style.display = "none";
document.getElementById("picture_canvas").style.display = "block";
document.getElementById("example_demo").style.display = "none";
document.getElementById("video_canvas").style.display = "none";

var canvas = document.getElementById("picture_canvas");
var ctx = canvas.getContext("2d");
var img = new Image();
img.src = e.src;
img.crossOrigin = "anonymous";

ctx.clearRect(0, 0, canvas.width, canvas.height);

img.onload = function () {
setImageState(
LOADING_URL,
"picture_canvas"
);
var [sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight, scalingRatio] =
getCoordinates(img);

var base64 = getBase64Image(img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

apiRequest(base64).then(function (predictions) {
ctx.beginPath();
// draw image to canvas
ctx.drawImage(img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
var predictions = predictions.map(function (prediction) {
return {
bbox: { x: prediction.x, y: prediction.y, width: prediction.width, height: prediction.height},
class: prediction.class,
confidence: prediction.confidence,
}});

drawBoundingBoxes(predictions, canvas, ctx, scalingRatio, sx, sy, true);
});
};
}

function processDrop(e) {
e.preventDefault();
Expand Down
Loading