C# 读取图片传递给Opencv编写的动态库

网上查了好多资料,还有查看opencv的文档终于解决了C#传递给C++编写的Opencv库图像传递不正确的问题。 基本思路是C#读取图片转成byte[]数组,然后传递给Opencv,通过Mat (int rows, int cols, int type, void *data, size_t step=AUTO_STEP)构造函数接收。由于读取的图片格式可能有ARGB和RGB格式,统一转成RGB格式。
讲讲我遇到的各个坑

  1. C#读取图片转成RGB格式。先贴上代码:
Bitmap bmpInitial = (Bitmap)System.Drawing.Image.FromFile("1.jpg");
Bitmap bmp = null;
 //将图像转换为24位rgb图像
if (bmpInitial.PixelFormat != System.Drawing.Imaging.PixelFormat.Format24bppRgb)
{
	bmp = new Bitmap(bmpInitial.Width, bmpInitial.Height,System.Drawing.Imaging.PixelFormat.Format24bppRgb);
	using (Graphics g = Graphics.FromImage(bmp))
	{
		g.DrawImage(bmpInitial, new Rectangle(0, 0, bmpInitial.Width, bmpInitial.Height));
	}  
}
else
{
	 bmp = bmpInitial;
}
//设置dpi=96
bmp.SetResolution(96, 96);

DrawImage必须指定图像的宽高,不然图像显示的不全,原因和图像的分辨率和系统分辨率有关。
2. 图像转Byte[]数组

System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat);
//Get the address of the first line.
IntPtr ptr = bmpData.Scan0;
// Declare an array to hold the bytes of the bitmap. 
int bytesLength = Math.Abs(bmpData.Stride) * bmp.Height;
int imageWeidth = bmp.Width;
int imageHeight = bmp.Height;
//图像的Stride
int imageStride = bmpData.Stride;
byte[] buffer = new byte[bytesLength];
// Copy the RGB values into the array.
Marshal.Copy(ptr, buffer, 0, bytesLength);
bmp.UnlockBits(bmpData);

这个是msdn里LockBits的示例,试过网上其他通过MemoryStream,FileStream转换,传递的数据都不正确。
3. Mat构造函数Mat (int rows, int cols, int type, void *data, size_t step=AUTO_STEP)
这里需要理解Stride。参数step的含义是Number of bytes each matrix row occupies.,就我理解就是图像的Stride。涉及到位数对齐的问题。
(1) Stride = 每像素占用的字节数(也就是像素位数/8) * Width;
(2) 如果 Stride 不是 4 的倍数, 那么 Stride = Stride + (4 - Stride mod 4);
step的默认值是不包含padding位,也就是默认按(1)来处理,这样得到的图像会发生错位,显示不全。
4. Opencv中接收图像的代码Byte[]->Mat

Mat ByteToMat(BYTE* pImg, int nH, int nW,int stride)
{
	Mat image = Mat(nH, nW, CV_8UC3, pImg,stride).clone();
	return image;
}

关于dll的编写调用,这里提供一下我用的函数原型。
C#中:

[DllImport("VesselExportCp.dll", EntryPoint = "GetResult", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
public static extern void GetResult(byte[] bimage, int nH, int nW, int stride, [In, Out] ref StructResult result);

C++中:

extern "C" VES_API void __stdcall GetResult(BYTE* bimage, int nH, int nW, int stride, StructResult* result);
  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值