概述
交友项目要求"非人脸照片不得上传",头像存进 OSS 之后还得再判一次:这张图里到底有没有一张合规的人脸。这个判断靠第三方人脸识别服务来做,本篇先把能力谱系、平台对接方式和返回结果读法讲清楚,代码实现放到下一篇。
纲要
- 人脸识别在项目里的定位:内容合规校验,不是身份核验
- 能力谱系:人脸检测 / 人脸对比 / 人脸搜索 / 活体检测 / 人脸库管理,各自输入输出与适用场景
- 为什么本项目只用人脸检测这一档,不用对比和搜索
- 百度 AI 开放平台:账号 → 创建应用 → AppID / API Key / Secret Key 三件套 → 开通能力 → 免费额度与计费
- 鉴权机制:SDK 用 AK/SK 换 access_token,token 有效期与自动刷新
- SDK 与 HTTP API 两种调用方式的取舍
- 输入形式:图片 URL 与图片 Base64,以及"URL 必须公网可访问"这个高频坑
- 返回结果逐字段解读:
error_code、face_num、face_list - 成本、隐私合规与数据安全
- 与其他厂商方案的对比定位
- 工程现状与本篇讲解的差异(注入写法的实测澄清留给下一篇)
人脸识别能做什么
人脸识别(Face Recognition)是基于图像或视频中的人脸做检测、分析与比对的一类技术。它不是一个单一接口,而是一组按"难度"分层的能力。很多新手把它们混为一谈,做选型时容易一上来就用最重的功能,白白增加成本与合规风险。
| 能力 | 输入 | 输出 | 典型场景 |
|---|---|---|---|
| 人脸检测 detect | 单张图片(URL 或 Base64) | 有没有人脸、几个人、位置框、以及年龄/性别/表情/是否戴眼镜等属性 | 头像合规校验、内容审核、人数统计、相册分类 |
| 人脸对比 match | 两张人脸图 | 相似度分值(0-100),判断是否同一人 | 身份核验、刷脸登录、证件照比对 |
| 人脸搜索 search | 一张人脸图 + 一个人脸库 | 库里最相似的 TopN 人脸及相似度(1:N) | 找人、门禁通行、会员识别 |
| 活体检测 liveness | 摄像头采集(照片或视频流) | 是否为真人操作 | 刷脸支付、金融开户、闸机通行 |
| 人脸库管理 | 人脸图 + 分组标识 | 注册 / 更新 / 删除结果 | 维护用户人脸底库 |
几个容易踩线的认知差别:
- 检测 ≠ 对比。检测只回答"这里有没有脸",不回答"这是谁"。
- 对比 ≠ 搜索。对比是 1:1(是不是同一个人),搜索是 1:N(在库里找最像的)。
- 活体检测是独立的一层。前四类里只有它解决"是不是真人在摄像头前"这个问题,防的是拿照片、视频、面具来伪造。金融、门禁这类场景它几乎是硬要求,普通内容审核用不上。
#mermaid-svg-Lzi07elQZg6ucmpK{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Lzi07elQZg6ucmpK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Lzi07elQZg6ucmpK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Lzi07elQZg6ucmpK .error-icon{fill:#552222;}#mermaid-svg-Lzi07elQZg6ucmpK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Lzi07elQZg6ucmpK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Lzi07elQZg6ucmpK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Lzi07elQZg6ucmpK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Lzi07elQZg6ucmpK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Lzi07elQZg6ucmpK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Lzi07elQZg6ucmpK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Lzi07elQZg6ucmpK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Lzi07elQZg6ucmpK .marker.cross{stroke:#333333;}#mermaid-svg-Lzi07elQZg6ucmpK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Lzi07elQZg6ucmpK p{margin:0;}#mermaid-svg-Lzi07elQZg6ucmpK .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Lzi07elQZg6ucmpK .cluster-label text{fill:#333;}#mermaid-svg-Lzi07elQZg6ucmpK .cluster-label span{color:#333;}#mermaid-svg-Lzi07elQZg6ucmpK .cluster-label span p{background-color:transparent;}#mermaid-svg-Lzi07elQZg6ucmpK .label text,#mermaid-svg-Lzi07elQZg6ucmpK span{fill:#333;color:#333;}#mermaid-svg-Lzi07elQZg6ucmpK .node rect,#mermaid-svg-Lzi07elQZg6ucmpK .node circle,#mermaid-svg-Lzi07elQZg6ucmpK .node ellipse,#mermaid-svg-Lzi07elQZg6ucmpK .node polygon,#mermaid-svg-Lzi07elQZg6ucmpK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Lzi07elQZg6ucmpK .rough-node .label text,#mermaid-svg-Lzi07elQZg6ucmpK .node .label text,#mermaid-svg-Lzi07elQZg6ucmpK .image-shape .label,#mermaid-svg-Lzi07elQZg6ucmpK .icon-shape .label{text-anchor:middle;}#mermaid-svg-Lzi07elQZg6ucmpK .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Lzi07elQZg6ucmpK .rough-node .label,#mermaid-svg-Lzi07elQZg6ucmpK .node .label,#mermaid-svg-Lzi07elQZg6ucmpK .image-shape .label,#mermaid-svg-Lzi07elQZg6ucmpK .icon-shape .label{text-align:center;}#mermaid-svg-Lzi07elQZg6ucmpK .node.clickable{cursor:pointer;}#mermaid-svg-Lzi07elQZg6ucmpK .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Lzi07elQZg6ucmpK .arrowheadPath{fill:#333333;}#mermaid-svg-Lzi07elQZg6ucmpK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Lzi07elQZg6ucmpK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Lzi07elQZg6ucmpK .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Lzi07elQZg6ucmpK .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Lzi07elQZg6ucmpK .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Lzi07elQZg6ucmpK .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Lzi07elQZg6ucmpK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Lzi07elQZg6ucmpK .cluster text{fill:#333;}#mermaid-svg-Lzi07elQZg6ucmpK .cluster span{color:#333;}#mermaid-svg-Lzi07elQZg6ucmpK div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Lzi07elQZg6ucmpK .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Lzi07elQZg6ucmpK rect.text{fill:none;stroke-width:0;}#mermaid-svg-Lzi07elQZg6ucmpK .icon-shape,#mermaid-svg-Lzi07elQZg6ucmpK .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Lzi07elQZg6ucmpK .icon-shape p,#mermaid-svg-Lzi07elQZg6ucmpK .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Lzi07elQZg6ucmpK .icon-shape .label rect,#mermaid-svg-Lzi07elQZg6ucmpK .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Lzi07elQZg6ucmpK .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Lzi07elQZg6ucmpK .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Lzi07elQZg6ucmpK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 没有人脸
检测到人脸
合规校验
身份核验
找人
防伪造
一张图片
人脸检测
拒绝
拿到 face_token / 位置 / 属性
业务需要做什么
结束
人脸对比 1:1
人脸搜索 1:N
活体检测
本项目怎么用它
交友项目用到的是最轻的一档:人脸检测。目标只有一个------校验用户上传的头像照片里确实有一张合规的人脸,挡住风景图、卡通图、多人合照以及违规图片。
这里有个选型判断值得说透。为什么不上人脸对比或人脸搜索?
- 目的不同 。本项目要解决的是内容合规 (头像得是个正常人脸),不是身份核验(证明你是不是张三)。合规校验只需要"有没有脸",检测足够了。
- 成本与合规成本。对比、搜索要维护人脸底库,涉及人脸数据的长期留存,而人脸属于敏感个人信息,留存就意味着更高的合规义务。检测是"用完即走",业务侧不需要存原始人脸数据。
- 响应更快。检测是单图分析,链路最短。
一句话:能用检测解决的,别上对比和搜索。这是工程上很典型的一步------先明确业务真正需要哪一档能力,再决定用哪个接口。
百度人脸识别 阿里云 OSS mf-app-server 用户端 百度人脸识别 阿里云 OSS mf-app-server 用户端 #mermaid-svg-45Oe1LLjOaMuNq04{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-45Oe1LLjOaMuNq04 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-45Oe1LLjOaMuNq04 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-45Oe1LLjOaMuNq04 .error-icon{fill:#552222;}#mermaid-svg-45Oe1LLjOaMuNq04 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-45Oe1LLjOaMuNq04 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-45Oe1LLjOaMuNq04 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-45Oe1LLjOaMuNq04 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-45Oe1LLjOaMuNq04 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-45Oe1LLjOaMuNq04 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-45Oe1LLjOaMuNq04 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-45Oe1LLjOaMuNq04 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-45Oe1LLjOaMuNq04 .marker.cross{stroke:#333333;}#mermaid-svg-45Oe1LLjOaMuNq04 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-45Oe1LLjOaMuNq04 p{margin:0;}#mermaid-svg-45Oe1LLjOaMuNq04 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-45Oe1LLjOaMuNq04 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-45Oe1LLjOaMuNq04 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-45Oe1LLjOaMuNq04 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-45Oe1LLjOaMuNq04 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-45Oe1LLjOaMuNq04 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-45Oe1LLjOaMuNq04 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-45Oe1LLjOaMuNq04 .sequenceNumber{fill:white;}#mermaid-svg-45Oe1LLjOaMuNq04 #sequencenumber{fill:#333;}#mermaid-svg-45Oe1LLjOaMuNq04 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-45Oe1LLjOaMuNq04 .messageText{fill:#333;stroke:none;}#mermaid-svg-45Oe1LLjOaMuNq04 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-45Oe1LLjOaMuNq04 .labelText,#mermaid-svg-45Oe1LLjOaMuNq04 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-45Oe1LLjOaMuNq04 .loopText,#mermaid-svg-45Oe1LLjOaMuNq04 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-45Oe1LLjOaMuNq04 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-45Oe1LLjOaMuNq04 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-45Oe1LLjOaMuNq04 .noteText,#mermaid-svg-45Oe1LLjOaMuNq04 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-45Oe1LLjOaMuNq04 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-45Oe1LLjOaMuNq04 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-45Oe1LLjOaMuNq04 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-45Oe1LLjOaMuNq04 .actorPopupMenu{position:absolute;}#mermaid-svg-45Oe1LLjOaMuNq04 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-45Oe1LLjOaMuNq04 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-45Oe1LLjOaMuNq04 .actor-man circle,#mermaid-svg-45Oe1LLjOaMuNq04 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-45Oe1LLjOaMuNq04 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} alt error_code == 0 且 face_num == 1 上传头像图片 上传图片,拿到访问 URL 调用人脸检测(图片 URL) error_code + face_num 校验通过,保存头像地址 抛出"不包含人脸",拒绝
注意上图里 OSS 是阿里云、人脸识别是百度,两家厂商混着用。项目这个项目本身就是混用第三方服务:阿里云短信 + 阿里云 OSS + 百度人脸识别 + 环信 IM 。所以别看到"人脸识别"就默认是阿里云的------本节课用的确实是百度 AI 开放平台。
百度 AI 开放平台的接入流程
整体四步:注册登录 → 创建应用 → 开通能力 → 调 API。
#mermaid-svg-zdY3WlruASWhgah2{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-zdY3WlruASWhgah2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zdY3WlruASWhgah2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zdY3WlruASWhgah2 .error-icon{fill:#552222;}#mermaid-svg-zdY3WlruASWhgah2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zdY3WlruASWhgah2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zdY3WlruASWhgah2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zdY3WlruASWhgah2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zdY3WlruASWhgah2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zdY3WlruASWhgah2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zdY3WlruASWhgah2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zdY3WlruASWhgah2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zdY3WlruASWhgah2 .marker.cross{stroke:#333333;}#mermaid-svg-zdY3WlruASWhgah2 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zdY3WlruASWhgah2 p{margin:0;}#mermaid-svg-zdY3WlruASWhgah2 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-zdY3WlruASWhgah2 .cluster-label text{fill:#333;}#mermaid-svg-zdY3WlruASWhgah2 .cluster-label span{color:#333;}#mermaid-svg-zdY3WlruASWhgah2 .cluster-label span p{background-color:transparent;}#mermaid-svg-zdY3WlruASWhgah2 .label text,#mermaid-svg-zdY3WlruASWhgah2 span{fill:#333;color:#333;}#mermaid-svg-zdY3WlruASWhgah2 .node rect,#mermaid-svg-zdY3WlruASWhgah2 .node circle,#mermaid-svg-zdY3WlruASWhgah2 .node ellipse,#mermaid-svg-zdY3WlruASWhgah2 .node polygon,#mermaid-svg-zdY3WlruASWhgah2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zdY3WlruASWhgah2 .rough-node .label text,#mermaid-svg-zdY3WlruASWhgah2 .node .label text,#mermaid-svg-zdY3WlruASWhgah2 .image-shape .label,#mermaid-svg-zdY3WlruASWhgah2 .icon-shape .label{text-anchor:middle;}#mermaid-svg-zdY3WlruASWhgah2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-zdY3WlruASWhgah2 .rough-node .label,#mermaid-svg-zdY3WlruASWhgah2 .node .label,#mermaid-svg-zdY3WlruASWhgah2 .image-shape .label,#mermaid-svg-zdY3WlruASWhgah2 .icon-shape .label{text-align:center;}#mermaid-svg-zdY3WlruASWhgah2 .node.clickable{cursor:pointer;}#mermaid-svg-zdY3WlruASWhgah2 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-zdY3WlruASWhgah2 .arrowheadPath{fill:#333333;}#mermaid-svg-zdY3WlruASWhgah2 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-zdY3WlruASWhgah2 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-zdY3WlruASWhgah2 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zdY3WlruASWhgah2 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-zdY3WlruASWhgah2 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zdY3WlruASWhgah2 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-zdY3WlruASWhgah2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-zdY3WlruASWhgah2 .cluster text{fill:#333;}#mermaid-svg-zdY3WlruASWhgah2 .cluster span{color:#333;}#mermaid-svg-zdY3WlruASWhgah2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-zdY3WlruASWhgah2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-zdY3WlruASWhgah2 rect.text{fill:none;stroke-width:0;}#mermaid-svg-zdY3WlruASWhgah2 .icon-shape,#mermaid-svg-zdY3WlruASWhgah2 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zdY3WlruASWhgah2 .icon-shape p,#mermaid-svg-zdY3WlruASWhgah2 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-zdY3WlruASWhgah2 .icon-shape .label rect,#mermaid-svg-zdY3WlruASWhgah2 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zdY3WlruASWhgah2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-zdY3WlruASWhgah2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-zdY3WlruASWhgah2 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 注册/登录百度智能云账号
进入人脸识别控制台
创建应用, 填写应用名称与描述
拿到 AppID / API Key / Secret Key 三件套
勾选需要的能力, 如人脸检测
在代码中用三件套初始化 SDK 并调用
控制台地址:https://ai.baidu.com/tech/face,用个人百度账号扫码就能登录,也支持注册云账号,学习阶段用个人账号足够。
创建应用时要留意两点:
- 应用名称随便填,课程里叫"项目",描述写"项目测试"。
- 接口权限默认勾选,一般不用手动改。
创建完成后回到应用列表,应用的三件套(AppID 、API Key 、Secret Key)就是后面初始化 SDK 的凭据。AppID 是一串数字,两个 Key 是字符串,别弄混。
免费额度与计费
百度人脸识别不需要额外付费购买 就能用,有一定的免费调用额度,超出后按量计费。另外它有并发限制 ------课程里这个默认额度大约是每秒 2 次请求(QPS = 2) ,做单元测试和课程练习完全够,但不足以支撑生产环境的并发量。
要知道的两件事:
- 免费额度和 QPS 都是有上限的,不是无限白嫖。压测或者批量跑的时候很容易撞到限流。
- 具体额度数值、超出后的单价会调整,以百度智能云官方定价页为准,别在代码注释里写死价格。
鉴权机制
百度 AI 的鉴权走 OAuth 那一套:用 API Key + Secret Key 换一个 access_token,之后每次请求带上这个 token。
- token 有有效期(通常是 30 天,以官方文档为准)。
- Java SDK 内部会自动缓存和刷新 token,业务代码不用自己管。你只要在初始化时把三件套传进去,SDK 会帮你完成换取和续期。
- 只有直接裸调 HTTP API 时,才需要自己实现 token 的获取与缓存------这也是 SDK 省事的地方。
SDK 与 HTTP API 怎么选
| 维度 | Java SDK | HTTP API |
|---|---|---|
| 鉴权 | 自动换取/刷新 token | 自己请求 token 并缓存 |
| 请求封装 | 参数打包、JSON 解析都封装好了 | 自己拼 JSON、自己解析 |
| 语言支持 | 绑定具体语言(Java SDK 只给 Java 用) | 任意语言,HTTP 客户端即可 |
| 依赖 | 引入 aip-java-sdk 之类的依赖 |
无额外依赖 |
| 适用 | 业务代码集成,本项目用这个 | 跨语言、轻量脚本、SDK 不适配的场景 |
项目用的是 Java SDK ,依赖坐标 com.baidu.aip:java-sdk(Baidu AIP Java SDK)。引入后直接 new AipFace(APP_ID, API_KEY, SECRET_KEY) 就能用。
输入形式:URL 与 Base64
这是个高频坑,单独拎出来讲。百度人脸检测支持两种图片来源,靠 image_type 参数区分:
| image_type | 传的内容 | 适用条件 |
|---|---|---|
URL |
图片的公网访问地址 | 该 URL 必须能被百度的服务器公网访问到 |
BASE64 |
图片文件内容的 Base64 编码 | 无网络可达性要求,但请求体更大,编码有开销 |
URL 这一档必须强调 :百度是从它自己的服务器去拉这张图 的,不是你本地直接上传。如果图片放在私有读的 Bucket 里(比如设了私有权限的 OSS),百度拉不到,检测就会失败,通常会返回一个图片下载失败的 error_code(如 222203)。这个报错很迷惑人------detect() 本身没抛异常,就是结果里 error_code 非 0,很容易被当成"图片里没有人脸"而误判。
由此推出两条可行路线:
- 先传 OSS 拿公网 URL,再送检。前提是 Bucket 允许公网读,或者图片有可访问的临时 URL。
- 直接传 Base64 绕过可达性问题。把图片字节编码后送过去,不依赖任何外部能否访问。
课程讲义里 detect(String imageUrl) 的签名和 String imageType = "URL" 的写法,走的是第一条路线,图片是上传到 OSS 后拿到的公网地址。至于本项目最终在业务代码里具体选哪条,以对应实现篇的代码为准;这里把两种方式的适用条件讲清楚就够了。
返回结果怎么读
detect() 返回的是一个 JSONObject(org.json 包),核心字段如下:
json
{
"face_num": 1,
"face_list": [
{
"face_token": "0a4d8b1b2b6c9e3f7a1d5c8b0e4f2a6d",
"location": { "left": 117.0, "top": 131.0, "width": 169.0, "height": 196.0, "rotation": 0 },
"face_probability": 1.0,
"angle": { "yaw": -12.0, "pitch": 6.0, "roll": 3.0 },
"age": 24,
"gender": { "type": "male", "probability": 1.0 }
}
],
"error_code": 0,
"error_msg": "SUCCESS",
"log_id": 1234567890123456789,
"timestamp": 1618812345,
"cached": 0,
"result_num": 1
}
| 字段 | 含义 |
|---|---|
error_code |
0 表示调用成功 ;非 0 是各种失败(参数错、图片下载失败、未检测到人脸等),具体含义看 error_msg |
error_msg |
错误描述,成功时为 SUCCESS |
face_num |
检测到的人脸数量,0 表示图里没人脸 |
face_list |
每张人脸的详情数组,长度与 face_num 对应 |
face_list[].face_token |
这张脸的唯一标识,人脸对比/搜索时用它指代"某张脸" |
face_list[].location |
人脸框位置(left/top/width/height)与旋转角度 |
face_list[].face_probability |
是人脸的概率,一般接近 1.0 |
face_list[].age / gender |
需要 face_field 里显式请求才会返回属性 |
face_list[].angle |
三个方向的偏转角,判断脸是不是歪的/侧脸 |
log_id |
请求日志 ID,排查问题时拿它找百度技术支持 |
几个概念级的用法:
face_field决定返回哪些属性 。不请求就不返回,比如options.put("face_field", "age")才会带出age字段。请求的属性越多,耗时和计费口径可能不同。max_face_num限制返回人脸的个数 ,讲义里传的是"2"。face_type与liveness_control用来控制人脸类型与活体检测的严格程度,讲义里是LIVE+LOW。- 业务判断怎么写 :常见做法是
error_code == 0 且 face_num == 1才算"一张合规的单人头像"。人脸数为 0 说明没人脸,大于 1 说明是多人合照,都不该通过。讲义里的AipFaceTemplate.detect()目前只判了error_code == 0,够用但不严,严格的产品要求应该连face_num一起判。
成本与合规的现实考虑
这部分讲的是上线前必须想清楚的,不是走个流程。
成本
- 先看免费额度够不够。学习项目、小体量产品通常够用;一旦量上来,按量计费就是持续支出。
- 并发限制容易被忽略。免费档的 QPS 很低,秒杀式的头像上传高峰会直接撞限流,要么排队、要么升级配额。
隐私合规
人脸属于敏感个人信息,采集和使用受法律约束。这类功能上线前的工程动作:
- 明确告知并取得用户单独授权。用户得知道你把他的照片送去做人脸分析了,不能偷偷做。
- 最小必要。只采集业务真正需要的,本项目只做检测,就不要顺带把人脸底库也建起来。
- 不长期留存。检测完就丢掉原图与人脸数据,业务侧只留"通过/不通过"这个结论。真要留,得有明确的用途和期限。
- 可删除。用户要能撤回授权、删掉相关数据。
- 具体条款不展开,以现行法律法规为准。
数据安全
- 图片传输走 HTTPS。
- OSS Bucket 权限别图省事设成公网可写;读权限按需开,必要时用带签名的临时 URL,而不是永久公网地址。
与其他厂商方案的对比
只给定位,不给编造的数值。
| 方案 | 定位 | 取舍方向 |
|---|---|---|
| 百度 AI 开放平台 | 通用云服务,能力强、文档全 | 免运维,按调用量付费,数据要外发给厂商 |
| 阿里云人脸 | 通用云服务 | 与其他阿里云产品联动方便;早期版本对图片存放位置、地域有限制 |
| 腾讯云人脸 | 通用云服务 | 与腾讯生态结合紧密 |
| 开源方案(face_recognition、RetinaFace 等) | 自建 | 无调用费、数据不出内网,但模型部署、算力、准确率调优和维护都要自己扛 |
一句话取舍:云服务免运维但有调用费用与数据外发;开源自建无调用费但要自己训练部署与维护 。选哪个看数据敏感度、调用量和团队运维能力。各厂商面向不同,详细信息以各自官方文档为准。
顺带说一下课程选百度的原因:不是百度独一档,而是当时阿里云人脸识别还处在起步阶段,限制较多------只支持把图片先存到 OSS 再检测,地域也仅限上海。这些限制对课程演示不友好,所以换成了百度。
工程现状与本篇讲解的差异
工程里确实已经抽出了两个类(下一步讲抽取组件时会细看):
tree
mf-autoconfig/
└── src/main/java/com/mf/autoconfig/
├── mfAutoConfiguration.java # @Bean 里 new AipFaceTemplate()
├── properties/
│ ├── AipFaceProperties.java # @ConfigurationProperties("mf.aip")
│ ├── OssProperties.java
│ └── SmsProperties.java
└── template/
├── AipFaceTemplate.java # @Autowired AipFace client + detect()
├── OssTemplate.java
└── SmsTemplate.java
对照 application.yml 里的配置:
yaml
mf:
aip:
appId: 你的AppID
apiKey: 你的APIKey
secretKey: 你的SecretKey
这里先澄清一个流传很广的推测:AipFaceTemplate 是在 @Bean 方法里 new 出来的、又用 @Autowired 注入 AipFace,看起来像"手工 new 的对象注入不生效",于是常被断定 AipFaceProperties 里的 @Bean 不会被解析、工程里并不存在 AipFace 这个 bean 、detect() 一调就 NPE。用工程真实的版本组合做最小复现后,这个推测被否掉了------它其实能跑,@Bean 方法的返回值本身就是容器 bean,字段注入照常生效。到底为什么能跑、哪些写法才真会炸,完整放在下一篇《百度人脸识别:抽取自动装配组件》里用实测讲清楚,本篇不展开。
常见误解
- 以为人脸识别都能认出"是谁"。检测只管有没有脸,对比是 1:1,搜索是 1:N,能力档次完全不同,别拿检测结果去当身份凭证。
- 以为免费额度无限。有调用量和 QPS 双重限制,量级上来就得付费或排队。
- 以为传 URL 就一定行。URL 必须能被百度服务器公网访问,私有 Bucket 会拉不到。
- 以为人脸数据想存就存。敏感个人信息,采集要授权、留存要必要、删除要可行。
- 以为只能用厂商云服务。开源自建也是一条路,只是运维成本换来了数据可控。
官方文档
总结
- 人脸识别按能力分层:检测、对比、搜索、活体检测、人脸库管理,选型时先定业务要哪一档,再挑接口。
- 项目只用最轻的人脸检测,目的是头像内容合规而非身份核验,检测结果按
error_code == 0 且 face_num == 1判断更稳妥。 - 百度 AI 平台接入四步走:注册 → 创建应用拿三件套 → 开通能力 → 调 API;SDK 自动管 token,比裸调 HTTP 省事。
image_type的URL与BASE64是两条路线,前者要求公网可达,私有 Bucket 是典型的坑。- 人脸是敏感个人信息,授权、最小必要、可删除这三点在上线前必须落到工程上。
下一篇进入动手环节,从零跑通一次人脸检测调用,见《百度人脸识别:入门案例》。