bonjour ! J’essaie d’enregistrer une vidéo depuis ma webcam et de lui appliquer un filtre de détection des contours avec openCV.js. L’enregistrement fonctionne bien, il est fait avec WebRTC, il me donne une vidéo stockée dans un blob, et je peux l’afficher sans problème. Voici le code de ma fonction de filtrage :
async function detectContours(inputBlob) {
console.trace("a");
const response = await fetch(URL.createObjectURL(inputBlob));
const blob = await response.blob();
const inputVideo = document.createElement("video");
inputVideo.src = URL.createObjectURL(blob);
await new Promise((resolve) => {
inputVideo.addEventListener("loadedmetadata", () => {
resolve();
});
inputVideo.load();
});
console.log("type de inputVideo : %o", typeof inputVideo);
console.log("vidéo d'entrée : %o * %o", inputVideo.height, inputVideo.width);
console.trace("b");
await new Promise((resolve) => {
inputVideo.addEventListener("canplaythrough", () => {
resolve();
});
inputVideo.load();
});
await inputVideo.play();
console.trace("c");
const outputCanvas = document.createElement("canvas");
outputCanvas.width = inputVideo.videoWidth;
outputCanvas.height = inputVideo.videoHeight;
const outputCtx = outputCanvas.getContext("2d");
console.trace("d");
outputCtx.drawImage(
inputVideo,
0,
0,
outputCanvas.width,
outputCanvas.height
);
console.trace("e");
const cvInput = cv.imread(outputCanvas);
const cvOutput = new cv.Mat();
console.trace("f");
cv.Canny(cvInput, cvOutput, 100, 200);
console.trace("g");
console.log(
"vidéo d'entrée : %o * %o",
inputVideo.videoHeight,
inputVideo.videoWidth
);
console.log("canvas de sortie : %o * %o", cvOutput.rows, cvOutput.cols);
console.log("%o bytes", cvOutput.data.length);
const outputImageData = new ImageData(
new Uint8ClampedArray(cvOutput.data),
cvOutput.cols,
cvOutput.rows / 4
);
console.trace("h");
const outputCanvas2 = document.createElement("canvas");
outputCanvas2.width = outputImageData.width;
outputCanvas2.height = outputImageData.height;
const outputCtx2 = outputCanvas2.getContext("2d");
outputCtx2.putImageData(outputImageData, 0, 0);
console.trace("i");
const outputBlob = await new Promise((resolve) =>
outputCanvas2.toBlob(resolve, "image/png")
);
console.trace("j");
URLvideoEdge = URL.createObjectURL(outputBlob);
blobVideoEdge = outputBlob;
console.trace("k");
}
Voici le code de ma fonction appelée quand j’appuie sur mon bouton pour arrêter d’enregistrer :
async function stopRecording() {
console.trace("1");
//Recording the video
for (let track of stream.getTracks()) {
track.stop(); //when this event is triggered, function called display the video without any issue
}
console.trace("2");
// verifying blobVideoCouleur actually is an object
while (typeof blobVideoCouleur !== "object") {
await new Promise(resolve => setTimeout(resolve, 100)); // Pause 100ms
}
console.trace("3");
//Applying edge detection filter
await detectContours(blobVideoCouleur);
console.trace("4");
//Displaying filtered video
playBack.src = URLvideoEdge;
playBack.autoplay = true;
console.trace("5");
}
playBack
est une variable globale définie comme l’élément html <vidéo>
où je joue la vidéo enregistrée. Ca fonctionne très bien pour la vidéo "normale". Voici le code qui la définie, cette fonction est appelée quand j’appuie sur mon bouton d’arrêt d’enregistrement :
recorder.onstop = () => { // Event triggered when I stop the recorder
const blob = new Blob(chunks, { //
type: 'video/webm' // Et il le fait en webm
})
chunks = [];
URLvideoCouleur = URL.createObjectURL(blob);
playBack = document.getElementById("playBack");
playBack.src = URLvideoCouleur;
playBack.controls = true;
blobVideoCouleur = blob;
}
J’ai eu pas mal de soucis avec cette fonction, c’est pourquoi il y a plein de console.trace
un peu partout, pour suivre l’exécution étape par étape. Ca m’a mené à corriger un dernier bug. La "solution" que j’ai trouvée était une division par 4 dans cette section de la fonction detectContours
:
const outputImageData = new ImageData(
new Uint8ClampedArray(cvOutput.data),
cvOutput.cols,
cvOutput.rows / 4
);
J’ai fait ça car apparemment ImageData a besoin que la taille totale des données soit largeur_frame*hauteur_frame*4, à cause des 4 couleurs (RGBA), mais moi j’ai une seule couche, en noir et blanc, après la détection des contours, donc je divise par 4 pour qu’il arrête de râler…
A partir de là, j’ai plus aucune erreur dans la console, ou interruption ou autre, pour me guider, mais malheureusement le comportement n’est pas celui attendu. playBack
ne joue pas ma vidéo filtrée à la place de la vidéo "normale". Il me donne juste un carré noir avec les contrôles du player, mais inutiles car la vidéo a une durée de 0s.
J’ai plus la console pour avance je disais, et j’ai plus d’idée farfelue comme la division par 4. Avez-vous une suggestion de ce qui peut clocher ? Aussi, pour moi cette division par 4 est un signe que ma fonction detectContours est plus que douteuse, et en la regardant ça m’a l’air d’une grosse usine à gaz. Il n’y a pas une méthode plus simple pour appliquer un filtre de détection des contours en js ? Merci par avance !