查看: 119|回复: 7

OpenHarmony OpenCV应用样例开发

[复制链接]

1

主题

0

回帖

13

积分

新手上路

积分
13
发表于 2025-3-30 13:19:21 | 显示全部楼层 |阅读模式
背景

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文件
    1. //
    2. // Created on 2024/3/5.
    3. //
    4. // Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
    5. // please include "napi/native_api.h".
    6. #ifndef OpencvSample_common_H
    7. #define OpencvSample_common_H
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include "opencv2/opencv.hpp"
    14. #include "opencv2/imgcodecs/legacy/constants_c.h"
    15. #include "hilog/log.h"
    16. #include "napi/native_api.h"
    17. #include "rawfile/raw_file_manager.h"
    18. #include "rawfile/raw_file.h"
    19. #include "rawfile/raw_dir.h"
    20. #define GLOBAL_RESMGR (0xFFEE)
    21. constexpr int32_t RGB_565 = 2;
    22. constexpr int32_t RGBA_8888 = 3;
    23. constexpr int32_t STR_MAX_SIZE = 200;
    24. constexpr int32_t LONG_STR_MAX_SIZE = 1024;
    25. constexpr int32_t ERR_OK = 0;
    26. constexpr int8_t NO_ERROR = 0;
    27. constexpr int8_t ERROR = -1;
    28. constexpr uint8_t PARAM0 = 0;
    29. constexpr uint8_t PARAM1 = 1;
    30. constexpr uint8_t PARAM2 = 2;
    31. constexpr uint8_t PARAM3 = 3;
    32. constexpr uint8_t PARAM4 = 4;
    33. constexpr uint8_t PARAM5 = 5;
    34. constexpr uint8_t PARAM6 = 6;
    35. constexpr uint8_t PARAM7 = 7;
    36. constexpr uint8_t PARAM8 = 8;
    37. constexpr uint8_t PARAM9 = 9;
    38. constexpr uint8_t PARAM10 = 10;
    39. constexpr uint8_t PARAM11 = 11;
    40. constexpr uint8_t PARAM12 = 12;
    41. constexpr int32_t ARGS_ONE = 1;
    42. constexpr int32_t ARGS_TWO = 2;
    43. constexpr int32_t ONLY_CALLBACK_MAX_PARA = 1;
    44. constexpr int32_t ONLY_CALLBACK_MIN_PARA = 0;
    45. struct CallbackPromiseInfo {
    46.    napi_ref callback = nullptr;
    47.    napi_deferred deferred = nullptr;
    48.    bool isCallback = false;
    49.    int32_t errorCode = 0;
    50. };
    51. template  void FreeMemory(T *p) {
    52.    if (p == nullptr) {
    53.        return;
    54.    }
    55.    delete p;
    56.    p = nullptr;
    57. }
    58. template  void FreeMemoryArray(T *p) {
    59.    if (p == nullptr) {
    60.        return;
    61.    }
    62.    delete[] p;
    63.    p = nullptr;
    64. }
    65. #define NAPI_RETVAL_NOTHING
    66. #define NAPI_CALL_BASE(env, theCall, retVal)                                                                           \
    67.    do {                                                                                                               \
    68.        if ((theCall) != 0) {                                                                                          \
    69.            return retVal;                                                                                             \
    70.        }                                                                                                              \
    71.    } while (0)
    72. #define NAPI_CALL(env, theCall) NAPI_CALL_BASE(env, theCall, nullptr)
    73. #define NAPI_CALL_RETURN_VOID(env, theCall) NAPI_CALL_BASE(env, theCall, NAPI_RETVAL_NOTHING)
    74. extern bool GetMatFromRawFile(napi_env env, napi_value jsResMgr, const std::string &rawfileDir,
    75.                              const std::string &fileName, cv::Mat &srcImage);
    76. extern bool cvtMat2Pixel(cv::InputArray _src, cv::OutputArray &_dst, int code);
    77. extern napi_value NapiGetNull(napi_env env);
    78. extern uint32_t GetMatDataBuffSize(const cv::Mat &mat);
    79. extern bool CreateArrayBuffer(napi_env env, uint8_t *src, size_t srcLen, napi_value *res);
    80. extern napi_value NapiGetUndefined(napi_env env);
    81. extern napi_value GetCallbackErrorValue(napi_env env, int32_t errCode);
    82. extern napi_value NapiGetBoolean(napi_env env, const bool &isValue);
    83. extern uint32_t GetMatDataBuffSize(const cv::Mat &mat);
    84. extern void SetCallback(const napi_env &env, const napi_ref &callbackIn, const int32_t &errorCode,
    85.                        const napi_value &result);
    86. extern void SetPromise(const napi_env &env, const napi_deferred &deferred, const int32_t &errorCode,
    87.                       const napi_value &result);
    88. extern void ReturnCallbackPromise(const napi_env &env, const CallbackPromiseInfo &info, const napi_value &result);
    89. extern napi_value JSParaError(const napi_env &env, const napi_ref &callback);
    90. extern void PaddingCallbackPromiseInfo(const napi_env &env, const napi_ref &callback, CallbackPromiseInfo &info,
    91.                                       napi_value &promise);
    92. extern bool WrapJsPixelInfoInfo(napi_env env, cv::Mat &outMat, napi_value &result);
    93. #endif //OpencvSample_common_H
    复制代码
  • 增加灰度转换方法
    1. using namespace std;
    2. using namespace cv;
    3. static const char *TAG = "[opencv_img2Gray]";
    4. napi_value Img2Gray(napi_env env, napi_callback_info info) {
    5.    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "Img2Gray Begin");
    6.    napi_value result = NapiGetNull(env);
    7.    size_t argc = 3;
    8.    napi_value argv[3] = {nullptr};
    9.    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
    10.    size_t strSize;
    11.    char strBuf[256];
    12.    napi_get_value_string_utf8(env, argv[1], strBuf, sizeof(strBuf), &strSize);
    13.    std::string fileDir(strBuf, strSize);
    14.    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "fileDir:%{public}s", fileDir.c_str());
    15.    napi_get_value_string_utf8(env, argv[2], strBuf, sizeof(strBuf), &strSize);
    16.    std::string fileName(strBuf, strSize);
    17.    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "fileName:%{public}s", fileName.c_str());
    18.    Mat srcImage;
    19.    if (!GetMatFromRawFile(env, argv[0], fileDir, fileName, srcImage)) {
    20.        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "Get Mat from rawfile failed!.");
    21.        return result;
    22.    }
    23.    Mat srcGray;
    24.    cvtColor(srcImage, srcGray, COLOR_RGB2GRAY);
    25.    // 將图像转换为pixelMap格式
    26.    Mat outMat;
    27.    cvtMat2Pixel(srcGray, outMat, RGBA_8888);
    28.    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "outMat size: %{public}d, cols:%{public}d, rows:%{public}d",
    29.                 outMat.total(), outMat.cols, outMat.rows);
    30.    napi_create_object(env, &result);
    31.    bool retVal = WrapJsPixelInfoInfo(env, outMat, result);
    32.    if (!retVal) {
    33.        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "WrapJsInfo failed!.");
    34.    }
    35.    return result;
    36. }
    复制代码
  • 导出 //hello.cpp
    1. EXTERN_C_START
    2. static napi_value Init(napi_env env, napi_value exports)
    3. {
    4.    napi_property_descriptor desc[] = {
    5.        {"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr},
    6.        {"img2Gray", nullptr, Img2Gray, nullptr, nullptr, nullptr, napi_default, nullptr}
    7.    };
    8.    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    9.    return exports;
    10. }
    11. EXTERN_C_END
    复制代码
  • 导出接口 //index.d.ts
    1. import resourceManager from '@ohos.resourceManager';
    2. export interface PixelInfo {
    3.  rows: number;
    4.  cols: number;
    5.  buffSize: number;
    6.  byteBuffer: ArrayBuffer;
    7. }
    8. export const add: (a: number, b: number) => number;
    9. export const img2Gray: (resmgr: resourceManager.ResourceManager, path: string, file: string) => PixelInfo;
    复制代码
  • 在页面添加交互 // index.ets
    1. Column() {
    2.  Image(this.isGray ? this.imagePixelMap : $rawfile('lena.jpg'))
    3.    .margin({ left: 24, right: 24 })
    4.    .objectFit(ImageFit.Contain)
    5.    .id('backBtn')
    6.   }
    7.   .width('100%')
    8.   .height('60%')
    9.   .alignItems(HorizontalAlign.Center)
    10.   .justifyContent(FlexAlign.Start)
    11.  Row() {
    12.    Button($r('app.string.image_gray'), { type: ButtonType.Capsule })
    13.      .backgroundColor(this.isGray ? Color.Gray : Color.Blue)
    14.      .margin({ left: 24 })
    15.      .width('30%')
    16.      .id('imageGray')
    17.      .enabled(this.isGray ? false : true)
    18.      .onClick(() => {
    19.        let pixelInfo: testNapi.PixelInfo = testNapi.img2Gray(getContext().resourceManager, '', 'lena.jpg');
    20.        Logger.info(TAG, `pixelInfo buffSize: ${pixelInfo.buffSize}`);
    21.        let opts: image.InitializationOptions = {
    22.          editable: true,
    23.          pixelFormat: this.pixelMapFormat,
    24.          size: { height: pixelInfo.rows, width: pixelInfo.cols }
    25.        }
    26.        image.createPixelMap(pixelInfo.byteBuffer, opts, (error, pixelmap) => {
    27.          if (error) {
    28.            Logger.error(TAG, `Failed to create pixelmap error_code ${error.code}`);
    29.          } else {
    30.            Logger.info(TAG, 'Succeeded in creating pixelmap.');
    31.            this.imagePixelMap = pixelmap;
    32.          }
    33.        })
    34.        this.isGray = true;
    35.    })
    36.    Button($r('app.string.image_recover'), { type: ButtonType.Capsule })
    37.      .backgroundColor(Color.Blue)
    38.      .width('30%')
    39.      .id('imageRecover')
    40.      .onClick(() => {
    41.        this.isGray = false;
    42.      })
    43.    }
    44.    .width('100%')
    复制代码
    展示

总结

    可以用nativec++方式导入opencv库直接开发应用,目前实现了一个简单接口,后面会实现场景应用
    目前只能做到可用,还有以下问题:

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

本帖子中包含更多资源

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

x

2

主题

1

回帖

17

积分

新手上路

积分
17
发表于 2025-3-30 13:19:36 | 显示全部楼层
这个能分享一下demo看看吗?

1

主题

2

回帖

14

积分

新手上路

积分
14
发表于 2025-3-30 13:20:20 | 显示全部楼层
lib库太大了就删了,只上传了代码,对应lib库需要从https://gitee.com/openharmony-si ... releases/tag/v4.5.5 下载

1

主题

6

回帖

17

积分

新手上路

积分
17
发表于 2025-3-30 13:20:53 | 显示全部楼层
回复 深开鸿_王石: 好的,感谢分享
[/td][/tr][/table][/td][/tr][tr][td]榜单了解详情')">有用 榜单了解详情')">无用 回复举报

