简介

相信大部分同学们都已了解或接触过OpenAtom OpenHarmony(以下简称“OpenHarmony”)了,但你一定没在OpenHarmony上实现过人脸识别功能,跟着本文带你快速在OpenHarmony标准设备上基于SeetaFace2和OpenCV实现人脸识别。

项目效果

本项目实现了导入人脸模型、人脸框选和人脸识别三大功能,操作流程如下:

1. 录入页面点击右下角按钮,跳转拍摄页面进行拍照;

2. 选择一张或多张人脸作为训练模型,并设置对应的名字;

3. 选择一张未录入的人脸图片,点击框选按钮实现人脸图片框选功能;

4. 最后点击识别,应用会对当前图片进行匹配,最终在界面中显示识别结果。

快速上手

设备端开发

设备端通过OpenCV对图像进行处理并通过Seetaface2对图形数据进行人脸头像的识别,最终输出对应的NAPI接口提供给应用端调用。因此设备端开发主要涉及到OpenCV和Seetaface2的移植以及NAPI接口的开发。

OpenCV库移植

OpenCV是一个功能非常强大的开源计算机视觉库。此库已由知识体系工作组移植到了OpenHarmony中,后期还会将此库合入到主仓。在此库上主仓之前,我们只需要以下几个步骤就可以实现OpenCV的移植使用。

1. 通过以下命令下载已经移植好的OpenCV

git clone git@gitee.com:zhong-luping/ohos_opencv.git

  

2. 将OpenCV拷贝到OpenHarmony目录的third_party下

cp -raf opencv ~/openharmony/third_party/

  

3. 适当裁剪编译选项

打开OpenCV目录下的BUILD.gn,如下:

不需要video以及flann功能,将对应的模块注释即可。

import("//build/ohos.gni")
group("opencv") {
deps = [
"//third_party/opencv/modules/core:opencv_core",
// "//third_party/opencv/modules/flann:opencv_flann",
"//third_party/opencv/modules/imgproc:opencv_imgproc",
"//third_party/opencv/modules/ml:opencv_ml",
"//third_party/opencv/modules/photo:opencv_photo",
"//third_party/opencv/modules/dnn:opencv_dnn",
"//third_party/opencv/modules/features2d:opencv_features2d",
"//third_party/opencv/modules/imgcodecs:opencv_imgcodecs",
"//third_party/opencv/modules/videoio:opencv_videoio",
"//third_party/opencv/modules/calib3d:opencv_calib3d",
"//third_party/opencv/modules/highgui:opencv_highgui",
"//third_party/opencv/modules/objdetect:opencv_objdetect",
"//third_party/opencv/modules/stitching:opencv_stitching",
"//third_party/opencv/modules/ts:opencv_ts",
// "//third_party/opencv/modules/video:opencv_video",
"//third_party/opencv/modules/gapi:opencv_gapi",
]
}

  

4. 添加依赖子系统的part_name,编译框架子系统会将编译出的库拷贝到系统文件中。

此项目中我们新建了一个SeetaFaceApp的子系统,该子系统中命名part_name为SeetafaceApi,所以我们需要在对应模块中的BUILD.gn中加上part_name="SeetafaceApi"

以module/core为例:

ohos_shared_library("opencv_core"){
sources = [ ... ]
configs = [ ... ]
deps = [ ... ]
part_name = "SeetafaceApi"
}

  

5. 编译工程需要添加OpenCV的依赖。

在生成NAPI的BUILD.gn中添加以下依赖:

deps += [ "//third_party/opencv:opencv" ]

  

至此,人脸识别中OpenCV的移植使用完成。

SeetaFace2库移植

SeetaFace2是中科视拓开源的第二代人脸识别库。包括了搭建一套全自动人脸识别系统所需的三个核心模块,即:人脸检测模块FaceDetector、面部关键点定位模块FaceLandmarker以及人脸特征提取与比对模块 FaceRecognizer。

关于SeetaFace2的移植请参照文档:SeetaFace2移植开发文档。

NAPI接口开发

关于OpenHarmony中的NAPI开发,参考视频:

OpenHarmony中napi的开发视频教程。本文将重点讲解NAPI接口如何实现OpenCV以及SeetaFace的调用。

1. 人脸框获取的NAPI接口的实现。

int GetRecognizePoints(const char *image_path);

