微信小程序 VisionKit 实战(二):静态图片人脸检测与人像区域提取

一、前言

微信小程序实现身份证识别与裁剪(基于 VisionKit)

在许多小程序场景中,身份证识别只是第一步,提取证件照人像 才是最终目的。

例如:

  • 实名认证时提取身份证头像;
  • 智能证件照生成;
  • 自动对比身份证照片与自拍人脸。

本文将介绍如何使用小程序 VisionKit 提供的 face 模块,完成静态图片人脸检测,并计算出头像的可视区域,实现精准截取。


二、核心逻辑与完整封装

我们先来看核心文件:utils/faceDetector.js

📘 完整代码

javascript 复制代码
/**
 * utils/faceDetector.js
 * 静态图片人脸检测封装
 */

/**
 * 初始化 VKSession
 */
function createVKSession(gl) {
  const session = wx.createVKSession({
    track: {
      face: { mode: 2 }, // 静态图片模式
    },
    version: "v1",
    gl,
  })
  return session
}

/**
 * 静态图片人脸检测
 * @param {Object} options
 * @param {string} options.imgUrl 本地图片路径
 * @param {number} options.width 图片宽
 * @param {number} options.height 图片高
 * @returns {Promise<Object>} 返回人脸框信息和关键点
 */
function detectFace({ imgUrl, width, height, gl }) {
  return new Promise(async (resolve, reject) => {
    try {
      const session = createVKSession(gl)
      const canvas = wx.createOffscreenCanvas({ type: "2d", width, height })
      const ctx = canvas.getContext("2d")

      const img = canvas.createImage()
      await new Promise((r) => {
        img.onload = r
        img.src = imgUrl
      })

      // 绘制图像
      ctx.clearRect(0, 0, width, height)
      ctx.drawImage(img, 0, 0, width, height)
      const imgData = ctx.getImageData(0, 0, width, height)

      // 监听识别结果
      session.on("updateAnchors", (anchors) => {
        if (anchors && anchors.length) {
          const faceData = anchors.map((a) => ({
            origin: a.origin,   // 左上角坐标(归一化 0~1)
            size: a.size,       // 宽高(归一化)
            points: a.points,   // 关键点(五官坐标)
          }))
          resolve(faceData)
        } else {
          reject("未识别到人脸")
        }
      })

      // 启动检测
      session.start(() => {
        session.detectFace({
          frameBuffer: imgData.data.buffer,
          width,
          height,
          scoreThreshold: 0.5,
          sourceType: 1, // 静态图片
          modelMode: 1,
        })
      })
    } catch (err) {
      reject(err)
    }
  })
}

module.exports = { detectFace }

三、使用示例

身份证识别完成后,我们会获得身份证的矫正图(cropImg)及其宽高信息。

接下来调用 detectFace() 即可检测身份证上的人脸区域。

arduino 复制代码
const faceData = await detectFace({
  imgUrl: detectIdCardInfo.cropImg,
  width: detectIdCardInfo.affineImgWidth,
  height: detectIdCardInfo.affineImgHeight,
  gl: this.gl,
})
this.computeFaceRegion(faceData[0], detectIdCardInfo)

四、人像区域计算与裁剪

人脸检测返回的坐标是归一化坐标(0~1) ,所以我们需要根据身份证图像的实际像素宽高换算出真实坐标。

下面是完整实现:

ini 复制代码
// 计算身份证人像完整区域的显示坐标
async computeFaceRegion(faceData, detectIdCardInfo) {
  const fixWidth = 375
  const expandRatioX = 1.4 // 宽度扩展比例
  const expandRatioY = 1.7 // 高度扩展比例

  const { cropImg, affineImgWidth, affineImgHeight } = detectIdCardInfo
  const fixHeight = (fixWidth / affineImgWidth) * affineImgHeight

  const originX = faceData.origin.x
  const originY = faceData.origin.y
  const width = faceData.size.width
  const height = faceData.size.height

  // 扩展人脸区域(避免裁切过紧)
  const newX = Math.max(originX - ((expandRatioX - 1) / 2) * width, 0)
  const newY = Math.max(originY - ((expandRatioY - 1) / 2) * height, 0)
  const newWidth = Math.min(width * expandRatioX, 1 - newX)
  const newHeight = Math.min(height * expandRatioY, 1 - newY)

  // 向上微调,让头像居中
  const moveUpRatio = 0.1
  const faceBoxTop = Math.max(newY * fixHeight - newHeight * fixHeight * moveUpRatio, 0)

  const faceRegion = {
    faceImgUrl: cropImg,
    faceImgWidth: fixWidth,
    faceImgHeight: fixHeight,
    faceBoxLeft: newX * fixWidth,
    faceBoxTop,
    faceBoxWidth: newWidth * fixWidth,
    faceBoxHeight: newHeight * fixHeight,
  }

  this.setData({ ...faceRegion })

  // 调用裁剪逻辑
  const cropResult = await cropFace(cropImg, faceRegion)
  this.setData({ cropUrl: cropResult.tempFilePath, cropBase64: cropResult.base64 })
}

这样就能从身份证中自动提取头像区域,生成标准证件照。


五、逻辑总结

模块 功能 说明
createVKSession 初始化 VisionKit 会话 指定人脸检测模式(静态图片)
detectFace 调用 VisionKit 识别人脸 返回人脸框坐标与五官关键点
computeFaceRegion 根据人脸框计算裁剪区域 支持扩展、上移、缩放调整
cropFace Canvas 裁剪函数 最终生成证件照或头像图

六、原理概述:VisionKit 人脸识别模块

VisionKit 是微信小程序提供的视觉识别能力,支持包括:

功能 模式
人脸检测 (face) 实时 / 静态
身份证识别 (IDCard) 照片模式
姿态估计 (body) 实时人体识别

在本例中,我们使用了:

css 复制代码
track: { face: { mode: 2 } }

代表静态图片模式,适合身份证头像识别、图片对比等场景。


七、结语

通过本文的封装与分析,我们实现了从身份证识别 → 人脸检测 → 头像提取的完整链路。

下一篇我们将进一步扩展,介绍如何利用识别结果进行 人脸对比验证(Face Compare) ,完成「身份证 + 自拍」双重校验功能。

相关推荐
顾青3 小时前
微信小程序实现身份证识别与裁剪(基于 VisionKit)
前端·微信小程序
星链引擎3 小时前
技术深度聚焦版(侧重技术原理与代码细节)
前端
呵阿咯咯3 小时前
ueditor富文本编辑器相关问题
前端
月弦笙音3 小时前
【Vue3】Keep-Alive 深度解析
前端·vue.js·源码阅读
地方地方3 小时前
手写 AJAX 与封装 MyAxios:深入理解前端网络请求
前端·javascript·面试
该用户已不存在3 小时前
7个没听过但绝对好用的工具
前端·后端
遇见火星4 小时前
Docker入门:快速部署你的第一个Web应用
前端·docker·容器
WeilinerL4 小时前
泛前端代码覆盖率探索之路
前端·javascript·测试
浮游本尊4 小时前
React 18.x 学习计划 - 第五天:React状态管理
前端·学习·react.js