[/td][/tr][/table]【1 条回复】OpencvSample.zip2024-3-7 17:48 上传
点击文件名下载附件




4.25 MB, 下载次数: 125




[/td][/tr][tr][td][/td][/tr][tr][/tr][tr][td]                                            回复举报
                    

[/td][/tr][tr][td][/td][/tr][/table]                                                <div class="ssfv" key="3" >                    <div id="post_5684" style="position: relative" class="a0a viewbox otherfloor cl" >           
<div class="viewinfo">[table][tr][td]
                 九弓子  
地板                                    发表于 2024-3-20 18:45:05


<div class="pct"><div class="pcb"><div class="t_fsz">[table][tr][td]大佬你好,最近在开发北向应用,想实现视频剪辑。
想仔细了解napi混合开发集成三方库的一些细节,您文章中的opencv是如何编译的呢?
我看到了您评论区回复的gitee链接中,有ffmpeg的三方库
https://gitee.com/openharmony-si ... ter/3rdparty/ffmpeg
这个库可以编译并应用么?
先感谢大佬啦···望回复~~

本帖子中包含更多资源

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

x

0

主题

4

回帖

10

积分

新手上路

积分
10
发表于 2025-3-30 13:21:30 | 显示全部楼层
回复 九弓子: 可以是可以,但是包起来了,直接用可以用这个https://gitee.com/openharmony-si ... r/thirdparty/FFmpeg
[/td][/tr][/table][/td][/tr][tr][td]榜单了解详情')">有用 榜单了解详情')">无用 回复举报