此接口主要是通过应用层输入一张图片,通过OpenCV的imread接口获取到图片数据,并通过人脸检测模块FaceDetector分析获得图片中所有的人脸矩形框(矩形框是以x,y,w,h的方式)并将人脸框矩形以数组的方式返回到应用层。

人脸框矩形获取的主要代码如下:

static int RecognizePoint(string image_path, FaceRect *rect, int num)
{
if (rect == nullptr) {
cerr << "NULL POINT!" << endl;
LOGE("NULL POINT! \n");
return -1;
}
seeta::ModelSetting::Device device = seeta::ModelSetting::CPU;
int id = 0; /* 设置人脸识别模型。*/
seeta::ModelSetting FD_model( "/system/usr/model/fd_2_00.dat", device, id );
seeta::ModelSetting FL_model( "/system/usr/model/pd_2_00_pts81.dat", device, id ); seeta::FaceDetector FD(FD_model);
seeta::FaceLandmarker FL(FL_model); FD.set(seeta::FaceDetector::PROPERTY_VIDEO_STABLE, 1); /* 读取图片数据 */
auto frame = imread(image_path);
seeta::cv::ImageData simage = frame;
if (simage.empty()) {
cerr << "Can not open image: " << image_path << endl;
LOGE("Can not open image: %{public}s", image_path.c_str());
return -1;
}
/* 图片数据进行人脸识别处理 ,获取所有的人脸框数据对象*/
auto faces = FD.detect(simage);
if (faces.size <= 0) {
cerr << "detect " << image_path << "failed!" << endl;
LOGE("detect image: %s failed!", image_path.c_str());
return -1;
}
for (int i = 0; (i < faces.size && i < num); i++) {
/* 将所有人脸框对象数据以坐标形式输出*/
auto &face = faces.data[i];
memcpy(&rect[i], &(face.pos), sizeof(FaceRect));
}
return faces.size;
}

  

其中FD_model是人脸检测模型,而FL_model是面部关键点定位模型(此模型分为5点定位和81点定位,本项目中使用的是81点定位模型),这些模型从开源项目中免费获取。

通过以上方式获取到对应的人脸矩形框后,再将矩形框以数组的方式返回到应用端:

    string image = path;
p = (FaceRect *)malloc(sizeof(FaceRect) * MAX_FACE_RECT);
/* 根据图片进行人脸识别并获取人脸框坐标点 */
int retval = RecognizePoint(image, p, MAX_FACE_RECT);
if (retval <= napi_ok) {
LOGE("GetNapiValueString failed!");
free(p);
return result;
}
/*将所有坐标点以数组方式返回到应用端*/
for (int i = 0; i < retval; i++) {
int arry_int[4] = {p[i].x, p[i].y, p[i].w, p[i].h};
int arraySize = (sizeof(arry_int) / sizeof(arry_int[0]));
for (int j = 0; j < arraySize; j++) {
napi_value num_val;
if (napi_create_int32(env, arry_int[j], &num_val) != napi_ok) {
LOGE("napi_create_int32 failed!");
return result;
}
napi_set_element(env, array, i*arraySize + j, num_val);
}
}
if (napi_create_object(env, &result) != napi_ok) {
LOGE("napi_create_object failed!");
free(p);
return result;
}
if (napi_set_named_property(env, result, "recognizeFrame", array) != napi_ok) {
LOGE("napi_set_named_property failed!");
free(p);
return result;
}
LOGI("");
free(p);
return result;

  

其中array是通过napi_create_array创建的一个NAPI数组对象,通过 napi_set_element将所有的矩形框数据保存到array对象中,最后通过 napi_set_named_property将array转换成应用端可识别的对象类型result并将其返回。

2. 人脸搜索识别初始化与逆初始化。

1. int FaceSearchInit();

2. int FaceSearchDeinit();

这2个接口主要是提供给人脸搜索以及识别调用的,初始化主要包含模型的注册以及识别模块的初始化:

static  int FaceSearchInit(FaceSearchInfo *info)
{
if (info == NULL) {
info = (FaceSearchInfo *)malloc(sizeof(FaceSearchInfo));
if (info == nullptr) {
cerr << "NULL POINT!" << endl;
return -1;
}
} seeta::ModelSetting::Device device = seeta::ModelSetting::CPU;
int id = 0;
seeta::ModelSetting FD_model( "/system/usr/model/fd_2_00.dat", device, id );
seeta::ModelSetting PD_model( "/system/usr//model/pd_2_00_pts5.dat", device, id );
seeta::ModelSetting FR_model( "/system/usr/model/fr_2_10.dat", device, id ); info->engine = make_shared<seeta::FaceEngine>(FD_model, PD_model, FR_model, 2, 16);
info->engine->FD.set( seeta::FaceDetector::PROPERTY_MIN_FACE_SIZE, 80); info->GalleryIndexMap.clear(); return 0;
}

  

