鸿蒙开发-如何将C++侧接收的PixelMap转换成cv::mat格式

目录

  • [1. 解决措施](#1. 解决措施)
  • [2. 示例代码](#2. 示例代码)
  • [3. 将arraybuffer转换成cv::mat](#3. 将arraybuffer转换成cv::mat)
  • [4. 使用OH_PixelMap_AccessPixels获取PixelMap的内存地址,将这个内存地址中的数据转换为cv::mat的](#4. 使用OH_PixelMap_AccessPixels获取PixelMap的内存地址,将这个内存地址中的数据转换为cv::mat的)

1. 解决措施

将PixelMap转换成cv::mat有两种方法:

  • 将PixelMap的arraybuffer转换成cv::mat。
  • 使用OH_PixelMap_AccessPixels获取PixelMap的内存地址,将这个内存地址中的数据转换为cv::mat。

上述两种方法都需确保PixelMap的格式与OpenCV中Mat的格式一致,否则会导致色彩偏差。

2. 示例代码

javascript 复制代码
import cPixelMapToMat from 'libcpixelmaptomat.so';
import { BusinessError } from '@kit.BasicServicesKit';
import { image } from '@kit.ImageKit';

@Entry
@Component
struct Index {
  @State pixelMap: image.PixelMap | undefined = undefined

  async arrayBufferToMat() {
    if (this.pixelMap == undefined || this.pixelMap){
      let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
      let resourceManager = context.resourceManager
      let imageArray = await resourceManager.getMediaContent($r('app.media.sample10'));
      let pixelBuffer = new Uint8Array(imageArray).buffer as Object as ArrayBuffer
      console.info("pixelBuffer length: " + pixelBuffer.byteLength);
      let imageResource = image.createImageSource(pixelBuffer);
      let opts: image.DecodingOptions = {
        editable: true,
        desiredPixelFormat: image.PixelMapFormat.RGBA_8888
      }
      this.pixelMap = await imageResource.createPixelMap(opts);
    }

    const readBuffer: ArrayBuffer = new ArrayBuffer(this.pixelMap.getPixelBytesNumber()); // Obtain the array buffer of the pixelmap
    console.info("readBuffer length: " + readBuffer.byteLength);
    this.pixelMap.readPixelsToBuffer(readBuffer).then(() => {
      console.info("No Error!")
    }).catch((err: BusinessError) => {
      console.error("Error! " + err.message)
    })
    const dir = getContext(this).filesDir;
    console.info('save path: ' + dir);
    cPixelMapToMat.arrayBufferToMat(this.pixelMap, readBuffer, dir);
  }

  async accessToMat(){
    if (this.pixelMap == undefined || this.pixelMap) {
      let resourceManager = getContext(this).resourceManager
      let imageArray = await resourceManager.getMediaContent($r('app.media.sample14'));
      let pixelBuffer = new Uint8Array(imageArray).buffer as Object as ArrayBuffer
      console.info("pixelBuffer length: " + pixelBuffer.byteLength);
      let imageResource = image.createImageSource(pixelBuffer);
      let opts: image.DecodingOptions = {
        editable: true,
        desiredPixelFormat: image.PixelMapFormat.RGBA_8888
      }
      this.pixelMap = await imageResource.createPixelMap(opts);
    }

    const dir = getContext(this).filesDir;
    console.info('save path: ' + dir);
    cPixelMapToMat.accessToMat(this.pixelMap, dir);
  }

  build() {
    Row() {
      Column() {
        Image(this.pixelMap)
          .width(200)
          .height(200)
        Button('ArrayBufferToMat')
          .onClick(() => {
            this.arrayBufferToMat();
          })

        Button('AccessToMat')
          .onClick(() => {
            this.accessToMat();
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

3. 将arraybuffer转换成cv::mat

cpp 复制代码
#include "napi/native_api.h"
#include <multimedia/image_framework/image_mdk.h>
#include <multimedia/image_framework/image_mdk_common.h>
#include <multimedia/image_framework/image_pixel_map_mdk.h>
#include <multimedia/image_framework/image_pixel_map_napi.h>
#include "hilog/log.h"
#include <opencv2/opencv.hpp>
#include <bits/alltypes.h>

static napi_value ArrayBufferToMat(napi_env env, napi_callback_info info) {
    size_t argc = 3;
    napi_value args[3] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    napi_value error;
    napi_create_int32(env, -1, &error);

    // Initialize PixelMap object data 
    NativePixelMap *native = OH_PixelMap_InitNativePixelMap(env, args[0]);
    if (native == nullptr) {
        return error;
    }
    // Obtaining Image Information
    struct OhosPixelMapInfos pixelMapInfos;
    if (OH_PixelMap_GetImageInfo(native, &pixelMapInfos) != IMAGE_RESULT_SUCCESS) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "Test", "Pure : -1");
        return error;
    }
    // Obtains the buffer
    napi_value buffer = args[1];
    napi_valuetype valueType;
    napi_typeof(env, buffer, &valueType);
    if (valueType == napi_object) {
        bool isArrayBuffer = false;
        napi_is_arraybuffer(env, buffer, &isArrayBuffer);
        if (!isArrayBuffer) {
            napi_throw_error(env, "EINVAL", "Error");
        }
    }

    void *data = nullptr;
    size_t byteLength = 0;
    napi_get_arraybuffer_info(env, buffer, &data, &byteLength);
    int32_t *saveBuffer = (int32_t *)(data);

    // Convert to Mat
    cv::Mat originMat(pixelMapInfos.height, pixelMapInfos.width, CV_8UC4, saveBuffer);
    if (!originMat.data) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "Read Image", "Pure : -1");
        return error;
    }

    // openCV defaults to BGRA or BGR. If the pixelmap is not created in one of these formats, a format conversion is required
    cv::Mat saveMat;
    cv::cvtColor(originMat, saveMat, cv::COLOR_BGRA2RGBA);
    char pathArray[1024];
    size_t length;
    napi_get_value_string_utf8(env, args[2], pathArray, 1024, &length);
    std::string path(pathArray);
    path += "/buffer.jpg";
    if (!cv::imwrite(path, saveMat)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "Write Image", "Pure : -1");
        return error;
    }

    napi_value res;
    napi_create_int32(env, 1, &res);
    return res;
}

4. 使用OH_PixelMap_AccessPixels获取PixelMap的内存地址,将这个内存地址中的数据转换为cv::mat的

cpp 复制代码
static napi_value AccessToMat(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value args[2] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    napi_value error;
    napi_create_int32(env, -1, &error);

    NativePixelMap *native = OH_PixelMap_InitNativePixelMap(env, args[0]);
    if (native == nullptr) {
        return error;
    }
    struct OhosPixelMapInfos pixelMapInfos;
    if (OH_PixelMap_GetImageInfo(native, &pixelMapInfos) != IMAGE_RESULT_SUCCESS) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "Test", "Pure : -1");
        return error;
    }

    void *pixel;
    // Obtain the memory address of the NativePixelMap object and lock the memory
    OH_PixelMap_AccessPixels(native, &pixel);

    // Convert to Mat, pay attention to alignment, so rowSize needs to be passed in
    cv::Mat originMat(pixelMapInfos.height, pixelMapInfos.width, CV_8UC4, pixel, pixelMapInfos.rowSize);
    if (!originMat.data) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "Read Image", "Pure : -1");
        return error;
    }

    // openCV defaults to BGRA or BGR. If the pixelmap is not created in one of these formats, a format conversion is required
    cv::Mat saveMat;
    cv::cvtColor(originMat, saveMat, cv::COLOR_BGRA2RGBA);
    char pathArray[1024];
    size_t length;
    napi_get_value_string_utf8(env, args[1], pathArray, 1024, &length);
    std::string path(pathArray);
    path += "/access.jpg";
    if (!cv::imwrite(path, saveMat)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "Write Image", "Pure : -1");
        return error;
    }

    napi_value res;
    napi_create_int32(env, 1, &res);
    return res;
}

