鸿蒙5.0【在OpenHarmony上使用SeetaFace2人脸识别库】

打印 上一主题 下一主题

主题 874|帖子 874|积分 2622

简介

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

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

  • 录入页面点击右下角按钮,跳转拍摄页面举行照相;
  • 选择一张或多张人脸作为训练模子,并设置对应的名字;
  • 选择一张未录入的人脸图片,点击框选按钮实现人脸图片框选功能;
  • 最后点击识别,应用会对当前图片举行匹配,最终在界面中显示识别效果。
快速上手

   装备端开发
  装备端通过OpenCV对图像举行处理并通过Seetaface2对图形数据举行人脸头像的识别,最终输出对应的NAPI接口提供给应用端调用。因此装备端开发重要涉及到OpenCV和Seetaface2的移植以及NAPI接口的开发。
OpenCV库移植
OpenCV是一个功能非常强大的开源盘算机视觉库。此库已由知识体系工作组移植到了OpenHarmony中,后期还会将此库合入到主仓。在此库上主仓之前,我们只必要以下几个步调就可以实现OpenCV的移植使用。

  • 通过以下命令下载已经移植好的OpenCV
  1. git clone git@gitee.com:zhong-luping/ohos_opencv.git
复制代码

  • 将OpenCV拷贝到OpenHarmony目录的third_party下
  1. cp -raf opencv ~/openharmony/third_party/
复制代码

  • 恰当裁剪编译选项
打开OpenCV目录下的BUILD.gn,如下:
不必要video以及flann功能,将对应的模块注释即可。
  1. import("//build/ohos.gni")
  2. group("opencv") {
  3.     deps = [
  4.         "//third_party/opencv/modules/core:opencv_core",
  5.       //  "//third_party/opencv/modules/flann:opencv_flann",
  6.         "//third_party/opencv/modules/imgproc:opencv_imgproc",
  7.         "//third_party/opencv/modules/ml:opencv_ml",
  8.         "//third_party/opencv/modules/photo:opencv_photo",
  9.         "//third_party/opencv/modules/dnn:opencv_dnn",
  10.         "//third_party/opencv/modules/features2d:opencv_features2d",
  11.         "//third_party/opencv/modules/imgcodecs:opencv_imgcodecs",
  12.         "//third_party/opencv/modules/videoio:opencv_videoio",
  13.         "//third_party/opencv/modules/calib3d:opencv_calib3d",
  14.         "//third_party/opencv/modules/highgui:opencv_highgui",
  15.         "//third_party/opencv/modules/objdetect:opencv_objdetect",
  16.         "//third_party/opencv/modules/stitching:opencv_stitching",
  17.         "//third_party/opencv/modules/ts:opencv_ts",
  18.      //   "//third_party/opencv/modules/video:opencv_video",
  19.        "//third_party/opencv/modules/gapi:opencv_gapi",
  20.     ]
  21. }
复制代码

  • 添加依赖子系统的part_name,编译框架子系统会将编译出的库拷贝到系统文件中。
此项目中我们新建了一个SeetaFaceApp的子系统,该子系统中命名part_name为SeetafaceApi,所以我们必要在对应模块中的BUILD.gn中加上part_name=“SeetafaceApi”
以module/core为例:
  1. ohos_shared_library("opencv_core"){
  2. sources = [ ... ]
  3. configs = [  ... ]
  4. deps = [ ... ]
  5. part_name = "SeetafaceApi"
  6. }
复制代码

  • 编译工程必要添加OpenCV的依赖。
在生成NAPI的BUILD.gn中添加以下依赖:
  1. deps += [ "//third_party/opencv:opencv" ]
