虹软人脸检测算法评测

现在开源的人脸检测、识别算法也越来越多,同时有些算法厂商也开始将他们的产品免费提供给用户。前些天,下了虹软的人脸检测算法,与开源的Dlib人脸检测算法进行了一个对比,过程和结果如下:

  • 虹软人脸检测算法

(1)从虹软官网上下载评测版本,我下来的zip包是:ARCSOFT_FSDK_FACE_DETECTION_1.1.0.197_LINUX64_05212018.zip

(2)编译测试代码,这里不得不吐槽一下,虹软提供的测试代码真是相当简单,没有编译说明文档不说,连测试输入也在代码中写死成YUV格式的某个固定文件。所以我对测试代码进行了修改,输入改成任意的JPG格式的文件,输出是检测到人脸的位置坐标信息。
#cat arcsoft_afd_samplecode.cpp

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <iostream>
#include <opencv2/opencv.hpp>
#include <string.h>

#include "arcsoft_fsdk_face_detection.h"
#include "merror.h"

#define APPID     "86aGodkxpbeC3CM11sV85H6ByLFjAmsdU3qBiWnwXoJX"
#define SDKKEY    "3wFJQRRSBSjc6Q9F1uX97pTFeXXUd6DSgu6XWKbcXxVF"


#define INPUT_IMAGE_FORMAT  ASVL_PAF_RGB24_B8G8R8

#define WORKBUF_SIZE        (40*1024*1024)
#define MAX_FACE_NUM        (50)

using namespace std;
using namespace cv;

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

    Mat img;

    img = imread(argv[1]);


    MByte *pWorkMem = (MByte *)malloc(WORKBUF_SIZE);
    if(pWorkMem == nullptr){
        fprintf(stderr, "fail to malloc workbuf\r\n");
        exit(0);
    }

    MHandle hEngine = nullptr;

    int ret = AFD_FSDK_InitialFaceEngine((MPChar)APPID, (MPChar)SDKKEY, pWorkMem, WORKBUF_SIZE, 
                                         &hEngine, AFD_FSDK_OPF_0_HIGHER_EXT, 16, MAX_FACE_NUM);
    if (ret != 0) {
        fprintf(stderr, "fail to AFD_FSDK_InitialFaceEngine(): 0x%x\r\n", ret);
        free(pWorkMem);
        exit(0);
    }

    const AFD_FSDK_Version*pVersionInfo = AFD_FSDK_GetVersion(hEngine);
    printf("%d %d %d %d\r\n", pVersionInfo->lCodebase, pVersionInfo->lMajor,
                                 pVersionInfo->lMinor, pVersionInfo->lBuild);
    printf("%s\r\n", pVersionInfo->Version);
    printf("%s\r\n", pVersionInfo->BuildDate);
    printf("%s\r\n", pVersionInfo->CopyRight);

    ASVLOFFSCREEN inputImg = { 0 };
    inputImg.u32PixelArrayFormat = INPUT_IMAGE_FORMAT;
#if 0
    inputImg.i32Width = INPUT_IMAGE_WIDTH;
    inputImg.i32Height = INPUT_IMAGE_HEIGHT;
#else
    inputImg.i32Width = img.size().width;
    inputImg.i32Height = img.size().height;
#endif

#if 0
    inputImg.ppu8Plane[0] = nullptr;
    fu_ReadFile(INPUT_IMAGE_PATH, (uint8_t**)&inputImg.ppu8Plane[0], nullptr);
     if (!inputImg.ppu8Plane[0]) {
        fprintf(stderr, "fail to fu_ReadFile(%s): %s\r\n", INPUT_IMAGE_PATH, strerror(errno));
                AFD_FSDK_UninitialFaceEngine(hEngine);
        free(pWorkMem);
        exit(0);
    }
#else
     inputImg.ppu8Plane[0] = (MUInt8*)malloc(inputImg.i32Width * inputImg.i32Height * 3);
     memcpy(inputImg.ppu8Plane[0], img.data, inputImg.i32Width * inputImg.i32Height * 3);
