LBP+SVM 活体识别

针对上一篇“深度摄像头-活体识别”的改进版

大致思路:

1.RGB人脸检测

2.同步人脸位置到深度图矩形框

3.裁剪矩形框,提取LBP特征

4.训练SVM模型。

5.集成模型到demo程序

 

详细说明:

1.RGB人脸检测使用的是seetaface,速度和准确率比opencv自带的检测器好。返回一个faces的数组,包括人脸个数和位置信息。这里可以根据要求选择做不做最大化人脸选取,选取的过程非常简单,这里不做赘述。其实我们主要就是获取人脸位置信息(x,y表示人脸框的左上角位置,w表示框宽,h表示框高)

2.因为摄像头出产做过对齐,所以这里可以省去对齐的操作。RGB和深度都是640*480画面,所以直接同步就行了。需要注意的是深度图的原始数据是16位,所以在转成mat格式的时候最好也使用16位,不丢失细节。cv::Mat u16depth(depthHeight,depthWidth,CV_16UC1,(void)*m_depthFrame.getData());

3.裁剪深度人脸框位置cv::Mat depth_face = u16depth(Rect(roi.x,roi.y,roi.width,roi.height)).clone;然后主要就是对depth_face做文章了。

(1).人脸框距离检测,因为摄像头硬件的原因,在距离较远的时候,分布到人脸上的深度信息很少。所以我人为设定在一米的距离里做活体检测。

int font = cv::FONT_HERSHEY_COMPLEX;//字体格式
double nosemean = cv::mean(depth_face)[0];
if (nosemean > 1000)
{
    cv::rectangle(depth,roi,cv::Scalar(0,0,255),2);//在深度图像中画出人脸
    cv::putText(depth,"far",cvPoint(roi.x,roi.y),font,1.5,cv::Scalar(0,0,255),2);
}
else
{
    int numOfblank = 0;//记录颜色位黑色的像素点
    float rate;//黑色像素点占的比例
    int mindepth = MAX_DEPTH;
    int maxdepth = 0;
    int maxrow = 0;
    int minrow = 0;
    for (int i = 0; i < depth_face.rows; i++)
    {
        for (int j = 0; j < depth_face.cols; j++)
        {
            int depth = depth_face.at<ushort>(i,j);
            if (depth == 0)
            {
                numOfblank++;
            }
        }
    }
    rate = (float)numOfblank / (float)(depth_face.rows * depth_face.cols);
    if (rate > 0.4)//黑色像素点占的比例超过40%时,不进入识别模块
    {
        cv::rectangle(depth,roi,cv::Scalar(0,255,0),2);//在深度图像中画出人脸
        cv::putText(depth,"close",cvPoint(roi.x,roi.y),font,1.5,cv::Scalar(0,255,0),2);
    }
    else
    {
        Size dsize = Size(128,128);//resize到128*128,识别模型训练的训练数据都是128*128尺寸
        cv::Mat image2 = Mat(dsize,CV_16UC1);
        cv::resize(depth_face,image2,dsize);
        cv::rectangle(depth,roi,cv::Scalar(255,0,0),2);//在深度图像中画出人脸
        LBP lbp;
        Mat feature_lbp = Mat(image2.rows,image.cols,CV_8UC1,Scalar(0));
        lbp.elbp(image2,feature_lbp,1,8)//LBP提取特征,后续训练模型的时候会详细介绍
        const int chanels[1] = {0};
        //直方图的每一个维度的柱条的数目(就是将灰度级分组)
        int histSize[] = {256};
        float midRanges[] = {0,255};//定义一个变量来储存单个维度数值的取值范围
        const float *ranges[] = {midRanges};//确定每一个维度的取值范围,就是横坐标的总数
        cv::Mat dstHist;
        cv::calcHist(&feature_lbp,1,channels,Mat(),dstHist,1,hisSize,ranges,true,false);
        cv::Mat dstHist_new;
        transpose(hstHist,dstHist_new);
        normalize(dstHist_new,dstHist_new,0,dstHist.rows,NORM_MINMAX,-1,Mat());//归一化结果存在dstHist
        float response = svm->predict(dstHist_new,noArray(),cv::ml::StatModel::Flags::RAW_OUTPUT);//计算出样本距离超平面的距离
        float result = response * 1000000;//乘1000000是为了方便观看
        if(result >= -10)
        {
            cv::rectangle(depth,roi,cv::Scalar(0,255,0),2);//在深度图像中画出人脸
            cv::putText(depth,"real",cvPoint(roi.x,roi.y),font,1.5,cv::Scalar(0,255,0),2);
        }
        else
        {
            cv::rectangle(depth,roi,cv::Scalar(0,255,0),2);//在深度图像中画出人脸
            cv::putText(depth,"unreal",cvPoint(roi.x,roi.y),font,1.5,cv::Scalar(0,255,0),2);
    }
}

这里说几点:

试过直接用16位深度数据做识别,也试过用LBP特征图来做识别,但是训练出来的效果都不理想。最后使用的是LBP图的直方图。

LBP提取特征的方法将在下一篇模型训练里做说明

集成到demo程序里,活体识别准确率还可以,但是泛化效果欠佳

后续方向:

使用深度学习来替代SVM,现在已经基本实现,效果比svm好很多,但是速度没有svm快,采用的是MobileNet网络,直接对原始16位mat数据进行训练识别。

rgb人脸检测依赖光线问题的解决办法是,直接训练出深度人脸检测器,目前正在进行中

 

 

 

 

 

 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值