OpenHarmony 实战开发——OpenCV应用样例开发

268 篇文章 2 订阅
211 篇文章 3 订阅

背景

OpenCV 介绍

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

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

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

本文主要介绍 OpenHarmony 如何用 opencvlib 进行应用样例开发

应用开发

创建 HAP
  • 通过 DevEcoStudio 创建项目“File->New->Create Project"创建一个工程

  • 工程创建完毕后,界面入口为 Index.ets

引用 OpenCV lib 库
  • 引入 opencv 头文件库,放在 include 目录下

  • 引入 lib 库,放在 libs 目录下

  • 修改 CMAKE

  • 增加 common 头文件和 cpp 文件
    //
    // Created on 2024/3/5.
    //
    // Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
    // please include "napi/native_api.h".

    #ifndef OpencvSample_common_H
    #define OpencvSample_common_H

    #include <string>
    #include <stdio.h>
    #include <js_native_api.h>
    #include <js_native_api_types.h>
    #include <vector>
    #include "opencv2/opencv.hpp"
    #include "opencv2/imgcodecs/legacy/constants_c.h"
    #include "hilog/log.h"
    #include "napi/native_api.h"
    #include "rawfile/raw_file_manager.h"
    #include "rawfile/raw_file.h"
    #include "rawfile/raw_dir.h"

    #define GLOBAL_RESMGR (0xFFEE)
    constexpr int32_t RGB_565 = 2;
    constexpr int32_t RGBA_8888 = 3;

    constexpr int32_t STR_MAX_SIZE = 200;
    constexpr int32_t LONG_STR_MAX_SIZE = 1024;
    constexpr int32_t ERR_OK = 0;
    constexpr int8_t NO_ERROR = 0;
    constexpr int8_t ERROR = -1;
    constexpr uint8_t PARAM0 = 0;
    constexpr uint8_t PARAM1 = 1;
    constexpr uint8_t PARAM2 = 2;
    constexpr uint8_t PARAM3 = 3;
    constexpr uint8_t PARAM4 = 4;
    constexpr uint8_t PARAM5 = 5;
    constexpr uint8_t PARAM6 = 6;
    constexpr uint8_t PARAM7 = 7;
    constexpr uint8_t PARAM8 = 8;
    constexpr uint8_t PARAM9 = 9;
    constexpr uint8_t PARAM10 = 10;
    constexpr uint8_t PARAM11 = 11;
    constexpr uint8_t PARAM12 = 12;

    constexpr int32_t ARGS_ONE = 1;
    constexpr int32_t ARGS_TWO = 2;
    constexpr int32_t ONLY_CALLBACK_MAX_PARA = 1;
    constexpr int32_t ONLY_CALLBACK_MIN_PARA = 0;

    struct CallbackPromiseInfo {
        napi_ref callback = nullptr;
        napi_deferred deferred = nullptr;
        bool isCallback = false;
        int32_t errorCode = 0;
    };

    template <typename T> void FreeMemory(T *p) {
        if (p == nullptr) {
            return;
        }
        delete p;
        p = nullptr;
    }

    template <typename T> void FreeMemoryArray(T *p) {
        if (p == nullptr) {
            return;
        }
        delete[] p;
        p = nullptr;
    }
    #define NAPI_RETVAL_NOTHING
    #define NAPI_CALL_BASE(env, theCall, retVal)                                                                           \
        do {                                                                                                               \
            if ((theCall) != 0) {                                                                                          \
                return retVal;                                                                                             \
            }                                                                                                              \
        } while (0)

    #define NAPI_CALL(env, theCall) NAPI_CALL_BASE(env, theCall, nullptr)
    #define NAPI_CALL_RETURN_VOID(env, theCall) NAPI_CALL_BASE(env, theCall, NAPI_RETVAL_NOTHING)

    extern bool GetMatFromRawFile(napi_env env, napi_value jsResMgr, const std::string &rawfileDir,
                                  const std::string &fileName, cv::Mat &srcImage);
    extern bool cvtMat2Pixel(cv::InputArray _src, cv::OutputArray &_dst, int code);
    extern napi_value NapiGetNull(napi_env env);
    extern uint32_t GetMatDataBuffSize(const cv::Mat &mat);
    extern bool CreateArrayBuffer(napi_env env, uint8_t *src, size_t srcLen, napi_value *res);
    extern napi_value NapiGetUndefined(napi_env env);
    extern napi_value GetCallbackErrorValue(napi_env env, int32_t errCode);
    extern napi_value NapiGetBoolean(napi_env env, const bool &isValue);
    extern uint32_t GetMatDataBuffSize(const cv::Mat &mat);
    extern void SetCallback(const napi_env &env, const napi_ref &callbackIn, const int32_t &errorCode,
                            const napi_value &result);
    extern void SetPromise(const napi_env &env, const napi_deferred &deferred, const int32_t &errorCode,
                           const napi_value &result);
    extern void ReturnCallbackPromise(const napi_env &env, const CallbackPromiseInfo &info, const napi_value &result);
    extern napi_value JSParaError(const napi_env &env, const napi_ref &callback);
    extern void PaddingCallbackPromiseInfo(const napi_env &env, const napi_ref &callback, CallbackPromiseInfo &info,
                                           napi_value &promise);
    extern bool WrapJsPixelInfoInfo(napi_env env, cv::Mat &outMat, napi_value &result);

    #endif //OpencvSample_common_H

  • 增加灰度转换方法
    using namespace std;
    using namespace cv;
    static const char *TAG = "[opencv_img2Gray]";

    napi_value Img2Gray(napi_env env, napi_callback_info info) {
        OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "Img2Gray 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());

        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;
        }

        Mat srcGray;
        cvtColor(srcImage, srcGray, COLOR_RGB2GRAY);

        // 將图像转换为pixelMap格式
        Mat outMat;
        cvtMat2Pixel(srcGray, outMat, RGBA_8888);
        OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "outMat size: %{public}d, cols:%{public}d, rows:%{public}d",
                     outMat.total(), outMat.cols, outMat.rows);

        napi_create_object(env, &result);
        bool retVal = WrapJsPixelInfoInfo(env, outMat, result);
        if (!retVal) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "WrapJsInfo failed!.");
        }

        return result;
    }

  • 导出 //hello.cpp
    EXTERN_C_START
    static napi_value Init(napi_env env, napi_value exports)
    {
        napi_property_descriptor desc[] = {
            {"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr},
            {"img2Gray", nullptr, Img2Gray, nullptr, nullptr, nullptr, napi_default, nullptr}
        };
        napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
        return exports;
    }
    EXTERN_C_END

  • 导出接口 //index.d.ts
    import resourceManager from '@ohos.resourceManager';

    export interface PixelInfo {
      rows: number;
      cols: number;
      buffSize: number;
      byteBuffer: ArrayBuffer;
    }

    export const add: (a: number, b: number) => number;
    export const img2Gray: (resmgr: resourceManager.ResourceManager, path: string, file: string) => PixelInfo;
  • 在页面添加交互 // index.ets
    Column() {
      Image(this.isGray ? this.imagePixelMap : $rawfile('lena.jpg'))
        .margin({ left: 24, right: 24 })
        .objectFit(ImageFit.Contain)
        .id('backBtn')
      }
      .width('100%')
      .height('60%')
      .alignItems(HorizontalAlign.Center)
      .justifyContent(FlexAlign.Start)

      Row() {
        Button($r('app.string.image_gray'), { type: ButtonType.Capsule })
          .backgroundColor(this.isGray ? Color.Gray : Color.Blue)
          .margin({ left: 24 })
          .width('30%')
          .id('imageGray')
          .enabled(this.isGray ? false : true)
          .onClick(() => {
            let pixelInfo: testNapi.PixelInfo = testNapi.img2Gray(getContext().resourceManager, '', 'lena.jpg');
            Logger.info(TAG, `pixelInfo buffSize: ${pixelInfo.buffSize}`);

            let opts: image.InitializationOptions = {
              editable: true,
              pixelFormat: this.pixelMapFormat,
              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.');
                this.imagePixelMap = pixelmap;
              }
            })
            this.isGray = true;
        })

        Button($r('app.string.image_recover'), { type: ButtonType.Capsule })
          .backgroundColor(Color.Blue)
          .width('30%')
          .id('imageRecover')
          .onClick(() => {
            this.isGray = false;
          })
        }
        .width('100%')

  • 展示

