# 人脸检测 SDK

微信小程序人脸检测 SDK 是鳄梨科技提供的**人脸检测**、**人脸分析**及**人脸上报**服务，
支持在小程序端对视频推流`LivePusherContext实例`和图片进行人脸检测分析。

## :sparkles: 核心功能

1. 内置一套人脸分析和提示的规则，针对实时推流进行人脸分析，显示 toast 提示，对人脸变化进行上报

2. SDK 导出内置的规则和`FaceMonitor类`，`FaceMonitor类`支持对实时推流截取的图片进行自定义处理

3. `FaceMonitor类`支持对接口请求、是否显示检测 toast 进行配置，支持自定义业务数据`metadata`

4. `FaceMonitor类`提供了 获取推流截屏图片、获取图片像素点数据、人脸分析、接口请求、图片上传等功能

## 🔨 FaceMonitor 类提供的配置项

### 接口请求 `requestHeader`

> 实例化时传入的`requestHeader`会覆盖默认值

```js
// 默认配置
const DefaultRequestHeader = {
  Accept: 'application/json',
  'X-Avocado-Source': 'miniprogram',
  Authorization: 'Basic ' + wx.getStorageSync('authToken')
}

// 自定义配置
const CusRequestHeader = {
  'Content-Type': 'application/json',
  Accept: 'application/json',
  'X-Avocado-Source': 'miniprogram',
  Authorization: 'Basic ' + wx.getStorageSync('authToken'),
  'X-Avocado-Version': '',
  'X-Position-Token': '',
  'X-Wx-Appid': ''
}
// 配置示例
this.FaceMonitor = new FaceMonitor({
  requestHeader: CusRequestHeader
})
```

### 人脸检测 `config`

> 实例化时传入的`config`会和默认配置合并，优先级高于默认配置

```js
// 默认配置
const FaceDetectOneTimeCostMax = 1000 / 1.5
const DefalutConfig = {
  showToast: true, // 是否显示人脸异常的提示
  faceDetectOneTimeCostMax: FaceDetectOneTimeCostMax, // 一次人脸识别的最大耗时
  needPredict: true // 是否需要预检，差别: 预检不通过会直接关闭人脸检测
}

// 自定义配置
const CusConfig = {
  needPredict: false
}
// 配置示例
this.FaceMonitor = new FaceMonitor({
  config: CusConfig
})
```

### 业务数据 `metadata`

> 实例化时传入的`metadata`会和默认数据合并，优先级高于默认数据

```js
// 默认配置
const DefalutMetadata = {
  cheatKey: 'default' // 作弊上报key
}

// 自定义配置
const CusMetadata = {
  info: patternName, // 类型：string， 上报图片的标题或者表述，必填
  stepToken,
  mediaName: streamName,
  cheatKey: token
}
// 配置示例
this.FaceMonitor = new FaceMonitor({
  metadata: CusMetadata
})
```

## :factory: FaceMonitor 类提供的方法

### getSnapshotData

> 获取快照  
> 以 Promise 风格 调用：支持

- 参数

| 属性        | 类型   | 默认值 | 必填 | 说明                                           |
| :---------- | :----- | :----- | :--- | :--------------------------------------------- |
| livePushCtx | object | -      | 是   | 推流组件实例                                   |
| quality     | string | raw    | 否   | 图片的质量，默认原图。有效值为 raw、compressed |

- 返回值

Object res

| 属性          | 类型   | 说明               |
| :------------ | :----- | :----------------- |
| tempImagePath | string | 图片文件的临时路径 |
| width         | string | 图片的宽度         |
| height        | string | 图片的高度         |

- 使用示例

```js
const livePushCtx = wx.createLivePusherContext('pusher')
const res = await this.FaceMonitor.getSnapshotData(livePushCtx, 'raw、compressed')
```

### getImageData

> 获取图片像素点数据  
> 以 Promise 风格 调用：支持

- 参数

| 属性          | 类型   | 默认值 | 必填 | 说明               |
| :------------ | :----- | :----- | :--- | :----------------- |
| width         | number | -      | 是   | 图片的宽度         |
| height        | number | -      | 是   | 图片的高度         |
| tempImagePath | string | -      | 是   | 图片文件的临时路径 |

- 返回值

| 属性          | 类型              | 说明                                                  |
| :------------ | :---------------- | :---------------------------------------------------- |
| tempImagePath | string            | 图片文件的临时路径                                    |
| width         | number            | 图像数据矩形的宽度                                    |
| height        | number            | 图像数据矩形的高度                                    |
| data          | Uint8ClampedArray | 图像像素点数据，一维数组，每四项表示一个像素点的 rgba |

