DHEIVER's picture
Update app.js
e79d6a3 verified
import DeviceDetector from "https://cdn.skypack.dev/[email protected]";
// Uso: testSupport({client?: string, os?: string}[])
// Client e os são expressões regulares.
// Veja: https://cdn.jsdelivr.net/npm/[email protected]/README.md para
// valores legais para client e os
testSupport([
{client: 'Chrome'},
]);
function testSupport(supportedDevices:{client?: string; os?: string;}[]) {
const deviceDetector = new DeviceDetector();
const detectedDevice = deviceDetector.parse(navigator.userAgent);
let isSupported = false;
for (const device of supportedDevices) {
if (device.client !== undefined) {
const re = new RegExp(`^${device.client}$`);
if (!re.test(detectedDevice.client.name)) {
continue;
}
}
if (device.os !== undefined) {
const re = new RegExp(`^${device.os}$`);
if (!re.test(detectedDevice.os.name)) {
continue;
}
}
isSupported = true;
break;
}
if (!isSupported) {
alert(`Esta demonstração, rodando em ${detectedDevice.client.name}/${detectedDevice.os.name}, ` +
`não é bem suportada no momento, continue por sua conta e risco.`);
}
}
const controls = window;
const drawingUtils = window;
const mpFaceMesh = window;
const config = {locateFile: (file) => {
return `https://cdn.jsdelivr.net/npm/@mediapipe/face_mesh@` +
`${mpFaceMesh.VERSION}/${file}`;
}};
// Nossos quadros de entrada virão daqui.
const videoElement =
document.getElementsByClassName('input_video')[0] as HTMLVideoElement;
const canvasElement =
document.getElementsByClassName('output_canvas')[0] as HTMLCanvasElement;
const controlsElement =
document.getElementsByClassName('control-panel')[0] as HTMLDivElement;
const canvasCtx = canvasElement.getContext('2d')!;
/**
* Opções da solução.
*/
const solutionOptions = {
selfieMode: true,
enableFaceGeometry: false,
maxNumFaces: 1,
refineLandmarks: false,
minDetectionConfidence: 0.5,
minTrackingConfidence: 0.5
};
// Adicionaremos isso ao nosso painel de controle mais tarde, mas salvaremos aqui para que possamos
// chamar tick() cada vez que o gráfico for executado.
const fpsControl = new controls.FPS();
// Otimização: Desative o spinner animado após sua animação de ocultação ser concluída.
const spinner = document.querySelector('.loading')! as HTMLDivElement;
spinner.ontransitionend = () => {
spinner.style.display = 'none';
};
function onResults(results: mpFaceMesh.Results): void {
// Ocultar o spinner.
document.body.classList.add('loaded');
// Atualizar a taxa de quadros.
fpsControl.tick();
// Desenhar as sobreposições.
canvasCtx.save();
canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height);
canvasCtx.drawImage(
results.image, 0, 0, canvasElement.width, canvasElement.height);
if (results.multiFaceLandmarks) {
for (const landmarks of results.multiFaceLandmarks) {
drawingUtils.drawConnectors(
canvasCtx, landmarks, mpFaceMesh.FACEMESH_TESSELATION,
{color: '#C0C0C070', lineWidth: 1});
drawingUtils.drawConnectors(
canvasCtx, landmarks, mpFaceMesh.FACEMESH_RIGHT_EYE,
{color: '#FF3030'});
drawingUtils.drawConnectors(
canvasCtx, landmarks, mpFaceMesh.FACEMESH_RIGHT_EYEBROW,
{color: '#FF3030'});
drawingUtils.drawConnectors(
canvasCtx, landmarks, mpFaceMesh.FACEMESH_LEFT_EYE,
{color: '#30FF30'});
drawingUtils.drawConnectors(
canvasCtx, landmarks, mpFaceMesh.FACEMESH_LEFT_EYEBROW,
{color: '#30FF30'});
drawingUtils.drawConnectors(
canvasCtx, landmarks, mpFaceMesh.FACEMESH_FACE_OVAL,
{color: '#E0E0E0'});
drawingUtils.drawConnectors(
canvasCtx, landmarks, mpFaceMesh.FACEMESH_LIPS, {color: '#E0E0E0'});
if (solutionOptions.refineLandmarks) {
drawingUtils.drawConnectors(
canvasCtx, landmarks, mpFaceMesh.FACEMESH_RIGHT_IRIS,
{color: '#FF3030'});
drawingUtils.drawConnectors(
canvasCtx, landmarks, mpFaceMesh.FACEMESH_LEFT_IRIS,
{color: '#30FF30'});
}
}
}
canvasCtx.restore();
}
const faceMesh = new mpFaceMesh.FaceMesh(config);
faceMesh.setOptions(solutionOptions);
faceMesh.onResults(onResults);
// Apresentar um painel de controle através do qual o usuário pode manipular as opções da solução.
new controls
.ControlPanel(controlsElement, solutionOptions)
.add([
new controls.StaticText({title: 'MediaPipe Face Mesh'}),
fpsControl,
new controls.Toggle({title: 'Modo Selfie', field: 'selfieMode'}),
new controls.SourcePicker({
onFrame:
async (input: controls.InputImage, size: controls.Rectangle) => {
const aspect = size.height / size.width;
let width: number, height: number;
if (window.innerWidth > window.innerHeight) {
height = window.innerHeight;
width = height / aspect;
} else {
width = window.innerWidth;
height = width * aspect;
}
canvasElement.width = width;
canvasElement.height = height;
await faceMesh.send({image: input});
},
}),
new controls.Slider({
title: 'Número Máximo de Rostos',
field: 'maxNumFaces',
range: [1, 4],
step: 1
}),
new controls.Toggle(
{title: 'Refinar Pontos de Referência', field: 'refineLandmarks'}),
new controls.Slider({
title: 'Confiança Mínima de Detecção',
field: 'minDetectionConfidence',
range: [0, 1],
step: 0.01
}),
new controls.Slider({
title: 'Confiança Mínima de Rastreamento',
field: 'minTrackingConfidence',
range: [0, 1],
step: 0.01
}),
])
.on(x => {
const options = x as mpFaceMesh.Options;
videoElement.classList.toggle('selfie', options.selfieMode);
faceMesh.setOptions(options);
});