Java 项目实战: 交友项目 - 百度人脸识别:介绍

概述

交友项目要求"非人脸照片不得上传",头像存进 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 是典型的坑。
  • 人脸是敏感个人信息,授权、最小必要、可删除这三点在上线前必须落到工程上。

下一篇进入动手环节,从零跑通一次人脸检测调用,见《百度人脸识别:入门案例》。

相关推荐
障碍的枫子1 小时前
我的第一个Agent
开发语言·python·langchain
Pniubi1 小时前
区分agent中长期记忆和偏好记忆
开发语言·ai·智能体
一枕槐安4871 小时前
大模型应用后端设计:上下文管理、缓存、降级策略的工程方案总结
java·spring·缓存
T_Apollo1 小时前
2.9 Java 25 版本新增特性和类
java
我就是不信1 小时前
Swift 方法派发机制详解
开发语言·ios·swift
CCCCCCCCharlie2 小时前
深入解析I/O底层:文件描述符与缓冲区真相
linux·开发语言·c++·算法
步行cgn2 小时前
@RequestMapping 注解详解
java·后端·spring
鶴哥只手遮天2 小时前
Spring Boot 4.1.1 深度源码解析-第 15 章 · 条件注解体系:全部 `@ConditionalOnXxx` 的实现原理
java·后端·开源
鶴哥只手遮天2 小时前
Spring Boot 4.1.1 深度源码解析-第 30 章 · 基础设施能力:SSL Bundle、Task 与虚拟线程、Retry
java·后端·开源