dlib face detector 时间测试

首先记住一句话,让严谨成为工作习惯。
最近在做人脸特征点检测,考虑到dlib有人脸检测的API,所以测试一下性能。
最初用Python API测试人脸检测API dlib.get_frontal_face_detector()的速度 每张图片1300ms(CentOS服务器,图片大小960x960,等比例resize为 宽度800)。
然后在PC上测试C++ API get_frontal_face_detector(), 速度为每张图片800ms。
这看起来很正常。

然后看到基于dlib的face_recognition API 库:https://github.com/ageitgey/face_recognition
发现 的Python接口非常快,查看API封装发现,同样调用了dlib的Python API dlib.get_frontal_face_detector(),但是速度非常快。这里有一个相关的issue:https://github.com/ageitgey/face_recognition/issues/256

于是在CentOS服务器上重新测试dlib的Python接口,发现每张图片大约20ms,图片size:450x344, 等比例resize到 宽度为120。
猜想:因为在PC上测试dlib C++ API是自己编译的程序,使用单CPU,而服务器是多CPU环境,而且服务器上dlib是通过pip install 命令安装编译的。猜测是在这个编译过程中配置了多CPU选项,所以导致Python API会比C++API快很多,给人造成dlib face detect API速度很快的假象。

为保证严谨,基于同一张图片分别做Python API 和 C++ API速度测试
python 代码:

# USAGE
# python align_faces.py --shape-predictor shape_predictor_68_face_landmarks.dat --image images/example_01.jpg

# import the necessary packages
from imutils.face_utils import FaceAligner
from imutils.face_utils import rect_to_bb
import argparse
import imutils
import dlib
import cv2
import time

t1 = time.time()*1000

# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-p", "--shape-predictor", required=True,
    help="path to facial landmark predictor")
ap.add_argument("-i", "--image", required=True,
    help="path to input image")
args = vars(ap.parse_args())

# initialize dlib's face detector (HOG-based) and then create
# the facial landmark predictor and the face aligner
detector = dlib.get_frontal_face_detector()
#predictor = dlib.shape_predictor(args["shape_predictor"])
#predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
#fa = FaceAligner(predictor, desiredFaceWidth=256)

# load the input image, resize it, and convert it to grayscale
image = cv2.imread(args["image"])
#image = imutils.resize(image, width=120)
#gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray=image

# show the original input image and detect faces in the grayscale
# image
#cv2.imshow("Input", image)
t2 = time.time() * 1000
print("use time: {}ms".format(t2-t1))
t1=t2
rects = detector(gray, 2)
t2 = time.time() * 1000
print("use time: {}ms".format(t2-t1))
t1=t2
# loop over the face detections
for rect in rects:
    # extract the ROI of the *original* face, then align the face
    # using facial landmarks
        '''
    (x, y, w, h) = rect_to_bb(rect)
    faceOrig = imutils.resize(image[y:y + h, x:x + w], width=256)
    faceAligned = fa.align(image, gray, rect)
        '''
        '''
    import uuid
    f = str(uuid.uuid4())
    cv2.imwrite("foo/" + f + ".png", faceAligned)

    # display the output images
    cv2.imshow("Original", faceOrig)
    cv2.imshow("Aligned", faceAligned)
        #if cv2.waitKey(1) & 0xFF == ord('q'):
        #    break
        '''
t2 = time.time() * 1000
print("use time: {}ms".format(t2-t1))

C++测试代码:


// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This example program shows how to find frontal human faces in an image.  In
    particular, this program shows how you can take a list of images from the
    command line and display each on the screen with red boxes overlaid on each
    human face.

    The examples/faces folder contains some jpg images of people.  You can run
    this program on them and see the detections by executing the following command:
        ./face_detection_ex faces/*.jpg


    This face detector is made using the now classic Histogram of Oriented
    Gradients (HOG) feature combined with a linear classifier, an image pyramid,
    and sliding window detection scheme.  This type of object detector is fairly
    general and capable of detecting many types of semi-rigid objects in
    addition to human faces.  Therefore, if you are interested in making your
    own object detectors then read the fhog_object_detector_ex.cpp example
    program.  It shows how to use the machine learning tools which were used to
    create dlib's face detector.


    Finally, note that the face detector is fastest when compiled with at least
    SSE2 instructions enabled.  So if you are using a PC with an Intel or AMD
    chip then you should enable at least SSE2 instructions.  If you are using
    cmake to compile this program you can enable them by using one of the
    following commands when you create the build project:
        cmake path_to_dlib_root/examples -DUSE_SSE2_INSTRUCTIONS=ON
        cmake path_to_dlib_root/examples -DUSE_SSE4_INSTRUCTIONS=ON
        cmake path_to_dlib_root/examples -DUSE_AVX_INSTRUCTIONS=ON
    This will set the appropriate compiler options for GCC, clang, Visual
    Studio, or the Intel compiler.  If you are using another compiler then you
    need to consult your compiler's manual to determine how to enable these
    instructions.  Note that AVX is the fastest but requires a CPU from at least
    2011.  SSE4 is the next fastest and is supported by most current machines.
*/