- 使用示例

```js
const res = await this.FaceMonitor.getImageData({
  width,
  height,
  tempImagePath
})
```

### faceAnalyse

> 人脸分析  
> 以 Promise 风格 调用：支持

- 参数

| 属性          | 类型     | 默认值 | 必填 | 说明               |
| :------------ | :------- | :----- | :--- | :----------------- |
| width         | number   | -      | 是   | 图片的宽度         |
| height        | number   | -      | 是   | 图片的高度         |
| tempImagePath | string   | -      | 是   | 图片文件的临时路径 |
| data          | string   | -      | 是   | 图片文件的临时路径 |
| fn            | function | -      | 否   | 自定义分析处理方法 |

- 默认返回值

Object res

| 属性          | 类型   | 说明                |
| :------------ | :----- | :------------------ |
| tempImagePath | string | 图片文件的临时路径  |
| status        | string | 人脸状态            |
| toastType     | string | 提示类型            |
| res           | Object | faceDetect 原始数据 |

- 自定义分析时返回值

Object res

| 属性          | 类型   | 说明                |
| :------------ | :----- | :------------------ |
| tempImagePath | string | 图片文件的临时路径  |
| res           | Object | faceDetect 原始数据 |

- 使用示例

```js
const imageData = {} // imageData对象
// 自由组合api，对人脸识别结果进行自定义分析时使用
this.FaceMonitor.faceAnalyse(imageData, (res) => {
  console.log(res)
})

// 默认返回

const res = await this.FaceMonitor.faceAnalyse(imageData)
console.log(res)
```

### commonUpload

> wx.uploadFile 图片上传  
> 以 Promise 风格 调用：支持

- 参数

| 属性     | 类型   | 默认值                                 | 必填 | 说明                                                                          |
| :------- | :----- | :------------------------------------- | :--- | :---------------------------------------------------------------------------- |
| url      | string | -                                      | 是   | 开发者服务器地址                                                              |
| filePath | string | -                                      | 是   | 要上传文件资源的路径 (本地路径)                                               |
| name     | string | file                                   | 否   | 默认 file 文件对应的 key，开发者在服务端可以通过这个 key 获取文件的二进制内容 |
| formData | object | -                                      | 否   | HTTP 请求中其他额外的 form data                                               |
| header   | object | new FaceMonitor 时传入的 requestHeader | 否   | HTTP 请求 Header，Header 中不能设置 Referer                                   |

- 返回值

Object res

| 属性 | 类型   | 说明                 |
| :--- | :----- | :------------------- |
| url  | string | 上传后获取的图片地址 |

- 使用示例

```js
const res = await this.FaceMonitor.commonUpload({
  url,
  filePath
})
console.log(res.url)
```

### request

> wx.request 接口请求，支持失败重试  
> 以 Promise 风格 调用：支持

- 参数

| 属性       | 类型   | 默认值                                 | 必填 | 说明                                        |
| :--------- | :----- | :------------------------------------- | :--- | :------------------------------------------ |
| url        | string | -                                      | 是   | 接口完整路径包括域名                        |
| method     | string | post                                   | 否   | 请求方式                                    |
| data       | object | -                                      | 否   | 请求参数                                    |
| timeout    | number | 5000                                   | 否   | 超时时间及失败重试时间间隔                  |
| retryTimes | number | 2                                      | 否   | 失败重试次数                                |
| header     | object | new FaceMonitor 时传入的 requestHeader | 否   | HTTP 请求 Header，Header 中不能设置 Referer |

- 返回值

Object res

| 属性 | 类型   | 说明             |
| :--- | :----- | :--------------- |
| res  | object | 服务端返回的数据 |

- 使用示例

```js
const res = await this.FaceMonitor.request({
  url,
  data: {
    photo,
    offset,
    scene,
    info: metadata?.info || '',
    metadata
  }
})
console.log(res)
```

### start

> 推流组件人脸监控开始

- 参数

| 属性                  | 类型     | 默认值 | 必填 | 说明                                                         |
| :-------------------- | :------- | :----- | :--- | :----------------------------------------------------------- |
| FaceMonitorStartParam | object   | -      | 是   | 推流开始参数                                                 |
| fn                    | function | -      | 否   | 如果传入参数，使用方可对微信官方返回的人脸结果进行自定义处理 |

- FaceMonitorStartParam