在HarmonyOS开发中,针对图库支持硬解码的操作,需要指定图像的内存空间大小。OH_PixelMap_AccessPixels() 获取图片的内存地址并锁定该内存。实际图像的大小需要按 lineStride 对齐。因此,在构造成 mat 时,需指定 lineStride 对齐。lineStride即 rowSize。可以使用 OH_GetImageInfo 获取 imageInfo,其中包含 width、height 和 rowSize 等信息。

相关推荐
txinyu的博客1 分钟前
HTTP服务实现用户级窗口限流
开发语言·c++·分布式·网络协议·http
代码村新手1 分钟前
C++-类和对象(上)
开发语言·c++
txinyu的博客12 分钟前
map和unordered_map的性能对比
开发语言·数据结构·c++·算法·哈希算法·散列表
mjhcsp37 分钟前
C++ 后缀数组(SA):原理、实现与应用全解析
java·开发语言·c++·后缀数组sa
hui函数38 分钟前
如何解决 pip install 编译报错 ‘cl.exe’ not found(缺少 VS C++ 工具集)问题
开发语言·c++·pip
小雨下雨的雨38 分钟前
Flutter 框架跨平台鸿蒙开发 —— Stack 控件之三维层叠艺术
flutter·华为·harmonyos
晚风(●•σ )1 小时前
【华为 ICT & HCIA & eNSP 习题汇总】——题目集28
网络·计算机网络·华为·路由器·ensp·交换机
码农小韩1 小时前
基于Linux的C++学习——循环
linux·c语言·开发语言·c++·算法
消失的旧时光-19431 小时前
C++ 命名空间 namespace 讲透:从 std:: 到工程实践
开发语言·c++
程序员Jared1 小时前
C++11—thread库
c++·thread