C # / EmguCV - convert downloaded HttpPostedFileBase to Emgu.CV.Mat

I have an MVC application where one of my controllers gets the downloaded file (image) as an HttpPostedFileBase object.

I am trying to process an image using EmguCV , but it is difficult for me to convert my HttpPostedFileBase to an EmguCV matrix object Emgu.CV.Mat (which is an implementation of the C# cv::Mat object).

There is a constructor for Mat that looks like this:

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

but I'm not sure how to get type , data and step from my original HttpPostedFileBase object. Is it possible?

I see here that I can convert the HttpPostedFileBase object to an Image object (I think 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 Mat() constructor to?

+6
source share
2 answers

According to the Emgu specification , these 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 type CvEnum.DepthType , which is the image depth, you can go through CvEnum.DepthType.Cv32F , which means 32-bit depth images, other possible values ​​are CvEnum.DepthType.Cv{x}{t} , where {x} - any value of the set {8,16,32,64}, and {t} can be S for Single or F for Float .

  • channels , depends on the type of image, but I think you can use 4 of ARGB.

For the remaining 2 parameters, if you do not need the optimization part, you can simply 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 (continued):

  • data , you can pass Bitmap.GetHbitmap (), which returns IntPtr to user data.

  • step , for this guy I will give you a reasonable assumption if for each pixel you have 4 channels and each channel is in the range from 0 to 255 (8 bits), 8*4 = 32 , so for each block width you need 32 bit. Assuming this is correct, each line contains 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

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

 Bitmap bmp = new Bitmap(Image.FromStream(httpPostedFileBase.InputStream, true, true)); // Lock the bitmap 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); 

Did not test this solution, but you can try. My answer was based on Emgu code here . Bitmap IntPtr is here , as well as on this post , which will help me also get a further understanding of this.

I have seen other ways to do this, and if you really don't need to call this full constructor, I would try using this approach, it 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

The OpenCV documentation has some great tutorials. Just take a look at the available tutorials for the core module. In particular, this one .

+5
source

I think the easiest way to do what you want is to create a Bitmap from the image you get by following your link on how to convert the HttpPostedFileBase to Bitmap . The Bitmap class has a constructor with the Image parameter. Then you can create Emgu.CV.Image using this Bitmap , again the Image class can accept the Bitmap in the constructor. The disadvantage of this method is that you get Image , not Mat .

Now you asked how to create a Mat object, and I'm not sure what you're talking about, because I could not find this class in EmguCV (2.4.9). There is a Matrix class, but its constructor is not like the one in your question. Therefore, to give you more information about the type , data and step parameters, be aware that type depends on the PixelFormat property of the image. This is an enumeration that can have about 20 different meanings. In my test, the image had the value PixelFormat.Format24bppRgb , which means that these are 3-channel images, where each channel has 8 bits, so in this case the type should be a byte. I suggest following this link on how to get a bit depth for a given PixelFormat.

For the data parameter, you will need to get BitmapData from Bitmap and get the Scan0 property, as described here .

For the step parameter, you will again need BitmapData , but this time it is the Stride parameter, which represents the step.

+3
source

Source: https://habr.com/ru/post/970355/


All Articles