Как использовать python для доступа к Arcsoft ArcFace SDK

Идентификация изображения

Компании необходимо использовать SDK для распознавания лиц в проекте, и у нее очень высокие требования к информационной безопасности.После детального изучения нескольких основных SDK для распознавания лиц на рынке, Arcface SDK от Arcsoft в целом соответствует нашим потребностям. предоставляет бесплатную версию и может использоваться в автономном режиме, что полностью соответствует нашим требованиям безопасности.

Но жаль, наш проект в основном использует язык Python, Arcsoft не предоставляет версию SDK для Python, поэтому я использую Python для инкапсуляции SDK Arcface C++, который легко использовать в проекте, а основной процесс написан здесь, для всеобщего обсуждения. 

1. Описание окружающей среды

А. Обратите внимание, что Python в среде Win64 должен использовать ArcFace C++ (Win64) SDK, если платформа несовместима, иначе может возникнуть следующая ошибка. 

OSError: [WinError 193] %1 不是有效的 Win32 应用程序

б) Поскольку в SDK задействованы операции с памятью, в этой статье используются следующие методы, предоставляемые пакетом ctypes и пакетом cdll.

c_ubyte_p = POINTER(c_ubyte) memcpy = cdll.msvcrt.memcpy malloc = cdll.msvcrt.malloc malloc.restype = c_void_p free = cdll.msvcrt.free

2. Инкапсуляция базовой структуры данных Arcface SDK

При инкапсуляции структур данных обязательно обращайте внимание на типы параметров, иначе это может привести к ошибкам программы.

class MRECT(Structure): # 人脸框 
    _fields_ = [(u'left', c_int32), 
           (u'top', c_int32), 
           (u'right', c_int32), 
           (u'bottom', c_int32)]  class ASFVersion(Structure): # 版本信息 版本号 构建日期 版权说明 
    _fields_ = [ ('Version', c_char_p), 
           ('BuildDate', c_char_p), 
           ('CopyRight', c_char_p)]  class ASFSingleFaceInfo(Structure): # 单人脸信息 人脸框 人脸角度 
   _fields_ = [ ('faceRect', MRECT), 
          ('faceOrient', c_int32)]  class ASFMultiFaceInfo(Structure): # 多人脸信息 人脸框数组 人脸角度数组 人脸数 
    _fields_ = [ (u'faceRect', POINTER(MRECT)), 
           (u'faceOrient', POINTER(c_int32)), 
           (u'faceNum', c_int32)]  class ASFFaceFeature(Structure): # 人脸特征 人脸特征 人脸特征长度 
    _fields_ = [ ('feature', c_void_p), 
           ('featureSize', c_int32)]  class ASFFace3DAngle(Structure): # 人脸角度信息 
    _fields_ = [ ('roll', c_void_p), 
           ('yaw', c_void_p), 
           ('pitch', c_void_p), 
           ('status', c_void_p), 
           ('num', c_int32)]  class ASFAgeInfo(Structure): # 年龄 
    _fields_ = [ (u'ageArray', c_void_p), 
           (u'num', c_int32)]  class ASFGenderInfo(Structure): # 性别 
    _fields_ = [ (u'genderArray', c_void_p), 
           (u'num', c_int32)]  class ASFLivenessThreshold(Structure): # 活体阈值 
    _fields_ = [ (u'thresholdmodel_BGR', c_float), 
           (u'thresholdmodel_IR', c_int32)]  class ASFLivenessInfo(Structure): # 活体信息 
    _fields_ = [ (u'isLive', c_void_p), 
           (u'num', c_int32)] 

3. Интерфейсный пакет Arcface SDK

А. Библиотека dll должна быть загружена до инкапсуляции интерфейса, и все dll, предоставляемые Arcface SDK, должны быть загружены. 

б) Формат изображения в этой статье использует ASVL_PAF_RGB24_B8G8R8. 

C. Каждый интерфейс должен определять возвращаемые значения и типы параметров.Некоторые типы параметров зависят от базовых структур данных, описанных выше. 

from arcsoft_face_struct import * from ctypes import * from enum import Enum 

face_dll = CDLL("libarcsoft_face.dll") 
face_engine_dll = CDLL("libarcsoft_face_engine.dll") 

