人脸特征点检测(二)

2.Dlib人脸特征点检测

Dlib库是一个集机器学习、计算机视觉、图像处理等众多算法的开源库,其代码简洁,注释清晰,支持C++和Python接口,库中很多头文件可以直接放在C++应用中。Dlib实现了2014年一篇非常经典的人脸特征点检测的论文:Face Alignment at 3000 FPS via Regression Local Binary Features,其人脸特征点检测又快又准。

这里写图片描述

这里不探讨dlib库的编译问题,请自行编译。使用Dlib库进行人脸特征点检测十分简单,可以参考官网的examples,下面是画出人脸特征点的python脚本和效果图。

# coding: utf-8
import cv2
import dlib
#draw_all_landmarks_id
detector = dlib.get_frontal_face_detector()
#predictor = dlib.shape_predictor('/home/tanhui/notebook/shape_predictor_68_face_landmarks.dat')
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')

img = cv2.imread('test.jpg')
img_out = img.copy()
dets = detector(img,0) #dlib人脸检测
print dets[0]
for i,d in enumerate(dets):
    cv2.rectangle(img_out,(d.left(),d.top()),(d.right(),d.bottom()),(0,255,0),3)
    shape = predictor(img,d) #dlib人脸特征点检测
    for k in range(0,68): #68个特征点
        cv2.circle(img_out,(shape.part(k).x,shape.part(k).y),2,(255,0,0),-1) #-1表示填充
        #cv2.putText(img_out,'%d' % k,(shape.part(k).x,shape.part(k).y),cv2.FONT_HERSHEY_SIMPLEX,0.4,(0,0,255),1) #标记点号
        print (shape.part(k).x,shape.part(k).y)
cv2.imwrite('face_landmarks.jpg',img_out)
print 'success'

cv2.imshow('landmarks',img_out)
cv2.waitKey(0)
cv2.destroyAllWindows()

这里写图片描述
这里写图片描述

下面是用opencv调用摄像头、Dlib进行摄像头视频实时检测人脸和特征点python脚本。摄像头分辨率为640x480,在我的机器上(i7 6700K CPU @ 4.00GHz)测试人脸检测平均耗时44ms,人脸特征点检测平均耗时3ms。如果摄像头中人脸总是比较大(离镜头比较近),完全可以对图像下采样之后进行人脸检测,速度会提升很多,例如下采样一倍时,人脸检测平均耗时降低到11ms,因此在某些场景下达到实时检测也是完全可以的。

# -*- coding: utf-8 -*-
"""
Created on Thu Apr 06 20:52:04 2017

@author: Administrator
"""
import dlib
import cv2
import time

detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')

def find_face_landmarks(img):
    time0 = time.time()
    points = []
    rects = detector(img,0)
    time1 = time.time()
    print (time1 - time0)*1000,'ms'
    if len(rects) == 0:
        return [],points

    shape = predictor(img,rects[0])
    time2 = time.time()
    print (time2 - time1)*1000,'ms'
    for i in range(0,68):
        points.append((shape.part(i).x,shape.part(i).y))

    return rects[0],points

def draw_face_landmarks(img,rect,landmarks):
    img_dst = img.copy()
    cv2.rectangle(img_dst,(rect.left(),rect.top()),(rect.right(),rect.bottom()),(255,0,0),2)
    for i in range(0,68):
        cv2.circle(img_dst,points[i],2,(0,0,255),-1) #-1表示填充
    return img_dst

video = cv2.VideoCapture(0)
if video.isOpened():
    print 'width: %d' % video.get(cv2.CAP_PROP_FRAME_WIDTH)
    print 'height: %d' % video.get(cv2.CAP_PROP_FRAME_HEIGHT)
    success,frame = video.read()
    while success:
        rect,points = find_face_landmarks(frame)
        if not rect:
            success,frame = video.read()
            continue
        img = draw_face_landmarks(frame,rect,points)

        cv2.imshow('face_landmarks',img)
        if cv2.waitKey(1) > 0:
            break
        success,frame = video.read()
    video.release()
    cv2.destroyAllWindows()

3.libfacedetect人脸特征点检测