| 属性        | 类型   | 默认值     | 必填 | 说明                                           |
| :---------- | :----- | :--------- | :--- | :--------------------------------------------- | --------------------------------------- |
| livePushCtx | object | -          | 是   | 推流组件实例                                   |
| quality     | string | compressed | 否   | 图片的质量，默认原图。有效值为 raw、compressed |
| monitorType | string | monitor    | 否   | 检测类型 有效值为 monitor: 实时检测            | predict: 预检，检测设备是否支持人脸识别 |

- 使用示例

```js
const livePushCtx = wx.createLivePusherContext('pusher')
// 预检
this.FaceMonitor.start({ livePushCtx, monitorType: 'predict' })

// 实时检测
this.FaceMonitor.start({ livePushCtx })

// 自定义分析人脸结果
this.FaceMonitor.start({ livePushCtx }, (res) => {
  console.log(res)
})
```

### stop

> 推流组件人脸监控结束

- 参数

| 属性        | 类型   | 默认值 | 必填 | 说明         |
| :---------- | :----- | :----- | :--- | :----------- |
| livePushCtx | object | -      | 是   | 推流组件实例 |

### reportPhoto

> 上报图片  
> 以 Promise 风格 调用：支持

- 参数

| 属性     | 类型   | 默认值       | 必填 | 说明                                                  |
| :------- | :----- | :----------- | :--- | :---------------------------------------------------- |
| url      | string | -            | 是   | 上报的服务的 url                                      |
| photo    | string | -            | 是   | upload 后获取的图片线上地址                           |
| scene    | number | 1            | 是   | 1、第一次进入 2、离开再进入 3、一变二， 4、没有人脸时 |
| offset   | number | 0            | 是   | 视频偏移量：图片所在视频的位置                        |
| metadata | object | { info: '' } | 是   | 业务的自定义数据                                      |

- 使用示例

```js
const reportUrl = `${CONFIG.API_BASE_URL}/cheatDetection/${cheatKey}/reportPhoto`

this.reportPhoto({
  url: reportUrl,
  photo,
  scene,
  offset,
  metadata
})
```

## :gem: MonitorRules 内置检测规则

```js
// 人脸检测状态
export const FaceType = {
  NoFace: 'noFace',
  SingleFace: 'singleFace',
  MultiFace: 'multiFace',
  MaskFace: 'maskFace',
  FaceCenter: 'faceCenter'
}
// toast提示
export const ToastType = {
  noFace: '请保持人脸在画面中',
  multiFace: '检测到多人入镜',
  mouth: '请勿遮挡嘴巴',
  faceCenter: '请正对摄像头'
}

export const DefaultMonitorRules = [checkNoFace, checkMultiFace, checkMaskMouth]
```

## :package: 使用示例

```js
import { FaceMonitor, MonitorRules } from '../../common/aiService/FaceMonitor'

// 初始化
this.FaceMonitor = new FaceMonitor({
  metadata: {
    stepToken,
    mediaName: streamName,
    info: patternName,
    cheatKey: token
  },
  config: {
    needPredict: false
  },
  requestHeader: {
    'Content-Type': 'application/json',
    Accept: 'application/json',
    'X-Avocado-Source': 'miniprogram',
    Authorization: 'Basic ' + wx.getStorageSync('authToken'),
    'X-Avocado-Version': CONFIG.VERSION,
    'X-Position-Token': curSessionToken,
    'X-Wx-Appid': appId
  }
})

// 开始检测
this.FaceMonitor.start({ livePushCtx: this.ctx })

// 结束
this.FaceMonitor.stop(this.ctx)

// 身份验证流程只进行图片上报
const reportUrl = `${CONFIG.API_BASE_URL}/cheatDetection/${cheatKey}/reportPhoto`
this.FaceMonitor.reportPhoto({
  url: reportUrl,
  photo,
  scene,
  offset,
  metadata
})

// 内置规则，对人脸分析结果进行自定义处理时使用

const { DefaultMonitorRules, FaceType, ToastType, checkNoFace, checkMultiFace, checkMaskMouth, checkFaceCenter } = MonitorRules
```

## :link: 相关文档

1. [LivePusherContext](https://developers.weixin.qq.com/miniprogram/dev/component/live-pusher.html)
2. [snapshot](https://developers.weixin.qq.com/miniprogram/dev/api/media/live/LivePusherContext.snapshot.html)
3. [imageData 对象](https://developers.weixin.qq.com/miniprogram/dev/api/canvas/ImageData.html)
4. [faceDetect](https://developers.weixin.qq.com/miniprogram/dev/api/ai/face/wx.faceDetect.html)
5. [OffscreenCanvas](https://developers.weixin.qq.com/miniprogram/dev/api/canvas/wx.createOffscreenCanvas.html)
