
一、前言
在许多小程序场景中,身份证识别只是第一步,提取证件照人像 才是最终目的。
例如:
- 实名认证时提取身份证头像;
- 智能证件照生成;
- 自动对比身份证照片与自拍人脸。
本文将介绍如何使用小程序 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) ,完成「身份证 + 自拍」双重校验功能。