require("@tensorflow/tfjs-node"); const logger = require('./logger'); // 引入上面创建的logger const fs= require ('fs'); const express = require("express"); const moment = require("moment"); // 配置 cors 这个中间件 const cors = require('cors') // const faceapi = require("face-api.js"); const faceapi = require('@vladmandic/face-api'); const mongoose = require("mongoose"); const canvas = require("canvas"); const { Canvas, Image } = require("canvas"); const fileUpload = require("express-fileupload"); const multer = require('multer') console.log('----') faceapi.env.monkeyPatch({ Canvas, Image }); const app = express(); function getFileExtension(filename) { // 检查是否有点存在,如果没有直接返回空字符串 if (filename.indexOf('.') === -1) return ''; // 使用split方法根据最后一个点分割字符串,并取最后一部分作为扩展名 return filename.split('.').pop(); } // 设置存放格式 const storage = multer.diskStorage({ destination(req, file, cb) { cb(null, './uploads') }, filename(req, file, cb) { const originalname = getFileExtension(file.originalname) cb(null, Date.now() + '.'+originalname) } }) // 加载文件存储 const upload = multer({ storage }) // app.use( // fileUpload({ // useTempFiles: true, // }) // ); app.use(cors()) app.use(express.static('./web')) app.use('/uploads', express.static('./uploads')); async function LoadModels() { await faceapi.nets.faceRecognitionNet.loadFromDisk(__dirname + "/models"); await faceapi.nets.faceLandmark68Net.loadFromDisk(__dirname + "/models"); await faceapi.nets.ssdMobilenetv1.loadFromDisk(__dirname + "/models"); } LoadModels(); const faceSchema = new mongoose.Schema({ label: { type: String, required: true, unique: true, }, images:{ type:Array, required:true }, descriptions: { type: Array, required: true, }, }); const FaceModel = mongoose.model("Face", faceSchema); /** * * @param {图片} images * @param {图片标记:张三} label * @returns */ async function uploadLabeledImages(images, label) { try { let counter = 0; const descriptions = []; const imgs=[] // 循环图片 for (let i = 0; i < images.length; i++) { const img = await canvas.loadImage(images[i]); // 调整图像大小 const resizedImage = faceapi.resizeResults(img, { width: 600, height: 600 }); // 设置检测选项 const options = new faceapi.SsdMobilenetv1Options({ minConfidence: 0.3 }); counter = (i / images.length) * 100; console.log(`Progress = ${counter}%`); // Read each face and save the face descriptions in the descriptions array const detections = await faceapi.detectSingleFace(resizedImage,options).withFaceLandmarks().withFaceDescriptor(); if(detections?.descriptor){ descriptions.push(detections.descriptor); imgs.push(images[i]) } } console.log(descriptions,images) if(descriptions==[]){ console.log('人脸读取有错误') return false } //用给定的标签创建一个新的面文档,并将其保存在数据库中 const createFace = new FaceModel({ label: label, descriptions: descriptions, images:imgs }); try{ await createFace.save(); console.log('人脸录入成功!') return true }catch(error){ return error; } } catch (error) { console.log(error); return (error); } } /** * 清空 人脸库 * @param {人物标记} label * @returns */ async function deleteLabelImages(label) { try{ await FaceModel.deleteMany({ label: label }) return true }catch(error){ return error } } /** * 清空 人脸库 * @param {人物标记} label * @returns */ async function selectLabelImages(label) { try{ await FaceModel.findOne({ label: label }) return true }catch(error){ return error } } async function getDescriptorsFromDB(image) { // 从mongodb获取所有的面部数据,并循环遍历每个面部数据以读取数据 let faces = await FaceModel.find(); for (i = 0; i < faces.length; i++) { // 将面数据描述符从obiects更改为Float32Array类型 for (j = 0; j < faces[i].descriptions.length; j++) { faces[i].descriptions[j] = new Float32Array(Object.values(faces[i].descriptions[j])); } // 将DB面文档改为 faces[i] = new faceapi.LabeledFaceDescriptors(faces[i].label, faces[i].descriptions); } // 加载面匹配器以查找匹配面 const faceMatcher = new faceapi.FaceMatcher(faces, 0.5); // 使用画布或其他方法读取图像 const img = await canvas.loadImage(image); // // 调整图像大小 // const resizedImage = faceapi.resizeResults(img, { width: 600, height: 600 }); // // 设置检测选项 const options = new faceapi.SsdMobilenetv1Options({ minConfidence: 0.3 }); let temp = faceapi.createCanvasFromMedia(img); // 处理模型的图像 const displaySize = { width: 600, height: 600 }; faceapi.matchDimensions(temp, displaySize); const currentTime = moment().format("YYYY-MM-DD HH:mm:ss"); // 查找匹配的人脸 const detections = await faceapi.detectAllFaces(img,options).withFaceLandmarks().withFaceDescriptors(); const currentTime2 = moment().format("YYYY-MM-DD HH:mm:ss"); const resizedDetections = faceapi.resizeResults(detections, displaySize); const results = resizedDetections.map((d) => faceMatcher.findBestMatch(d.descriptor)); return results; } /** * 上传人脸信息 */ app.post("/post-face",upload.array('files',6),async (req,res)=>{ let imgs=[] for (let i = 0; i < req.files.length; i++) { imgs.push(req.files[i].path) } let label = req.body.label logger.info(`上传${label}人脸信息`) console.log('---------------',label) let result = await uploadLabeledImages(imgs, label); console.log('---------------',result) if(result===true){ logger.info(`上传${label}人脸信息成功`) res.json({code:200, message:"录入成功"}) }else{ // let result = await getDescriptorsFromDB(File1); imgs.forEach(e=>{ fs.unlink(e,(err)=>{ if(err){ console.log('删除失败') }else{ console.log('删除成功') } }) }) logger.info(`删除${label}人脸信息,录入失败`) res.json({code:400, message:"人脸模型录入失败,请重新录入"}) } }) /**验证人脸对比 */ app.post("/check-face",upload.single('file'), async (req, res) => { const File1 = req.file.path; logger.info(`验证人脸信息识别:${File1}`) try { let result = await getDescriptorsFromDB(File1); fs.unlink(File1,(err)=>{ if(err){ console.log('删除失败') }else{ console.log('删除成功') } }) res.json({code:200,result }); } catch (error) { res.json({code:200,error }); } }); // 获取人脸模型 app.post('/get-face',upload.single('file'),async (req, res) => { try{ const label = req.body.label logger.info(`获取人脸模型:${label}`) const result=await FaceModel.findOne({ "label": label }) logger.info(`返回人脸模型:${label}:${JSON.stringify(result)}`) res.json({code:200,result}) }catch(error){ res.json({code:200,error}) } }) // 清除人脸模型 app.post("/del-face",upload.single('file'),async(req,res)=>{ const label = req.body.label logger.info(`删除人脸库${label}`) FaceModel.findOne({ "label": label }).then(re=>{ console.log('kankan---') console.log(re.images) if(re.images.length>0){ for (let i = 0; i < re.images.length; i++) { fs.unlink(re.images[i],(err)=>{ if(err){ console.log('删除失败') }else{ console.log('删除成功') } }) } } }) let result= deleteLabelImages(label) if(result){ logger.info(`删除人脸库${label};成功`) res.json({message:'success'}) }else{ logger.info(`删除人脸库${label};失败`) res.json({message:"err"}) } }) app.post("/test",async(req,res)=>{ console.log('---测试--------') res.json({message:"err"}) }) //链接数据库初始化 mongoose .connect( `mongodb://localhost/test`, { useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true, } ) .then(() => { app.listen(process.env.PORT || 80,'0.0.0.0'); console.log("DB connected and server us running."); console.log('http-sse-'+80) logger.info('数据库连接成功,服务已启动,端口号80') }) .catch((err) => { console.log(err); });