总结

  • 可以用 nativec++ 方式导入 opencv 库直接开发应用,目前实现了一个简单接口,后面会实现场景应用

  • 目前只能做到可用,还有以下问题:

    • 需要 NAPI 接口进行 ArkTS 和 C/C++ 交互
    • 速度比较慢,是否可以通过 GPU 加速
    • Arkts 和 native 交互多,考虑转用 xcomponent 方式

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
OpenCV是一款非常强大的计算机视觉库,其中包含了很多功能强大的图像处理和计算机视觉算法。而在这个系列的第三篇文章中,我们将重点介绍如何在OpenCV中绘制图形和文本。 OpenCV中绘制图形的函数包括cv2.line(直线),cv2.rectangle(矩形),cv2.circle(圆),cv2.ellipse(椭圆)和cv2.putText(文本)。这些函数的使用非常简单,只需要指定图像,开始点和结束点(或中心点和半径),颜色和线宽即可。 例如,我们可以使用cv2.rectangle函数在图像上绘制一个矩形: ``` import cv2 import numpy as np img = np.zeros((512,512,3), np.uint8) # 创建一个黑色的图像 cv2.rectangle(img,(384,0),(510,128),(0,255,0),3) # 绘制矩形 cv2.imshow("image",img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在这个例子中,我们首先创建了一个512x512的黑色图像,然后使用cv2.rectangle函数在图像上绘制了一个矩形,并将其显示出来。在这里,矩形的左上角坐标是(384,0),右下角坐标是(510,128),颜色是绿色(0,255,0),线宽为3。 除了绘制图形,我们也可以使用cv2.putText函数在图像上绘制文本。这个函数的使用也非常简单,只需要指定图像,文本内容,位置,字体,字体大小和颜色即可。 例如,我们可以使用cv2.putText函数在图像上写入一个“Hello World!”的文本: ``` import cv2 import numpy as np img = np.zeros((512,512,3), np.uint8) # 创建一个黑色的图像 font = cv2.FONT_HERSHEY_SIMPLEX # 设置字体 cv2.putText(img,'Hello World!',(10,500), font, 1,(255,255,255),2,cv2.LINE_AA) # 绘制文本 cv2.imshow("image",img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在这个例子中,我们使用cv2.putText函数在左下角绘制了一个“Hello World!”的文本,并将其显示出来。在这里,我们首先选取了字体类型为cv2.FONT_HERSHEY_SIMPLEX,然后指定了文本的位置(10,500),字体大小为1,颜色为白色(255,255,255),线宽为2,并且使用了cv2.LINE_AA参数,以实现更好的文本渲染效果。 综上所述,OpenCV中可以很方便地对图像进行绘制和文本处理,这对于图像处理和计算机视觉应用来说是非常重要的一步。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值