[/td][/tr][/table]【1 条回复】

[/td][/tr][tr][td][/td][/tr][tr][/tr][tr][td]                                            回复举报
                    

[/td][/tr][tr][td][/td][/tr][/table]                                                <div class="ssfv" key="4" >                    <div id="post_5695" style="position: relative" class="a0a viewbox otherfloor cl" >           
<div class="viewinfo">[table][tr][td]
                 ouyangzhi  
5#                                    发表于 2024-3-21 11:17:01


<div class="pct"><div class="pcb"><div class="t_fsz">[table][tr][td]target_link_libraries(entry PUBLIC
    libace_napi.z.so
    librawfile.z.so
    libhilog_ndk.z.so
    ${OPENCV_LIB_PATH}/libopencv_core.so
    opencv_imgcodecs
    opencv_imgproc
    opencv_photo
    opencv_videoio
    opencv_flann
    opencv_features2d
    opencv_calib3d
    opencv_video
    opencv_highgui
    opencv_ml
    opencv_stitching
    opencv_dnn
    opencv_objdetect
    opencv_gapi)
想请问一下 ,libopencv_core.so后面的那些如:opencv_imgcodecs,opencv_imgproc等 是引用的libs目录底下的so吗?,这种是简写吗?

本帖子中包含更多资源

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

