微信小程序开发:人脸检测关键技术(接口)
发布:管理员 日期:2022-11-12 阅读: 次
图片文件选择与数据获取
在访问开放平台时经常需要找一些自己的图片进行测试,所以就需要这样一个方法来实现
wx.chooseImage({
success: function(csi) {
//获取图片缓存地址
var tempFilePaths = csi.tempFilePaths
imageUrl = tempFilePaths[0]
//获取图片信息
wx.getImageInfo({
src: imageUrl,
success (gii) {
//根据图片拍摄方向获取图片的宽高
if(gii.orientation=="up" || gii.orientation=="down" || gii.orientation=="up-mirrored" || gii.orientation=="down-mirrored"){
imageWidth = gii.width
imageHeight = gii.height
}else{
imageWidth = gii.height
imageHeight = gii.width
}
//获取图片Base64码,一般网络请求发送的图片数据均是该格式数据
let imageBase64 = wx.getFileSystemManager().readFileSync(imageUrl, "base64")
}
})
}
})
图片算法处理网络请求
在获取到图片数据后,就需要将图片数据发送到后端进行算法处理请求来获取算法运行结果
wx.request({
url: |#@@#|http://123.45.67.89:8080/face|#@@#|, //局域网接口地址(也可以是广域网/https地址)
data: {
"command": "detect",// 算法类型
"image": imageBase64Str,// 待检测图片base64字符串码
"max_face_num": 1,// 最大检测人脸数
"image_url": "",// 待检测图片URL
"face_attribute": 1,// 是否进行人脸属性检测
"face_quality": 1// 是否进行人脸质量检测
},
header: {
|#@@#|content-type|#@@#|: |#@@#|application/json|#@@#| // 请求头
},
method: "POST",// 请求方式
timeout: 5000,// 请求超时
dataType: "json",
success (response) {
// 请求成功处理
// 打印返回结果
console.log("face detect success:\n" + JSON.stringify(response, null ,2))
......
},
fail(res) {
// 请求失败处理
// 打印返回结果
console.log("face detect fail:\n" + JSON.stringify(res, null ,2))
//请求失败提示
wx.showToast({
title: |#@@#|请求失败:|#@@#| + res.errMsg,
icon: |#@@#|none|#@@#|,
duration: 2000
})
},
complete(res) {
// 请求完成处理
console.log("face detect complete.")
}
})
图片算法处理结果人脸框绘制
在拿到请求结果以后如果只是打印reponse数据并不能直观感受算法处理效果,这时如果能将结果通过图像绘制将人脸位置显示出来将是不错的处理方式
wx.createSelectorQuery()
.select(|#@@#|#canvas_preview|#@@#|)//显示控件
.fields({ node: true, size: true })
.exec((scvs) => {
// 获取控件像素尺寸
const dom = scvs[0]
const canvas = dom.node
const ctx = canvas.getContext(|#@@#|2d|#@@#|)
const dpr = wx.getSystemInfoSync().pixelRatio
canvas.width = dom.width * dpr
canvas.height = dom.height * dpr
ctx.scale(dpr, dpr)
const canvasMaxWidth = dom.width
const canvasMaxHeight = dom.height
// 获取图像缩放比例,保证图片在控件内完全显示
const widthAdjustPara = canvasMaxWidth / imageWidth
const heightAdjustPara = canvasMaxHeight / imageHeight
var currentAdjustPara = 1
if(widthAdjustPara<1 || heightAdjustPara<1) {
currentAdjustPara = (widthAdjustPara <= heightAdjustPara ? widthAdjustPara : heightAdjustPara)
}
const canvasCurrentWidth = (currentAdjustPara===1 ? imageWidth : (imageWidth * currentAdjustPara))
const canvasCurrentHeight = (currentAdjustPara===1 ? imageHeight : (imageHeight * currentAdjustPara))
// 在控件内绘制原图
var img = canvas.createImage()
img.src = imageUrl
img.onload = function () {
// 居中绘制
ctx.drawImage(
img,
(canvasMaxWidth-canvasCurrentWidth)/2 + 1, // image x start
(canvasMaxHeight-canvasCurrentHeight)/2 + 1, // image y start
canvasCurrentWidth, canvasCurrentHeight // image dst w, h
)
// 检测到人脸绘制人脸框(从返回数据reponseData中获取人脸框位置信息)
if(isDetected){
for (var i = 0; i < reponseData.data.face_num; i++) {
var x1 = reponseData.data.face_list[i].location.x1
var y1 = reponseData.data.face_list[i].location.y1
var x2 = reponseData.data.face_list[i].location.x2
var y2 = reponseData.data.face_list[i].location.y2
ctx.strokeStyle = |#@@#|#00e5ff|#@@#| // 绘制线颜色
// 矩形绘制
ctx.rect(
(canvasMaxWidth-canvasCurrentWidth)/2 + x1 * currentAdjustPara, // rect left value
(canvasMaxHeight-canvasCurrentHeight)/2 + y1 * currentAdjustPara, // rect top value
(x2-x1) * currentAdjustPara, (y2-y1) * currentAdjustPara // rect w, h
)
}
ctx.stroke()
}
}
})
图片算法处理结果人脸关键点绘制
在拿到请求结果以后如果只是打印reponse数据并不能直观感受算法处理效果,这时如果能将结果通过图像绘制将人脸关键点位置显示出来将是不错的处理方式
wx.createSelectorQuery()
.select(|#@@#|#canvas_preview|#@@#|)//显示控件
.fields({ node: true, size: true })
.exec((scvs) => {
// 获取控件像素尺寸
const dom = scvs[0]
const canvas = dom.node
const ctx = canvas.getContext(|#@@#|2d|#@@#|)
const dpr = wx.getSystemInfoSync().pixelRatio
canvas.width = dom.width * dpr
canvas.height = dom.height * dpr
ctx.scale(dpr, dpr)
const canvasMaxWidth = dom.width
const canvasMaxHeight = dom.height
// 获取图像缩放比例,保证图片在控件内完全显示
const widthAdjustPara = canvasMaxWidth / imageWidth
const heightAdjustPara = canvasMaxHeight / imageHeight
var currentAdjustPara = 1
if(widthAdjustPara<1 || heightAdjustPara<1) {
currentAdjustPara = (widthAdjustPara <= heightAdjustPara ? widthAdjustPara : heightAdjustPara)
}
const canvasCurrentWidth = (currentAdjustPara===1 ? imageWidth : (imageWidth * currentAdjustPara))
const canvasCurrentHeight = (currentAdjustPara===1 ? imageHeight : (imageHeight * currentAdjustPara))
// 在控件内绘制原图
var img = canvas.createImage()
img.src = imageUrl
img.onload = function () {
ctx.drawImage(
img,
(canvasMaxWidth-canvasCurrentWidth)/2 + 1, // image x start
(canvasMaxHeight-canvasCurrentHeight)/2 + 1, // image y start
canvasCurrentWidth, canvasCurrentHeight // image dst w, h
)
// 检测到人脸绘制人脸关键点(从返回数据reponseData中获取人脸关键点位置信息)
if(isDetected){
var dot_radius = 1 //绘制点半径
for (var i = 0; i < reponseData.data.face_num; i++) {
var pointNum = reponseData.data.face_list[i].landmark.length
for (var j = 0; j < pointNum; j++) {
var x = reponseData.data.face_list[i].landmark[j].x
var y = reponseData.data.face_list[i].landmark[j].y
ctx.beginPath()
ctx.fillStyle = "#00FFFF" // 绘制点颜色
// 圆点绘制
ctx.arc(
(canvasMaxWidth-canvasCurrentWidth)/2 + x * currentAdjustPara,
(canvasMaxHeight-canvasCurrentHeight)/2 + y * currentAdjustPara,
dot_radius, 0, 2 * Math.PI, true
)
ctx.closePath()
ctx.fill()
}
}
}
}
})
图片算法处理结果人脸属性列表显示
在拿到请求结果以后如果只是打印reponse数据会显得比较乱,如果能通过列表整理的方式显示出来将是不错的选择
index.js
Page({
data: {
systemInfo: {}, // 界面信息
isHiddenTable: false, //是否隐藏检测结果列表
scrollToView: "0", //滑动控件位置
resultListData:[], // 人脸检测结果列表
},
......
)
//拿到响应结果后的处理
if(data.data.face_num===1){ //单人脸情况
that.setData({
userInfo:{
tips:|#@@#|单人脸检测结果|#@@#|
},
isHiddenTable: false,//是否隐藏结果列表
scrollToView: "单人脸检测结果",
resultListData:[
{"attribute":"坐标","valuetext":data.data.face_list[0].location.x1 + " "
+ data.data.face_list[0].location.y1 + " "
+ data.data.face_list[0].location.x2 + " "
+ data.data.face_list[0].location.y2
},
{"attribute":"口罩","valuetext":data.data.face_list[0].attributes.mask===0 ? "无" : "有"},
{"attribute":"睁眼","valuetext":data.data.face_list[0].attributes.eyeopen===0 ? "否" : "是"},
{"attribute":"表情","valuetext":data.data.face_list[0].attributes.expression===0 ? "正常" : "夸张"},
{"attribute":"姿态","valuetext":data.data.face_list[0].attributes.yaw + " "
+ data.data.face_list[0].attributes.pitch + " "
+ data.data.face_list[0].attributes.roll
},
{"attribute":"亮度","valuetext":data.data.face_list[0].quality.brightness===0 ? "正常" : "异常"},
{"attribute":"模糊","valuetext":data.data.face_list[0].quality.blur===0 ? "否" : "是"},
{"attribute":"遮挡","valuetext":data.data.face_list[0].quality.occlusion.left_eye===0
&& data.data.face_list[0].quality.occlusion.right_eye===0
&& data.data.face_list[0].quality.occlusion.nose===0
&& data.data.face_list[0].quality.occlusion.mouth===0
&& data.data.face_list[0].quality.occlusion.chin===0
&& data.data.face_list[0].quality.occlusion.left_cheek===0
&& data.data.face_list[0].quality.occlusion.right_cheek===0 ? "无" : "有"
}
]
})
}
index.wxml
{{userInfo.tips}} 属性 结果值 {{item.attribute}} {{item.valuetext}} {{item.attribute}} {{item.valuetext}}
功能切换导航栏定义
为了便于不同功能之间的切换演示,需要引入导航栏功能
index,js
Page({
data: {
systemInfo: {}, // 界面信息
navbar: [|#@@#|人脸检测|#@@#|, |#@@#|人脸五官|#@@#|, |#@@#|人脸比对|#@@#|], // 功能界面选项列表
currentNavbar: |#@@#|0|#@@#|, //界面选项ID
isHiddenTable: false, //是否隐藏检测结果列表
scrollToView: "0", //滑动控件位置
resultListData:[], // 人脸检测结果列表
compareResultData:[], //人脸比对结果列表
}
......
)
index.wxml
{{item}}