ASF_DETECT_MODE_VIDEO = 0x00000000 
ASF_DETECT_MODE_IMAGE = 0xFFFFFFFF ASF_NONE = 0x00000000 
ASF_FACE_DETECT = 0x00000001 ASF_FACE_RECOGNITION = 0x00000004 
ASF_AGE = 0x00000008 
ASF_GENDER = 0x00000010 
ASF_FACE3DANGLE = 0x00000020 
ASF_LIVENESS = 0x00000080 
ASF_IR_LIVENESS = 0x00000400 
ASVL_PAF_RGB24_B8G8R8 = 0x201 

class ArcSoftFaceOrientPriority(Enum): 
    ASF_OP_0_ONLY = 0x1, 
    ASF_OP_90_ONLY = 0x2, 
    ASF_OP_270_ONLY = 0x3, 
    ASF_OP_180_ONLY = 0x4, 
    ASF_OP_0_HIGHER_EXT = 0x5, 

activate = face_engine_dll.ASFActivation 
activate.restype = c_int32 
activate.argtypes = (c_char_p, c_char_p) 

init_engine = face_engine_dll.ASFInitEngine 
init_engine.restype = c_int32 
init_engine.argtypes = (c_long, c_int32, c_int32, c_int32, c_int32, POINTER(c_void_p)) 

detect_face = face_engine_dll.ASFDetectFaces 
detect_face.restype = c_int32 
detect_face.argtypes = (c_void_p, c_int32, c_int32, c_int32, POINTER(c_ubyte), POINTER(ASFMultiFaceInfo)) 

extract_feature = face_engine_dll.ASFFaceFeatureExtract 
extract_feature.restype = c_int32 
extract_feature.argtypes = (c_void_p, c_int32, c_int32, c_int32, POINTER(c_ubyte), 
                            POINTER(ASFSingleFaceInfo), POINTER(ASFFaceFeature)) 

compare_feature = face_engine_dll.ASFFaceFeature
Compare compare_feature.restype = c_int32 
compare_feature.argtypes = (c_void_p, POINTER(ASFFaceFeature), POINTER(ASFFaceFeature), POINTER(c_float)) 

set_liveness_param = face_engine_dll.ASFSetLivenessParam 
set_liveness_param.restype = c_int32 
set_liveness_param.argtypes = (c_void_p, POINTER(ASFLivenessThreshold)) 

process = face_engine_dll.ASFProcess process.restype = 
c_int32 process.argtypes = (c_void_p, c_int32, c_int32, c_int32, POINTER(c_ubyte), 
                            POINTER(ASFMultiFaceInfo), c_int32) 

get_age = face_engine_dll.ASFGetAge 
get_age.restype = c_int32 
get_age.argtypes = (c_void_p, POINTER(ASFAgeInfo)) 

get_gender = face_engine_dll.ASFGetGender 
get_gender.restype = c_int32 
get_gender.argtypes = (c_void_p, POINTER(ASFGenderInfo)) 

get_3d_angle = face_engine_dll.ASFGetFace3DAngle 
get_3d_angle.restype = c_int32 
get_3d_angle.argtypes = (c_void_p, POINTER(ASFFace3DAngle)) 

get_liveness_info = face_engine_dll.ASFGetLivenessScore 
get_liveness_info.restype = c_int32 
get_liveness_info.argtypes = (c_void_p, POINTER(ASFLivenessInfo)) 

4. Инкапсулировать вызов интерфейса

Затем следуйте приведенной ниже блок-схеме, чтобы представить вызовы интерфейса (эта схема создается автоматически с помощью Microsoft Visio 2016).

   

На следующем рисунке показана карта эффектов, полученная путем обработки в соответствии с этим процессом.Из-за ограниченного экрана отображаются только информация о возрасте, поле и живом теле.


а. для активации

Обратите внимание, что app_id и sdk_key должны использовать байтовый тип.

app_id = b"" 
sdk_key = b"" 
ret = arcsoft_face_func.activate(app_id, sdk_key) # 激活 
if ret == 0 or ret == 90114: 
    print("激活成功") 
else: 
    print("激活失败:", ret) 

б. Инициализировать

Инициализация должна передавать все необходимые функциональные параметры одновременно.В этом документе используются такие функции, как обнаружение лиц и извлечение признаков. 