而逆初始化就是做一些内存的释放。


static void FaceSearchDeinit(FaceSearchInfo *info, int need_delete)
{
if (info != nullptr) {
if (info->engine != nullptr) {
} info->GalleryIndexMap.clear();
if (need_delete) {
free(info);
info = nullptr;
}
}
}

  

3. 人脸搜索识别注册接口的实现。

int FaceSearchRegister(const char *value);

需要注意的是,该接口需要应用端传入一个json数据的参数,主要包含注册人脸的名字,图片以及图片个数,如{"name":"刘德华","sum":"2","image":{"11.jpg","12.jpg"}}。而解析参数的时候需要调用 napi_get_named_property对json数据的各个对象进行解析,具体代码如下:

    napi_get_cb_info(env, info, &argc, &argv, &thisVar, &data);
napi_value object = argv;
napi_value value = nullptr; if (napi_get_named_property(env, object, (const char *)"name", &value) == napi_ok) {
char name[64] = {0};
if (GetNapiValueString(env, value, (char *)name, sizeof(name)) < 0) {
LOGE("GetNapiValueString failed!");
return result;
}
reg_info.name = name;
}
LOGI("name = %{public}s", reg_info.name.c_str());
if (napi_get_named_property(env, object, (const char *)"sum", &value) == napi_ok) { if (napi_get_value_uint32(env, value, &sum) != napi_ok) {
LOGE("napi_get_value_uint32 failed!");
return result;
}
}
LOGI("sum = %{public}d", sum);
if (napi_get_named_property(env, object, (const char *)"image", &value) == napi_ok) {
bool res = false;
if (napi_is_array(env, value, &res) != napi_ok || res == false) {
LOGE("napi_is_array failed!");
return result;
}
for (int i = 0; i < sum; i++) {
char image[256] = {0};
napi_value imgPath = nullptr;
if (napi_get_element(env, value, i, &imgPath) != napi_ok) {
LOGE("napi_get_element failed!");
return result;
}
if (GetNapiValueString(env, imgPath, (char *)image, sizeof(image)) < 0) {
LOGE("GetNapiValueString failed!");
return result;
}
reg_info.path = image;
if (FaceSearchRegister(g_FaceSearch, reg_info) != napi_ok) {
retval = -1;
break;
}
}
}

  

通过napi_get_cb_info获取从应用端传来的参数,并通过 napi_get_named_property获取对应的name以及图片个数,最后通过napi_get_element获取图片数组中的各个image,将name和image通过FaceSearchRegister接口将图片和名字注册到SeetaFace2模块的识别引擎中。具体实现如下:

static int FaceSearchRegister(FaceSearchInfo &info, RegisterInfo &gegister)
{
if (info.engine == nullptr) {
cerr << "NULL POINT!" << endl;
return -1;
} seeta::cv::ImageData image = cv::imread(gegister.path);
auto id = info.engine->Register(image);
if (id >= 0) {
info.GalleryIndexMap.insert(make_pair(id, gegister.name));
} return 0;
}

  

注册完数据后,后续可以通过该引擎来识别对应的图片。

4. 获取人脸搜索识别结果接口的实现。

char *FaceSearchGetRecognize(const char *image_path);

  

该接口实现了通过传入一张图片,在识别引擎中进行搜索识别。如果识别引擎中有类似的人脸注册,则返回对应人脸注册时的名字,否则返回不识别(ignored)字样。该方法是通过异步回调的方式实现的:

    // 创建async work,创建成功后通过最后一个参数(commandStrData->asyncWork)返回async work的handle
napi_value resourceName = nullptr;
napi_create_string_utf8(env, "FaceSearchGetPersonRecognizeMethod", NAPI_AUTO_LENGTH, &resourceName);
napi_create_async_work(env, nullptr, resourceName, FaceSearchRecognizeExecuteCB, FaceSearchRecognizeCompleteCB,
(void *)commandStrData, &commandStrData->asyncWork); // 将刚创建的async work加到队列,由底层去调度执行
napi_queue_async_work(env, commandStrData->asyncWork);

  