复制代码
至此,人脸识别中OpenCV的移植使用完成。
SeetaFace2库移植
SeetaFace2是中科视拓开源的第二代人脸识别库。包罗了搭建一套全自动人脸识别系统所需的三个核心模块,即:人脸检测模块FaceDetector、面部关键点定位模块FaceLandmarker以及人脸特性提取与比对模块 FaceRecognizer。
关于SeetaFace2的移植请参照文档:SeetaFace2移植开发文档。
NAPI接口开发
关于OpenHarmony中的NAPI开发,参考视频:
OpenHarmony中napi的开发视频教程。本文将重点讲解NAPI接口怎样实现OpenCV以及SeetaFace的调用。

  • 人脸框获取的NAPI接口的实现。
int GetRecognizePoints(const char *image_path);
此接口重要是通过应用层输入一张图片,通过OpenCV的imread接口获取到图片数据,并通过人脸检测模块FaceDetector分析获得图片中全部的人脸矩形框(矩形框是以x,y,w,h的方式)并将人脸框矩形以数组的方式返回到应用层。
人脸框矩形获取的重要代码如下:
  1. static int RecognizePoint(string image_path, FaceRect *rect, int num)
  2. {
  3.     if (rect == nullptr) {
  4.         cerr << "NULL POINT!" << endl;
  5.         LOGE("NULL POINT! \n");
  6.         return -1;
  7.     }
  8.     seeta::ModelSetting::Device device = seeta::ModelSetting::CPU;
  9.     int id = 0;
  10.     /* 设置人脸识别模型。*/
  11.     seeta::ModelSetting FD_model( "/system/usr/model/fd_2_00.dat", device, id );
  12.     seeta::ModelSetting FL_model( "/system/usr/model/pd_2_00_pts81.dat", device, id );
  13.     seeta::FaceDetector FD(FD_model);
  14.     seeta::FaceLandmarker FL(FL_model);
  15.     FD.set(seeta::FaceDetector::PROPERTY_VIDEO_STABLE, 1);
  16.     /* 读取图片数据 */
  17.     auto frame = imread(image_path);
  18.     seeta::cv::ImageData simage = frame;
  19.     if (simage.empty()) {
  20.         cerr << "Can not open image: " << image_path << endl;
  21.         LOGE("Can not open image: %{public}s", image_path.c_str());
  22.         return -1;
  23.     }
  24.     /* 图片数据进行人脸识别处理 ,获取所有的人脸框数据对象*/
  25.     auto faces = FD.detect(simage);
  26.     if (faces.size <= 0) {
  27.         cerr << "detect " << image_path << "failed!" << endl;
  28.         LOGE("detect image: %s failed!", image_path.c_str());
  29.         return -1;
  30.     }
  31.     for (int i = 0; (i < faces.size && i < num); i++) {
  32.         /* 将所有人脸框对象数据以坐标形式输出*/
  33.         auto &face = faces.data[i];
  34.         memcpy(&rect[i], &(face.pos), sizeof(FaceRect));
  35.     }
  36.     return faces.size;
  37. }
复制代码
其中FD_model是人脸检测模子,而FL_model是面部关键点定位模子(此模子分为5点定位和81点定位,本项目中使用的是81点定位模子),这些模子从开源项目中免费获取。
通过以上方式获取到对应的人脸矩形框后,再将矩形框以数组的方式返回到应用端:
  1.     string image = path;
  2.     p = (FaceRect *)malloc(sizeof(FaceRect) * MAX_FACE_RECT);
  3.     /* 根据图片进行人脸识别并获取人脸框坐标点 */
  4.     int retval = RecognizePoint(image, p, MAX_FACE_RECT);
  5.     if (retval <= napi_ok) {
  6.         LOGE("GetNapiValueString failed!");
  7.         free(p);
  8.         return result;
  9.     }  
  10.     /*将所有坐标点以数组方式返回到应用端*/
  11.     for (int i = 0; i < retval; i++) {
  12.         int arry_int[4] = {p[i].x, p[i].y, p[i].w, p[i].h};
  13.         int arraySize = (sizeof(arry_int) / sizeof(arry_int[0]));
  14.         for (int j = 0; j < arraySize; j++) {
  15.             napi_value num_val;
  16.             if (napi_create_int32(env, arry_int[j], &num_val) != napi_ok) {
  17.                 LOGE("napi_create_int32 failed!");
  18.                 return result;
  19.             }
  20.             napi_set_element(env, array, i*arraySize + j, num_val);
  21.         }
  22.     }
  23.     if (napi_create_object(env, &result) != napi_ok) {
  24.         LOGE("napi_create_object failed!");
  25.         free(p);
  26.         return result;
  27.     }
  28.     if (napi_set_named_property(env, result, "recognizeFrame", array) != napi_ok) {
  29.         LOGE("napi_set_named_property failed!");
  30.         free(p);
  31.         return result;
  32.     }
  33.     LOGI("");
  34.     free(p);
  35.     return result;
