HarmonyOS的 NDK 中的 opencv cv::mat 格式数据转换问题?

NDK 中的 opencv cv::mat 格式数据如何转为 ArkTS 正确解析的 pixelMap 图片数据 ?

阅读 753
avatarAI BotBETA

在HarmonyOS中,将OpenCV的cv::Mat格式数据转换为ArkTS(HarmonyOS的UI框架之一,支持使用TypeScript/JS进行UI开发)能够正确解析的pixelMap图片数据,通常涉及到几个步骤:确保数据格式匹配、内存分配和拷贝。

由于ArkTS直接操作的是HarmonyOS的图形API,而不是直接操作OpenCV的cv::Mat,因此你需要先将cv::Mat数据转换为HarmonyOS能够识别的图像格式,如BitmapPixelMap。以下是一个基本的转换流程示例:

1. 确保数据类型和通道数匹配

首先,确保你的cv::Mat对象的类型(如CV_8UC4表示4通道8位无符号整型,常用于RGBA图像)与你要转换成的PixelMap兼容。PixelMap通常要求像素数据为连续的字节数组。

2. 创建HarmonyOS的PixelMap

你需要根据cv::Mat的尺寸和类型来创建一个PixelMap实例。这通常涉及到调用HarmonyOS的API来分配内存和设置像素格式。

3. 数据拷贝

cv::Mat的数据拷贝到PixelMap的像素缓冲区中。注意,如果通道顺序或数据类型不匹配,你可能需要在此步骤中进行转换。

示例代码(伪代码)

由于直接编写完整的ArkTS和NDK交互代码比较复杂,这里提供一个简化的伪代码示例来说明思路:

// 假设你有一个cv::Mat对象
cv::Mat cvMat = ...; // 假设这是你的OpenCV图像

// 转换为PixelMap(伪代码)
// 注意:以下代码需要根据你的实际环境进行调整
PixelMap* pixelMap = new PixelMap();

// 设置PixelMap的大小和格式
// 例如,如果cvMat是RGBA格式,你可能需要设置PixelMap的pixelFormat为PixelFormat::RGBA_8888
pixelMap->SetSize(cvMat.cols, cvMat.rows);
// 设置PixelFormat等(根据cvMat的类型调整)

// 分配PixelMap的像素缓冲区(具体API根据HarmonyOS版本而定)
// 假设有一个SetPixelBytes方法来设置像素数据
uint8_t* buffer = new uint8_t[cvMat.total() * cvMat.elemSize()];
memcpy(buffer, cvMat.data, cvMat.total() * cvMat.elemSize());
pixelMap->SetPixelBytes(buffer, cvMat.total() * cvMat.elemSize());

// 注意:上面的SetPixelBytes方法是伪造的,你需要根据HarmonyOS的API来实现

// 现在,pixelMap包含了cvMat的图像数据,可以在ArkTS中使用
// ... 将pixelMap传递给ArkTS的UI组件 ...

// 清理资源
delete[] buffer;
delete pixelMap;

注意

  • 上面的代码是一个高度简化的示例,实际实现时需要考虑内存管理、错误处理以及HarmonyOS和OpenCV的API细节。
  • 确保在ArkTS侧正确处理和释放传入的PixelMap资源,避免内存泄漏。
  • 如果cv::MatPixelMap的像素格式或通道顺序不匹配,你需要在拷贝数据之前进行转换。
1 个回答

napi接受及转换,可以参考NDK开发部分 :https://developer.huawei.com/consumer/cn/doc/harmonyos-guides...,JS和C++相互调用ArrayBuffer
具体实现如下Native侧接受传入的 ArkTS Array。

