上传视频时截取正脸照片

张开发
2026/4/14 22:42:21 15 分钟阅读

分享文章

上传视频时截取正脸照片
借助ai模型vladmandic/face-api实现截取视频中的正脸照片npm i vladmandic/face-api加载模型//可以加载CDN资源const MODEL_URL ‘https://cdn.jsdelivr.net/npm/vladmandic/face-api/model/’//也可以将face-api的模型直接拷贝下来放在public下const MODEL_URL ‘/models’;//在public下新建文件夹models将模型文件放到该文件夹下如下图所示templatediv classface-extractor-containerdiv classcardh2Vue2视频正脸自动提取/h2!--状态显示--p:class[status, { error: isError }]{{statusText}}/p!--进度条--div v-ifprocessingclassprogress-containerdiv classprogress-bar:style{ width: progress % }/divspan{{progress}}%/span/div!--操作按钮--div classcontrolsinput typefilereffileInputacceptvideo/*changehandleFileUploadstyledisplay: nonebutton classbtnclick$refs.fileInput.click():disabled!modelsLoaded || processing{{processing?正在处理...:上传视频并提取}}/button/div!--结果展示--div v-ifbestFace.bestDataUrlclassresult-areap检测到的最佳正脸截图/pimg:srcbestFace.bestDataUrlclassresult-img/br/button classbtn download-btnclickdownloadImage下载截图/button/div!--隐藏的辅助元素--video refhiddenVideomuted styledisplay: none/videocanvas refhiddenCanvasstyledisplay: none/canvas/div/div/templatescript// 注意如果通过 npm 安装使用 import * as faceapi from face-api.js// 这里假设通过 CDN 在 index.html 引入了 face-api.min.jsimport*as faceapi fromvladmandic/face-apiexportdefault{data(){return{modelsLoaded:false,processing:false,isError:false,statusText:正在初始化 AI 模型...,progress:0,bestFace:{score:100,// 分数越小越好越对称bestDataUrl:null},sampleStep:0.5,// 采样间隔秒越小越精细但越慢};},mounted(){this.initModels();},methods:{// 1. 加载模型asyncinitModels(){constMODEL_URL/models;constMODEL_URLhttps://cdn.jsdelivr.net/npm/vladmandic/face-api/model/;try{// 加载人脸检测和特征点识别模型await faceapi.nets.tinyFaceDetector.loadFromUri(MODEL_URL);await faceapi.nets.faceLandmark68Net.loadFromUri(MODEL_URL);this.modelsLoadedtrue;this.statusText模型加载成功请上传视频;}catch(err){this.isErrortrue;this.statusText模型加载失败请检查网络或 CORS 限制;console.error(err);}},// 2. 处理文件上传asynchandleFileUpload(event){constfileevent.target.files[0];if(!file)return;this.processingtrue;this.progress0;this.bestFace.score100;this.bestFace.bestDataUrlnull;this.statusText读取视频中...;constvideothis.$refs.hiddenVideo;video.srcURL.createObjectURL(file);video.onloadedmetadataasync(){await this.startExtraction();};},// 3. 核心提取逻辑asyncstartExtraction(){constvideothis.$refs.hiddenVideo;constdurationvideo.duration;for(let currentTime0;currentTimeduration;currentTimethis.sampleStep){// 跳转到指定时间点不播放video.currentTimecurrentTime;// 等待视频跳转完成await newPromise(resolve(video.onseekedresolve));// 进行人脸检测constdetectionawait faceapi.detectSingleFace(video,new faceapi.TinyFaceDetectorOptions()).withFaceLandmarks();if(detection){constscorethis.calculateFaceScore(detection.landmarks);// 如果得分比之前的好则更新截图if(scorethis.bestFace.score){this.bestFace.scorescore;this.captureFrame();}}// 更新进度this.progressMath.round((currentTime/duration)*100);}this.finish();},// 4. 计算正脸分值基于面部对称性calculateFaceScore(landmarks){constnoselandmarks.getNose()[0];constjawlandmarks.getJawOutline();constleftEdgejaw[0];constrightEdgejaw[16];// 鼻子到左边缘和右边缘的距离constdistLMath.abs(nose.x-leftEdge.x);constdistRMath.abs(nose.x-rightEdge.x);// 理想正脸比例为 1:1计算其偏离程度returnMath.abs(distL/distR-1);},// 5. 截取当前视频帧captureFrame(){constvideothis.$refs.hiddenVideo;constcanvasthis.$refs.hiddenCanvas;canvas.widthvideo.videoWidth;canvas.heightvideo.videoHeight;constctxcanvas.getContext(2d);ctx.drawImage(video,0,0,canvas.width,canvas.height);this.bestFace.bestDataUrlcanvas.toDataURL(image/jpeg,0.9);},finish(){this.processingfalse;this.progress100;this.statusTextthis.bestFace.bestDataUrl?提取完成:未检测到人脸;},downloadImage(){constlinkdocument.createElement(a);link.hrefthis.bestFace.bestDataUrl;link.downloadbest_face.jpg;link.click();}}};/scriptstyle scoped.face-extractor-container{display:flex;justify-content:center;padding:40px;font-family:Arial,sans-serif;}.card{background:white;padding:2rem;border-radius:12px;box-shadow:04px6pxrgba(0,0,0,0.1);width:100%;max-width:500px;}.status{color:#666;font-size:0.9rem;}.status.error{color:#ff4d4f;}.progress-container{width:100%;background:#eee;height:20px;border-radius:10px;margin:20px0;position:relative;overflow:hidden;}.progress-bar{background:#1890ff;height:100%;transition:width0.2s;}.progress-container span{position:absolute;top:0;left:50%;transform:translateX(-50%);font-size:12px;line-height:20px;color:#333;}.btn{background:#1890ff;color:white;border:none;padding:10px20px;border-radius:4px;cursor:pointer;}.btn:disabled{background:#d9d9d9;cursor:not-allowed;}.result-area{margin-top:30px;}.result-img{width:100%;border:3px solid #52c41a;border-radius:8px;}.download-btn{background:#52c41a;margin-top:10px;}/style但在上传视频没有人脸的视频也能截取到照片包括闭眼照片可能功能主要是五官截取本文章是为了记录分享欢迎大家评论区留言~

更多文章