复制代码
其中array是通过napi_create_array创建的一个NAPI数组对象,通过 napi_set_element将全部的矩形框数据保存到array对象中,最后通过 napi_set_named_property将array转换成应用端可识别的对象类型result并将其返回。

  • 人脸搜索识别初始化与逆初始化。
  • int FaceSearchInit();
  • int FaceSearchDeinit();
这2个接口重要是提供给人脸搜索以及识别调用的,初始化重要包含模子的注册以及识别模块的初始化:
  1. static  int FaceSearchInit(FaceSearchInfo *info)
  2. {
  3.     if (info == NULL) {
  4.         info = (FaceSearchInfo *)malloc(sizeof(FaceSearchInfo));
  5.         if (info == nullptr) {
  6.             cerr << "NULL POINT!" << endl;
  7.             return -1;
  8.         }
  9.     }
  10.     seeta::ModelSetting::Device device = seeta::ModelSetting::CPU;
  11.     int id = 0;
  12.     seeta::ModelSetting FD_model( "/system/usr/model/fd_2_00.dat", device, id );
  13.     seeta::ModelSetting PD_model( "/system/usr//model/pd_2_00_pts5.dat", device, id );
  14.     seeta::ModelSetting FR_model( "/system/usr/model/fr_2_10.dat", device, id );
  15.     info->engine = make_shared<seeta::FaceEngine>(FD_model, PD_model, FR_model, 2, 16);
  16.     info->engine->FD.set( seeta::FaceDetector::PROPERTY_MIN_FACE_SIZE, 80);
  17.     info->GalleryIndexMap.clear();
  18.     return 0;
  19. }
复制代码
而逆初始化就是做一些内存的开释。
  1. static void FaceSearchDeinit(FaceSearchInfo *info, int need_delete)
  2. {
  3.     if (info != nullptr) {
  4.         if (info->engine != nullptr) {
  5.         }
  6.         info->GalleryIndexMap.clear();
  7.         if (need_delete) {
  8.             free(info);
  9.             info = nullptr;
  10.         }
  11.     }
  12. }
复制代码

  • 人脸搜索识别注册接口的实现。
