C#/ EmguCV - 将上传的HttpPostedFileBase转换为Emgu.CV.Mat

时间:2014-06-05 02:46:08

标签: c# opencv emgucv

我有一个MVC应用程序,其中一个控制器收到一个上传的文件(图像)作为HttpPostedFileBase对象。

我正在尝试使用EmguCV处理图片,但我很难将HttpPostedFileBase转换为EmguCV矩阵对象Emgu.CV.Mat(这只是C#对象的cv::Mat实现。

Mat有一个构造函数,如下所示:

public Mat(int rows, int cols, DepthType type, int channels, IntPtr data, int step);

但我不确定如何从我的起始type对象中获取datastepHttpPostedFileBase。这可能吗?

我看到here,我可以将HttpPostedFileBase转换为Image对象(我认为System.Drawing名称空间中的对象),这样我就可以了看高度和宽度。 但是如何使用此信息获取其余所需参数以发送Mat()构造函数?

2 个答案:

答案 0 :(得分:5)

根据 Emgu 规范,这些参数意味着:

  /// <param name="type">Mat element type

  /// <param name="channels">Number of channels

  /// <param name="data">
  /// Pointer to the user data. Matrix constructors that take data and step parameters do not  
  /// allocate matrix data. Instead, they just initialize the matrix header that points to the 
  /// specified data, which means that no data is copied. This operation is very efficient and 
  /// can be used to process external data using OpenCV functions. The external data is not 
  /// automatically deallocated, so you should take care of it.

  /// <param name="step">
  /// Number of bytes each matrix row occupies. 
  /// The value should include the padding bytes at the end of each row, if any.
  • type属于CvEnum.DepthType类型,它是图像的深度,您可以传递CvEnum.DepthType.Cv32F代表32位深度图像,其他可能的值属于表单CvEnum.DepthType.Cv{x}{t},其中{x}是集{8,16,32,64}和{t}的任何值,SSingle可以是F Float

  • channels,取决于图片类型,但我认为您可以使用ARGB中的4

对于其他2个参数,如果您不需要优化部分,则可以使用Mat类的此构造函数:

public Mat(int rows, int cols, DepthType type, int channels)

如果您真的想使用优化版本,那么(继续):

  • data,您可以传递Bitmap.GetHbitmap(),它将IntPtr返回给用户数据。

  • step,对于这个人,我会给你一个明智的猜测,如果每个像素你有4个通道,每个通道的范围是0到255(8位),{{1}因此,对于每个单位宽度,您需要32位。假设这是正确的,每行都有8*4 = 32位,将其转换为字节32*width,这是通道数乘以图像宽度。

更新

获取((8*4)*width)/8 = 4*widthdata的其他方式来自BitmapData类,就像这样(摘自MSDN资源):

step

尚未测试此解决方案,但您可以尝试一下。 我的回答是基于 Emgu 代码here。, Bitmap IntPtr here以及此post,这有助于我获取进一步了解这一点。

我已经看到了其他方法,除非你真的需要调用那个完整的构造函数,否则我会尝试这种方法,看起来更干净:

Bitmap bmp = new Bitmap(Image.FromStream(httpPostedFileBase.InputStream, true, true));

// Lock the bitmap's bits.  
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);

System.Drawing.Imaging.BitmapData bmpData =
    bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
        bmp.PixelFormat);

// data = scan0 is a pointer to our memory block.
IntPtr data = bmpData.Scan0;

// step = stride = amount of bytes for a single line of the image
int step = bmpData.Stride;

// So you can try to get you Mat instance like this:
Mat mat = new Mat(bmp.Height, bmp.Width, CvEnum.DepthType.Cv32F, 4, data, step);

// Unlock the bits.
bmp.UnlockBits(bmpData);

注意

OpenCV documentation中有很棒的教程。只需查看核心模块的可用教程。特别是,one

答案 1 :(得分:3)

我认为,最简单的方法是根据您获得的关于如何将Bitmap转换为HttpPostedFileBase的链接的图片创建BitmapBitmap类有一个带Image参数的构造函数。然后,您可以使用此Emgu.CV.Image创建BitmapImage类可以在构造函数中使用Bitmap。这些方法的缺点是您将获得Image而不是Mat

现在,你问如何创建一个Mat对象,我不确定你在谈论什么,因为我在EmguCV(2.4.9)中找不到这个类。有一个Matrix类,但它的构造函数看起来不像你问题中的那个。因此,为了向您提供有关typedatastep参数的更多信息,请知道type依赖于Image的PixelFormat属性。它是一个枚举,可以有大约20个不同的值。在我的测试中,图像具有PixelFormat.Format24bppRgb值,这意味着它是3通道图像,其中每个通道是8位,因此在这种情况下类型应该是字节。我建议关注如何获取指定PixelFormat的位深度的this链接。

对于数据参数,您需要从BitmapData获取Bitmap并获取Scan0属性,因为它已解释为here

对于step参数,您将再次需要BitmapData,但这次是表示该步骤的Stride参数。