背景
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
- 基本概念
- 构建第一个ArkTS应用
- ......
开发基础知识:https://qr21.cn/FV7h05
- 应用基础知识
- 配置文件
- 应用数据管理
- 应用安全管理
- 应用隐私保护
- 三方应用调用管控机制
- 资源分类与访问
- 学习ArkTS语言
- ......
基于ArkTS 开发:https://qr21.cn/FV7h05
- Ability开发
- UI开发
- 公共事件与通知
- 窗口管理
- 媒体
- 安全
- 网络与链接
- 电话服务
- 数据管理
- 后台任务(Background Task)管理
- 设备管理
- 设备使用信息统计
- DFX
- 国际化开发
- 折叠屏系列
- ......
鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH
鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH
1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向