其中FaceSearchRecognizeExecuteCB实现了人脸识别

static void FaceSearchRecognizeExecuteCB(napi_env env, void *data)
{
CommandStrData *commandStrData = dynamic_cast<CommandStrData*>((CommandStrData *)data);
if (commandStrData == nullptr) {
HILOG_ERROR("nullptr point!", __FUNCTION__, __LINE__);
return;
} FaceSearchInfo faceSearch = *(commandStrData->mFaceSearch);
commandStrData->result = FaceSearchSearchRecognizer(faceSearch, commandStrData->filename);
LOGI("Recognize result : %s !", __FUNCTION__, __LINE__, commandStrData->result.c_str());
}

  

FaceSearchRecognizeCompleteCB函数通过napi_resolve_deferred接口将识别结果返回到应用端。

static void FaceSearchRecognizeCompleteCB(napi_env env, napi_status status, void *data)
{
CommandStrData *commandStrData = dynamic_cast<CommandStrData*>((CommandStrData *)data);
napi_value result; if (commandStrData == nullptr || commandStrData->deferred == nullptr) {
LOGE("nullptr", __FUNCTION__, __LINE__);
if (commandStrData != nullptr) {
napi_delete_async_work(env, commandStrData->asyncWork);
delete commandStrData;
} return;
} const char *result_str = (const char *)commandStrData->result.c_str();
if (napi_create_string_utf8(env, result_str, strlen(result_str), &result) != napi_ok) {
LOGE("napi_create_string_utf8 failed!", __FUNCTION__, __LINE__);
napi_delete_async_work(env, commandStrData->asyncWork);
delete commandStrData;
return;
} napi_resolve_deferred(env, commandStrData->deferred, result);
napi_delete_async_work(env, commandStrData->asyncWork); delete commandStrData;
}

  

通过人脸特征提取与比对模块,对传入的数据与已注册的数据进行对比,并通过返回对比的相似度来进行判断当前人脸是否为可识别的,最后返回识别结果。具体实现代码:

static string FaceSearchSearchRecognizer(FaceSearchInfo &info, string filename)
{
if (info.engine == nullptr) {
cerr << "NULL POINT!" << endl;
return "recognize error 0";
}
string name;
float threshold = 0.7f;
seeta::QualityAssessor QA;
auto frame = cv::imread(filename);
if (frame.empty()) {
LOGE("read image %{public}s failed!", filename.c_str());
return "recognize error 1!";
}
seeta::cv::ImageData image = frame;
std::vector<SeetaFaceInfo> faces = info.engine->DetectFaces(image); for (SeetaFaceInfo &face : faces) {
int64_t index = 0;
float similarity = 0; auto points = info.engine->DetectPoints(image, face); auto score = QA.evaluate(image, face.pos, points.data());
if (score == 0) {
name = "ignored";
} else {
auto queried = info.engine->QueryTop(image, points.data(), 1, &index, &similarity);
// no face queried from database
if (queried < 1) continue;
// similarity greater than threshold, means recognized
if( similarity > threshold ) {
name = info.GalleryIndexMap[index];
}
}
}
LOGI("name : %{public}s \n", name.length() > 0 ? name.c_str() : "null");
return name.length() > 0 ? name : "recognize failed";
}

  

至此,所有的NAPI接口已经开发完成。

5. NAPI库编译开发完NAPI接口后,我们需要将我们编写的库加入到系统中进行编译,我们需要添加一个自己的子系统。

首先在库目录下新建一个ohos.build

{
"subsystem": "SeetafaceApp",
"parts": {
"SeetafaceApi": {
"module_list": [
"//seetaface:seetafaceapp_napi"
],
"test_list": [ ]
}
}
}

  

其次同一目录新建一个BUILD.gn,将库源文件以及对应的依赖加上,如下:


import("//build/ohos.gni")