int FaceSearchRegister(const char *value);
必要留意的是,该接口必要应用端传入一个json数据的参数,重要包含注册人脸的名字,图片以及图片个数,如{“name”:“刘德华”,“sum”:“2”,“image”:{“11.jpg”,“12.jpg”}}。而剖析参数的时候必要调用 napi_get_named_property对json数据的各个对象举行剖析,具体代码如下:
  1.     napi_get_cb_info(env, info, &argc, &argv, &thisVar, &data);
  2.     napi_value object = argv;
  3.     napi_value value = nullptr;
  4.     if (napi_get_named_property(env, object, (const char *)"name", &value) == napi_ok) {
  5.         char name[64] = {0};
  6.         if (GetNapiValueString(env, value, (char *)name, sizeof(name)) < 0) {
  7.             LOGE("GetNapiValueString failed!");
  8.             return result;
  9.         }
  10.         reg_info.name = name;
  11.     }
  12.     LOGI("name = %{public}s", reg_info.name.c_str());
  13.     if (napi_get_named_property(env, object, (const char *)"sum", &value) == napi_ok) {
  14.         
  15.         if (napi_get_value_uint32(env, value, &sum) != napi_ok) {
  16.             LOGE("napi_get_value_uint32 failed!");
  17.             return result;
  18.         }
  19.     }
  20.     LOGI("sum = %{public}d", sum);
  21.     if (napi_get_named_property(env, object, (const char *)"image", &value) == napi_ok) {
  22.         bool res = false;
  23.         if (napi_is_array(env, value, &res) != napi_ok || res == false) {
  24.             LOGE("napi_is_array failed!");
  25.             return result;
  26.         }
  27.         for (int i = 0; i < sum; i++) {
  28.             char image[256] = {0};
  29.             napi_value imgPath = nullptr;
  30.             if (napi_get_element(env, value, i, &imgPath) != napi_ok) {
  31.                 LOGE("napi_get_element failed!");
  32.                 return result;
  33.             }
  34.             if (GetNapiValueString(env, imgPath, (char *)image, sizeof(image)) < 0) {
  35.                 LOGE("GetNapiValueString failed!");
  36.                 return result;
  37.             }
  38.             reg_info.path = image;
  39.             if (FaceSearchRegister(g_FaceSearch, reg_info) != napi_ok) {
  40.                 retval = -1;
  41.                 break;
  42.             }
  43.         }
  44.     }
复制代码
通过napi_get_cb_info获取从应用端传来的参数,并通过 napi_get_named_property获取对应的name以及图片个数,最后通过napi_get_element获取图片数组中的各个image,将name和image通过FaceSearchRegister接口将图片和名字注册到SeetaFace2模块的识别引擎中。具体实现如下:
  1. static int FaceSearchRegister(FaceSearchInfo &info, RegisterInfo &gegister)
  2. {
  3.     if (info.engine == nullptr) {
  4.         cerr << "NULL POINT!" << endl;
  5.         return -1;
  6.     }
  7.     seeta::cv::ImageData image = cv::imread(gegister.path);
  8.     auto id = info.engine->Register(image);
  9.     if (id >= 0) {
  10.         info.GalleryIndexMap.insert(make_pair(id, gegister.name));
  11.     }
  12.     return 0;
  13. }
复制代码
注册完数据后,后续可以通过该引擎来识别对应的图片。

  • 获取人脸搜索识别效果接口的实现。
  1. char *FaceSearchGetRecognize(const char *image_path);
复制代码
该接口实现了通过传入一张图片,在识别引擎中举行搜索识别。如果识别引擎中有类似的人脸注册,则返回对应人脸注册时的名字,否则返回不识别(ignored)字样。该方法是通过异步回调的方式实现的:
  1.     // 创建async work,创建成功后通过最后一个参数(commandStrData->asyncWork)返回async work的handle
  2.     napi_value resourceName = nullptr;
  3.     napi_create_string_utf8(env, "FaceSearchGetPersonRecognizeMethod", NAPI_AUTO_LENGTH, &resourceName);
  4.     napi_create_async_work(env, nullptr, resourceName, FaceSearchRecognizeExecuteCB, FaceSearchRecognizeCompleteCB,
  5.             (void *)commandStrData, &commandStrData->asyncWork);
  6.     // 将刚创建的async work加到队列,由底层去调度执行
  7.     napi_queue_async_work(env, commandStrData->asyncWork);
复制代码
其中FaceSearchRecognizeExecuteCB实现了人脸识别
  1. static void FaceSearchRecognizeExecuteCB(napi_env env, void *data)
  2. {
  3.     CommandStrData *commandStrData = dynamic_cast<CommandStrData*>((CommandStrData *)data);
  4.     if (commandStrData == nullptr) {
  5.         HILOG_ERROR("nullptr point!", __FUNCTION__, __LINE__);
  6.         return;
  7.     }
  8.     FaceSearchInfo faceSearch = *(commandStrData->mFaceSearch);
  9.     commandStrData->result = FaceSearchSearchRecognizer(faceSearch, commandStrData->filename);
  10.     LOGI("Recognize result : %s !", __FUNCTION__, __LINE__, commandStrData->result.c_str());
  11. }
复制代码
FaceSearchRecognizeCompleteCB函数通过napi_resolve_deferred接口将识别效果返回到应用端。
  1. static void FaceSearchRecognizeCompleteCB(napi_env env, napi_status status, void *data)
  2. {
  3.     CommandStrData *commandStrData = dynamic_cast<CommandStrData*>((CommandStrData *)data);
  4.     napi_value result;
  5.     if (commandStrData == nullptr || commandStrData->deferred == nullptr) {
  6.         LOGE("nullptr", __FUNCTION__, __LINE__);
  7.         if (commandStrData != nullptr) {
  8.             napi_delete_async_work(env, commandStrData->asyncWork);
  9.             delete commandStrData;
  10.         }
  11.         return;
  12.     }
  13.     const char *result_str = (const char *)commandStrData->result.c_str();
  14.     if (napi_create_string_utf8(env, result_str, strlen(result_str), &result) != napi_ok) {
  15.         LOGE("napi_create_string_utf8 failed!", __FUNCTION__, __LINE__);
  16.         napi_delete_async_work(env, commandStrData->asyncWork);
  17.         delete commandStrData;
  18.         return;
  19.     }
  20.     napi_resolve_deferred(env, commandStrData->deferred, result);
  21.     napi_delete_async_work(env, commandStrData->asyncWork);
  22.     delete commandStrData;
  23. }
复制代码
通过人脸特性提取与比对模块,对传入的数据与已注册的数据举行对比,并通过返回对比的相似度来举行判断当前人脸是否为可识别的,最后返回识别效果。具体实今世码:
  1. static string FaceSearchSearchRecognizer(FaceSearchInfo &info, string filename)
  2. {
  3.     if (info.engine == nullptr) {
  4.         cerr << "NULL POINT!" << endl;
  5.         return "recognize error 0";
  6.     }
  7.     string name;
  8.     float threshold = 0.7f;
  9.     seeta::QualityAssessor QA;
  10.     auto frame = cv::imread(filename);
  11.     if (frame.empty()) {
  12.         LOGE("read image %{public}s failed!", filename.c_str());
  13.         return "recognize error 1!";
  14.     }
  15.     seeta::cv::ImageData image = frame;
  16.     std::vector<SeetaFaceInfo> faces = info.engine->DetectFaces(image);
  17.     for (SeetaFaceInfo &face : faces) {
  18.         int64_t index = 0;
  19.         float similarity = 0;
  20.         auto points = info.engine->DetectPoints(image, face);
  21.         auto score = QA.evaluate(image, face.pos, points.data());
  22.         if (score == 0) {
  23.             name = "ignored";
  24.         } else {
  25.             auto queried = info.engine->QueryTop(image, points.data(), 1, &index, &similarity);
  26.             // no face queried from database
  27.             if (queried < 1) continue;
  28.                 // similarity greater than threshold, means recognized
  29.             if( similarity > threshold ) {
  30.                 name = info.GalleryIndexMap[index];
  31.             }
  32.         }
  33.     }
  34.     LOGI("name : %{public}s \n", name.length() > 0 ? name.c_str() : "null");
  35.     return name.length() > 0 ? name : "recognize failed";
  36. }
复制代码
至此,全部的NAPI接口已经开发完成。

  • NAPI库编译开发完NAPI接口后,我们必要将我们编写的库加入到系统中举行编译,我们必要添加一个自己的子系统。