static napi_value TS2NAPI(napi_env env, napi_callback_info info) 
{ 
  // 获取TS层传来的参数 
  size_t argc = 1; 
  napi_value args; 
  napi_get_cb_info(env, info, &argc, &args, NULL, NULL); 
  napi_value input_array = args; 
  // 获取传入数组typedarray生成input_buffer 
  napi_typedarray_type type;// 数据类型 
  napi_value input_buffer; 
  size_t byte_offset;//数据偏移 
  size_t i, length;//数据字节大小 
  napi_get_typedarray_info(env, input_array, &type, &length, NULL, &input_buffer, &byte_offset); 
  // 获取数组数据z 
  void *data; 
  size_t byte_length; 
  napi_get_arraybuffer_info(env, input_buffer, &data, &byte_length); 
  if (type == napi_int32_array) { 
    int32_t *data_bytes = (int32_t *)(data); 
    for (i = 0; i < length/sizeof(int32_t); i++) { 
      OH_LOG_INFO(LOG_APP, "TS2NAPI: C++ %{public}d", *((int32_t *)(data_bytes) + i)); 
    } 
  } 
  return NULL; 
} 
TS侧 接收 Native侧返回的Array 
// NAPI层 array 传到TS层 
static napi_value NAPI2TS(napi_env env, napi_callback_info info) 
{ 
  // 数据个数 
  int num = 10; 
  // 创建output_buffer 
  napi_value output_buffer; 
  void *output_ptr = NULL; 
  napi_create_arraybuffer(env, num * sizeof(int32_t), &output_ptr, &output_buffer); 
  // output_array 
  napi_value output_array; 
  napi_create_typedarray(env, napi_int32_array, num, output_buffer, 0, &output_array); 
  // 给output_ptr、output_buffer赋值 
  int32_t * output_bytes = (int32_t *)output_ptr; 
  for (int32_t i = 0; i < num; i++) { 
  output_bytes[i] = i; 
} 
  for (int32_t i = 0; i < num; i++) { 
  OH_LOG_INFO(LOG_APP, "NAPI2TS: C++ %{public}d", *((int32_t *)(output_ptr) + i)); 
} 
  return output_array; 
}

TS 获取 Native 层回调的Object 值Native 层创建Object,通过ArkTS 传入的callback,并将Object回调给ArkTS具体实现如下:

let da:Record<string, number> = testNapi.CallbackToArkTs((value:object)=> 
{ 
  let data:Record<string, number> = value as Record<string, number>; 
  console.info("修改前type: " + data["type"].toString()) 
  console.info(JSON.stringify(value)) 
  data["type"] += 10 
  return value; 
}); 
console.info(JSON.stringify(da))

C++ 侧接收ArkTS 传入的 callback。

static bool Napi_AddPropertyInt32(napi_env env, napi_value obj, const char *key, int32_t value) { 
  napi_value key_napi = nullptr; 
  napi_status status = napi_create_string_utf8(env, key, NAPI_AUTO_LENGTH, &key_napi); 
  napi_value value_napi = nullptr; 
  status = napi_create_int32(env, value, &value_napi); 
  status = napi_set_property(env, obj, key_napi, value_napi); 
  return true; 
} 
static napi_value CallbackToArkTs(napi_env env, napi_callback_info info) { 
  // 获取ArkTS参数 
  size_t argc = 1; 
  napi_value js_cb = nullptr; 
  napi_get_cb_info(env, info, &argc, &js_cb, nullptr, nullptr); 
  // native回调到ts层的object 
  napi_value argv = nullptr; 
  napi_create_object(env, &argv); 
  Napi_AddPropertyInt32(env, argv, "type", 1); 
  Napi_AddPropertyInt32(env, argv, "index", 2); 
  // native回调到ts层 
  napi_value result = nullptr; 
  napi_call_function(env, NULL, js_cb, 1, &argv, &result); 
  // 获取ts修改后的object 
  napi_value typeNumber = nullptr; 
  napi_get_named_property(env, result, "type", &typeNumber); 
  int32_t number; 
  napi_get_value_int32(env, typeNumber, &number); 
  OH_LOG_INFO(LOG_APP, "修改后type: %{public}d", number); 
  // 返回修改后的object 
  return result; 
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题