config("lib_config") {
cflags_cc = [
"-frtti",
"-fexceptions",
"-DCVAPI_EXPORTS",
"-DOPENCV_ALLOCATOR_STATS_COUNTER_TYPE=int",
"-D_USE_MATH_DEFINES",
"-D__OPENCV_BUILD=1",
"-D__STDC_CONSTANT_MACROS",
"-D__STDC_FORMAT_MACROS",
"-D__STDC_LIMIT_MACROS",
"-O2",
"-Wno-error=header-hygiene",
]
} ohos_shared_library("seetafaceapp_napi") {
sources = [
"app.cpp",
] include_dirs = [
"./",
"//third_party/opencv/include",
"//third_party/opencv/common",
"//third_party/opencv/modules/core/include",
"//third_party/opencv/modules/highgui/include",
"//third_party/opencv/modules/imgcodecs/include",
"//third_party/opencv/modules/imgproc/include",
"//third_party/opencv/modules/calib3d/include",
"//third_party/opencv/modules/dnn/include",
"//third_party/opencv/modules/features2d/include",
"//third_party/opencv/modules/flann/include",
"//third_party/opencv/modules/ts/include",
"//third_party/opencv/modules/video/include",
"//third_party/opencv/modules/videoio/include",
"//third_party/opencv/modules/ml/include",
"//third_party/opencv/modules/objdetect/include",
"//third_party/opencv/modules/photo/include",
"//third_party/opencv/modules/stitching/include",
"//third_party/SeetaFace2/FaceDetector/include",
"//third_party/SeetaFace2/FaceLandmarker/include",
"//third_party/SeetaFace2/FaceRecognizer/include",
"//third_party/SeetaFace2/QualityAssessor/include",
"//base/accessibility/common/log/include",
"//base/hiviewdfx/hilog_lite/interfaces/native/innerkits"
] deps = [ "//foundation/ace/napi:ace_napi" ]
deps += [ "//third_party/opencv:opencv" ]
deps += [ "//third_party/SeetaFace2:SeetaFace2" ] external_deps = [
"hiviewdfx_hilog_native:libhilog",
] configs = [
":lib_config"
] # 指定库生成的路径
relative_install_dir = "module"
# 子系统及其组件,后面会引用
subsystem_name = "SeetafaceApp"
part_name = "SeetafaceApi"
}

  

添加完对应的文件后,我们需要将我们的子系统添加到系统中进行编译,打开build/subsystem_config.json并在最后添加以下代码:

  "SeetafaceApp": {
"path": "seetaface",
"name": "SeetafaceApp"
}

  

添加完子系统再修改产对应的品配置

打开productdefine/common/products/rk3568.json并在最后添加以下代码:

"SeetafaceApp:SeetafaceApi":{}

做完以上修改后我们就可以通过以下命令直接编译NAPI的库文件了:

./build.sh --product-name rk3568 --ccache

  

参考RK3568快速上手-镜像烧录完成烧录即可。

应用端开发

在完成设备NAPI功能开发后,应用端通过调用NAPI组件中暴露给应用的人脸识别接口,即可实现对应功能。接下来就带着大家使用NAPI实现人脸识别功能。

开发准备

1. 下载DevEco Studio 3.0 Beta4;

2. 搭建开发环境,参考开发准备;

3. 了解属性eTS开发,参考eTS语言快速入门;

SeetaFace2初始化

1. 首先将SeetaFace2 NAPI接口声明文件放置于SDK目录/api下;

2. 然后导入SeetaFace2 NAPI模块;ck-start/star

3. 调用初始化接口;

// 首页实例创建后
async aboutToAppear() {
await StorageUtils.clearModel();
CommonLog.info(TAG,'aboutToAppear')
// 初始化人脸识别
let res = SeetafaceApp.FaceSearchInit()
CommonLog.info(TAG,`FaceSearchInit res=${res}`)
this.requestPermissions()
} // 请求权限
requestPermissions(){
CommonLog.info(TAG,'requestPermissions')
let context = featureAbility.getContext()
context.requestPermissionsFromUser(PERMISSIONS, 666,(res)=>{
this.getMediaImage()
})
}

  

获取所有人脸图片

通过文件管理模块fileio和媒体库管理mediaLibrary,获取指定应用数据目录下所有的图片信息,并将路径赋值给faceList,faceList数据用于Image组件提供url进行加载图片

// 获取所有图片
async getMediaImage(){
let context = featureAbility.getContext();
// 获取本地应用沙箱路径
let localPath = await context.getOrCreateLocalDir()
CommonLog.info(TAG, `localPath:${localPath}`)
let facePath = localPath + "/files"
// 获取所有照片
this.faceList = await FileUtil.getImagePath(facePath)
}

  

设置人脸模型

获取选中的人脸图片地址和输入的名字,调用SeetafaceApp.FaceSearchRegister(params)进行设置人脸模型。其中参数params由name名字、image图片地址集合和sum图片数量组成。

