vue纯前端实现人脸识别、表情识别、年龄性别识别,无需后端服务,使用 tensorflow.js + face-api.js 实现

一、技术选型

公司要研究人脸识别、表情分析需求, 不想花钱调用各家api ... 遂前端来实现这个事, 研究后使用 tensorflow.js + face-api.js 可以完美实现, 所有操作都在前端浏览器端完成, 不需要传输数据到后端处理.

实现效果: 

二、前期准备

我是基于vue项目做的 demo,  理论上可以兼容所有前端框架, 首先安装依赖:

npm i @tensorflow-models/body-pix
npm i @tensorflow/tfjs
npm i face-api.js

然后去 face-api 的官方将模型文件下载下来

https://github.com/justadudewhohacks/face-api.js

将 weights 文件夹下的所有文件 全部下载到 项目中 public/models 文件夹下

三、具体使用

在使用的页面引入 face-api.js

import * as faceapi from 'face-api.js';

mounted 周期内 加载模型

async mounted() {
		try {
			// 加载模型并赋值给 net
			await Promise.all([
				faceapi.nets.tinyFaceDetector.loadFromUri('/models'), // 人脸检测器
				faceapi.nets.faceExpressionNet.loadFromUri('/models'), // 表情识别模型
				faceapi.nets.ageGenderNet.loadFromUri('/models') // 加载年龄和性别模型
			]);
			console.log('Face-api.js 模型加载成功');
		} catch (error) {
			console.error('加载模型失败:', error);
		}
	},

如果打印出模型加载成功, 那么说明前期准备一切正常,直接复制完整代码去使用吧

<template>
	<div class="container">
		<h1>面部表情识别</h1>
		<input type="file" id="image-upload" accept="image/*" @change="handleImageUpload" />
		<div class="content">
			<!-- 绘制上传的图片 -->
			<div class="image-container">
				<canvas id="result-canvas" class="result-canvas"></canvas>
			</div>
			<!-- 用于显示表情结果的容器 -->
			<div id="expression-results" class="expression-results"></div>
		</div>
	</div>
</template>

<script>
import * as faceapi from 'face-api.js';

export default {
	data() {
		return {
			net: null, // 用于存储加载的模型
			imageSrc: null // 用于存储上传的图片 URL
		};
	},
	async mounted() {
		try {
			// 加载模型并赋值给 net
			this.net = await Promise.all([
				faceapi.nets.tinyFaceDetector.loadFromUri('/models'), // 人脸检测器
				faceapi.nets.faceExpressionNet.loadFromUri('/models'), // 表情识别模型(中性、开心、悲伤、生气、害怕、厌恶、惊讶)
				faceapi.nets.ageGenderNet.loadFromUri('/models') // 加载年龄和性别模型
			]);
			console.log('Face-api.js 模型加载成功');
		} catch (error) {
			console.error('加载模型失败:', error);
		}
	},
	methods: {
		async detectFaces(imageElement) {
			if (!this.net) {
				console.error('模型未加载');
				return;
			}

			console.log('图片尺寸:', imageElement.width, imageElement.height); // 调试日志

			// 检测面部、表情、年龄和性别
			const detections = await faceapi
				.detectAllFaces(
					imageElement,
					new faceapi.TinyFaceDetectorOptions({
						inputSize: 512, // 调整输入尺寸
						scoreThreshold: 0.5 // 调整置信度阈值
					})
				)
				.withFaceExpressions()
				.withAgeAndGender(); // 检测年龄和性别

			console.log('检测结果:', detections);

			// 在页面上显示结果
			this.displayResults(imageElement, detections);
		},
		displayResults(imageElement, detections) {
			const canvas = document.getElementById('result-canvas');
			const ctx = canvas.getContext('2d');

			// 调整 Canvas 尺寸
			canvas.width = imageElement.width;
			canvas.height = imageElement.height;
			ctx.drawImage(imageElement, 0, 0, canvas.width, canvas.height);

			// 绘制检测结果
			const resizedDetections = faceapi.resizeResults(detections, {
				width: canvas.width,
				height: canvas.height
			});
			faceapi.draw.drawDetections(canvas, resizedDetections);
			faceapi.draw.drawFaceExpressions(canvas, resizedDetections);

			// 显示表情、年龄和性别结果
			this.displayExpressions(detections);
		},
		displayExpressions(detections) {
			const expressionContainer = document.getElementById('expression-results');
			if (!expressionContainer) {
				console.error('表情结果容器未找到');
				return;
			}
			expressionContainer.innerHTML = ''; // 清空之前的结果

			// 遍历每个检测到的人脸
			detections.forEach((detection, index) => {
				const expressions = detection.expressions;
				const age = detection.age; // 年龄
				const gender = detection.gender; // 性别

				// 获取表情、年龄和性别信息
				const expressionText = this.getExpressionText(expressions);
				const ageText = this.getAgeText(age);
				const genderText = this.getGenderText(gender);

				// 创建结果元素
				const resultElement = document.createElement('div');
				resultElement.className = 'result-item';
				resultElement.innerHTML = `
					<strong>人脸 ${index + 1}:</strong><br>
					${expressionText}<br>
					${ageText}<br>
					${genderText}
					`;
				expressionContainer.appendChild(resultElement);
			});
		},
		getExpressionText(expressions) {
			// 将表情概率转换为中文
			const expressionMap = {
				neutral: '中性',
				happy: '开心',
				sad: '悲伤',
				angry: '生气',
				fearful: '害怕',
				disgusted: '厌恶',
				surprised: '惊讶'
			};

			// 找到概率最高的表情
			let maxExpression = '';
			let maxProbability = 0;
			for (const [expression, probability] of Object.entries(expressions)) {
				if (probability > maxProbability) {
					maxExpression = expression;
					maxProbability = probability;
				}
			}

			// 返回中文表情
			return `表情: ${expressionMap[maxExpression]} (${(maxProbability * 100).toFixed(2)}%)`;
		},
		getAgeText(age) {
			// 返回年龄信息
			return `年龄: ${Math.round(age)} 岁`;
		},
		getGenderText(gender) {
			// 返回性别信息
			return `性别: ${gender === 'male' ? '男' : '女'}`;
		},
		handleImageUpload(event) {
			const file = event.target.files[0];
			if (file) {
				const imageElement = document.createElement('img');
				imageElement.src = URL.createObjectURL(file);
				imageElement.onload = () => {
					console.log('图片加载成功'); // 调试日志
					this.imageSrc = imageElement.src; // 保存图片 URL
					this.detectFaces(imageElement);
				};
				imageElement.onerror = (error) => {
					console.error('图片加载失败:', error); // 错误日志
				};
			}
		}
	}
};
</script>

