c# / EmguCV -将上传的HttpPostedFileBase转换为Emgu.CV.Mat
本文关键字:转换 HttpPostedFileBase Emgu Mat CV EmguCV | 更新日期: 2023-09-27 18:06:42
我有一个MVC
应用程序,其中一个控制器接收一个上传的文件(图像)作为HttpPostedFileBase
对象。
我正试图使用EmguCV
处理图像,但我很难将我的HttpPostedFileBase
转换为EmguCV
矩阵对象Emgu.CV.Mat
(这只是cv::Mat
对象的C#
实现)。
Mat
的构造函数如下:
public Mat(int rows, int cols, DepthType type, int channels, IntPtr data, int step);
但我不确定如何从我的开始HttpPostedFileBase
对象获得type
, data
和step
。这可能吗?
我在这里看到,我可以将HttpPostedFileBase
转换为Image
对象(我认为这是在System.Drawing
名称空间中),这允许我看到高度和宽度。但是我如何使用这些信息来获得发送Mat()
构造函数所需的其余参数呢?
根据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
,表示图像的深度,您可以传递代表32位深度图像的CvEnum.DepthType.Cv32F
,其他可能的值形式为CvEnum.DepthType.Cv{x}{t}
,其中{x}是集合{8,16,32,64}中的任意值,{t}可以为Single
的S
或Float
的F
。channels
,取决于图像的类型,但我认为你可以使用4
从ARGB
对于其他2个参数,如果您不需要优化部分,您可以使用Mat
类的这个构造函数:
public Mat(int rows, int cols, DepthType type, int channels)
如果你真的想使用优化后的版本,那么(继续):
data
,你可以传递Bitmap.GetHbitmap(),它返回一个IntPtr给用户数据。step
,对于这个家伙,我会给你一个知情的猜测,如果每个像素你有4个通道,每个通道的范围从0到255(8位),8*4 = 32
,所以对于每个单位的宽度你需要32位。假设这是正确的,每一行都有32*width
位,将其转换为字节((8*4)*width)/8 = 4*width
,这是通道数量乘以图像宽度。
获取data
和step
的另一种方法是从BitmapData类,像这样(摘自MSDN资源):
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);
没有测试过这个解决方案,但你可以试一试。我的答案是基于这里的Emgu代码。位图IntPtr在这里,也在这篇文章中,这有助于我进一步了解这一点。
我也见过其他方法,除非你真的需要调用完整的构造函数,否则我会尝试这种方法,看起来更干净:
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);
}
注意
在OpenCV文档中有很棒的教程。只要看看核心模块的可用教程就可以了。尤其是这个
我认为做你想做的最简单的方法是创建一个Bitmap
的图像,你得到你的链接如何将HttpPostedFileBase
转换为Bitmap
。Bitmap
类有一个带Image
参数的构造函数。然后,您可以使用此Bitmap
创建Emgu.CV.Image
,同样,Image
类可以在构造函数中接受Bitmap
。这些方法的缺点是您将获得Image
而不是Mat
。
现在,你问如何创建一个Mat
对象,我不确定你在说什么,因为我在EmguCV(2.4.9)中找不到这个类。有一个Matrix
类,但它的构造函数看起来不像你的问题。因此,为了向您提供有关type
, data
和step
参数的更多信息,请了解type
依赖于图像的PixelFormat
属性。它是一个enum,可以有大约20个不同的值。在我的测试中,图像有一个PixelFormat.Format24bppRgb
值,这意味着它是一个3通道图像,每个通道是8位,所以在这种情况下类型应该是字节。我建议按照这个链接获取指定PixelFormat的位深。
对于data参数,您需要从Bitmap
中获取BitmapData
,并获得Scan0
属性,正如这里所解释的那样。
对于step参数,您将再次需要BitmapData
,但这次是Stride
参数,表示步骤。