最近在做人脸识别的研究和开发,其中用的还是传统的支持向量机 ——SVM和特征提取方法 LBP(具有灰度不变形的优点)
在少量的数据下,传统的机器学习方法相对于现在比较热门的深度学习算法有一定的优势,比如计算速度等。
其中的SVM我使用的是台湾大学的LIBSVM的开源项目,这个开源项目是很经典而且很实用。
对于非端对端的学习,一个好的分类问题,需要的就是提取最有价值的特征,那么如何更好的使用LBP和对图片的预处理是至关重要的。
那么,对于LBP算法,我对他进行了改进,依照的是很多论文中的改进算法,通过做了很多的实验,也验证了对LBP算法改进的优势。
那么剩下的就是图片的预处理问题了,其中的最重要的步骤就是对人脸图片的归一化。
怎么进行归一化呢?
一般情况下我们先进行人脸检测,那么检测出的 人脸类似下图。
除了有些背景稍微大些之外,这已经算是很标准的人脸图了。
但是特殊情况
对这种情况我们该怎么办?
无疑,我们需要对图片进行旋转。
那么问题来了,改怎么旋转?
就引入了我们的题目,我们的方法如下:
通过人脸检测,找到双眼的位置,然后根据坐标,找到旋转角度,然后进行旋转。
下面我们介绍如何寻找人脸的位置。
方法一:
通过Opencv 自带的 CascadeClassifier类,然后使用自带的训练好的人眼模型。
核心代码(JAVA)如下:
detector2.detectMultiScale(eyeMat , eyeDetections , 1.01 , 2 , 0 , new Size(10 , 10) , new Size(60 , 60));
我通过实验得出 参数 为以上 代码中的值(这个和图片的大小有一定的关系,我的测试集合图片的大小为(100,100) )时,在face set 集中识别双眼率最高,c代码也一样。
Opencv官网代码
CascadeClassifier类介绍
缺点,识别率低。
方法二
就是通过商业项目 face++ 来做人眼检测。他们的准确率比Opecv自带的要 高的多。 不过,我使用的方法是通过Json网络请求。
官方也提供了离线的人脸检测和特征点检测。不过,并没有详细的例子介绍,所以,我就介绍下网络异步请求人眼检测。
face++提供的SDK中提供了人脸检测的demo不过没有介绍人眼检测的。
不过,face++提供服务 包括以下 json信息。
JSON信息
其中有以下两条JSONObject
"eye_left": {
"x": 43.3692,
"y": 30.8192
},
"eye_right": {
"x": 56.5606,
"y": 30.9886
},
这俩个的含义是: 相对于 整张图片的 相对位置。
那么通过图片大小乘该位置就是人眼中心点的位置,也就找到了人眼的中心点。
部分代码如下:
//需要上传文件的路径
File f = new File(Environment.getExternalStorageDirectory()+"/jaychou.jpg");
PostParameters postP = new PostParameters();
postP.setImg(f);
result = httpRequests.detectionDetect(postP);
JSONObject ageJson = result.getJSONArray("face").getJSONObject(0).getJSONObject("attribute").getJSONObject("age");
JSONObject left_eyeJson = result.getJSONArray("face").getJSONObject(0).getJSONObject("position").getJSONObject("eye_left");
JSONObject right_eyeJson = result.getJSONArray("face").getJSONObject(0).getJSONObject("position").getJSONObject("eye_right");
int img_width = result.getInt("img_width");
int img_height = result.getInt("img_height");
String str = ageJson.getString("value");
int x1 = left_eyeJson.getInt("x")*img_width/100;
int y1 = left_eyeJson.getInt("y")*img_height/100;
int x2 = right_eyeJson.getInt("x")*img_width/100;
int y2 = right_eyeJson.getInt("y")*img_height/100;
Rect rect1 = new Rect(x1 - 5 , y1 - 5 , x1 + 5 , y1 + 5);
Rect rect2 = new Rect(x2 - 5 , y2 - 5 , x2 + 5 , y2 + 5);
其中的两个Rect就是人脸的位置。
运行结果如下: