一、什么是OpenCV

OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件库。它由一系列的C函数和少量C++类构成,同时提供Python、Java和MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。

OpenCV具有极广的应用领域,它包括但不限于:

  • 人脸识别和物体识别:这是OpenCV的一项重要功能,应用在许多领域,如安全监控、交互设计等。
  • 图像和视频分析:如图像增强、图像分割、视频跟踪等。
  • 图像合成和3D重建:在图像处理和计算机视觉领域,OpenCV可以用于创建AR或VR效果,生成3D模型等。
  • 机器学习:OpenCV内置了大量的机器学习算法,可以用于图像分类、聚类等任务。
  • 深度学习:OpenCV中的dnn模块提供了一系列深度学习模型的接口,用户可以加载预训练模型进行图像识别、目标检测等任务。

三、本项目介绍

本项目参考opencv_app_sample应用实现,本项目是基于Haar 级联实现人脸检测,haarcascade_frontalface_alt.xml文件在rawfile文件夹。后续会基于FaceDetectorYNFaceRecognizerSF是实现人脸检测、比对。两种实现方式差别较大,感兴趣可以自行搜索。

项目流程梳理

img

三、项目实操

3.1、环境准备

设备环境:OH4.1及以上设备

开发环境:DevEco Studio 4.1 Release(构建版本:4.1.0.400)

SDK版本:4.1.9.2 Release full sdk

源码地址:https://gitee.com/MIKECODE/opencv_face_demo.git

3.2、修改代码

首先使用git clone https://gitee.com/MIKECODE/opencv_face_demo.git 获取代码并用DevEco4.1打开项目文件。

3.2.1、获取openCV库

下载opencv-4.5.5-ndk,解压后将libs下内容复制到 entry/libs 目录。(项目限制空间大小,所以库文件需要单独下载)

3.2.2、项目签名

  1. 打开项目结构(快捷键Ctrl+Alt+Shift+S)

    img

3.3、运行代码

  • 确保以上步骤完成,用数据线连接设备和pc,点击run,应用即可安装至设备。
首页切换图片识别中识别完成

img

img

img

img

使用说明

  1. 首先打开应用,点击FaceDetect开始人脸识别。
  2. 识别完成后点击Recover开始滑动文件名进行图片切换

四、如何集成FaceDetectorYN和FaceRecognizerSF

FaceDetectorYN和FaceRecognizerSF依赖神经网络实现人脸识别,准确率高,速度快,目前还在调试中,可以按以下方法接着调试。

4.1、修改entry/src/main/ets/workers/dealPictureWorker.ets

修改以调用getFaceFeatures函数。

workerPort.onmessage = (e: MessageEvents) => {
  const path = e.data['path'] as string;
  const fileName = e.data['fileName'] as string;
  const context = e.data['context'] as Context;
  Logger.info(TAG, `worker onmessage ${fileName}`);

  let pixelInfo = opencv.getFaceFeatures(context.resourceManager, path, fileName);

  // let pixelInfo: opencv.PixelInfo = opencv.faceDetect(context.resourceManager, path, fileName);
  // Logger.info(TAG, `pixelInfo buffSize: ${pixelInfo.buffSize}`);
  //
  // let opts: image.InitializationOptions = {
  //   editable: true,
  //   pixelFormat: image.PixelMapFormat.RGBA_8888,
  //   size: { height: pixelInfo.rows, width: pixelInfo.cols }
  // }
  // image.createPixelMap(pixelInfo.byteBuffer, opts, (error, pixelMap) => {
  //   if (error) {
  //     Logger.error(TAG, `Failed to create pixelmap error_code ${error.code}`);
  //   } else {
  //     Logger.info(TAG, 'Succeeded in creating pixelmap.');
  //     workerPort.postMessage(pixelMap);
  //   }
  // })
}

4.2、修改src/main/cpp/image_basic/faceDetect.cpp

这里是getFaceFeatures函数的实现,目前调用会报错,可以根据报错内容修改

