【发布时间】:2022-06-22 05:53:04
【问题描述】:
我正在做一个项目,我想使用 C++ OpenCV 处理我的图像。
为简单起见,我只想将Uint8List 转换为cv::Mat 并返回。
按照this 教程,我设法制作了一个不会使应用程序崩溃的管道。具体来说:
- 我在
.cpp中创建了一个函数,它接收指向我的Uint8List、rawBytes的指针,并将其编码为.jpg:
int encodeIm(int h, int w, uchar *rawBytes, uchar **encodedOutput) {
cv::Mat img = cv::Mat(h, w, CV_8UC3, rawBytes); //CV_8UC3
vector<uchar> buf;
cv:imencode(".jpg", img, buf); // save output into buf. Note that Dart Image.memory can process either .png or .jpg, which is why we're doing this encoding
*encodedOutput = (unsigned char *) malloc(buf.size());
for (int i=0; i < buf.size(); i++)
(*encodedOutput)[i] = buf[i];
return (int) buf.size();
}
- 然后我在
.dart中编写了一个函数,调用我的c++encodeIm(int h, int w, uchar *rawBytes, uchar **encodedOutput):
//allocate memory heap for the image
Pointer<Uint8> imgPtr = malloc.allocate(imgBytes.lengthInBytes);
//allocate just 8 bytes to store a pointer that will be malloced in C++ that points to our variably sized encoded image
Pointer<Pointer<Uint8>> encodedImgPtr = malloc.allocate(8);
//copy the image data into the memory heap we just allocated
imgPtr.asTypedList(imgBytes.length).setAll(0, imgBytes);
//c++ image processing
//image in memory heap -> processing... -> processed image in memory heap
int encodedImgLen = _encodeIm(height, width, imgPtr, encodedImgPtr);
//
//retrieve the image data from the memory heap
Pointer<Uint8> cppPointer = encodedImgPtr.elementAt(0).value;
Uint8List encodedImBytes = cppPointer.asTypedList(encodedImgLen);
//myImg = Image.memory(encodedImBytes);
return encodedImBytes;
//free memory heap
//malloc.free(imgPtr);
//malloc.free(cppPointer);
//malloc.free(encodedImgPtr); // always frees 8 bytes
}
- 然后我通过以下方式将 c++ 与 dart 链接起来:
final DynamicLibrary nativeLib = Platform.isAndroid
? DynamicLibrary.open("libnative_opencv.so")
: DynamicLibrary.process();
final int Function(int height, int width, Pointer<Uint8> bytes, Pointer<Pointer<Uint8>> encodedOutput)
_encodeIm = nativeLib
.lookup<NativeFunction<Int32 Function(Int32 height, Int32 width,
Pointer<Uint8> bytes, Pointer<Pointer<Uint8>> encodedOutput)>>('encodeIm').asFunction();
- 最后我通过以下方式在 Flutter 中显示结果:
Image.memory(...)
现在,管道没有崩溃,这意味着我还没有完全搞砸内存处理,但它也没有返回原始图像,这意味着我确实在某个地方搞砸了。
原图:
管道输出:
【问题讨论】:
-
你从哪里得到
imgBytes?我敢打赌它不是 8 位无符号 3 通道。 -
@RichardHeap 这是我使用
(await rootBundle .load('assets/images/tmp.jpeg')).buffer.asUint8List()从资产加载的图像 -
如果是 jpeg,你为什么要告诉 Mat 是 8UC3?
cv::Mat(h, w, CV_8UC3, rawBytes); //CV_8UC3 -
我的意思是,
rawBytes参数和imgBytes变量是 Uint8List,但是这个 Uint8List 我从存储在我的资产文件夹中的.jpeg中恢复。所以我不明白使用 8UC3 的问题,因为 Uint8List 是一个 8 位无符号整数列表,而我的图像有 3 个通道 - RGB -
但是 jpeg 是压缩的,你实际上是在告诉 Mat 数据是未压缩的。
标签: c++ flutter dart opencv dart-ffi