Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 25 additions & 35 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -1,65 +1,55 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const globals = require("globals");
require('@rushstack/eslint-patch/modern-module-resolution')
const globals = require('globals');
require('@rushstack/eslint-patch/modern-module-resolution');

module.exports = {
env: {
browser: true,
node: true,
node: true
},
globals: globals.browser,
plugins: [
"import",
"@typescript-eslint",
"no-loops"
],
plugins: ['import', '@typescript-eslint', 'no-loops', 'eslint-plugin-tsdoc'],
rules: {
"@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
"no-unused-vars": "off",
"import/order": 2,
"no-loops/no-loops": 2,
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
'no-unused-vars': 'off',
'import/order': 2,
'no-loops/no-loops': 2
},
root: true,
extends: [
'plugin:vue/vue3-essential',
'@vue/eslint-config-typescript',
'@vue/eslint-config-prettier/skip-formatting',
"eslint:recommended",
"plugin:import/recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
'eslint:recommended',
'plugin:import/recommended',
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
'prettier'
],
overrides: [
{
files: [
'e2e/**/*.{test,spec}.{js,ts,jsx,tsx}'
],
'extends': [
'plugin:playwright/recommended'
]
files: ['e2e/**/*.{test,spec}.{js,ts,jsx,tsx}'],
extends: ['plugin:playwright/recommended']
}
],
parser: "vue-eslint-parser",
parser: 'vue-eslint-parser',
parserOptions: {
ecmaVersion: 'latest'
},
settings: {
"import/resolver": {
"typescript": {
'import/resolver': {
typescript: {
alwaysTryTypes: true,
"project": "./tsconfig.app.json",
project: './tsconfig.app.json'
},
"node": true,
"tsconfigRootDir": "./"
node: true,
tsconfigRootDir: './'
},
"import/order": [
"error",
'import/order': [
'error',
{
"groups": [
"builtin", "external", "internal", "parent", "sibling", "index", "object", "type"
]
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type']
}
]
}
};
};
48 changes: 35 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
<div align="center">

______________________________________________________________________

# Face Mesh Editor

#### An Editor to manually adjust automatic Face Mesh Detections

______________________________________________________________________

![Build](https://github.com/hcmlab/FaceMeshEditor/actions/workflows/build.yaml/badge.svg)

[**Demo**](https://hcmlab.github.io/FaceMeshEditor/)

Check the [Documentation](https://hcmlab.github.io/FaceMeshEditor/doc/)

![Screenshot of the Demo as a Preview](static/images/PreviewAnimation.gif)
</div>


## Features

### General

<details> <summary>Image(s) Upload</summary>

Supported formats: **jpg** and **png**
Supported formats: **jpg** and **png**
</details>

<details> <summary>Annotation Upload</summary>
Expand All @@ -37,61 +41,79 @@ Format: **json**
* **Redo**: Allows users to repeat a previous action. Useful for reverting to a specific state.
* **Undo**: Reverts the most recent action. Handy for correcting mistakes.
* **Reset**: Restores the system to its initial state. Useful for starting over.

</details>

<details> <summary>Model Selection</summary>

* MediaPipe (Default): Works offline. This mode utilizes a pre-trained model within the system.
* Webservice (Custom): Operates online. Users can connect to a custom external service for specialized processing.

</details>

<details> <summary>Delete Features</summary>

If a displayed face lacks a trait, marking it as hidden signifies its non-existence, and eliminated points are flagged as such in the json file.
If a displayed face lacks a trait, marking it as hidden signifies its non-existence, and eliminated points are flagged
as such in the json file.
</details>

<details> <summary>Image Preview</summary>

Displays thumbnails of uploaded images. These small visual representations help users quickly identify and select the desired image.
Displays thumbnails of uploaded images. These small visual representations help users quickly identify and select the
desired image.
</details>

### Editor

<details> <summary>Cascading Drag</summary>

The Cascading Drag tool facilitates smooth movement of points by considering their neighboring points. When a user drags a point, the tool calculates the movement distance for nearby points using an incremental function. This real-time update ensures a responsive and intuitive interface.
The Cascading Drag tool facilitates smooth movement of points by considering their neighboring points. When a user drags
a point, the tool calculates the movement distance for nearby points using an incremental function. This real-time
update ensures a responsive and intuitive interface.
</details>

<details> <summary>Hide Tesselation</summary>

The Hide Tesselation feature enhances focus on specific regions during annotation. Even when tesselation and their corresponding points are hidden, users can still manipulate points via cascading drag if they are selected closely enough. This allows precise adjustments while maintaining a clutter-free view.
The Hide Tesselation feature enhances focus on specific regions during annotation. Even when tesselation and their
corresponding points are hidden, users can still manipulate points via cascading drag if they are selected closely
enough. This allows precise adjustments while maintaining a clutter-free view.
</details>

<details> <summary>Zoom</summary>

The Zoom functionality allows users to adjust the magnification level of the image. By zooming in, users can examine finer details with clarity. Conversely, zooming out provides a broader view of the entire image.
The Zoom functionality allows users to adjust the magnification level of the image. By zooming in, users can examine
finer details with clarity. Conversely, zooming out provides a broader view of the entire image.
</details>

<details> <summary>Pan</summary>

The Pan feature enables users to shift the visible portion of the image. By panning, users can explore different areas without changing the zoom level. It’s particularly useful for navigating large or detailed images.
The Pan feature enables users to shift the visible portion of the image. By panning, users can explore different areas
without changing the zoom level. It’s particularly useful for navigating large or detailed images.
</details>


## Custom Webservice API
As a user, you have the flexibility to integrate various face mesh detection models seamlessly into our application. Whether you want to provide a pre-trained model via the webservice or create a dynamic model that continues to learn, this API empowers you to tailor face mesh detection to your specific needs.

As a user, you have the flexibility to integrate various face mesh detection models seamlessly into our application.
Whether you want to provide a pre-trained model via the webservice or create a dynamic model that continues to learn,
this API empowers you to tailor face mesh detection to your specific needs.

### Key Endpoints

```
/detect
```

* **Method**: POST and GET
* **Input**: Form-data with a file (supported formats: jpg and png)
* **Return**: JSON response containing detection results
* **Description**: This endpoint allows users to submit an image for detection. The supported formats are jpg and png. The system processes the uploaded file and responds with detection information in JSON format.
* **Return**: JSON response containing detection results
* **Description**: This endpoint allows users to submit an image for detection. The supported formats are jpg and png.
The system processes the uploaded file and responds with detection information in JSON format.

```
/annotations
```

* **Method**: POST
* **Input**: JSON string
* **Description**: Users can send annotation data in JSON format to this endpoint. The system processes the annotations and performs relevant actions based on the provided information.
* **Description**: Users can send annotation data in JSON format to this endpoint. The system processes the annotations
and performs relevant actions based on the provided information.
1 change: 1 addition & 0 deletions doc/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
typedoc
91 changes: 91 additions & 0 deletions doc/adding_new_model.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>Adding new landmark models</title>

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.5/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/showdown@2.1.0/dist/showdown.min.js"></script>
</head>
<body
class="d-flex flex-column d-flex align-items-center justify-content-center flex-column overflow-y-auto min-vh-100">

<div class="d-flex justify-content-between align-items-center mt-5 container">
<a class="btn btn-outline-dark me-3" href="index.html">
<i class="bi bi-arrow-left fs-1"></i>
</a>
<div class="d-flex justify-content-between align-items-center container">
<img id="icon-image"
alt="Face Mesh Logo"
src="https://hcmlab.github.io/FaceMeshEditor/assets/FaceMesh-ByCQ6hfM.png" style="width: 10rem">
<div class="p-4">
<h1>Landmark Editor Documentation</h1>
<h2>Adding new Models</h2>
</div>
</div>
</div>
<div class="mx-5 my-3">
<div id="output"></div>
</div>
</body>

<script>
async function loadFileFromUrl(url) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.text();
} catch (error) {
console.error('Error loading file:', error);
}
}

async function renderMarkdown() {
const url = 'https://raw.githubusercontent.com/hcmlab/FaceMeshEditor/refs/heads/main/other-tools/AddNewModels.md';
let markdown = await loadFileFromUrl(url);
if (markdown) {
const converter = new showdown.Converter();
markdown = markdown.replace(/^[\s\S]*?(?=## Features)/, '');
document.getElementById('output').innerHTML = converter.makeHtml(markdown);
}
}

renderMarkdown();
const htmlElement = document.documentElement;
const anchorButtons = document.querySelectorAll('a');
const icon = document.querySelector('#icon-image');

// Function to apply the theme based on system settings
function applySystemTheme() {
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
htmlElement.setAttribute('data-bs-theme', prefersDark ? 'dark' : 'light');
anchorButtons.forEach(anchor => {
anchor.classList.remove(prefersDark ? 'btn-outline-dark' : 'btn-outline-light');
anchor.classList.add(prefersDark ? 'btn-outline-light' : 'btn-outline-dark');
});

if (prefersDark) {
icon.classList.add('inverted');
} else {
icon.classList.remove('inverted');
}
}

// Initial theme application
applySystemTheme();

// Listen for changes in system settings
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', applySystemTheme);
</script>
<style>
.inverted {
filter: invert(1);
transition: filter 0.5s ease;
}
</style>

</html>
Loading