#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>