1. 程式人生 > >Dlib人臉特徵點檢測(速度優化)

Dlib人臉特徵點檢測(速度優化)

最近在做人臉先關的研究,人臉識別其實有很多部分組成,每一個環節都關係到整體的效果。因為主要精力在識別這塊,前面的人臉檢測以及特徵點的提取就沒有花費太多精力,開始時使用的dlib提供的介面進行人臉對齊。效果是不錯,但是缺點也非常明顯,dlib的人臉檢測實在太慢,320*240的圖片,差不多需要0.15s的時間。
看了很多的解決方法https://github.com/cmusatyalab/openface/issues/85 這裡有提到通過tbb加速dlib;通過track來加速檢測;還有一篇比較讚的文章https://arxiv.org/ftp/arxiv/papers/1508/1508.01292.pdf 可以達到28fps at 4K, 54fps at 1080p的檢測速度(沒有公開原始碼),不過方法感覺比較可信,有時間的話一定要試一試。
以上的方法都很好,不過沒有時間一一嘗試,這裡使用了一個比較簡單的方法,通過Opencv的檢測器進行人臉檢測,然後呼叫Dlib的特徵點檢測方法進行檢測,對齊。
之前考慮到使用不同的檢測器可能會對Landmark的提取有影響,所以一直沒有試,今天實驗了一下,效果竟然還不錯,不過個人認為,如果要達到較好的精度,Landmark的模型最好針對自己的檢測器做訓練。Dlib使用的是One Millisecond Face Alignment with an Ensemble of Regression Trees 這篇文章的方法,不知道Dlib中有沒有留出訓練的介面,不過檢測的原始碼都是有的,可以研究一下。之前本來準備使用Face Alignment at 3000 FPS via Regressing Local Binary Features做人臉對齊,不過看到別人說自己訓練很難達到文章的效果,所以就沒有嘗試。
下面貼程式碼:
程式先從通過opencv檢測人臉,然後使用了Dlib進行人臉對齊,opencv中有很多引數可以設定,可以根據自己的需要加快檢測速度。這裡對於640*480的圖片進行最大人臉檢測以及對齊的時間消耗只要差不多70ms就可以完成。
dlib還是不太瞭解,下面的對齊程式碼如何實現不是很清楚,不過還是可以轉換成opencv的格式通過getAffineTransform以及warpAffine函式完成人臉對齊,下面寫出基本的例程。

#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/image_processing/render_face_detections.h>
#include <dlib/image_processing.h>
#include <dlib/gui_widgets.h>
#include <dlib/image_io.h>
#include <iostream>
#include "opencv2/opencv.hpp"
#include "opencv2/core/core.hpp"
#include "time.h" using namespace dlib; using namespace std; //using namespace cv; 和dlib的名稱空間有衝突 // ---------------------------------------------------------------------------------------- int main(int argc, char** argv) { image_window win, win_faces; string face_cascade_name = "/home/f/ClionProjects/test_cython/koestinger_cascade_aflw_lbp.xml"
; //這裡使用的LBP檢測器,速度較haar檢測器速度快,沒有的話使用opencv自帶的haar特徵檢測器也可以 cv::CascadeClassifier face_cascade; face_cascade.load(face_cascade_name); shape_predictor sp; string shape_model = "/home/f/ClionProjects/test_cython/shape_predictor_68_face_landmarks.dat"; //模型下載地址如下: //http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2 deserialize(shape_model) >> sp; string img_path = "/home/f/ClionProjects/test_cython/faces/1.jpg"; array2d<rgb_pixel> img; load_image(img, img_path); cv::Mat face = cv::imread(img_path); std::vector<cv::Rect> faces; cv::Mat face_gray; cvtColor( face, face_gray, CV_BGR2GRAY ); //rgb型別轉換為灰度型別 equalizeHist( face_gray, face_gray ); //直方圖均衡化 face_cascade.detectMultiScale(face_gray,faces,1.2,2,0|CV_HAAR_FIND_BIGGEST_OBJECT,cv::Size(20,20)); dlib::rectangle det; //將opencv檢測到的矩形轉換為dlib需要的資料結構,這裡沒有判斷檢測不到人臉的情況 det.set_left(faces[0].x); det.set_top(faces[0].y); det.set_right(faces[0].x+faces[0].width); det.set_bottom(faces[0].y+faces[0].height); // Now we will go ask the shape_predictor to tell us the pose of // each face we detected. std::vector<full_object_detection> shapes; full_object_detection shape = sp(img, det); cout << "number of parts: "<< shape.num_parts() << endl; cout << "pixel position of first part: " << shape.part(0) << endl; cout << "pixel position of second part: " << shape.part(1) << endl; shapes.push_back(shape); // Now let's view our face poses on the screen. win.clear_overlay(); win.set_image(img); win.add_overlay(render_face_detections(shapes)); // We can also extract copies of each face that are cropped, rotated upright, // and scaled to a standard size as shown here: dlib::array<array2d<rgb_pixel> > face_chips; extract_image_chips(img, get_face_chip_details(shapes), face_chips); win_faces.set_image(tile_images(face_chips)); char pause; cin>>pause; return 0; }

下面的CMakeLists.txt稍微介紹一下,寫不對的話是編譯不了的。
需要將自己的dlib檔案引入進來,根據自己的地址做修改,Dlib有點麻煩就是對jpg,png格式圖片的載入使用需要自己手動新增相關支援,比如讀取JPEG的檔案,需要自己載入jpeg.so而且在編譯過程中也要宣告。

cmake_minimum_required(VERSION 3.5)
project(face_align)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -DDLIB_JPEG_SUPPORT  -DCMAKE_BUILD_TYPE=Release")
include_directories(${CMAKE_SOURCE_DIR})
include_directories(/home/f/downLoad/dlib/) #dlib.h....
link_directories(/usr/lib/x86_64-linux-gnu/) #jpeg.so
link_directories(/home/f/downLoad/dlib/build/dlib/) #dlib.so

set(SOURCE_FILES main.cpp)
add_executable(face_align ${SOURCE_FILES})
find_package(OpenCV REQUIRED)
target_link_libraries(face_align ${OpenCV_LIBS} dlib.so jpeg.so)

今天在Openface下測試了這種方法對識別的結果影響,又看了一下對齊的效果,確實對齊的不是很準,人臉識別原模型在LFW資料庫上是93%的準確率,換了這種對齊方式,下降到87.6%。看來要想達到較好的結果,每一環都不能忽略。

最近看到一個程式碼很不錯,方法簡單,而且速度很快。程式碼地址如下https://github.com/mc-jesus/face_detect_n_track
這裡是作者給出的流程圖,意思就是說第一幀圖片先進行普通的全圖搜尋,如果找到了人臉那就在這個boundingBox兩倍大的區域內再次呼叫檢測器檢測,如果檢測不到就使用模板匹配的方法檢測,2s內檢測不到就重置演算法。跑了一下發現模板匹配其實沒怎麼用到,而且要配合特徵點檢測演算法,這裡不能使用模板匹配來搜尋人臉,簡化一下演算法,只要使用兩倍大的搜尋框搜尋就可以達到不錯的效果。按照這個思想修改了Dlib版本的程式碼,在320*240的圖片裡檢測人臉可以達到30ms以內。320*240的解析度不做縮放可以檢測到差不多3米遠的人臉。可以根據應用場景再做優化,而且現在這個速度其實也不快,還有很多簡單的優化方法。