// 获取人脸特征值接口
napi_value GetFaceFeatures(napi_env env, napi_callback_info info) {
    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "GetFaceFeatures Begin");
    napi_value result = NapiGetNull(env);
    size_t argc = 3;
    napi_value argv[3] = {nullptr};

    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);

    size_t strSize;
    char strBuf[256];
    napi_get_value_string_utf8(env, argv[1], strBuf, sizeof(strBuf), &strSize);
    std::string fileDir(strBuf, strSize);
    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "fileDir:%{public}s", fileDir.c_str());

    napi_get_value_string_utf8(env, argv[2], strBuf, sizeof(strBuf), &strSize);
    std::string fileName(strBuf, strSize);
    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "fileName:%{public}s", fileName.c_str());

    cv::Mat srcImage;
    if (!GetMatFromRawFile(env, argv[0], fileDir, fileName, srcImage)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "Get Mat from rawfile failed!.");
        return result;
    }

    // 确保图像为三通道RGB
    if (srcImage.channels() == 1) {
        cv::cvtColor(srcImage, srcImage, cv::COLOR_GRAY2RGB);
    } else if (srcImage.channels() == 4) {
        cv::cvtColor(srcImage, srcImage, cv::COLOR_BGRA2RGB);
    }

    // 调整图像大小为 320*320
    cv::Mat resizedImage;
    cv::resize(srcImage, resizedImage, cv::Size(320, 320));

    // 转换图像数据类型为float32并归一化
    cv::Mat floatImage;
    resizedImage.convertTo(floatImage, CV_32F, 1.0 / 255.0);

    // 创建符合 [1, 3, 320, 320] 格式的张量
    cv::Mat blob = cv::dnn::blobFromImage(floatImage, 1.0, cv::Size(320, 320), cv::Scalar(), true, false);

    // 创建人脸检测器
    cv::Ptr<cv::FaceDetectorYN> detector =
        cv::FaceDetectorYN::create("/data/storage/el2/base/haps/entry/files/yunet_s_320_320.onnx", "", cv::Size());
    if (!detector) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "Failed to create face detector!");
        return result;
    }

    // 设置输入大小为 320*320
    detector->setInputSize(cv::Size(320, 320));

    cv::Mat faces;
    try {
        // 传入预处理后的张量
        detector->detect(floatImage, faces);
    } catch (const cv::Exception &e) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "OpenCV exception: %s", e.what());
        return result;
    }

    if (faces.rows > 0) {
        // 创建人脸识别器
        cv::Ptr<cv::FaceRecognizerSF> recognizer =
            cv::FaceRecognizerSF::create("/data/storage/el2/base/haps/entry/files/face_recognizer_fast.onnx", "");
        if (!recognizer) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "Failed to create face recognizer!");
            return result;
        }

        cv::Mat alignedFace;
        recognizer->alignCrop(srcImage, faces.row(0), alignedFace);

        cv::Mat faceFeature;
        recognizer->feature(alignedFace, faceFeature);

        // 将特征值转换为 JavaScript 数组
        napi_create_array(env, &result);
        for (int i = 0; i < faceFeature.cols; ++i) {
            napi_value value;
            napi_create_double(env, faceFeature.at<float>(0, i), &value);
            napi_set_element(env, result, i, value);
        }
    }

    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "GetFaceFeatures End");
    return result;
}

4.3、先安装应用,再手动上传onnx文件到项目目录,最后再执行FaceDetect

4.2中有加载部分onnx文件,目前还没实现文件复制,通过hdc手动推送两个文件到/data/app/el2/100/base/com.demo.opencvface/haps/entry/files,文件在项目rawfile目录

4.4、根据报错排查

E     OpenCV exception: OpenCV(4.5.5) C:/Users/Administrator/DevEcoStudioProjects/MyApplication15/libtest/src/main/cpp/opencv/modules/dnn/src/dnn.cpp:1559: error: (-204:Requested object was not found) Layer with requested id=-1 not found in function 'getLayerData'

五、其他

待更新

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