#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/gui_widgets.h>
#include <dlib/image_io.h>
#include <iostream>
#include <time.h>

using namespace dlib;
using namespace std;

// ----------------------------------------------------------------------------------------

int main(int argc, char** argv)
{

    try
    {
        if (argc == 1)
        {
            cout << "Give some image files as arguments to this program." << endl;
            return 0;
        }

        frontal_face_detector detector = get_frontal_face_detector();
        image_window win;

        // Loop over all the images provided on the command line.
        for (int i = 1; i < argc; ++i)
        {
            cout << "processing image " << argv[i] << endl;
            array2d<unsigned char> img;
            load_image(img, argv[i]);
            // Make the image bigger by a factor of two.  This is useful since
            // the face detector looks for faces that are about 80 by 80 pixels
            // or larger.  Therefore, if you want to find faces that are smaller
            // than that then you need to upsample the image as we do here by
            // calling pyramid_up().  So this will allow it to detect faces that
            // are at least 40 by 40 pixels in size.  We could call pyramid_up()
            // again to find even smaller faces, but note that every time we
            // upsample the image we make the detector run slower since it must
            // process a larger image.
            pyramid_up(img);

            // Now tell the face detector to give us a list of bounding boxes
            // around all the faces it can find in the image.
            clock_t start, ends;
            start = clock();

            std::vector<rectangle> dets = detector(img);

            ends = clock();
            cout << ends - start << endl;

            cout << "Number of faces detected: " << dets.size() << endl;
            // Now we show the image on the screen and the face detections as
            // red overlay boxes.
            win.clear_overlay();
            win.set_image(img);
            win.add_overlay(dets, rgb_pixel(255, 0, 0));

            cout << "Hit enter to process the next image..." << endl;
            //cin.get();
        }
    }
    catch (exception& e)
    {
        cout << "\nexception thrown!" << endl;
        cout << e.what() << endl;
    }

    
}

// --------------------------------------------------------------------------------

Python API运行时间为:大约130ms

(env) [hongjie.li@test face-alignment]$ python align_faces.py -p True -i test2_0.5_0.5.png 
use time: 402.801025391ms
use time: 130.208007812ms
use time: 0.198974609375ms
(env) [hongjie.li@test face-alignment]$ python align_faces.py -p True -i test2_0.5_0.5.png 
use time: 310.430908203ms
use time: 130.185302734ms
use time: 0.200927734375ms


C++ API 运行时间约为:50ms

PS C:\files\face_detection_dlib\build\Release> .\face_detect.exe ..\..\test2_0.5_0.5.png
processing image ..\..\test2_0.5_0.5.png
56
Number of faces detected: 1
Hit enter to process the next image...
PS C:\files\face_detection_dlib\build\Release> .\face_detect.exe ..\..\test2_0.5_0.5.png
processing image ..\..\test2_0.5_0.5.png
48
Number of faces detected: 1
Hit enter to process the next image...

测试图片,图片大小为 225x216


test2_0.5_0.5.png

总结:由于之前用Python API 和 C++ API分别测试时忽略了图片的大小(resize操作),甚至C++ API测试时不是严格对detector测试,含包括了其他函数比如

            win.clear_overlay();
            win.set_image(img);
            win.add_overlay(dets, rgb_pixel(255, 0, 0));

后来发现这些操作也占用了大量的时间,导致得到dlib C++ API比Python API要慢的错误结论。
虽然在dlib的setup.py中确实有多CPU的编译配置,可能dlib在pip install安装编译的时候确实使用了多CPU,但是 dlib 的 face detector C++ API速度并不比Python API慢。
关于dlib face detector API是否使用多CPU,影响到dlib是否适合在移动端使用,所以才会有这个测试过程。
整个总结重测过程花了不少时间,吃了不严谨的亏。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容