C# / EmguCV - Convert an uploaded HttpPostedFileBase to a Emgu.CV.Mat

c#, emgucv, opencv

Solution

According to the Emgu specification those parameters mean:

  /// <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` is of the type `CvEnum.DepthType`, which is the depth of the image, you can pass `CvEnum.DepthType.Cv32F` which stands for 32bit depth images, other possible values are of the form `CvEnum.DepthType.Cv{x}{t}`, where {x} is any value of the set {8,16,32,64} and {t} can be `S`for `Single` or `F` for `Float`.

`channels`, depend on the type of image but I think you can use `4`from ARGB.

For the other 2 parameters, if you don't need the optimization part, you can just use this constructor of the `Mat` class:

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

If you really want to use the optimized version, then (continuing):

`data`, you can pass the Bitmap.GetHbitmap() which returns an IntPtr to the user data.

`step`, for this guy, I'll give you an informed guess, if for each pixel you have 4 channels, and each channel ranges from 0 to 255 (8bits), `8*4 = 32`, so for every width of unit you need 32 bits. Assuming this is correct, each row haves `32*width` bits, converting it to bytes `((8*4)*width)/8 = 4*width`, which is the number of channels, multiplied by the image width.

UPDATE

Other way to get the `data` and `step` is from BitmapData class, like this (excerpt from the MSDN resource):

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);

Have not tested this solution, but you can give it a try. My answer was based on the Emgu code here., Bitmap IntPtr here and also on this post which help me also acquiring further understanding on this.

I have seen other ways to do it also, and unless you really need to call that complete constructor, I would try this approach, seems cleaner:

HttpPostedFileBase file //your file must be available is this context.

if (file.ContentLength > 0)
{
    string filename = Path.GetFileName(file.FileName);

    // your so wanted Mat!
    Mat img = imread(filename, CV_LOAD_IMAGE_COLOR);
}

NOTE

There are great tutorials in the OpenCV documentation. Just have a look at the available tutorials for the core module. In particular, this one.

Problem

I have an `MVC` application where one of my controllers receives an uploaded file (image) as an `HttpPostedFileBase` object. I am trying to process the image using `EmguCV`, but I'm having difficulty converting my `HttpPostedFileBase` to the `EmguCV` matrix object `Emgu.CV.Mat` (which is just a `C#` implementation of a `cv::Mat` object). There is a constructor for `Mat` that looks like: ``` public Mat(int rows, int cols, DepthType type, int channels, IntPtr data, int step); ``` but I'm not sure how to get the `type`, `data`, and `step` from my starting `HttpPostedFileBase` object. Is this possible? I see here, that I can convert an `HttpPostedFileBase` to an `Image` object (I think that's in the `System.Drawing` namespace), which allows me to see the height and width. But how can I use this information to get the rest of the required parameters to send the the `Mat()` constructor?

Original source

Related problems