opencv中的图片是cv::Mat类型的,HarmonyOS 相机拍摄得到的图像帧能否转换为cv::Mat类型?

通过HarmonyOS 系统相机API采集到的是ArrayBuffer类型的图片数据流,现在使用opencv库,需要转为是cv::Mat类型的图片,请问该如何转换,目前是在Napi中方法需要用到cv::Mat类型的参数。

HarmonyOS
2024-12-27 17:33:54
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
zxjiu

情景描述为图片缓冲流arrayBuffer传入Native,然后将arrayBuffer转换成需要cvMat格式。

ArrayBuffer是二进制数组,是对固定长度的连续内存空间的引用,在将ArrayBuffer转换成OpenCV的Mat对象时,可以将ArrayBuffer作为作为内存数据传给OpenCV,如构造函数Mat::Mat(Size size, int type, void* data, size_t step=AUTO_STEP)中,可以将ArrayBuffer作为data使用

在HarmonyOS 开发中,针对图库支持硬解码的操作, 需要指定图像的内存空间大小,原本OH_AccessPixels(env, args[0], &imagePixels)获取到图片的内存地址并锁定该内存,但是实际图像的大小需要lineStride对齐,所以需要补充这部分信息,跟上层对齐,可以用OH_GetImageInfo获取到imageInfo,其中包含width,height,rowSize等信息:

OHOS: :Media: :OhosPixelMapInfo bitmap;
if (OH_GetImageInfo(env, args[0], &bitmap) < 0 ) {
return napiErrorCode;
}

int width = bitmap.width;
int height = bitmap.height;
int rowSize = bitmap.rowSize;

其中rowSize被定义为lineStride,就是我们需要的信息,具体到业务代码,我们在使用OH_AccessPixels获取到图像对象内存地址后,转为opencv::Mat进行数组运算,由于图库硬解码限制line_stride必须为256的倍数,如果图像的宽*4不是256的整数倍数就会出现上述读取错误的问题,

需要补充lineStride,从而避免mat数据用到auto_stride补齐

ImageInfo Bitmap2Mat(OHOS: : Media: :OhosPixelMapinfo & bitmap, void *imagePixels, int lineStride)
{
  // convert bitmap to opencv mat
  timeval tvBegin;
  BenchStart( &: tvBegin);
  cv: : Mat src(rows: bitmap.height, cols: bitmap.width, type: CV_8UC4, data: imagePixels, step: lineStride) ;
  cv: : Mat dst(rows: bitmap.height, cols: bitmap.width, type: CV_8UC3) ;

  cv: : cvtColor(src, dst, code: CV_RGBA2RGB);
  BenchEnd(&: tvBegin, comment: "cvtColor time");
  return ImageInfo(img: dst, wid: bitmap.width, bitmap.height);
}

提供pixemap的获取内存地址的接口,不负责维护构造其他数据结构.对应的参考资料:

napi接受及转换,可以参考NDK开发部分

https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/napi-data-types-interfaces-V5

arraybuffer、object类型的接收和返回,参考demo:

arraybuffer:

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

object:TS 获取 Native 层回调的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;
}
分享
微博
QQ
微信
回复
2024-12-27 18:49:00
相关问题
OH_ImageNative转为cv::Mat
437浏览 • 1回复 待解决
HarmonyOS OH_ImageNative *image转为cv ::mat
128浏览 • 1回复 待解决
HarmonyOS getParamByName结果类型转换
215浏览 • 1回复 待解决
HarmonyOS Long类型和number相互转换
264浏览 • 1回复 待解决
HarmonyOS ArkTS类型转换问题
1092浏览 • 1回复 待解决