async submit(name) {
if (!name || name.length == 0) {
CommonLog.info(TAG, 'name is empty')
return
}
let selectArr = this.faceList.filter(item => item.isSelect)
if (selectArr.length == 0) {
CommonLog.info(TAG, 'faceList is empty')
return
}
// 关闭弹窗
this.dialogController.close()
try {
let urls = []
let files = []
selectArr.forEach(item => {
let source = item.url.replace('file://', '')
CommonLog.info(TAG, `source:${source}`)
urls.push(item.url)
files.push(source)
}) // 设置人脸识别模型参数
let params = {
name: name,
image: files,
sum: files.length
}
CommonLog.info(TAG, 'FaceSearchRegister' + JSON.stringify(params))
let res = SeetafaceApp.FaceSearchRegister(params)
CommonLog.info(TAG, 'FaceSearchRegister res ' + res)
// 保存已设置的人脸模型到轻量存储
let data = {
name:name,
urls:urls
}
let modelStr = await StorageUtils.getModel()
let modelList = JSON.parse(modelStr)
modelList.push(data)
StorageUtils.setModel(modelList)
router.back()
} catch (err) {
CommonLog.error(TAG, 'submit fail ' + err)
}
}

  

实现框选人脸

调用SeetafaceApp.GetRecognizePoints传入当前图片地址,获取到人脸左上和右下坐标,再通过CanvasRenderingContext2D对象绘画出人脸框。

实现人脸识别

调用SeetafaceApp.FaceSearchGetRecognize(url),传入图片地址对人脸进行识别并返回对应识别出来的名字。

// 人脸识别
recognize(){
SeetafaceApp.FaceSearchGetRecognize(this.url).then(res=>{
CommonLog.info(TAG,'recognize suceess' + JSON.stringify(res))
if(res && res != 'ignored' && res != "recognize failed" && res != 'recognize error 1!'){
// 赋值识别到的人物模型
this.name = res
}else{
this.name = '未识别到该模型'
}
}).catch(err=>{
CommonLog.error(TAG,'recognize' + err)
this.name = '未识别到该模型'
})
}

 

参考文档

SeetaFace2移植开发文档:

https://gitee.com/openharmony-sig/knowledge_demo_smart_home/blob/master/docs/SeetaFace2/%E4%BA%BA%E8%84%B8%E8%AF%86%E5%88%AB%E5%BA%93%E7%9A%84%E7%A7%BB%E6%A4%8D.md

OpenHarmony中napi的开发视频教程:

https://www.bilibili.com/video/BV1L44y1p7KE?spm_id_from=333.999.0.0

RK3568快速上手:

https://growing.openharmony.cn/mainPlay/learnPathMaps?id=27

人脸识别应用:

https://gitee.com/openharmony-sig/knowledge_demo_travel/blob/master/docs/FaceRecognition_ETS/README_zh.md

应用开发准备:

https://docs.openharmony.cn/pages/v3.2Beta/zh-cn/application-dev/quick-start/start-overview.md/

eTS语言快速入门:

https://docs.openharmony.cn/pages/v3.2Beta/zh-cn/application-dev/quick-start/start-with-ets.md/

知识体系工作组:

https://gitee.com/openharmony-sig/knowledge