<style scoped>
.container {
	max-width: 1200px;
	margin: 0 auto;
	padding: 20px;
	text-align: center;
}

h1 {
	font-size: 24px;
	margin-bottom: 20px;
}

#image-upload {
	margin-bottom: 20px;
}

.content {
	display: flex;
	justify-content: space-between;
	align-items: flex-start;
	gap: 20px;
}

.image-container {
	flex: 1;
}

.result-canvas {
	max-width: 100%;
	height: auto;
	border: 1px solid #ccc;
}

.expression-results {
	flex: 1;
	padding: 10px;
	border: 1px;
}
</style>

`face-api.js` 是一个JavaScript库,专门用于面部识别和人脸操作,如检测、标记关键点、人脸识别等。它基于TensorFlow.js,提供了一个直观易用的API,可以在浏览器端和Node.js环境中运行。 在 Vue3 + Node.js 的项目中,你可以将 `face-api.js` 结合使用实现以下功能: 1. **前端应用**:在Vue组件里,通过`import faceapi` 导入库,并利用`faceapi.detectAllFaces()`、`faceapi.drawFaceLandmarks()`等功能实时处理图片中的脸部信息。 ```javascript <template> <div> <img ref="faceImage" /> <canvas ref="canvas"></canvas> </div> </template> <script setup> import faceapi from 'face-api.js'; // 初始化 face-api.js onMounted(() => { await faceapi.nets.ssdMobilenetv1.loadFromUri('/models'); // 更多初始化步骤... }) </script> ``` 2. **后端服务**:如果你需要在服务器上进行复杂的面部分析,可以使用Node.js作为后端,利用`face-api.js`提供的工具对上传的图像进行处理。例如,处理用户上传的图片并返回结果给前端。 ```javascript (server-side) const express = require('express'); const faceapi = require('face-api.js'); const app = express(); app.post('/detect-faces', async (req, res) => { const imageBuffer = req.body.image; try { const results = await detectFaces(imageBuffer); res.json(results); } catch (error) { res.status(500).json({ error }); } }); async function detectFaces(buffer) { // 使用face-api.js在Node.js中检测人脸... } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值