如何将 OpenCV Mat 转换为 Halide Image 并返回?

How to convert OpenCV Mat to Halide Image and back?

我的目标是使用 OpenCV 功能(例如 NL 意味着去噪)来增强我现有的图像处理管道(用 Halide 编写)。 OpenCV 函数将无法使用 Halide 的调度功能,因此我的计划是在每个 OpenCV 阶段之前实现每个 Halide Func。剩下的问题是如何最好地从 Halide Image(Func 实现的结果)转换为 OpenCV Mat(作为 OpenCV 函数的输入)以及完成后如何从 OpenCV Mat 转换为 Halide Image。我的 Halide Images 是 float 类型的,有 3 个通道。

一个明显的解决方案是编写将数据从一种数据类型复制到另一种数据类型的函数,但这让我觉得很浪费。复制数据不仅会花费宝贵的时间,而且还会浪费内存,因为图像将被存储为两种不同的数据类型。有没有办法使用指针或数据缓冲区以新格式简单地重新包装图像数据?希望这个过程是可逆的,这样我就可以从 Halide 转到 OpenCV,然后在 OpenCV 函数完成后回到 Halide。

是的,您可以避免复制数据。我看到了两种可能的方法:要么自己分配内存,然后在 OpenCV Mat 实例和 Halide buffer_t 结构中引用该内存;或者让 OpenCV 的 Mat class 分配内存并在 buffer_t 结构中引用该内存。

对于第一种方法,您可以使用带有数据指针的 Mat 构造函数:

float* data = new float[3 * width * height];
cv::Mat image(height, width, CV_32FC3, data, AUTO_STEP);

对于第二种方法,您可以使用通常的构造函数或Mat::create方法:

cv::Mat image(height, width, CV_32FC3);

无论哪种方式,您都可以使用类似于以下代码的代码将内存包装在 Halide buffer_t 结构中:

buffer_t buffer;
memset(&buffer, 0, sizeof(buffer));
buffer.host = image.data;
buffer.elem_size = image.elemSize1();
buffer.extent[0] = image.cols;
buffer.extent[1] = image.rows;
buffer.extent[2] = image.channels();
buffer.stride[0] = image.step1(1);
buffer.stride[1] = image.step1(0);
buffer.stride[2] = 1;

现在您应该能够使用 OpenCV 和 Halide 函数在同一内存上进行操作了。

buffer_t 现在不见了,所以我应该更新这个答案。当前制作包装 OpenCV 垫(使用交错存储布局)的缓冲区的方法是:

Halide::Runtime::Buffer<float>::make_interleaved(image.data, image.cols, image.rows, image.channels());

如果OpenCV矩阵在行之间有填充,则较长的形式是:

halide_dimension_t shape[3] = {{0, image.cols, image.step1(1)}, 
                               {0, image.rows, image.step1(0)},
                               {0, image.channels(), 1}};
Halide::Runtime::Buffer<float> buffer(image.data, 3, shape);

a halide_dimension_t是最小坐标,范围,然后是那个维度的stride/step。