如何在OpenHarmony上使用SeetaFace2人脸识别库?的更多相关文章

  1. Python的开源人脸识别库:离线识别率高达99.38%

    Python的开源人脸识别库:离线识别率高达99.38%   github源码:https://github.com/ageitgey/face_recognition#face-recognitio ...

  2. Python的开源人脸识别库:离线识别率高达99.38%(附源码)

    Python的开源人脸识别库:离线识别率高达99.38%(附源码) 转https://cloud.tencent.com/developer/article/1359073   11.11 智慧上云 ...

  3. face_recognition开源人脸识别库:离线识别率高达99.38%

    基于Python的开源人脸识别库:离线识别率高达99.38%——新开源的用了一下感受一下 原创 2017年07月28日 21:25:28 标签: 人脸识别 / 人脸自动定位 / 人脸识别开源库 / f ...

  4. C# 人脸识别库 0.2

    ViewFaceCore 0.2 超简单的 C# 人脸识别库 前言: 首先谢谢大家对这个库的关注,前一篇博文得到了大家的 支持 和 Star,十分开心.本想尽快实现大家的期待的活体检测功能,但是前段时 ...

  5. [深度学习] Python人脸识别库face_recognition使用教程

    Python人脸识别库face_recognition使用教程 face_recognition号称是世界上最简单的开源人脸识别库,可以通过Python或命令行识别和操作人脸.face_recogni ...

  6. 如何在Pypi上发表自己的Python库

    背景 最近兴趣使然写了几个Python库,也发布到了Pypi上,虽然没什么人下载,但自己在其他机器上用着也会很方便.这里我向大家介绍一下如何在Pypi上发表自己的Python库. 准备 注册账号 很显 ...

  7. [深度学习工具]·极简安装Dlib人脸识别库

    [深度学习工具]·极简安装Dlib人脸识别库 Dlib介绍 Dlib是一个现代化的C ++工具箱,其中包含用于在C ++中创建复杂软件以解决实际问题的机器学习算法和工具.它广泛应用于工业界和学术界,包 ...

  8. C# 人脸识别库

    .NET 人脸识别库 ViewFaceCore 这是基于 SeetaFace6 人脸识别开发的 .NET 平台下的人脸识别库这是一个使用超简单的人脸识别库这是一个基于 .NET Standard 2. ...

  9. [深度学习] Python人脸识别库Deepface使用教程

    deepface是一个Python轻量级人脸识别和人脸属性分析(年龄.性别.情感和种族)框架,提供非常简单的接口就可以实现各种人脸识别算法的应用.deepface官方仓库为deepface.deepf ...

  10. 基于Python的开源人脸识别库:离线识别率高达99.38%

    项目地址:https://github.com/ageitgey/face_recognition#face-recognition 本文的模型使用了C++工具箱dlib基于深度学习的最新人脸识别方法 ...

随机推荐

  1. heapq模块通过nlargest()和nsmallest()找到最大或最小的N个元素

    问题 我们想在某个集合中找出最大或最小的N个元素 解决方案 heapq模块中有两个函数nlargest()和nsmallest() import heapq nums = [1,8,2,23,7,-4 ...

  2. Flask学习(三)

    数据库操作 数据库驱动(drivers)模块:pymysql.MySQLDB ORM ORM 全拼Object-Relation Mapping,中文意为 对象-关系映射.主要实现模型对象到关系数据库 ...

  3. [App Service for Windows]通过 KUDU 查看 Tomcat 配置信息

    问题描述 在App Service 中选择了Java Tomcat后,如何查看Azure App Service的Tomcat的配置信息呢? 问题解答 可以通过以下的 3个步骤查看: 第一步:登录 K ...

  4. 【Azure App Service for Linux】Linux Web App如何安装系统未安装的包

    问题描述 Linux Web App中如何安装系统默认未安装的包,如何来执行如 apt install XXX命令呢?现在遇见的问题时,通过Azure App Service门户中的SSH登录后,执行 ...

  5. 【Azure 服务总线】有何办法可以把原来老环境的Azure Service Bus 配置快速复制到新环境配置,而且原环境不删除

    问题描述 有何办法可以把原来老环境的Azure Service Bus 配置快速复制到新环境配置,而且原环境不删除 问题解答 在通常的做法中,是可以在Service Bus所在的资源组中,通过&quo ...

  6. HashMap很美好,但线程不安全怎么办?ConcurrentHashMap告诉你答案!

    写在开头 在<耗时2天,写完HashMap>这篇文章中,我们提到关于HashMap线程不安全的问题,主要存在如下3点风险: 风险1: put的时候导致元素丢失:如两个线程同时put,且ke ...

  7. Linux安装Docker教程

    介绍 Docker利用Linux核心中的资源分脱机制,例如cgroups,以及Linux核心名字空间(name space),来创建独立的软件容器(containers).可以在单一Linux实体下运 ...

  8. STL-queue模拟实现

    #include<list> #include<assert.h> #include<deque> #include<iostream> using s ...

  9. [C++逆向] 8 数组和指针的寻址

    目录 数组在函数中 字符串 数组作为参数 下标寻址和指针寻址 多维数组 存放指针类型数据的数组 指向数组的指针变量 函数指针 数组是相同类型数据的集合,以先行方式连续储存在内冲中 而指针只是一个保存地 ...

  10. 影刀rpa:第二个项目学习心得

    教程有说到元素的关联操作,教程说自上而下的html路径,一时之间没弄清楚,索性就去看了下网页的html源码,才弄清楚到底是咋回事: 我是先选中了列表子元素的价格字段,选择两次以后就能选择到所有列表子元 ...