# FaceDetectSDK **Repository Path**: librastalker/face-detect-sdk ## Basic Information - **Project Name**: FaceDetectSDK - **Description**: 百度前端实战训练营大作业项目,实现了图像人脸框和关键点检测模型的SDK封装,以及基于vue开发的调用人脸检测模型SDK的展示界面。 - **Primary Language**: TypeScript - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 0 - **Created**: 2023-01-28 - **Last Updated**: 2025-12-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 基于Paddle.js WebGL计算方案实现人脸关键点检测SDK 结合PaddleDetection blazeface_1000e人脸检测模型和PaddleHub face_landmark模型实现人脸关键点检测; 模型地址: - blazeface_1000e https://github.com/PaddlePaddle/PaddleDetection/tree/release/2.5/configs/face_detection - face_landmark_localization https://github.com/PaddlePaddle/PaddleHub/tree/release/v2.3/modules/image/keypoint_detection/face_landmark_localization ## 参考版本 - Paddle.js 2.2.5 https://github.com/PaddlePaddle/Paddle.js/tree/release/v2.2.5 - PaddleDetection: 2.5 https://github.com/PaddlePaddle/PaddleDetection/tree/release/2.5 - PaddleHub: 2.3 https://github.com/PaddlePaddle/PaddleHub/tree/release/v2.3 ## 作业说明 本次作业包含两个文件夹,`facekeypoint`文件夹是本次作业的主要内容,封装了图像->人脸框+关键点 的全流程SDK,`face_detect_demo`文件夹是基于vue开发的展示界面,使用了`facekeypoint`中封装好的SDK来检测图像的人脸框和关键点。 ## 作业展示 ![image-20230128083802665](README.assets/image-20230128083802665.png) ![image-20230128083911096](README.assets/image-20230128083911096.png) ![image-20230128085937356](README.assets/image-20230128085937356.png) ### 展示说明 - 本次作业基于Vue3+antd-vue,仿照百度AI开放平台的人脸检测功能演示区域实现了一个展示界面,该展示界面调用了自己封装好的人脸检测SDK来进行人脸检测,可以访问 http://www.librastalker.top/index.html 查看我的展示界面。 - 本次作业还部署了一个简易版本的测试用的展示界面,网址为[paddlejs mobilenet demo (librastalker.top)](http://www.librastalker.top/demo/index.html),来源于`Paddle.js/packages/paddlejs-models/facedetect/src/demo`,略有修改。 - 展示界面可以通过网络图片URL,本地图片,以及页面的示例图片三种方式加载图片进行人脸检测。 - 展示界面右上角有图片检测和实时检测两个功能切换按钮,但是目前只实现了图片的人脸检测功能。实时检测需要通过摄像头捕获视频流,来对视频中的人脸进行实时检测,但是由于自己的设备性能较低,实时检测时设备经常会卡崩掉,难以测试,所以这部分暂时还没实现视频流人脸检测的功能。 ### 注意事项 - 首次进入展示页面时会加载一张默认图片,初始化模型进行检测。模型初始化需要一定时间,初始化时可能会造成卡顿,用户设备性能低的话可能无法顺利进行检测,会出现闪退等情况。 - 使用网络图片URL进行人脸检测时,由于跨域问题可能无法加载图片检测。 ## 亮点介绍 - 封装了 图像->人脸框+关键点 的全流程SDK - 符合 https://ai.baidu.com/sdk 的接口命名 - 代码分层良好,借助webpack模块化开发 - README文档完善 - 代码基本符合ESLint规范,参数类型明确 - 注释完善,函数签名完善,明确说明了函数的作用、参数和返回值的含义 - 函数长短合理,逻辑性合理,遵循高内聚低耦合的设计模式 ## 完成情况 ### 已完成 - 人脸框检测模型的前后处理、初始化 - 人脸关键点检测模型的前后处理、初始化 - 封装 图像->人脸框+关键点 的全流程SDK - 符合 https://ai.baidu.com/sdk 的接口命名 ### 待完成 - 将人脸识别模型换成blazeface_1000e > 使用tools/model-check检查模型后发现blazeface_1000e人脸检测模型有4个算子没有完成 > ``` > python tools/model-check/check/check.py --modelPath=packages/paddlejs-converter/origin_model/blazeface_1000e/model.pdmodel --paramPath=packages/paddlejs-converter/origin_model/blazeface_1000e/model.pdiparams > Model has unsupported op ! > ['exp', 'slice', 'multiclass_nms3', 'stack'] > Model can run in PC WebGL successfully. > Model can run in WISE WebGL successfully. > ``` > 实现了一部分slice算子后发现算子开发较难、耗时较长,可能无法全部实现,于是使用了原先`packages/paddlejs-models/facedetect/src/index.ts`中的模型与face_landmark_localization模型进行人脸框和关键点检测。 - E2E验证 ## 使用方法 ### node开发环境 在终端里运行 ```shell npm install npm run dev ``` 浏览器打开 `http://localhost:8868` ### node生产环境 在终端里运行 ```shell npm install . ``` index.ts ```TypeScript import {createImage, FaceDetector, interfaces} from 'facekeypoint'; const {ModelConfig, FaceInfo} = interfaces; const imgPath = 'img/multi_small_face.jpeg'; const face_detect_model_config: ModelConfig = { modelPath: 'https://paddlejs.cdn.bcebos.com/models/fuse/facedetect_opt/model.json', mean: [0.407843137, 0.458823529, 0.482352941], std: [0.5, 0.5, 0.5], feedShape: { fc: 3, fw: 1024, fh: 1024 } }; const face_keypoint_model_config: ModelConfig = { modelPath: 'model/face_landmark_localization/model.json', feedShape: { fc: 1, fw: 60, fh: 60 } }; const imgEle = await createImage(imgPath); const img_bitmap = await createImageBitmap(imgEle); const faceDetector = new FaceDetector(face_detect_model_config, [['landmark68', face_keypoint_model_config]]); await faceDetector.init(); const res: FaceInfo = await faceDetector.detect(img_bitmap); console.log(res); ``` 由于内部逻辑使用了DOM,需要使用html-webpack-plugin等在浏览器端执行,暂时无法直接在控制台中执行 ### script标签引用 在终端里运行 ```shell npm run build ``` index.html ```HTML ``` index.js ```JavaScript const {createImage, FaceDetector, interfaces} = paddlejs.facekeypoint; // const {ModelConfig, FaceInfo} = interfaces; const imgPath = 'img/multi_small_face.jpeg'; const face_detect_model_config = { modelPath: 'https://paddlejs.cdn.bcebos.com/models/fuse/facedetect_opt/model.json', mean: [0.407843137, 0.458823529, 0.482352941], std: [0.5, 0.5, 0.5], feedShape: { fc: 3, fw: 1024, fh: 1024 } }; const face_keypoint_model_config = { modelPath: 'model/face_landmark_localization/model.json', feedShape: { fc: 1, fw: 60, fh: 60 } }; async function run(){ const imgEle = await createImage(imgPath); const img_bitmap = await createImageBitmap(imgEle); const faceDetector = new FaceDetector(face_detect_model_config, [['landmark68', face_keypoint_model_config]]); await faceDetector.init(); const res = await faceDetector.detect(img_bitmap); console.log(res); } run(); ``` ### 返回说明 | 字段 | 必选 | 类型 | 说明 | | :--: | :--: | :--: | :--: | |+location | 是 | array |人脸在图片中的位置 | |++left | 是 | number |人脸区域离左边界的距离| |++top | 是 | number |人脸区域离上边界的距离| |++width | 是 | number |人脸区域的宽度| |++height | 是 | number |人脸区域的高度| |+face_probability| 是 | number |人脸置信度,范围【0~1】,代表这是一张人脸的概率,0最小、1最大。| |+landmark68 | 否 |array |68个特征点位置 face_field包含landmark68时返回| ### 返回示例 ```json [ { "face_probability": 0.9999551773071289, "location": { "left": 189.60514831542966, "top": 373.5043487548827, "width": 58.93386840820313, "height": 76.06300354003906 }, "landmark68": [ { "x": 189.74958720803258, "y": 403.02942955493916 }, { "x": 189.10191151499745, "y": 412.0189151763915 }, { "x": 189.1603065729141, "y": 420.4263811111449 }, ... ] }, { "face_probability": 0.9996778964996338, "location": { "left": 735.6203918457031, "top": 31.359802246093693, "width": 53.21441650390626, "height": 68.90792846679688 }, "landmark68": [ { "x": 737.0279772281647, "y": 61.23914527893061 }, { "x": 736.0815037488937, "y": 68.29021310806269 }, { "x": 736.9159166812897, "y": 74.30404806137079 }, ... ] }, ... ] ``` ## facekeypoint文件结构 - demo —— 来源于`Paddle.js/packages/paddlejs-models/facedetect/src/demo`,略有修改,展示用 - index.html —— 一个简易的展示界面 - index.ts - img —— 示例图片,来源于`Paddle.js/packages/paddlejs-models/facedetect/src/img`,无修改,展示用 - multi_small_face.jpeg - single_big_face.jpeg - lib —— `npm run build`的输出目录 - index.js —— 编译好的SDK,可以直接使用script标签导入 - LICENSE —— 与Paddle.js的开源协议相同 - model —— 所有的预训练模型 - blazeface_1000e —— 由原始的PaddlePaddle模型转换后的Paddle.js模型 - chunk_1.dat —— 模型参数 - model.json —— 模型结构 - face_landmark_localization —— 由原始的PaddlePaddle模型转换后的Paddle.js模型 - chunk_1.dat —— 模型参数 - model.json —— 模型结构 - origin_model —— 原始PaddlePaddle模型 - blazeface_1000e —— 使用PaddleDetection导出的人脸框检测模型 - infer_cfg.yml - model.pdiparams - model.pdiparams.info - model.pdmodel - face_landmark_localization —— 使用PaddleHub导出的人脸关键点检测模型 - model.pdiparams - model.pdmodel - package.json - README.md - src —— 主要代码 - commons - interface.ts —— 所有的接口 - customOp —— 自己实现的算子 - abs.ts - modelSDK —— 封装的SDK - base.ts —— 所有检测类的基类 - facedetector.ts —— 人脸框检测 - landmark68.ts —— 人脸关键点检测 - index.ts —— 入口文件 - tsconfig.json - unused —— 废稿与半成品 - new_slice_test.ts —— 测试slice算子 - slice.ts —— 自己实现的slice算子 - webpack.dev.js —— 开发环境配置 - webpack.prod.js —— 生产环境配置 ### 目录说明 |目录|说明| |-|-| |demo|来源于`Paddle.js/packages/paddlejs-models/facedetect/src/demo`,略有修改,展示用| |img|来源于`Paddle.js/packages/paddlejs-models/facedetect/src/img`,无修改,展示用| |lib|`npm run build`的输出目录,可以直接使用script标签导入其中的`index.js`,即可使用SDK| |model|所有的预训练模型| |src|项目的主要代码| |unused|废稿与半成品| ## 项目架构 ```TypeScript import {interfaces, createImage, FaceDetector} from 'facekeypoint'; ``` ### interfaces 包含了所有的接口,属性: #### all_supported_face_field 在人脸框检测的基础上所有支持的额外检测负载,目前只有一个68关键点检测,后续可以扩展,比如增加表情识别等 ```TypeScript export const all_supported_face_field = { landmark68: Landmark68 }; ``` #### FeedShape 提供给模型的输入的形状 ```TypeScript export interface FeedShape { // 通道数 fc: number; // 宽度 fw: number; // 高度 fh: number; } ``` #### ModelConfig 模型的可选配置 ```TypeScript export interface ModelConfig { // 模型的路径,可以为相对路径或网络URL modelPath?: string; // 输入的图像转化成0-1之间的浮点数后的三个通道的平均值,预处理时对输入标准化时用到 mean?: number[]; // 输入的图像转化成0-1之间的浮点数后的三个通道的标准差,预处理时对输入标准化时用到 std?: number[]; // 提供给模型的输入的形状 feedShape?: FeedShape; // 因为有的模型里自带了这个参数所以这个参数不是必需的 } ``` #### NaturalSize 输入图像的原始宽度和高度 ```TypeScript export interface NaturalSize { naturalWidth: number; naturalHeight: number; } ``` #### Location 人脸框的位置,左、上、宽、高,单位为像素 ```TypeScript export interface Location { // 人脸图片的左边界与原始图片的左边界的像素距离,一般为非负数 left: number; // 人脸图片的上边界与原始图片的上边界的像素距离,一般为非负数 top: number; // 人脸图片的像素宽度,正数 width: number; // 人脸图片的像素高度,正数 height: number; } ``` #### Coordinate 关键点相对于原始图片的坐标,x横坐标,y纵坐标,单位为像素 ```TypeScript export interface Coordinate { x: number; y: number; } ``` #### FaceInfo 模型最终的返回结果,API命名参考:https://ai.baidu.com/sdk ```TypeScript export interface FaceInfo { // 人脸框的位置,左、上、宽、高 location: Location; // 人脸框的置信度 face_probability: number; // 68个人脸关键点的坐标 landmark68?: Coordinate[]; } ``` ### createImage 从图片路径创建图片元素,等待图片加载完成后再resolve,来源于`Paddle.js/packages/paddlejs-models/facedetect/src/index.ts` **参数** - **imgPath** 图片的路径,可以是相对路径或网络URL **返回** - resolve图片元素的Promise ```TypeScript function createImage(imgPath: string): Promise { return new Promise(resolve => { const image = new Image(); image.crossOrigin = 'anonymous'; image.onload = () => { resolve(image); }; image.src = imgPath; }); } ``` ### FaceDetector 人脸检测的核心部分 **属性** #### modelConfig: *ModelConfig* 由于模型配置只在初始化时用到,因此如果需要更改配置,就直接重新实例化一个类吧。 #### feedShape: *FeedShape* 提供给模型的输入的形状 #### face_field: *[string, ModelSDK][]* 需要使用的额外检测负载,ModelSDK的意思是ModelSDK的子类的实例。 **方法** #### constructor 初始化 modelConfig 和 face_field **参数** - **modelConfig** 模型配置 - **face_field** 需要使用的额外检测负载 **返回** - 无 ```TypeScript constructor(modelConfig?: ModelConfig, face_field: [string, ModelConfig?][] = []): void; ``` #### init 初始化当前模型和所有的额外负载,在当前模型和所有额外负载都初始化完成后才会resolve **返回** - Promise,在当前模型和所有额外负载都初始化完成后才会resolve ```TypeScript async init(): Promise; ``` #### detect 从图片中检测所有的人脸,并对所有检测出的人脸区域使用检测负载进行再次检测,并添加到结果中 **参数** - **input** 原始图片,可以通过createImageBitmap()获取 - **opts** 可选参数 - **opts.threshold** 取值范围是0-1,默认0.6,表示只取置信度大于此数值的人脸 - **opts.shrink** 取值范围是0-1,默认0.4,预测前先将图片按此比例缩小,对于占图片比例较大的人脸可以提升检测效果 **返回** - 每个人脸识别的结果,包含了所有请求负载,返回的格式参考https://ai.baidu.com/sdk ```TypeScript async detect( input: ImageBitmap, opts? ): Promise; ``` **注意:一定要先确保init方法resolve了才能调用detect** ```TypeScript const faceDetector = new FaceDetector(face_detect_model_config, [['landmark68', face_keypoint_model_config]]); await faceDetector.init(); const res: FaceInfo = await faceDetector.detect(img_bitmap); console.log(res); ``` ## 参考文献 [1] https://github.com/PaddlePaddle/Paddle.js [2] https://github.com/PaddlePaddle/PaddleDetection [3] https://github.com/PaddlePaddle/PaddleHub [4] https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement/getContext [5] https://developer.mozilla.org/zh-CN/docs/Web/API/WebGLRenderingContext/shaderSource [6] https://github.com/PaddlePaddle/Paddle.js/issues/392 [7] https://stackoverflow.com/questions/29059306/three-js-webgl-invalid-operation-bindtexture-object-not-from-this-context/29067763 [8] https://stackoverflow.com/questions/51582282/error-when-creating-textures-in-webgl-with-the-rgb-format [9] https://www.webpackjs.com/configuration/output/#outputlibrary [10] https://arxiv.org/abs/1907.05047