GithubHelp home page GithubHelp logo

facemeshfacegeometry's Introduction

FaceMeshFaceGeometry

Three.js helper for FaceMesh https://github.com/tensorflow/tfjs-models/tree/master/facemesh


Demo with textured mask: https://spite.github.io/FaceMeshFaceGeometry/examples/mask/index.html

Demo with remapped video: https://spite.github.io/FaceMeshFaceGeometry/examples/video/index.html

Demo with instanced geometry: https://spite.github.io/FaceMeshFaceGeometry/examples/instanced/index.html

Demo of texture mapping from an image: https://spite.github.io/FaceMeshFaceGeometry/examples/face_transfer/index.html

Demo of face switching: https://spite.github.io/FaceMeshFaceGeometry/examples/face_off/index.html

FaceMeshFaceGeometry

How to use

After following the code in the FaceMesh repo, you end up with a face estimation.

First import the class.

import { FaceMeshFaceGeometry } from './face.js';

Create a new geometry helper.

const faceGeometry = new FaceMeshFaceGeometry();

On the update loop, after the model returns some faces:

const faces = await model.estimateFaces(video);
if(faces.length) {
  faceGeometry.update(faces[0]);
}

You have to call FaceMeshFaceGeometry::setSize with the width and height of the video to normalise the coordinates so they align with the video source.

That's all there is. You can use faceGeometry as any other BufferGeometry:

const mask = new Mesh(faceGeometry, material);
scene.add(mask);

Mirrored video

This works for the video as it comes. If your source is a webcam, you might want to flip it horizontally.

In that case -besides flipping the video element, by using transform: scaleX(-1), for instance- you'll have to pass a flag to estimateFaces and update:

const faces = await model.estimateFaces(video, false, true);
if(faces.length) {
  faceGeometry.update(faces[0], true);
}

How to use the video/input as a texture for the face

You can use the input to the FaceMesh model to texture the 3d mesh of the face. Constuct the helper with:

const faceGeometry = new FaceMeshFaceGeometry({useVideoTexture: true});

That will remap the UV coordinates of the geometry to fit the input. The vertex coordinates from the estimation will be projected every frame into the UV space. That means that the UV coordinates for the shader won't work for texture mapping (i.e,, alpha mask, ao map, etc. will be mapped differently and probably wrong).

There seem to be issues with instanced video in macOs Chrome and Safari.

How to use as a 3d mesh, independently of the camera

The range of the vertices is based on the resolution of the input feed, so it changes depending on the chosen video or image input. Construct the FaceGeometry helper with the option normalizeCoords set to true and the mesh will be in a resonable consistent size.

const faceGeometry = new FaceMeshFaceGeometry({normalizeCoords: true});

How to update my threejs camera

FaceMesh data works better with an Orthographic camera. First create a camera:

const camera = new OrthographicCamera(1, 1, 1, 1, -1000, 1000);

and then when the video is ready, or the video dimensions change (width, height), run:

camera.left = -.5 * width;
camera.right = .5 * width;
camera.top = .5 * height;
camera.bottom = -.5 * height;
camera.updateProjectionMatrix();

Track points in geometry

After faceGeometry.update() you can use faceGeometry.track() to place objects relative to the surface of the face.

dummy.position.copy(track.position);
dummy.rotation.setFromRotationMatrix(track.rotation);

It will calculate a triangle defined by the three provided vertex ids, and return a position, a normal, and an orthogonal basis rotation that cane be used to rotate and object along the correct normal of that triangle.

Use this image as a reference for vertex Ids.

API

FaceMeshFaceGeometry::update(face: FaceEstimation, cameraIsFlipped: boolean): void

Updates the vertices and recalculates normals.

FaceMeshFaceGeometry::setSize(width: number, height: number): void

Sets the internal values to reframe the coordinates.

FaceMeshFaceGeometry::track(id0: number, id1: number, id2: number): { position: Vector3, normal: Vector3, rotation: Matrix4 }

Calculates a triangle defined by vertices id0, id1 and id2, return its center, normal and orthogonal basis.

facemeshfacegeometry's People

Contributors

spite avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

facemeshfacegeometry's Issues

normalizeCoords: true doesn't seem to do anything

I'm trying to use just the mesh, but have it static, just moving the face expressions, ignoring the position and rotation, and I'm having no luck. This setting should at least prevent the mesh from growing and shrinking. Or am I going in the wrong direction. Do you have any tips on achieving the above? Many thanks for the THREE helper by the way.

Scale 3D object according to the Z transpose

  • Currently the only issue I'm facing is the static size of the model due to Orthographic camera which leads to undesired behavior
  • When I move away or close to the camera the object size doesn't change which doesn't look nice
  • Along with position, normal and rotation data I have calculated scale data also which it exposes through track return object

Unhandled Promise Rejection: TypeError: av.ready is not a function. (In 'av.ready()', 'av.ready' is undefined)

gum av not being recognized. Any idea how to fix this? this is how I've implemented:

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js webgl - GLTF / FACE TEST </title>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<link type="text/css" rel="stylesheet" href="main.css">

	  <script src="https://unpkg.com/@tensorflow/[email protected]/dist/tf-core.js"></script>
	  <script src="https://unpkg.com/@tensorflow/[email protected]/dist/tf-converter.js"></script>
	  <script src="https://unpkg.com/@tensorflow/[email protected]/dist/tf-backend-cpu.js"></script>
	  <script src="https://unpkg.com/@tensorflow/[email protected]/dist/tf-backend-wasm.js"></script>
	  <script src="https://unpkg.com/@tensorflow/[email protected]/dist/tf-backend-webgl.js"></script>
	  <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/facemesh"></script> 
  

		<style>
			gum-av,
	      canvas {
	        position: absolute;
	        left: 0;
	        top: 0;
	        right: 0;
	        bottom: 0;
	        width: 100%;
	        height: 100%;
	      }

	      canvas {
	        margin: auto;
	      }

	      #container {
	        position: absolute;
	        left: 0;
	        top: 0;
	        width: 100%;
	        height: 100%;
	        background-color: black;
	      }

	      #status {
	        position: absolute;
	        left: 0;
	        top: 0;
	        pointer-events: none;
	        color: white;
	        padding: 1em;
	        font-family: roboto, sans-serif;
	        z-index: 1;
	      }

	      gum-av {
	        font-family: roboto, sans-serif;
	        color: white;
	        opacity: 0;
	        transition: opacity 1s ease-out;
	      }
			a {
				color: blue;
			}
			.control-inactive button {
				color: #888;
			}

		</style>

	</head>
	<body>
		<div id="container"></div>
		<div id="info">
			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> GLTF / FACE TEST
			(model from <a href="https://www.mixamo.com/" target="_blank" rel="noopener">mixamo.com</a>)<br/>
		</div>
		 <p id="status">Loading...</p>
	    <div id="container">
	      <gum-av></gum-av>
	      <canvas id="canvas"></canvas>
	    </div>
	  	  
		<script type="importmap">
			{
				"imports": {
					"three": "../build/three.module.js",
					"three/addons/": "./jsm/",
					"gum": "/third_party/gum-av.js"
				}
			}
		</script>
</body>
</html>

Geometry normals are flipped

Currently, to have materials display correctly, you need to set side as BackSide or DoubleSide. I don't think this is particularly intuitive. I reversed the array in geometry.js and it works fine now. Not sure if this is something you want fixed but I thought it was worth mentioning! Haven't tested with UVs yet.

License

Loving what you've done here! Just wondering what the license is for this project? I'd love to use some parts of the code in another non-commercial open source project I'm working on.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.