文档管理中心
FAQ媒体开发拍照和图片图片处理(Image)如何将C++侧接收的PixelMap转换成cv::mat格式

如何将C++侧接收的PixelMap转换成cv::mat格式

本文导读

解决措施

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

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

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

示例代码如下:

ArkTS侧传递参数:

收起
自动换行
深色代码主题
复制
  1. import cPixelMapToMat from 'libcpixelmaptomat.so';
  2. import { BusinessError } from '@kit.BasicServicesKit';
  3. import { image } from '@kit.ImageKit';
  4. @Entry
  5. @Component
  6. struct Index {
  7. @State pixelMap: image.PixelMap | undefined = undefined
  8. async arrayBufferToMat() {
  9. if (this.pixelMap == undefined || this.pixelMap){
  10. let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
  11. let resourceManager = context.resourceManager
  12. let imageArray = await resourceManager.getMediaContent($r('app.media.sample10'));
  13. let pixelBuffer = new Uint8Array(imageArray).buffer as Object as ArrayBuffer
  14. console.info("pixelBuffer length: " + pixelBuffer.byteLength);
  15. let imageResource = image.createImageSource(pixelBuffer);
  16. let opts: image.DecodingOptions = {
  17. editable: true,
  18. desiredPixelFormat: image.PixelMapFormat.RGBA_8888
  19. }
  20. this.pixelMap = await imageResource.createPixelMap(opts);
  21. }
  22. const readBuffer: ArrayBuffer = new ArrayBuffer(this.pixelMap.getPixelBytesNumber()); // Obtain the array buffer of the pixelmap
  23. console.info("readBuffer length: " + readBuffer.byteLength);
  24. this.pixelMap.readPixelsToBuffer(readBuffer).then(() => {
  25. console.info("No Error!")
  26. }).catch((err: BusinessError) => {
  27. console.error("Error! " + err.message)
  28. })
  29. const dir = getContext(this).filesDir;
  30. console.info('save path: ' + dir);
  31. cPixelMapToMat.arrayBufferToMat(this.pixelMap, readBuffer, dir);
  32. }
  33. async accessToMat(){
  34. if (this.pixelMap == undefined || this.pixelMap) {
  35. let resourceManager = getContext(this).resourceManager
  36. let imageArray = await resourceManager.getMediaContent($r('app.media.sample14'));
  37. let pixelBuffer = new Uint8Array(imageArray).buffer as Object as ArrayBuffer
  38. console.info("pixelBuffer length: " + pixelBuffer.byteLength);
  39. let imageResource = image.createImageSource(pixelBuffer);
  40. let opts: image.DecodingOptions = {
  41. editable: true,
  42. desiredPixelFormat: image.PixelMapFormat.RGBA_8888
  43. }
  44. this.pixelMap = await imageResource.createPixelMap(opts);
  45. }
  46. const dir = getContext(this).filesDir;
  47. console.info('save path: ' + dir);
  48. cPixelMapToMat.accessToMat(this.pixelMap, dir);
  49. }
  50. build() {
  51. Row() {
  52. Column() {
  53. Image(this.pixelMap)
  54. .width(200)
  55. .height(200)
  56. Button('ArrayBufferToMat')
  57. .onClick(() => {
  58. this.arrayBufferToMat();
  59. })
  60. Button('AccessToMat')
  61. .onClick(() => {
  62. this.accessToMat();
  63. })
  64. }
  65. .width('100%')
  66. }
  67. .height('100%')
  68. }
  69. }
  • 方案一:将arraybuffer转换成cv::mat代码如下:
    收起
    自动换行
    深色代码主题
    复制
    1. #include "napi/native_api.h"
    2. #include <multimedia/image_framework/image_mdk.h>
    3. #include <multimedia/image_framework/image_mdk_common.h>
    4. #include <multimedia/image_framework/image_pixel_map_mdk.h>
    5. #include <multimedia/image_framework/image_pixel_map_napi.h>
    6. #include "hilog/log.h"
    7. #include <opencv2/opencv.hpp>
    8. #include <bits/alltypes.h>
    9. static napi_value ArrayBufferToMat(napi_env env, napi_callback_info info) {
    10. size_t argc = 3;
    11. napi_value args[3] = {nullptr};
    12. napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    13. napi_value error;
    14. napi_create_int32(env, -1, &error);
    15. // Initialize PixelMap object data
    16. NativePixelMap *native = OH_PixelMap_InitNativePixelMap(env, args[0]);
    17. if (native == nullptr) {
    18. return error;
    19. }
    20. // Obtaining Image Information
    21. struct OhosPixelMapInfos pixelMapInfos;
    22. if (OH_PixelMap_GetImageInfo(native, &pixelMapInfos) != IMAGE_RESULT_SUCCESS) {
    23. OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "Test", "Pure : -1");
    24. return error;
    25. }
    26. // Obtains the buffer
    27. napi_value buffer = args[1];
    28. napi_valuetype valueType;
    29. napi_typeof(env, buffer, &valueType);
    30. if (valueType == napi_object) {
    31. bool isArrayBuffer = false;
    32. napi_is_arraybuffer(env, buffer, &isArrayBuffer);
    33. if (!isArrayBuffer) {
    34. napi_throw_error(env, "EINVAL", "Error");
    35. }
    36. }
    37. void *data = nullptr;
    38. size_t byteLength = 0;
    39. napi_get_arraybuffer_info(env, buffer, &data, &byteLength);
    40. int32_t *saveBuffer = (int32_t *)(data);
    41. // Convert to Mat
    42. cv::Mat originMat(pixelMapInfos.height, pixelMapInfos.width, CV_8UC4, saveBuffer);
    43. if (!originMat.data) {
    44. OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "Read Image", "Pure : -1");
    45. return error;
    46. }
    47. // openCV defaults to BGRA or BGR. If the pixelmap is not created in one of these formats, a format conversion is required
    48. cv::Mat saveMat;
    49. cv::cvtColor(originMat, saveMat, cv::COLOR_BGRA2RGBA);
    50. char pathArray[1024];
    51. size_t length;
    52. napi_get_value_string_utf8(env, args[2], pathArray, 1024, &length);
    53. std::string path(pathArray);
    54. path += "/buffer.jpg";
    55. if (!cv::imwrite(path, saveMat)) {
    56. OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "Write Image", "Pure : -1");
    57. return error;
    58. }
    59. napi_value res;
    60. napi_create_int32(env, 1, &res);
    61. return res;
    62. }
  • 方案二:使用OH_PixelMap_AccessPixels获取PixelMap的内存地址,将这个内存地址中的数据转换为cv::mat的代码如下:
    收起
    自动换行
    深色代码主题
    复制
    1. static napi_value AccessToMat(napi_env env, napi_callback_info info) {
    2. size_t argc = 2;
    3. napi_value args[2] = {nullptr};
    4. napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    5. napi_value error;
    6. napi_create_int32(env, -1, &error);
    7. NativePixelMap *native = OH_PixelMap_InitNativePixelMap(env, args[0]);
    8. if (native == nullptr) {
    9. return error;
    10. }
    11. struct OhosPixelMapInfos pixelMapInfos;
    12. if (OH_PixelMap_GetImageInfo(native, &pixelMapInfos) != IMAGE_RESULT_SUCCESS) {
    13. OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "Test", "Pure : -1");
    14. return error;
    15. }
    16. void *pixel;
    17. // Obtain the memory address of the NativePixelMap object and lock the memory
    18. OH_PixelMap_AccessPixels(native, &pixel);
    19. // Convert to Mat, pay attention to alignment, so rowSize needs to be passed in
    20. cv::Mat originMat(pixelMapInfos.height, pixelMapInfos.width, CV_8UC4, pixel, pixelMapInfos.rowSize);
    21. if (!originMat.data) {
    22. OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "Read Image", "Pure : -1");
    23. return error;
    24. }
    25. // openCV defaults to BGRA or BGR. If the pixelmap is not created in one of these formats, a format conversion is required
    26. cv::Mat saveMat;
    27. cv::cvtColor(originMat, saveMat, cv::COLOR_BGRA2RGBA);
    28. char pathArray[1024];
    29. size_t length;
    30. napi_get_value_string_utf8(env, args[1], pathArray, 1024, &length);
    31. std::string path(pathArray);
    32. path += "/access.jpg";
    33. if (!cv::imwrite(path, saveMat)) {
    34. OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "Write Image", "Pure : -1");
    35. return error;
    36. }
    37. napi_value res;
    38. napi_create_int32(env, 1, &res);
    39. return res;
    40. }

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

在 FAQ 中进行搜索
请输入您想要搜索的关键词