Как я могу расположить холст точно поверх потока с веб-камеры?

#javascript #html #css #canvas

#javascript #HTML #css #холст

Вопрос:

Вот код:

 <!DOCTYPE html>
<html lang="en">
    <head>
        <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-core"></script>
        <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-converter"></script>
        <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/facemesh"></script>
        <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-webgl"></script>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
        <script>
            async function get_facemesh() {
                var canvas = document.getElementById("facemesh");

                var draw = canvas.getContext("2d");

                const stream = document.getElementById("movie");

                const model = await facemesh.load((maxFaces = 1));

                while (1) {
                    const faces = await model.estimateFaces(stream);

                    if (faces.length != 0) {
                        canvas.width = canvas.width;

                        var mesh = faces[0].scaledMesh;
                        var widthAcross = mesh[454][0] - mesh[234][0];
                        var heightVertical = mesh[152][1] - mesh[10][1];

                        console.log(heightVertical);

                        draw.fillStyle = "red";

                        for (var i = 0; i < mesh.length; i  ) {
                            draw.fillRect(mesh[i][0], mesh[i][1], 2, 2);
                        }
                    } else {
                        console.log(`No faces have been detected`);
                    }

                    await tf.nextFrame();
                }
            }
        </script>
    </head>
    <body>
        <div class="webcam">
            <video width="600" height="450" autoplay id="movie"></video>
            <canvas width="600" height="450" id="facemesh"> </canvas>
        </div>
        <script>
            video = document.getElementById("movie");
            if (navigator.mediaDevices.getUserMedia) {
                navigator.mediaDevices.getUserMedia({ video: true }).then(function (stream) {
                    video.srcObject = stream;
                });
            }

            main();

            function main() {
                if (video.readyState == 4) {
                    console.log("video is ready for processing..");
                    get_facemesh();
                } else {
                    console.log("nope, not loaded yet..");
                    setTimeout(main, 1000 / 30);
                }
            }
        </script>
    </body>
    <style>
        body {
            background-color: limegreen;
            margin: 0;
            padding: 0;
        }
        video,
        canvas {
            -webkit-transform: scaleX(-1);
            transform: scaleX(-1);
            position: fixed;
            margin: 0 auto;
        }

        .webcam {
            width: 600px;
            height: 450px;
            background-color: limegreen;
            margin: auto;
        }
    </style>
</html>
  

Вот codepen.io ссылка для тех, кому это нравится:https://codepen.io/mdsiam8/pen/gOrPayp .

Я пытался использовать трюк с фиксированным положением, но это не сработало, хотя они расположены точно друг над другом. Такое ощущение, что холст немного растянут или, возможно, слегка смещен влево. Я пытался поработать с этим, но не смог найти исправления, поэтому я был бы очень признателен, если кто-нибудь из вас, ребята, сможет помочь с этим. Кстати, я знаю, что маленькая лицевая сетка, смещенная поверх веб-камеры, ненормальна, потому что у меня есть другой файл, и я использовал трюк с фиксированным положением, и он идеален, поэтому я не уверен, почему это не относится и к этому.

Комментарии:

1. position: absolute работает для любого элемента. Примите во внимание ваше z-index .

Ответ №1:

<video> ‘s width и height атрибуты задают «размеры визуального содержимого элемента» ref, то есть только то, как он будет представлен.
Ваш детектор лиц работает с видеоданными в внутренних размерах видео, то есть в тех, которые определяются самим носителем, а не элементом, который либо растягивает, либо сжимает визуальный контент при его отображении.

С другой стороны, width и height атрибуты canvasустанавливают его внутренние размеры.

Таким образом, внутренние размеры обоих носителей на самом деле разные, и координаты, которые можно найти в видео, не совпадают с координатами на холсте.

Чтобы исправить это, вы можете просто установить для вашего canvas’ width and height значение video.videoWidth и video.videoHeight соответственно, чтобы оно соответствовало внутренним размерам вашего видеоконтента, а затем с помощью CSS измените его размер так, чтобы он соответствовал размерам отображения <video> элемента.

Однако обратите внимание, что медиапотоки могут изменять свои размеры во время воспроизведения, поэтому вы можете захотеть прослушать resize событие вашего <video> .

Ссылка на обновленный codepen, поскольку StackSnippets не допускает gUM.

И наиболее заметные изменения:

 const canvas = document.getElementById("facemesh");
const video = document.getElementById("movie");
if (navigator.mediaDevices.getUserMedia) {
  navigator.mediaDevices.getUserMedia({ video: true })
    .then( stream => {
    video.srcObject = stream;
    video.addEventListener( "resize", (evt) => {
      canvas.width = video.videoWidth;
      canvas.height = video.videoHeight;
    } );
    // don't poll, use events
    video.addEventListener( "loadedmetadata", (evt) => {
      get_facemesh();
    } );
  } );
}
  
 video,
canvas {
  -webkit-transform: scaleX(-1);
  transform: scaleX(-1);
  position: fixed;
  margin: 0 auto;
  /* here set the same display dimensions */
  width: 600px;
  height: 450px;
  /* force same object fit too */
  object-fit: contain;
}
  
 <div class="webcam">
  <video autoplay id="movie"></video>
  <canvas id="facemesh"> </canvas>
</div>