mask = arcsoft_face_func.ASF_FACE_DETECT | \
            arcsoft_face_func.ASF_FACE_RECOGNITION | \
            arcsoft_face_func.ASF_AGE | \
            arcsoft_face_func.ASF_GENDER | \
            arcsoft_face_func.ASF_FACE3DANGLE |\
            arcsoft_face_func.ASF_LIVENESS

    engine = c_void_p()
    ret = arcsoft_face_func.init_engine(arcsoft_face_func.ASF_DETECT_MODE_IMAGE,
                                        arcsoft_face_func.ArcSoftFaceOrientPriority.ASF_OP_0_ONLY.value[0],
                                   30, 10, mask, byref(engine))
    if ret == 0:
        print("初始化成功")
    else:
        print("初始化失败:", ret)

в. Распознавание лиц

В этой статье используется opencv для чтения изображений, который имеет лучшую совместимость, и пользовательскую структуру данных для записи информации об изображении.Обратите внимание, что ArcFace C++ SDK требует, чтобы ширина входящего изображения была кратна 4, а следующее обрезается.

 class Image:
    def __init__(self):
        self.width = 0
        self.height = 0
        self.imageData = None

def load_image(file_path):
    img = cv2.imread(file_path)
    sp = img.shape
    img = cv2.resize(img, (sp[1]//4*4, sp[0]))# 四字节对齐

    image = Image()
    image.width = img.shape[1]
    image.height = img.shape[0]
    image.imageData = img
    return image
###################### 人脸检测 ##################################

    image1 = load_image(r"1.jpg")
    image_bytes = bytes(image1.imageData)
    image_ubytes = cast(image_bytes, c_ubyte_p)

    detect_faces = ASFMultiFaceInfo()
    ret = arcsoft_face_func.detect_face(
        engine,
        image1.width,
        image1.height,
        arcsoft_face_func.ASVL_PAF_RGB24_B8G8R8,
        image_ubytes,
        byref(detect_faces)
    )

    if ret == 0:
        print("检测人脸成功")
    else:
        print("检测人脸失败:", ret)

г. Извлечение признаков

Извлечение элементов поддерживает только одно лицо, поэтому выполняется операция обработки лица, а извлеченные элементы лица необходимо вовремя копировать, иначе они будут перезаписаны. 

 single_face1 = ASFSingleFaceInfo()
    single_face1.faceRect = detect_faces.faceRect[0]
    single_face1.faceOrient = detect_faces.faceOrient[0]

    face_feature = ASFFaceFeature()
    ret = arcsoft_face_func.extract_feature(
        engine,
        image1.width,
        image1.height,
        arcsoft_face_func.ASVL_PAF_RGB24_B8G8R8,
        image_ubytes,
        single_face1,
        byref(face_feature)
    )

    if ret == 0:
        print("提取特征1成功")
    else:
        print("提取特征1失败:", ret)

    feature1 = ASFFaceFeature()
    feature1.featureSize = face_feature.featureSize
    feature1.feature = malloc(feature1.featureSize)
    memcpy(c_void_p(feature1.feature),
           c_void_p(face_feature.feature),
           feature1.featureSize)

д. Сравнение функций

Извлеките черты лица, как описано выше, то есть вы можете выполнить следующие операции сравнения черт лица.

compare_threshold = c_float()
    ret = arcsoft_face_func.compare_feature(
        engine, feature1, feature2, compare_threshold
    )

    free(c_void_p(feature1.feature))
    free(c_void_p(feature2.feature))

    if ret == 0:
        print("特征比对成功,相似度:", compare_threshold.value)
    else:
        print("特征比对失败:", ret)

е. Возраст, пол, 3D угол

Интерфейс процесса в настоящее время обеспечивает определение возраста, пола, 3D-ракурса и живого тела, однако возраст, пол и 3D-ракурс поддерживают несколько лиц, в то время как живые тела поддерживают только отдельные лица, поэтому ниже они обрабатываются отдельно. 

process_mask = arcsoft_face_func.ASF_AGE | \
                   arcsoft_face_func.ASF_GENDER | \
                   arcsoft_face_func.ASF_FACE3DANGLE

    ret = arcsoft_face_func.process(
        engine,
        image1.width,
        image1.height,
        arcsoft_face_func.ASVL_PAF_RGB24_B8G8R8,
        image_ubytes,
        byref(detect_faces),
        c_int32(process_mask)
    )

    if ret == 0:
        print("process成功")
    else:
        print("process失败:", ret) 
######################## Age ################################

    age_info = ASFAgeInfo()
    ret = arcsoft_face_func.get_age(engine, byref(age_info))

    if ret == 0:
        print("get_age 成功")
        age_ptr = cast(age_info.ageArray, POINTER(c_int))
        for i in range(age_info.num):
            print("face", i, "age:", age_ptr[i])
    else:
        print("get_age 失败:", ret)

####################### Gender #################################

    gender_info = ASFGenderInfo()
    ret = arcsoft_face_func.get_gender(engine, byref(gender_info))

    if ret == 0:
        print("get_gender 成功")
        gender_ptr = cast(gender_info.genderArray, POINTER(c_int))
        for i in range(gender_info.num):
            print("face", i, "gender:",
                  "女性" if (gender_ptr[i] == 1) else (
                      "男性" if (gender_ptr[i] == 0) else "未知"
                  ))
    else:
        print("get_gender 失败:", ret)

####################### 3D Angle #################################

    angle_info = ASFFace3DAngle()
    ret = arcsoft_face_func.get_3d_angle(engine, byref(angle_info))

    if ret == 0:
        print("get_3d_angle 成功")
        roll_ptr = cast(angle_info.roll, POINTER(c_float))
        yaw_ptr = cast(angle_info.yaw, POINTER(c_float))
        pitch_ptr = cast(angle_info.pitch, POINTER(c_float))
        status_ptr = cast(angle_info.status, POINTER(c_int32))
        for i in range(angle_info.num):
            print("face", i,
                  "roll:", roll_ptr[i],
                  "yaw:", yaw_ptr[i],
                  "pitch:", pitch_ptr[i],
                  "status:", "正常" if status_ptr[i] == 0 else "出错")

    else:
        print("get_3d_angle 失败:", ret)

г. Живое тело RGB

Перед обнаружением живого тела рекомендуется установить порог живого тела в соответствии с реальной сценой.Если вы не установите его, используйте порог по умолчанию.Здесь пороговое значение живого тела RGB установлено на 0,75. А обнаруженные несколько лиц преобразуются в параметры одного лица и передаются в интерфейс.

######################### 活体阈值设置 ############################### 
    threshold_param = ASFLivenessThreshold()
    threshold_param.thresholdmodel_BGR = 0.75
    ret = arcsoft_face_func.set_liveness_param(engine,threshold_param)

    if ret == 0:
        print("set_liveness_param成功")
    else:
        print("set_liveness_param 失败:", ret)

    temp_face_info = ASFMultiFaceInfo()
    temp_face_info.faceNum = 1
    LP_MRECT = POINTER(MRECT)
    temp_face_info.faceRect = LP_MRECT(MRECT(malloc(sizeof(MRECT))))
    LP_c_long = POINTER(c_long)
    temp_face_info.faceOrient = LP_c_long(c_long(malloc(sizeof(c_long))))

    for i in range(detect_faces.faceNum):
        temp_face_info.faceRect[0] = detect_faces.faceRect[i]
        temp_face_info.faceOrient[0] = detect_faces.faceOrient[i]

        ret = arcsoft_face_func.process(
            engine,
            image1.width,
            image1.height,
            arcsoft_face_func.ASVL_PAF_RGB24_B8G8R8,
            image_ubytes,
            byref(temp_face_info),
            c_int32(arcsoft_face_func.ASF_LIVENESS)
        )

        if ret == 0:
            print("process成功")
        else:
            print("process失败:", ret)
        ## RGB活体检测
        ret = arcsoft_face_func.process(
            engine,
            image1.width,
            image1.height,
            arcsoft_face_func.ASVL_PAF_RGB24_B8G8R8,
            image_ubytes,
            byref(temp_face_info),
            c_int32(arcsoft_face_func.ASF_LIVENESS)
        )

        if ret == 0:
            print("process成功")
        else:
            print("process失败:", ret)

        liveness_info = ASFLivenessInfo()
        ret = arcsoft_face_func.get_liveness_info(engine, byref(liveness_info))

        if ret == 0:
            print("get_liveness_info 成功")
            liveness_ptr = cast(liveness_info.isLive, POINTER(c_int))
            print("face", i, "liveness:",
                  "非真人" if (liveness_ptr[0] == 0) else (
                      "真人" if (liveness_ptr[0] == 1) else (
                          "不确定" if (liveness_ptr[0] == -1) else (
                              "传入人脸数>1" if (liveness_ptr[0] == -2) else
                              (liveness_ptr[0])
                          )
                      )
                  ))
        else:
            print("get_liveness_info 失败:", ret)

Наконец, приветствую ваш совет~

Рекомендуется понимать SDK Arcsoft Face Recognition ~

love.arcsoft.com.can/u center/use…