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?