#endif

    if (ASVL_PAF_I420 == inputImg.u32PixelArrayFormat) {
        inputImg.pi32Pitch[0] = inputImg.i32Width;
        inputImg.pi32Pitch[1] = inputImg.i32Width/2;
        inputImg.pi32Pitch[2] = inputImg.i32Width/2;
        inputImg.ppu8Plane[1] = inputImg.ppu8Plane[0] + inputImg.pi32Pitch[0] * inputImg.i32Height;
        inputImg.ppu8Plane[2] = inputImg.ppu8Plane[1] + inputImg.pi32Pitch[1] * inputImg.i32Height/2;
    } else if (ASVL_PAF_NV12 == inputImg.u32PixelArrayFormat) {
        inputImg.pi32Pitch[0] = inputImg.i32Width;
        inputImg.pi32Pitch[1] = inputImg.i32Width;
        inputImg.ppu8Plane[1] = inputImg.ppu8Plane[0] + (inputImg.pi32Pitch[0] * inputImg.i32Height);
    } else if (ASVL_PAF_NV21 == inputImg.u32PixelArrayFormat) {
        inputImg.pi32Pitch[0] = inputImg.i32Width;
        inputImg.pi32Pitch[1] = inputImg.i32Width;
        inputImg.ppu8Plane[1] = inputImg.ppu8Plane[0] + (inputImg.pi32Pitch[0] * inputImg.i32Height);
    } else if (ASVL_PAF_YUYV == inputImg.u32PixelArrayFormat) {
        inputImg.pi32Pitch[0] = inputImg.i32Width*2;
    } else if (ASVL_PAF_I422H == inputImg.u32PixelArrayFormat) {
        inputImg.pi32Pitch[0] = inputImg.i32Width;
        inputImg.pi32Pitch[1] = inputImg.i32Width / 2;
        inputImg.pi32Pitch[2] = inputImg.i32Width / 2;
        inputImg.ppu8Plane[1] = inputImg.ppu8Plane[0] + inputImg.pi32Pitch[0] * inputImg.i32Height;
        inputImg.ppu8Plane[2] = inputImg.ppu8Plane[1] + inputImg.pi32Pitch[1] * inputImg.i32Height;
    } else if (ASVL_PAF_LPI422H == inputImg.u32PixelArrayFormat) {
        inputImg.pi32Pitch[0] = inputImg.i32Width;
        inputImg.pi32Pitch[1] = inputImg.i32Width;
        inputImg.ppu8Plane[1] = inputImg.ppu8Plane[0] + (inputImg.pi32Pitch[0] * inputImg.i32Height);
    } else if (ASVL_PAF_RGB24_B8G8R8 == inputImg.u32PixelArrayFormat) {
        inputImg.pi32Pitch[0] = inputImg.i32Width*3;
    } else {
        fprintf(stderr, "unsupported Image format: 0x%x\r\n",inputImg.u32PixelArrayFormat);
        free(inputImg.ppu8Plane[0]);
        AFD_FSDK_UninitialFaceEngine(hEngine);
        free(pWorkMem);
        exit(0);
    }
    LPAFD_FSDK_FACERES faceResult;
    ret = AFD_FSDK_StillImageFaceDetection(hEngine, &inputImg, &faceResult);
    if (ret != 0) {
        fprintf(stderr, "fail to AFD_FSDK_StillImageFaceDetection(): 0x%x\r\n", ret);
        free(inputImg.ppu8Plane[0]);
                AFD_FSDK_UninitialFaceEngine(hEngine);
        free(pWorkMem);
        exit(0);
    }

    printf("faceResult->nFace = %d\n", faceResult->nFace);
    for (int i = 0; i < faceResult->nFace; i++) {
        printf("face %d:(%d,%d,%d,%d)\n", i, 
               faceResult->rcFace[i].left, faceResult->rcFace[i].top,
               faceResult->rcFace[i].right, faceResult->rcFace[i].bottom);

    }

    
    free(inputImg.ppu8Plane[0]);
        AFD_FSDK_UninitialFaceEngine(hEngine);
    free(pWorkMem);

    return 0;
}

修改后的测试代码中使用了opencv库,编译命令如下:
#g++ -std=c++11 -I../inc/ -L ../lib/linux_x64 -o arcsoft_fd ./arcsoft_afd_samplecode.cpp -larcsoft_fsdk_face_detection -lopencv_core -lopencv_imgproc -lopencv_highgui

  • DLib开源算法

(1) 使用了开源的face_recognition python库,这个库底层就是基于Dlib的,写了一个测试程序,代码如下:

# -*- coding: utf-8 -*-
# 

# 检测人脸
import face_recognition
import cv2
import sys

# 读取图片并识别人脸
img = face_recognition.load_image_file(sys.argv[1])
face_locations = face_recognition.face_locations(img)
print face_locations

# 调用opencv函数显示图片
img = cv2.imread(sys.argv[1])
cv2.namedWindow("原图")
cv2.imshow("原图", img)
#size = cv2.GetSize(img)
#print size

sp = img.shape
print sp

# 遍历每个人脸,并标注
faceNum = len(face_locations)
for i in range(0, faceNum):
    top =  face_locations[i][0]
    right =  face_locations[i][1]
    bottom = face_locations[i][2]
    left = face_locations[i][3]

    start = (left, top)
    end = (right, bottom)

    color = (55,255,155)
    thickness = 1
    cv2.rectangle(img, start, end, color, thickness)



# 显示识别结果

cv2.namedWindow("识别")

cv2.imshow("识别", img)

cv2.waitKey(0)
cv2.destroyAllWindows()
  • 对比测试

使用同一张照片,原图如下:


image.png

(1) Dlib算法检测结果:


image.png

(2) 虹软算法检测结果:

$ LD_LIBRARY_PATH=../lib/linux_x64/ ./test ../test3.jpg
0 1 1 197
ArcSoft_FreeSDK_Face_Detection_1.1.0.197
May 21 2018
Copyright 2017 ArcSoft, Inc. All rights reserved.
faceResult->nFace = 1
face 0:(63,142,113,191)

 import cv2
 img = cv2.imread("./test3.jpg")
 start = (63,142)
 end = (113,191)
 color = (55,255,155)
 thickness = 1
 cv2.rectangle(img, start, end, color, thickness)
 cv2.imshow("ArcSoft", img)
cv2.waitKey(0)
image.png
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容