将 byte[] 转换为 Emgu/OpenCV 图片

Convert a byte[] into an Emgu/OpenCV Image

我有一个表示灰度图像的字节数组,我想使用 Emgu 包装器在 C# 中与 openCV 一起使用。我想弄清楚如何在不先将其转换为 System.Drawing.Bitmap.

的情况下将其转换为 Emu.CV.Image

到目前为止,Imagethis 构造函数看起来很有希望。看起来它需要像素行、列,然后是包含我的数据的数组来构建图像。但是,它希望它们采用一种奇怪的格式,我正在为如何正确构造 TDepth[,,] data 参数而苦苦挣扎。

这是我目前的情况:

// This gets initialized in the constructor and filled in with greyscale image data elsewhere in the code:
byte[] depthPixelData

// Once my depthPixelData is processed, I'm trying to convert it to an Image and this is where I'm having issues
Image<Gray, Byte> depthImage = new Image<Gray, Byte>([depthBitmap.PixelHeight, depthBitmap.pixelWidth, depthPixelData]);

Visual studio 让我明白,仅仅传入一个数组并不会削减它,但我不知道如何用我的像素数据构造必要的 TDepth[,,] 对象传递给 Image 构造函数。

这段代码需要 运行 ~30fps,所以我试图在对象创建、内存分配等方面尽可能高效。

就我个人而言,我会按照这些思路做一些事情:

byte[] depthPixelData = ...;

int imageWidth = ...;
int imageHeight = ...;
int channelCount = 1; // grayscale

byte[,,] depthPixelData3d = new byte[imageHeight, imageWidth, channelCount];

for(int line = 0, offset = 0; line < imageHeight; line++)
    for(int column = 0; column < imageWidth; column++, offset++)
        depthPixelData3d[line, column, 0] = depthPixelData[offset];

出于性能方面的考虑,您可能希望:

  • 把它变成一个不安全的块(应该是微不足道的)
  • 只分配你的字节[]一次(除非你的图像大小改变)

Emu.Cv.Image class 定义为

public class Image<TColor, TDepth> : CvArray<TDepth>, ...

TColor
此图像的颜色类型(Gray、Bgr、Bgra、Hsv、Hls、Lab、Luv、Xyz、Ycc、Rgb 或 Rbga) 深度
此图像的深度(Byte、SByte、Single、double、UInt16、Int16 或 Int32)

这个通用参数 TDepth 具有误导性。在您的情况下 TDepth[,,] 表示 byte[,,]

要将一个数组复制到另一个数组,您可以使用 Buffer.BlockCopy:

byte[, ,] imageData = new byte[depthBitmap.PixelHeight , depthBitmap.PixelWidth , colorChannels];
Buffer.BlockCopy(depthPixelData, 0, imageData, 0, imageData.Length);
Image<Gray, Byte> depthImage = new Image<Gray, Byte>(imageData);

另一种解决方案是仅使用图像的宽度和高度来创建 EMGU.CV.Image。然后你可以这样做:

byte[] depthPixelData = new byte[640*480]; // your data

Image<Gray, byte> depthImage = new Image<Gray, byte>(640, 480);

depthImage.Bytes = depthPixelData;

只要宽高正确,宽度能被4整除(Emgu.CV.Image的实现方式)应该没有问题。如果您不需要保存对象,您甚至可以重用 Emgu.CV.Image 对象并在每一帧更改字节。