x

0

主题

2

回帖

10

积分

新手上路

积分
10
发表于 2025-3-30 13:21:35 | 显示全部楼层
回复 ouyangzhi: 是的,偷懒了,简写的,
[/td][/tr][/table][/td][/tr][tr][td]榜单了解详情')">有用 榜单了解详情')">无用 回复举报

[/td][/tr][/table]【1 条回复】

[/td][/tr][tr][td][/td][/tr][tr][/tr][tr][td]                                            回复举报
                    

[/td][/tr][tr][td][/td][/tr][/table]                                                <div class="ssfv" key="5" >                    <div id="post_5993" style="position: relative" class="a0a viewbox otherfloor cl" >           
<div class="viewinfo">[table][tr][td]
                 golden-king  
6#                                    发表于 2024-4-1 16:09:50


<div class="pct"><div class="pcb"><div class="t_fsz">[table][tr][td]很感谢楼主分享这个opencv 应用样例开发 非常感谢
但是发现这个样例在本地无法运行 点击 按钮会报错退出应用
手机:华为畅享 60 Pro
系统:harmonyOS 4.0.0.132

需要修改两处报错才能运行,修改如下
1.common.cpp文件下
  1. //    if (!isFileExist) {//        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "Raw file directory not exist file: %{public}s.",//                     fileName.c_str());//        OH_ResourceManager_CloseRawDir(rawDir);//        OH_ResourceManager_ReleaseNativeResourceManager(mNativeResMgr);//        return false;//    }
复制代码

这段代码需要注释 实际存在lena.jpg文件但是判断条件中多了rawfile// 前缀导致isFileExist一直为false
看了上下文发现注释这段检验代码问题不大(正常需要修改校验逻辑,但是本人c++不懂只能先注释)
2.index.ets文件下
  @State isGray: Boolean = false;其中Boolean 需要修改为boolean (如果为大写Boolean 会导致isGray失去响应式)
  @State isGray: boolean = false;
希望我的这些发现对大家跑代码的时候少走一点弯路 也非常感谢楼主分享相关代码

本帖子中包含更多资源

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

x

0

主题

6

回帖

10

积分

新手上路

积分
10
发表于 2025-3-30 13:22:25 | 显示全部楼层
大佬,灰度转换和到户接口没有在你给你文件里看到

0

主题

6

回帖

10

积分

新手上路

积分
10
发表于 2025-3-30 13:23:04 | 显示全部楼层
请教下,OpenHarmony 4.0 API10运行后,点击Gray后程序挂了。是不是不支持直接调用so
错误信息。
Module name:com.example.opencvsample
Version:1.0.0
Pid:17475
Uid:20010047
Lifetime: 0.000000s
Js-Engine: ark
page: pages/Index.js
Error message: Cannot read property img2Gray of undefined
SourceCode:
                let pixelInfo: testNapi.PixelInfo = testNapi.img2Gray(getContext().resourceManager, '', 'lena.jpg');
                                                    ^
Stacktrace:
    at anonymous (entry/src/main/ets/pages/Index.ets:53:51)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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