libfacedetect是深圳大学于仕祺老师提供的免费的人脸检测库,以二进制的方式免费发布可商用,可将这个库应用到系统中,无论是科研目的还是商业目的,无任何限制。该库调用非常简单,只有一个函数,纯C语言编译而成,不依赖任何第三方库。libfacedetect只提供了C++接口,其提供了四套接口,分别为frontal、frontal_surveillance、multiview、multiview_reinforce,其中multiview_reinforce效果最好,可以检测侧脸,速度比其它稍慢。
libfacedetect人脸检测和特征点检测的速度奇快,非常好用,对侧脸检测也有很好的效果。测试了一张500x750大小的图像,如果最小检测脸设置为48时,人脸检测和特征点检测总共耗时7ms左右。它和opencv一样,将灰度化的图像作为输入,且对灰度图做直方图均衡化可以改善极端情况下的检测。
在于仕祺老师的github主页上有libfacedetect库 github 里面也提供了examples,下面是修改后的代码。

/*
The MIT License (MIT)

Copyright (c) 2015-2017 Shiqi Yu
[email protected]

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#include <stdio.h>
#include <opencv2/opencv.hpp>
#include "facedetect-dll.h"
#include "time.h"
using namespace std;

//#pragma comment(lib,"libfacedetect.lib")
#pragma comment(lib,"libfacedetect-x64.lib")

//define the buffer size. Do not change the size!
#define DETECT_BUFFER_SIZE 0x20000
using namespace cv;

int main()
{
    //load an image and convert it to gray (single-channel)
    Mat image = imread("C:\\Users\\Administrator\\Desktop\\faces\\39649a2f070828388e658cb3ba99a9014d08f1cc.jpg");
    Mat gray;
    cvtColor(image, gray, CV_BGR2GRAY);

    clock_t start_t, end_t;
    start_t = clock();
    int * pResults = NULL;
    //pBuffer is used in the detection functions.
    //If you call functions in multiple threads, please create one buffer for each thread!
    unsigned char * pBuffer = (unsigned char *)malloc(DETECT_BUFFER_SIZE);
    if (!pBuffer)
    {
        fprintf(stderr, "Can not alloc buffer.\n");
        return -1;
    }

    int doLandmark = 1;

    ///////////////////////////////////////////
    // frontal face detection / 68 landmark detection
    // it's fast, but cannot detect side view faces
    //////////////////////////////////////////
    //!!! The input image must be a gray one (single-channel)
    //!!! DO NOT RELEASE pResults !!!
    pResults = facedetect_frontal(pBuffer, (unsigned char*)(gray.ptr(0)), gray.cols, gray.rows, (int)gray.step,
        1.2f, 2, 48, 0, doLandmark);
    end_t = clock();
    cout << (double)(end_t - start_t) / CLOCKS_PER_SEC << "s" << endl;
    cout << gray.cols << "," << gray.rows << endl;

    printf("%d faces detected.\n", (pResults ? *pResults : 0));
    Mat result_frontal = image.clone();
    //print the detection results
    for (int i = 0; i < (pResults ? *pResults : 0); i++)
    {
        short * p = ((short*)(pResults + 1)) + 142 * i;
        int x = p[0];
        int y = p[1];
        int w = p[2];
        int h = p[3];
        int neighbors = p[4];
        int angle = p[5];

        printf("face_rect=[%d, %d, %d, %d], neighbors=%d, angle=%d\n", x, y, w, h, neighbors, angle);
        rectangle(result_frontal, Rect(x, y, w, h), Scalar(0, 255, 0), 2);
        if (doLandmark)
        {
            for (int j = 0; j < 68; j++)
                circle(result_frontal, Point((int)p[6 + 2 * j], (int)p[6 + 2 * j + 1]), 1, Scalar(0, 255, 0));
        }
    }
    imshow("Results_frontal", result_frontal);

    /////////////////////////////////////////////
    //// frontal face detection designed for video surveillance / 68 landmark detection
    //// it can detect faces with bad illumination.
    ////////////////////////////////////////////
    ////!!! the input image must be a gray one (single-channel)
    ////!!! do not release presults !!!
    //presults = facedetect_frontal_surveillance(pbuffer, (unsigned char*)(gray.ptr(0)), gray.cols, gray.rows, (int)gray.step,
    //  1.2f, 2, 48, 0, dolandmark);
    //printf("%d faces detected.\n", (presults ? *presults : 0));
    //mat result_frontal_surveillance = image.clone();;
    ////print the detection results
    //for (int i = 0; i < (presults ? *presults : 0); i++)
    //{
    //  short * p = ((short*)(presults + 1)) + 142 * i;
    //  int x = p[0];
    //  int y = p[1];
    //  int w = p[2];
    //  int h = p[3];
    //  int neighbors = p[4];
    //  int angle = p[5];

    //  printf("face_rect=[%d, %d, %d, %d], neighbors=%d, angle=%d\n", x, y, w, h, neighbors, angle);
    //  rectangle(result_frontal_surveillance, rect(x, y, w, h), scalar(0, 255, 0), 2);
    //  if (dolandmark)
    //  {
    //      for (int j = 0; j < 68; j++)
    //          circle(result_frontal_surveillance, point((int)p[6 + 2 * j], (int)p[6 + 2 * j + 1]), 1, scalar(0, 255, 0));
    //  }
    //}
    //imshow("results_frontal_surveillance", result_frontal_surveillance);


    /////////////////////////////////////////////
    //// multiview face detection / 68 landmark detection
    //// it can detect side view faces, but slower than facedetect_frontal().
    ////////////////////////////////////////////
    ////!!! the input image must be a gray one (single-channel)
    ////!!! do not release presults !!!
    //presults = facedetect_multiview(pbuffer, (unsigned char*)(gray.ptr(0)), gray.cols, gray.rows, (int)gray.step,
    //  1.2f, 2, 48, 0, dolandmark);

    //printf("%d faces detected.\n", (presults ? *presults : 0));
    //mat result_multiview = image.clone();;
    ////print the detection results
    //for (int i = 0; i < (presults ? *presults : 0); i++)
    //{
    //  short * p = ((short*)(presults + 1)) + 142 * i;
    //  int x = p[0];
    //  int y = p[1];
    //  int w = p[2];
    //  int h = p[3];
    //  int neighbors = p[4];
    //  int angle = p[5];

    //  printf("face_rect=[%d, %d, %d, %d], neighbors=%d, angle=%d\n", x, y, w, h, neighbors, angle);
    //  rectangle(result_multiview, rect(x, y, w, h), scalar(0, 255, 0), 2);
    //  if (dolandmark)
    //  {
    //      for (int j = 0; j < 68; j++)
    //          circle(result_multiview, point((int)p[6 + 2 * j], (int)p[6 + 2 * j + 1]), 1, scalar(0, 255, 0));
    //  }
    //}
    //imshow("results_multiview", result_multiview);


    /////////////////////////////////////////////
    //// reinforced multiview face detection / 68 landmark detection
    //// it can detect side view faces, better but slower than facedetect_multiview().
    ////////////////////////////////////////////
    ////!!! the input image must be a gray one (single-channel)
    ////!!! do not release presults !!!
    //presults = facedetect_multiview_reinforce(pbuffer, (unsigned char*)(gray.ptr(0)), gray.cols, gray.rows, (int)gray.step,
    //  1.2f, 3, 48, 0, dolandmark);

    //printf("%d faces detected.\n", (presults ? *presults : 0));
    //mat result_multiview_reinforce = image.clone();;
    ////print the detection results
    //for (int i = 0; i < (presults ? *presults : 0); i++)
    //{
    //  short * p = ((short*)(presults + 1)) + 142 * i;
    //  int x = p[0];
    //  int y = p[1];
    //  int w = p[2];
    //  int h = p[3];
    //  int neighbors = p[4];
    //  int angle = p[5];

    //  printf("face_rect=[%d, %d, %d, %d], neighbors=%d, angle=%d\n", x, y, w, h, neighbors, angle);
    //  rectangle(result_multiview_reinforce, rect(x, y, w, h), scalar(0, 255, 0), 2);
    //  if (dolandmark)
    //  {
    //      for (int j = 0; j < 68; j++)
    //          circle(result_multiview_reinforce, point((int)p[6 + 2 * j], (int)p[6 + 2 * j + 1]), 1, scalar(0, 255, 0));
    //  }
    //}
    //imshow("results_multiview_reinforce", result_multiview_reinforce);

    waitKey();

    //release the buffer
    free(pBuffer);

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章