人臉特徵點檢測(二)

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章