
# 动作活体检测 - DetectLive
#### 功能介绍
**动作活体检测是实人检测的常见技术方案之一**，通过判断视频中的人物动作与传入动作列表是否一致来识别视频中人物是否为活体，仅检测指定动作是否发生，不对人物真实性做校验，如果有多张人脸出现，则选取最大的人脸进行判定。新老用户均可用该接口。
**实人检测方案可结合具体业务诉求、成本等因素灵活设计，动作活体检测可作为其中一种技术手段，与其他方案按需组合使用**。
**前提条件：**
请确保您已开通[人脸识别服务](https://console.huaweicloud.com/frs/?locale=zh-cn#/frs/management/faceRecognized)，具体操作方法请参见[申请服务](https://support.huaweicloud.com/api-face/face_02_0006.html)。
**约束限制：**
- 目前支持检测视频文件，或视频的Base64编码，不支持直接检测视频流，需要用户客户端自己获取视频流并保存成文件，客户需要确保传入的人脸视频由摄像头实时采集，然后调用活体检测接口。
- 视频文件大小**不超过8MB** ，建议客户端压缩到**200KB\~2MB**。
- application/json请求的body中，请使用标准Json格式。
- Base64编码中请勿使用回车换行。
- 系统不保存用户视频。
- 具体的约束限制信息请参见[约束与限制](https://support.huaweicloud.com/api-face/face_02_0078.html)章节。
**建议：**
- 建议帧率**10fps～30fps**。
- 视频文件的大小建议客户端压缩到**200KB\~2MB**。
 
#### 调试
您可以在[API Explorer](https://apiexplorer.developer.huaweicloud.com/apiexplorer/doc?product=FRS&api=DetectLiveByUrl)中调试该接口，支持自动认证鉴权。API Explorer可以自动生成SDK代码示例，并提供SDK代码示例调试功能。
#### 授权信息
账号具备所有API的调用权限，如果使用账号下的IAM用户调用当前API，该IAM用户需具备调用API所需的权限，具体权限要求请参见[权限和授权项](https://support.huaweicloud.com/usermanual-face/face_01_0011.html)。
#### URI
POST /v1/{project_id}/live-detect
表1路径参数 
| 参数         | 是否必选 | 参数类型   | 描述                                                                                                                                                                                                                                                                                                                                                                   |
|:---|:---|:---|:---|
| project_id | 是    | String | **参数解释：** 项目ID，获取方法请参见[获取项目ID/账号名/AK/SK](https://support.huaweicloud.com/api-face/face_02_0056.html)。 **约束限制：** 不涉及。 **取值范围：** 不涉及。 **默认取值：** 不涉及。 |
   
#### 请求参数
表2请求Header参数 
| 参数                    | 是否必选 | 参数类型   | 描述                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
|:---|:---|:---|:---|
| X-Auth-Token          | 是    | String | **参数解释：** 用户Token，用于获取操作API的权限。获取方法请参见[认证鉴权](https://support.huaweicloud.com/api-face/face_02_0004.html)。 **约束限制：** 不涉及。 **取值范围：** 不涉及。 **默认取值：** 不涉及。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| Content-Type          | 是    | String | **参数解释：** 发送的实体的MIME类型。 **约束限制：** 不涉及。 **取值范围：** 参数值为"application/json" **默认取值：** 不涉及。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| Enterprise-Project-Id | 否    | String | **参数解释：** 企业项目ID。FRS支持通过企业项目管理（EPS）对不同用户组和用户的资源使用，进行分账，当前仅支持按需计费模式。 获取方法：进入"[企业项目管理](https://console.huaweicloud.com/eps/?#/eps/manager/projects)"页面，单击企业项目名称，在企业项目详情页获取Enterprise-Project-Id（企业项目ID）。 ![](https://support.huaweicloud.com/api-face/zh-cn_image_0000002572719696.png "点击放大") 说明： 创建企业项目后，在传参时，有以下三类场景。 - 携带正确的ID，正常使用FRS服务，账单的企业项目会被分类到企业ID对应的企业项目中。  - 携带格式正确但不存在的ID，正常使用FRS服务，账单的企业项目会显示对应不存在的企业项目ID。  - 不携带ID或格式错误ID（包含特殊字符等），正常使用FRS服务，账单的企业项目会被分类到"default"中。   **约束限制：** 不涉及。 **取值范围：** 不涉及。 **默认取值：** 不涉及。 |
   
表3请求Body参数 
| 参数名           | 是否必选                        | 参数类型   | 说明                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
|:---|:---|:---|:---|
| video_url     | 与video_file、video_base64三选一 | String | **参数解释：** 视频的URL路径，目前仅支持华为云上OBS的URL，使用时只需保证FRS有权限读取该OBS桶的数据。开通读取权限的操作请参见[服务授权](https://support.huaweicloud.com/api-face/face_02_0006.html)。 **约束限制：** 视频要求： - 视频Base64编码后大小不超过8MB，建议客户端压缩到**200KB\~2MB**。  - 限制视频时长1～15秒。  - 建议帧率10fps～30fps。  - 封装格式：mp4、avi、flv、webm、asf、mov。  - 视频编码格式： h261、h263、h264、hevc、vc1、vp8、vp9、wmv3。   **取值范围：** 不涉及。 **默认取值：** 不涉及。 |
| video_file    | 与video_url、video_base64三选一  | File   | **参数解释：** 本地视频文件。上传文件时，请求格式为multipart。 **约束限制：** 视频要求 - 视频文件大小不超过8MB，建议客户端压缩到**200KB\~2MB**。  - 限制视频时长1～15秒。  - 建议帧率10fps～30fps。  - 封装格式：mp4、avi、flv、webm、asf、mov。  - 视频编码格式： h261、h263、h264、hevc、vc1、vp8、vp9、wmv3。   **取值范围：** 不涉及。 **默认取值：** 不涉及。                                                                                                                |
| video_base64  | 与video_file、video_url三选一    | String | **参数解释：** 视频数据，Base64编码。 **约束限制：** - Base64编码后大小不超过8MB，建议客户端压缩到**200KB\~2MB**。  - 限制视频时长1～15秒。  - 建议帧率10fps～30fps。  - 封装格式：mp4、avi、flv、webm、asf、mov。  - 视频编码格式： h261、h263、h264、hevc、vc1、vp8、vp9、wmv3。   **取值范围：** 不涉及。 **默认取值：** 不涉及。                                                                                                                                                 |
| actions       | 是                           | String | **参数解释：** 动作代码顺序列表，英文逗号（,）分隔。建议单动作。 **约束限制：** 仅当actions的传参顺序和视频中的动作顺序一致时返回true。例如，视频中人物动作顺序为点头、嘴部动作，传参顺序需为3,4。 左右摇头动作建议角度15-30度，嘴部动作建议张嘴距离大于3厘米。 **取值范围：** 目前支持的动作有： - 1：左摇头  - 2：右摇头  - 3：点头  - 4：嘴部动作  - 5：眨眼   **默认取值：** 不涉及。                                                                                                      |
| action_time   | 否                           | String | **参数解释：** 该参数为动作时间数组拼接的字符串，数组的长度和actions的数量一致，每一项代表了对应次序动作的起始时间和结束时间，单位为距视频开始的毫秒数。 **约束限制：** 不涉及。 **取值范围：** 不涉及。 **默认取值：** 不涉及。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| nod_threshold | 否                           | double | **参数解释：** 该参数为点头动作幅度的判断门限。该值设置越大，则越难判断为点头。 **约束限制：** 不涉及。 **取值范围：** 取值范围:\[1,90\]。 **默认取值：** 10。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
   
#### 响应参数
**状态码：200**
表4响应Body参数 
| 参数           | 参数类型                                                                | 描述                                                                                                                                                                                                                                                                                                                                                                                                       |
|:---|:---|:---|
| video-result | [video-result] object         | **参数解释：** 活体检测结果，video-result数据结构请见[VideoDetectResult](https://support.huaweicloud.com/api-face/face_02_0010.html)。 调用失败时无此字段。 **约束限制：** 不涉及。 **取值范围：** 不涉及。 **默认取值：** 不涉及。 |
| warning-list | Array of [WarningList] objects | **参数解释：** 警告信息列表，warning-list数据结构请见[WarningList](https://support.huaweicloud.com/api-face/face_02_0077.html)。 调用失败时无此字段。 **约束限制：** 不涉及。 **取值范围：** 不涉及。 **默认取值：** 不涉及。           |
   
 表5video-result 
| 参数      | 参数类型                                                                | 描述                                                                                                                                                                                                                                                                                                                                                        |
|:---|:---|:---|
| alive   | Boolean                                                             | **参数解释：** 是否是活体。 **约束限制：** 不涉及。 **取值范围：** 不涉及。 **默认取值：** 不涉及。                                                                             |
| actions | Array of [ActionsList] objects | **参数解释：** 动作列表。 **约束限制：** 不涉及。 **取值范围：** 不涉及。 **默认取值：** 不涉及。                                                                             |
| picture | String                                                              | **参数解释：** 返回检测出最大人脸图片的base64编码。 其中，图片格式为jpg，分辨率与视频分辨率相等。 **约束限制：** 不涉及。 **取值范围：** 不涉及。 **默认取值：** 不涉及。 |
   
 表6ActionsList 
| 参数         | 参数类型    | 描述                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
|:---|:---|:---|
| confidence | Double  | **参数解释：** 置信度。 **约束限制：** 不涉及。 **取值范围：** 0～1。 **默认取值：** 不涉及。                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| action     | Integer | **参数解释：** 动作编号。 **约束限制：** 不涉及。 **取值范围：** 取值范围：\[1,2,3,4,5\]。 - 1：左摇头  - 2：右摇头  - 3：点头  - 4：嘴部动作  - 5：眨眼   **默认取值：** 不涉及。 |
   
 表7WarningList 
| 参数          | 参数类型    | 描述                                                                                                                                                                                                                                                                                    |
|:---|:---|:---|
| warningCode | Integer | **参数解释：** 警告ID。 **约束限制：** 不涉及。 **取值范围：** 不涉及。 **默认取值：** 不涉及。 |
| warningMsg  | String  | **参数解释：** 告警消息。 **约束限制：** 不涉及。 **取值范围：** 不涉及。 **默认取值：** 不涉及。   |
   
**状态码： 400**
表8响应Body参数 
| 参数         | 参数类型   | 描述                                                                                                                                                                                                                                                                                                                                                                               |
|:---|:---|:---|
| error_code | String | **参数解释：** 调用失败时的错误码，具体请参考[错误码](https://support.huaweicloud.com/api-face/face_02_0045.html)。 调用成功时无此字段。 **约束限制：** 不涉及。 **取值范围：** 不涉及。 **默认取值：** 不涉及。 |
| error_msg  | String | **参数解释：** 调用失败时的错误信息。 调用成功时无此字段。 **约束限制：** 不涉及。 **取值范围：** 不涉及。 **默认取值：** 不涉及。                                                                            |
   
#### 请求示例
X-Auth-Token值获取方法请参见[快速入门](https://support.huaweicloud.com/qs-face/face_09_0003.html)。
- 通过传入视频的BASE64编码，判断视频中的人物动作与传入动作列表是否一致来识别视频中人物是否为活体
  ```
  POST https://{endpoint}/v1/{project_id}/live-detect
   Request Header: 
   Content-Type: application/json 
   X-Auth-Token: MIINRwYJKoZIhvcNAQcCoIINODCCDTQCAQExDT... 
    
   Request Body: 
   { 
      "video_base64":"/9j/4AAQSkZJRgABAgEASABIAAD...", 
      "actions":"1,3,2",
      "action_time":"1000-3000,4000-7000,9000-12000",
      "nod_threshold": 10
   }
  ```
  
- 通过传入视频文件，判断视频中的人物动作与传入动作列表是否一致来识别视频中人物是否为活体
  ```
  POST https://{endpoint}/v1/{project_id}/live-detect
   Request Header: 
   X-Auth-Token: MIINRwYJKoZIhvcNAQcCoIINODCCDTQCAQExDT... 
    
   Request Body: 
   video_file: File(视频文件) 
   actions: 1,3,2
   action_time: 1000-3000,4000-7000,9000-12000
   nod_threshold: 10
  ```
  
- 通过传入视频URL，判断视频中的人物动作与传入动作列表是否一致来识别视频中人物是否为活体
  ```
  POST https://{endpoint}/v1/{project_id}/live-detect
   Request Header: 
   Content-Type: application/json 
   X-Auth-Token: MIINRwYJKoZIhvcNAQcCoIINODCCDTQCAQExDT... 
    
   Request Body: 
   { 
      "video_url":"https://<bucket-name>.<endpoint>/<object-name>", 
      "actions":"1,3,2",
      "action_time":"1000-3000,4000-7000,9000-12000",
      "nod_threshold": 10
   }
  ```
  
- 使用Python3语言读取视频文件，判断视频中的人物动作与传入动作列表是否一致来识别视频中人物是否为活体
  ```
  # -*- coding:utf-8 -*-
  import requests
  import base64
  endpoint = '开通服务所在region的人脸识别服务域名'
  project_id = '开通服务所在region的用户项目ID'
  token = "用户获取得到的实际token值"
  headers = {'Content-Type': 'application/json', 'X-Auth-Token': token}
  url = "https://{endpoint}/v1/{project_id}/live-detect".format(endpoint=endpoint, project_id=project_id)
  video_file_path = r'./data/face-video-demo.mp4'
  with open(video_file_path, "rb") as bin_data:
      video_data = bin_data.read()
  video_base64 = base64.b64encode(video_data).("utf-8") 
  body = {"video_base64": video_base64, "actions": "1,2,3", "action_time": "1000-3000,4000-7000,9000-12000"}
  response = requests.post(url, headers=headers, json=body, verify=False)
  print(response.text)
  ```
  

- 使用Java语言读取视频base64编码，判断视频中的人物动作与传入动作列表是否一致来识别视频中人物是否为活体
  ```
  import com.huawei.trace.http.apache.httpclient.TraceApacheHttpClientBuilder;
  import org.apache.http.HttpEntity;
  import org.apache.http.HttpHeaders;
  import org.apache.http.HttpResponse;
  import org.apache.http.client.config.RequestConfig;
  import org.apache.http.client.methods.HttpPost;
  import org.apache.http.config.Registry;
  import org.apache.http.config.RegistryBuilder;
  import org.apache.http.conn.socket.ConnectionSocketFactory;
  import org.apache.http.conn.socket.PlainConnectionSocketFactory;
  import org.apache.http.conn.ssl.NoopHostnameVerifier;
  import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
  import org.apache.http.entity.ContentType;
  import org.apache.http.entity.StringEntity;
  import org.apache.http.impl.client.CloseableHttpClient;
  import org.apache.http.impl.client.HttpClientBuilder;
  import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
  import org.apache.http.ssl.SSLContextBuilder;
  import org.apache.http.ssl.TrustStrategy;
  import org.apache.http.util.EntityUtils;
  import java.io.IOException;
  import java.nio.charset.StandardCharsets;
  import java.security.KeyManagementException;
  import java.security.KeyStoreException;
  import java.security.NoSuchAlgorithmException;
  import java.security.cert.CertificateException;
  import java.security.cert.X509Certificate;
  import java.util.concurrent.TimeUnit;
  import javax.net.ssl.HostnameVerifier;
  import javax.net.ssl.SSLContext;
  /**
   * 此demo仅供测试使用，强烈建议使用SDK
   * 使用前需已配置HttpClient jar包。jar包可通过下载SDK获取
   */
  public class LiveDetect {
      protected static HttpClientBuilder buildClient(HttpClientBuilder httpClientBuilder) {
          SSLContext sslContext = null;
          try {
              sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                  public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                      return true;
                  }
              }).build();
          } catch (NoSuchAlgorithmException e) {
              throw new RuntimeException(e.getMessage());
          } catch (KeyManagementException e) {
              throw new RuntimeException(e.getMessage());
          } catch (KeyStoreException e) {
              throw new RuntimeException(e.getMessage());
          }
          httpClientBuilder.setSSLContext(sslContext);
          httpClientBuilder.setConnectionTimeToLive(30, TimeUnit.SECONDS);
          HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
          SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
          Registry<ConnectionSocketFactory> socketFactoryRegistry
              = RegistryBuilder.<ConnectionSocketFactory>create().register("http",
              PlainConnectionSocketFactory.getSocketFactory()).register("https", sslSocketFactory).build();
          PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
          connMgr.setMaxTotal(200);
          connMgr.setDefaultMaxPerRoute(100);
          httpClientBuilder.setConnectionManager(connMgr);
          return httpClientBuilder;
      }
      public static String doPost(String url, String jsonStr, String token, CloseableHttpClient client) {
          HttpPost post = new HttpPost(url);
          StringEntity entity = new StringEntity(jsonStr, ContentType.APPLICATION_JSON);
          post.setEntity(entity);
          post.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
          //time unit is milliseconds
          RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(3000).setSocketTimeout(3000).build();
          post.setConfig(requestConfig);
          post.setHeader("X-Auth-Token", token);
          HttpResponse response = null;
          String result = "";
          try {
              response = client.execute(post);
              HttpEntity responseBody = response.getEntity();
              if (responseBody == null) {
                  System.out.println("the response body is null.");
                  return result;
              } else {
                  byte[] byteStream = EntityUtils.toByteArray(responseBody);
                  System.arraycopy(byteStream, 0, new byte[byteStream.length], 0, byteStream.length);
                  result = new String(byteStream, StandardCharsets.UTF_8);
              }
          } catch (IOException e) {
              e.printStackTrace();
          }
          return result;
      }
      public static void main(String[] args) {
          CloseableHttpClient client = buildClient(TraceApacheHttpClientBuilder.create()).build();
          // endpoint和project_id需要替换成实际信息。
          String url = "https://{{endpoint}}/v1/{{project_id}}/live-detect";
          String jsonStr = "{ \"video_base64\": \"/9j/4AAQSkZJRgABAgEASABIAAD...\", \"actions\": \"1,2,3\", \"action_time\": \"1000-3000,4000-7000,9000-12000\"}";
          String token = "对应region的token";
          String result = doPost(url, jsonStr, token, client);
          System.out.println(result);
      }
  }
  ```
  
 
#### 响应样例
**状态码：200**
成功响应样例
```
{
  "video-result": {
    "alive": true,
    "actions": [
      {
        "confidence": 0.823,
        "action": 1
      },
      {
        "confidence": 0.823,
        "action": 3
      },
      {
        "confidence": 0.823,
        "action": 2
      }
    ],
    "picture": "/9j/4AAQSkZJRgABAQEAYABgAAD/2w..."
  },
  "warning-list": []
}
```
**状态码：400**
失败响应样例
```
{ 
   "error_code": "FRS.0701", 
   "error_msg": "Parse video data failed."
 }
```
#### 状态码
状态码请参见[状态码](https://support.huaweicloud.com/api-face/face_02_0082.html)。
#### 错误码
错误码请参见[错误码](https://support.huaweicloud.com/api-face/face_02_0045.html)。
