实训日记4:情绪分析
本周实现通过用户的面部图像来分析该用户的情绪的功能,分析的方法是调用了Face++旷世的api。
Face++的文档在https://console.faceplusplus.com.cn/documents/4888373该api可以对传入图片进行人脸检测和人脸分析。
需要注意的是,使用Face++的API需要进行注册等操作
- 在官网注册账号: https://www.faceplusplus.com.cn/
- 创建APIKey来使用: https://console.faceplusplus.com.cn/app/apikey/create (试用的APIKey可以免费使用,可能有并发数错误.正式APIKey需要充值后使用)
图片要求
图片格式:JPG(JPEG),PNG
图片像素尺寸:最小 4848 像素,最大 40964096 像素
图片文件大小:2 MB
最小人脸像素尺寸: 系统能够检测到的人脸框为一个正方形,正方形边长的最小值为图像短边长度的 48 分之一,最小值不低于 48 像素。 例如图片为 4096*3200 像素,则最小人脸像素尺寸为 66*66 像素。
调用URL
https://api-cn.faceplusplus.com/facepp/v3/detect
调用方法
POST
请求参数
我们需要的请求参数如下:
其中最为需要的是emotion参数,emotion是情绪识别结果。返回值包含以下字段。每个字段的值都是一个浮点数,范围 [0,100],小数点后 3 位有效数字。每个字段的返回值越大,则该字段代表的状态的置信度越高。字段值的总和等于 100。
- anger:愤怒
- disgust:厌恶
- fear:恐惧
- happiness:高兴
- neutral:平静
- sadness:伤心
- surprise:惊讶
测试
参考https://github.com/FacePlusPlus/facepp-javascript-sdk?tdsourcetag=s_pctim_aiomsg
- 首先把facepp_sdk这个文件夹拖入到自己的项目
- 在项目中引用
<script type="text/javascript" src="facepp_sdk/jquery.min.js"></script>
<script type="text/javascript" src="facepp_sdk/exif.js"></script>
<script type="text/javascript" src="facepp_sdk/facepp_sdk.js"></script>
在使用文件选择框选择图片后,使用如下代码以二进制的方式上传图片,并显示回调结果
<script>
var facepp = new FACEPP(APIKEY,APISERET,1);
// 选择照片
function selectImage(input){
let imageView = document.getElementById('preview');
const reader = new FileReader();
reader.readAsDataURL(input.files[0]);
reader.onload = function (e) {
//移除之前的人脸框
$("#facesContainer div").remove();
//图片的base64数据
const base64Image = e.target.result;
//显示图片
//修复显示方向不对问题
fixOrientention(base64Image,imageView);
/*
//base64方式上传图片
let dic = {'image_base64' : base64Image};
facepp.detectFace(dic,success,failed);
*/
// 以二进制的方式上传图片
// 将base64转为二进制
let imageData = facepp.dataURItoBlob(base64Image);
//根据个人需求填写的参数,这里全部写上了,包括年龄性别等,详情看官方文档
let attributes = 'gender,age,smiling,headpose,facequality,blur,eyestatus,emotion,ethnicity,beauty,mouthstatus,eyegaze,skinstatus';
//上传图片,获取结果
let dataDic = {'image_file':imageData,'return_landmark':2,'return_attributes':attributes};
//调用接口,检测人脸
facepp.detectFace(dataDic,success,failed);
}
}
//成功的回调
function success(e){
//显示结果
console.log(e);
let textView = document.getElementById('text');
textView.innerText = JSON.stringify(e,null,"\t");
// 画上人脸框,男女颜色不一样
let imageView = document.getElementById('preview');
const faces = e.faces;
for (const index in faces){
const face = faces[index];
const face_rectangle = face.face_rectangle;
//脸部旋转角度
var roll = face.attributes.headpose.roll_angle;
//性别
var gender = face.attributes.gender.value;
const borderColor = (gender == 'Male') ? 'blue' : 'red';
console.log('人脸框颜色:' + borderColor);
//脸部坐标
var faceX = face_rectangle.left;
var faceY = face_rectangle.top;
var faceW = face_rectangle.width;
var faceH = face_rectangle.height;
//faceContainer尺寸
var width = 320;
var height = 320;
//img尺寸
var imageW = imageView.width;
var imageH = imageView.height;
//图片实际尺寸
var naturalWidth = imageView.naturalWidth;
var naturalHeight = imageView.naturalHeight;
console.log('container尺寸' + width + '----' + height);
console.log('img尺寸' + imageW + '----' + imageH);
console.log('图片实际尺寸' + naturalWidth + '----' + imageH);
const scale = imageW / naturalWidth;
console.log('scale > ' + scale);
const offsetX = (width - imageW)*0.5;
const offsetY = (height - imageH)*0.5;
console.log('offsetX:' + offsetX + 'offsetY' + offsetY);
//添加人脸框
$('<div/>').css({
position: 'absolute',
top: faceY * scale + offsetY,
left: faceX * scale + offsetX,
height: faceH * scale,
width: faceW * scale,
border: '2px solid ' + borderColor,
transform: 'rotate(' + roll + 'deg)'
}).appendTo($("#facesContainer"));
}
}
//失败的回调
function failed(e){
console.log(e);
let textView = document.getElementById('text');
textView.innerText = JSON.stringify(e);
}
//图片方向矫正
function fixOrientention(base64Image,imageView) {
const image = new Image();
image.onload = () => {
const canvas = document.createElement('canvas');
const initSize = image.src.length;
let width = image.naturalWidth;
let height = image.naturalHeight;
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 旋转图片操作
EXIF.getData(image, function () {
const orientation = EXIF.getTag(this, 'Orientation');
console.log(`orientation:${orientation}`);
switch (orientation) {
// 正常状态
case 1:
console.log('旋转0°');
canvas.height = height;
canvas.width = width;
ctx.drawImage(image, 0, 0, width, height);
break;
// 旋转90度
case 6:
console.log('旋转90°');
canvas.height = width;
canvas.width = height;
ctx.rotate(Math.PI / 2);
ctx.translate(0, -height);
ctx.drawImage(image, 0, 0, width, height);
break;
// 旋转180°
case 3:
console.log('旋转180°');
canvas.height = height;
canvas.width = width;
ctx.rotate(Math.PI);
ctx.translate(-width, -height);
ctx.drawImage(image, 0, 0, width, height);
break;
// 旋转270°
case 8:
console.log('旋转270°');
canvas.height = width;
canvas.width = height;
ctx.rotate(-Math.PI / 2);
ctx.translate(-width, 0);
ctx.drawImage(image, 0, 0, width, height);
break;
default:
console.log('default 旋转0°');
canvas.height = height;
canvas.width = width;
ctx.drawImage(image, 0, 0, width, height);
break;
}
});
var newBase64 = canvas.toDataURL('image/jpeg', 1.0);
imageView.src = newBase64;
};
image.src = base64Image;
}
</script>
基本思路是把图片转为base64,再转为二进制;接下来根据个人需求填写的参数,这里全部写上;然后上传图片,调用接口;最后获取结果,结果是json格式的数据,把它展示在文本框中即可。
测试结果
测试结果如下
这里用到了个人练习生蔡徐坤先生用标准姿势手拿篮球的照片,可以看到准确地框出了人脸的位置,并在下方文本框中写出了返回参数。
看一下我们最关心的emotion参数:
情绪分析的结果为:
- anger:愤怒——14.67%
- disgust:厌恶——0.163%
- fear:恐惧——0.163%
- happiness:高兴——1.936%
- neutral:平静——68.429%
- sadness:伤心——14.67%
- surprise:惊讶——11.633%