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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With