首先在库目录下新建一个ohos.build
  1. {
  2.     "subsystem": "SeetafaceApp",
  3.     "parts": {
  4.         "SeetafaceApi": {
  5.             "module_list": [
  6.                "//seetaface:seetafaceapp_napi"
  7.             ],
  8.             "test_list": [ ]
  9.         }
  10.     }
  11. }
复制代码
其次同一目录新建一个BUILD.gn,将库源文件以及对应的依赖加上,如下:
  1. 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" ]
  2.     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并在最后添加以下代码:
  1.   "SeetafaceApp": {
  2.     "path": "seetaface",
  3.     "name": "SeetafaceApp"
  4.   }
复制代码
添加完子系统再修改产对应的品配置
打开productdefine/common/products/rk3568.json并在最后添加以下代码:
  1. "SeetafaceApp:SeetafaceApi":{}
复制代码
做完以上修改后我们就可以通过以下命令直接编译NAPI的库文件了:
  1. ./build.sh --product-name rk3568 --ccache
复制代码
参考RK3568快速上手-镜像烧录完成烧录即可。
   应用端开发
  在完成装备NAPI功能开发后,应用端通过调用NAPI组件中暴露给应用的人脸识别接口,即可实现对应功能。接下来就带着大家使用NAPI实现人脸识别功能。
开发准备

  • 下载DevEco Studio 3.0 Beta4;
  • 搭建开发情况,参考开发准备;
  • 了解属性eTS开发,参考eTS语言快速入门;
SeetaFace2初始化

  • 首先将SeetaFace2 NAPI接口声明文件放置于SDK目录/api下;
  • 然后导入SeetaFace2 NAPI模块;ck-start/star
  • 调用初始化接口;
  1. // 首页实例创建后
  2. async aboutToAppear() {
  3.   await StorageUtils.clearModel();
  4.   CommonLog.info(TAG,'aboutToAppear')
  5.   // 初始化人脸识别
  6.   let res = SeetafaceApp.FaceSearchInit()
  7.   CommonLog.info(TAG,`FaceSearchInit res=${res}`)
  8.   this.requestPermissions()
  9. }
  10. // 请求权限
  11. requestPermissions(){
  12.   CommonLog.info(TAG,'requestPermissions')
  13.   let context = featureAbility.getContext()
  14.   context.requestPermissionsFromUser(PERMISSIONS, 666,(res)=>{
  15.     this.getMediaImage()
  16.   })
  17. }
复制代码
获取全部人脸图片

通过文件管理模块fileio和媒体库管理mediaLibrary,获取指定应用数据目录下全部的图片信息,并将路径赋值给faceList,faceList数据用于Image组件提供url举行加载图片
  1. // 获取所有图片
  2. async getMediaImage(){
  3.   let context = featureAbility.getContext();
  4.   // 获取本地应用沙箱路径
  5.   let localPath = await context.getOrCreateLocalDir()
  6.   CommonLog.info(TAG, `localPath:${localPath}`)
  7.   let facePath = localPath + "/files"
  8.   // 获取所有照片
  9.   this.faceList = await FileUtil.getImagePath(facePath)
  10. }
复制代码
设置人脸模子

