目录
- 1. 解决措施
- 2. 示例代码
- 3. 将arraybuffer转换成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. 示例代码
importcPixelMapToMatfrom'libcpixelmaptomat.so';import{BusinessError}from'@kit.BasicServicesKit';import{image}from'@kit.ImageKit';@Entry @Component struct Index{@State pixelMap:image.PixelMap|undefined=undefinedasyncarrayBufferToMat(){if(this.pixelMap==undefined||this.pixelMap){letcontext=this.getUIContext().getHostContext()ascommon.UIAbilityContext;letresourceManager=context.resourceManagerletimageArray=awaitresourceManager.getMediaContent($r('app.media.sample10'));letpixelBuffer=newUint8Array(imageArray).bufferasObjectasArrayBuffer console.info("pixelBuffer length: "+pixelBuffer.byteLength);letimageResource=image.createImageSource(pixelBuffer);letopts:image.DecodingOptions={editable:true,desiredPixelFormat:image.PixelMapFormat.RGBA_8888}this.pixelMap=awaitimageResource.createPixelMap(opts);}constreadBuffer:ArrayBuffer=newArrayBuffer(this.pixelMap.getPixelBytesNumber());// Obtain the array buffer of the pixelmapconsole.info("readBuffer length: "+readBuffer.byteLength);this.pixelMap.readPixelsToBuffer(readBuffer).then(()=>{console.info("No Error!")}).catch((err:BusinessError)=>{console.error("Error! "+err.message)})constdir=getContext(this).filesDir;console.info('save path: '+dir);cPixelMapToMat.arrayBufferToMat(this.pixelMap,readBuffer,dir);}asyncaccessToMat(){if(this.pixelMap==undefined||this.pixelMap){letresourceManager=getContext(this).resourceManagerletimageArray=awaitresourceManager.getMediaContent($r('app.media.sample14'));letpixelBuffer=newUint8Array(imageArray).bufferasObjectasArrayBuffer console.info("pixelBuffer length: "+pixelBuffer.byteLength);letimageResource=image.createImageSource(pixelBuffer);letopts:image.DecodingOptions={editable:true,desiredPixelFormat:image.PixelMapFormat.RGBA_8888}this.pixelMap=awaitimageResource.createPixelMap(opts);}constdir=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
#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>staticnapi_valueArrayBufferToMat(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 dataNativePixelMap*native=OH_PixelMap_InitNativePixelMap(env,args[0]);if(native==nullptr){returnerror;}// Obtaining Image InformationstructOhosPixelMapInfospixelMapInfos;if(OH_PixelMap_GetImageInfo(native,&pixelMapInfos)!=IMAGE_RESULT_SUCCESS){OH_LOG_Print(LOG_APP,LOG_ERROR,0xFF00,"Test","Pure : -1");returnerror;}// Obtains the buffernapi_value buffer=args[1];napi_valuetype valueType;napi_typeof(env,buffer,&valueType);if(valueType==napi_object){boolisArrayBuffer=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 Matcv::MatoriginMat(pixelMapInfos.height,pixelMapInfos.width,CV_8UC4,saveBuffer);if(!originMat.data){OH_LOG_Print(LOG_APP,LOG_ERROR,0xFF00,"Read Image","Pure : -1");returnerror;}// openCV defaults to BGRA or BGR. If the pixelmap is not created in one of these formats, a format conversion is requiredcv::Mat saveMat;cv::cvtColor(originMat,saveMat,cv::COLOR_BGRA2RGBA);charpathArray[1024];size_t length;napi_get_value_string_utf8(env,args[2],pathArray,1024,&length);std::stringpath(pathArray);path+="/buffer.jpg";if(!cv::imwrite(path,saveMat)){OH_LOG_Print(LOG_APP,LOG_ERROR,0xFF00,"Write Image","Pure : -1");returnerror;}napi_value res;napi_create_int32(env,1,&res);returnres;}4. 使用OH_PixelMap_AccessPixels获取PixelMap的内存地址,将这个内存地址中的数据转换为cv::mat的
staticnapi_valueAccessToMat(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){returnerror;}structOhosPixelMapInfospixelMapInfos;if(OH_PixelMap_GetImageInfo(native,&pixelMapInfos)!=IMAGE_RESULT_SUCCESS){OH_LOG_Print(LOG_APP,LOG_ERROR,0xFF00,"Test","Pure : -1");returnerror;}void*pixel;// Obtain the memory address of the NativePixelMap object and lock the memoryOH_PixelMap_AccessPixels(native,&pixel);// Convert to Mat, pay attention to alignment, so rowSize needs to be passed incv::MatoriginMat(pixelMapInfos.height,pixelMapInfos.width,CV_8UC4,pixel,pixelMapInfos.rowSize);if(!originMat.data){OH_LOG_Print(LOG_APP,LOG_ERROR,0xFF00,"Read Image","Pure : -1");returnerror;}// openCV defaults to BGRA or BGR. If the pixelmap is not created in one of these formats, a format conversion is requiredcv::Mat saveMat;cv::cvtColor(originMat,saveMat,cv::COLOR_BGRA2RGBA);charpathArray[1024];size_t length;napi_get_value_string_utf8(env,args[1],pathArray,1024,&length);std::stringpath(pathArray);path+="/access.jpg";if(!cv::imwrite(path,saveMat)){OH_LOG_Print(LOG_APP,LOG_ERROR,0xFF00,"Write Image","Pure : -1");returnerror;}napi_value res;napi_create_int32(env,1,&res);returnres;}在HarmonyOS开发中,针对图库支持硬解码的操作,需要指定图像的内存空间大小。OH_PixelMap_AccessPixels() 获取图片的内存地址并锁定该内存。实际图像的大小需要按 lineStride 对齐。因此,在构造成 mat 时,需指定 lineStride 对齐。lineStride即 rowSize。可以使用 OH_GetImageInfo 获取 imageInfo,其中包含 width、height 和 rowSize 等信息。