从 WriteableBitmap 转换为 Mat,然后在 window 和 CvInvoke.Imshow 中显示它?
Converting from WriteableBitmap to Mat for then showing it in a window with CvInvoke.Imshow?
我正在从 Kinect V2 相机获取红外帧。帧以 WritableBitmap 的形式出现,因此我尝试使用我编写的代码对其进行转换:
public Mat WritableBitmapToMat(WriteableBitmap writeBmp)
{
Bitmap bmp;
using (MemoryStream outStream = new MemoryStream())
{
BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create((BitmapSource)writeBmp));
enc.Save(outStream);
bmp = new Bitmap(outStream);
}
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat);
IntPtr data = bmpData.Scan0;
int step = bmpData.Stride;
Mat mat = new Mat(bmp.Height, bmp.Width, Emgu.CV.CvEnum.DepthType.Cv32F, 4, data, step);
bmp.UnlockBits(bmpData);
return mat;
}
我不知道这是否是转换的问题,但是当我尝试使用以下代码在 window 中显示图像时:
CvInvoke.Imshow("window showing a picture", infraredMat);
我最终得到一个如下所示的异常:
异常:抛出异常:'System.AccessViolationException' in Emgu.CV.World.dll ("Attempted to read or write protected memory. This is often an indication that other memory is corrupt.").
我还想提一下我正在使用 EmguCV 3.1 和 Kinect SDK 2.0
提前感谢我得到的任何帮助。
如果您查看 Kinect 2.0 SDK 中的 InfraredBasics-WPF 示例,红外图像从 FrameReference.AcquireFrame()
方法提取到 ushort
矢量中。然后您可以使用 IntPtr infraredBuffer.UnderlyingBuffer
访问帧数据(以不安全的方法)以获取一维向量。如果需要,您可以稍后使用标准 2xfor 循环将一维矩阵转换为二维矩阵。
这样您就不必访问来自 `BitmapEncoder 的数据。另外,由于它在 SDK 中作为标准示例给出,因此我认为这是获取 IR 帧的推荐方法。此外,该示例还包含显示红外图像的方法;除非你有特定的 method/reason 来使用你的方式。
C#中的Bitmap可以很容易的转换成EMGUCV的Mat,使用下面的代码:
Bitmap bmp = new Bitmap("FilePath");//Declare a Bitmap Object
Image<Bgr, Byte> bmp_I = new Image<Bgr, byte>(bmp);//Creating an Image object in EMGUCV which can read Bitmap object.
Mat converted_mat = bmp_I.Mat;//Convert Image object into Mat
我用这个方法很成功:
public static Mat ToMat(BitmapSource source)
{
if (source.Format == PixelFormats.Bgra32)
{
Mat result = new Mat();
result.Create(source.PixelHeight, source.PixelWidth, DepthType.Cv8U, 4);
source.CopyPixels(Int32Rect.Empty, result.DataPointer, result.Step * result.Rows, result.Step);
return result;
}
else if (source.Format == PixelFormats.Bgr24)
{
Mat result = new Mat();
result.Create(source.PixelHeight, source.PixelWidth, DepthType.Cv8U, 3);
source.CopyPixels(Int32Rect.Empty, result.DataPointer, result.Step * result.Rows, result.Step);
return result;
}
else if (source.Format == PixelFormats.Pbgra32)
{
Mat result = new Mat();
result.Create(source.PixelHeight, source.PixelWidth, DepthType.Cv8U, 4);
source.CopyPixels(Int32Rect.Empty, result.DataPointer, result.Step * result.Rows, result.Step);
return result;
}
else
{
throw new Exception(String.Format("Conversion from BitmapSource of format {0} is not supported.", source.Format));
}
}
您可以根据需要进行调整。我不确定 ImShow 是否会处理 32 位浮点数的位图。位图通常充满了字节。我可能是错的,但我从来没有试图得到任何东西来证明它是花车。
道格
我正在从 Kinect V2 相机获取红外帧。帧以 WritableBitmap 的形式出现,因此我尝试使用我编写的代码对其进行转换:
public Mat WritableBitmapToMat(WriteableBitmap writeBmp)
{
Bitmap bmp;
using (MemoryStream outStream = new MemoryStream())
{
BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create((BitmapSource)writeBmp));
enc.Save(outStream);
bmp = new Bitmap(outStream);
}
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat);
IntPtr data = bmpData.Scan0;
int step = bmpData.Stride;
Mat mat = new Mat(bmp.Height, bmp.Width, Emgu.CV.CvEnum.DepthType.Cv32F, 4, data, step);
bmp.UnlockBits(bmpData);
return mat;
}
我不知道这是否是转换的问题,但是当我尝试使用以下代码在 window 中显示图像时:
CvInvoke.Imshow("window showing a picture", infraredMat);
我最终得到一个如下所示的异常:
异常:抛出异常:'System.AccessViolationException' in Emgu.CV.World.dll ("Attempted to read or write protected memory. This is often an indication that other memory is corrupt.").
我还想提一下我正在使用 EmguCV 3.1 和 Kinect SDK 2.0
提前感谢我得到的任何帮助。
如果您查看 Kinect 2.0 SDK 中的 InfraredBasics-WPF 示例,红外图像从 FrameReference.AcquireFrame()
方法提取到 ushort
矢量中。然后您可以使用 IntPtr infraredBuffer.UnderlyingBuffer
访问帧数据(以不安全的方法)以获取一维向量。如果需要,您可以稍后使用标准 2xfor 循环将一维矩阵转换为二维矩阵。
这样您就不必访问来自 `BitmapEncoder 的数据。另外,由于它在 SDK 中作为标准示例给出,因此我认为这是获取 IR 帧的推荐方法。此外,该示例还包含显示红外图像的方法;除非你有特定的 method/reason 来使用你的方式。
C#中的Bitmap可以很容易的转换成EMGUCV的Mat,使用下面的代码:
Bitmap bmp = new Bitmap("FilePath");//Declare a Bitmap Object
Image<Bgr, Byte> bmp_I = new Image<Bgr, byte>(bmp);//Creating an Image object in EMGUCV which can read Bitmap object.
Mat converted_mat = bmp_I.Mat;//Convert Image object into Mat
我用这个方法很成功:
public static Mat ToMat(BitmapSource source)
{
if (source.Format == PixelFormats.Bgra32)
{
Mat result = new Mat();
result.Create(source.PixelHeight, source.PixelWidth, DepthType.Cv8U, 4);
source.CopyPixels(Int32Rect.Empty, result.DataPointer, result.Step * result.Rows, result.Step);
return result;
}
else if (source.Format == PixelFormats.Bgr24)
{
Mat result = new Mat();
result.Create(source.PixelHeight, source.PixelWidth, DepthType.Cv8U, 3);
source.CopyPixels(Int32Rect.Empty, result.DataPointer, result.Step * result.Rows, result.Step);
return result;
}
else if (source.Format == PixelFormats.Pbgra32)
{
Mat result = new Mat();
result.Create(source.PixelHeight, source.PixelWidth, DepthType.Cv8U, 4);
source.CopyPixels(Int32Rect.Empty, result.DataPointer, result.Step * result.Rows, result.Step);
return result;
}
else
{
throw new Exception(String.Format("Conversion from BitmapSource of format {0} is not supported.", source.Format));
}
}
您可以根据需要进行调整。我不确定 ImShow 是否会处理 32 位浮点数的位图。位图通常充满了字节。我可能是错的,但我从来没有试图得到任何东西来证明它是花车。
道格