获取选中的人脸图片地点和输入的名字,调用SeetafaceApp.FaceSearchRegister(params)举行设置人脸模子。其中参数params由name名字、image图片地点集合和sum图片数量组成。
  1. async submit(name) {
  2.     if (!name || name.length == 0) {
  3.         CommonLog.info(TAG, 'name is empty')
  4.         return
  5.     }
  6.     let selectArr = this.faceList.filter(item => item.isSelect)
  7.     if (selectArr.length == 0) {
  8.         CommonLog.info(TAG, 'faceList is empty')
  9.         return
  10.     }
  11.     // 关闭弹窗
  12.     this.dialogController.close()
  13.     try {
  14.         let urls = []
  15.         let files = []
  16.         selectArr.forEach(item => {
  17.             let source = item.url.replace('file://', '')
  18.             CommonLog.info(TAG, `source:${source}`)
  19.             urls.push(item.url)
  20.             files.push(source)
  21.         })
  22.         // 设置人脸识别模型参数
  23.         let params = {
  24.             name: name,
  25.             image: files,
  26.             sum: files.length
  27.         }
  28.         CommonLog.info(TAG, 'FaceSearchRegister' + JSON.stringify(params))
  29.         let res = SeetafaceApp.FaceSearchRegister(params)
  30.         CommonLog.info(TAG, 'FaceSearchRegister res ' + res)
  31.         // 保存已设置的人脸模型到轻量存储
  32.         let data = {
  33.             name:name,
  34.             urls:urls
  35.         }
  36.         let modelStr = await StorageUtils.getModel()
  37.         let modelList = JSON.parse(modelStr)
  38.         modelList.push(data)
  39.         StorageUtils.setModel(modelList)
  40.         router.back()
  41.     } catch (err) {
  42.         CommonLog.error(TAG, 'submit fail ' + err)
  43.     }
  44. }
复制代码
实现框选人脸

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

调用SeetafaceApp.FaceSearchGetRecognize(url),传入图片地点对人脸举行识别并返回对应识别出来的名字。
  1. // 人脸识别
  2. recognize(){
  3.     SeetafaceApp.FaceSearchGetRecognize(this.url).then(res=>{
  4.         CommonLog.info(TAG,'recognize suceess' + JSON.stringify(res))
  5.         if(res && res != 'ignored' && res != "recognize failed" && res != 'recognize error 1!'){
  6.             // 赋值识别到的人物模型
  7.             this.name = res
  8.         }else{
  9.             this.name = '未识别到该模型'
  10.         }
  11.     }).catch(err=>{
  12.         CommonLog.error(TAG,'recognize' + err)
  13.         this.name = '未识别到该模型'
  14.     })
  15. }
复制代码

最后呢,很多开发朋侪不知道必要学习那些鸿蒙技能?鸿蒙开发岗位必要掌握那些核心技能点?为此鸿蒙的开发学习必须要系统性的举行。
而网上有关鸿蒙的开发资料非常的少,假如你想学好鸿蒙的应用开发与系统底层开发。你可以参考这份资料,少走很多弯路,节省没必要的麻烦。由两位前阿里高级研发工程师团结打造的《鸿蒙NEXT星河版OpenHarmony开发文档》里面内容包含了(ArkTS、ArkUI开发组件、Stage模子、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技能、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)技能知识点
如果你是一名Android、Java、前端等等开发人员,想要转入鸿蒙方向发展。可以直接领取这份资料辅助你的学习。下面是鸿蒙开发的学习路线图。
​​​​

高清完备版请点击→《鸿蒙NEXT星河版开发学习文档》
针对鸿蒙发展路线打造的鸿蒙学习文档。话不多说,我们直接看详细资料鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门讲授视频,帮助大家在技能的门路上更进一步。
《鸿蒙 (OpenHarmony)开发学习视频》
《鸿蒙生态应用开发V2.0白皮书》
《鸿蒙 (OpenHarmony)开发基础到实战手册》
《鸿蒙开发基础》
《鸿蒙开发进阶》
《鸿蒙开发实战》

获取这份鸿蒙星河版学习资料,请点击→《鸿蒙NEXT星河版开发学习文档》
总结

鸿蒙—作为国家主力推送的国产操纵系统。部分的高校已经取消了安卓课程,从而开设鸿蒙课程;企业纷纷跟进启动了鸿蒙研发。
并且鸿蒙是完全具备无与伦比的机会和潜力的;预计到年底将有 5,000 款的应用完成原生鸿蒙开发,未来将会支持 50 万款的应用。那么这么多的应用必要开发,也就意味着必要有更多的鸿蒙人才。鸿蒙开发工程师也将会迎来发作式的增长,学习鸿蒙势在必行!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

汕尾海湾

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表