C#与C++混合编程通过openCV调用摄像头

最近要做一个程序,程序主体用C#写的,要使用摄像头。

最先考虑的是用C++调用openCV写成dll,给C#调用。后来感觉有点复杂就转而使用EmguCV了。

但是使用中发现两个bug,其一是无法得到摄像头的名字(这个可以通过C#本身枚举系统设备实现,但是这之后还是遇到一个bug,摄像头名字跟编号不对应,有两个摄像头的话,用VidioCapture打开后是另外一个),其二是通过使用SetCaptureProperty方法修改摄像头参数时无效,网上搜了半天竟然没有人遇到类似问题,也无无从解决,真是莫名其妙。

又考虑到后续还有很多图像处理工作要用OpenCV,在C#里通过EmguCV调用效率恐怕也难以保证。

于是下定决心,回过头来再研究一下C++与C#混合编程的方法。

基本思路是,在C++中调用openCV读取摄像头的数据,传回给C#显示在PictureBox中。具体实现方法是通过将C#中的IntrPtr类型传入C++的函数,在其中赋值。

测试如下,在C++中

extern "C" __declspec(dllexport) void Test2(unsigned char* x) {
	for (int i = 0; i < 10; i++)
		x[i] = i;
}

在C#中,声明外部函数

[DllImport("C:\\Users\\boron\\source\\repos\\CVUtilityDll\\debug\\CVUtilityDll.dll"
    , CallingConvention = CallingConvention.Cdecl)]
static extern int Test2(IntPtr x);

在函数调用,

byte[] data = new byte[10];
IntPtr x = Marshal.AllocHGlobal(10);
Test2(x);
Marshal.Copy(x, data, 0, 10);

IntPtr x = Marshal.AllocHGlobal(10); 此句中的参数是10的话程序运行一切正常,而用更小的数,比如1,则程序运行有时正常,有时会出错,应该是因为内存使用上的冲突。

回到正题,调用摄像头时,在C++中创建三个函数,分别是启用相机,释放相机和获取一桢图像。

#define EXTERN_DLL extern "C" __declspec(dllexport)

// 全局变量
VideoCapture capture;
Mat I;

/* 
打开相机,设置分辨率
*/
EXTERN_DLL void InitializeCamera() {
	capture.open(0, CAP_DSHOW);
	capture.set(CAP_PROP_FRAME_WIDTH, 640);
	capture.set(CAP_PROP_FRAME_HEIGHT, 480);
}

/*
释放相机和图像矩阵
*/
EXTERN_DLL void ReleaseCamera() {
	capture.release();
	I.release();
}

/*
从相机中获取一桢图像,把数组传给外部的指针变量
*/
EXTERN_DLL void GetOneFrame(unsigned char* x) {
	capture.read(I);
	if (I.empty()) return;

	int channels = I.channels();
	int nRows = I.rows;
	int nCols = I.cols * channels;

	if (I.isContinuous())
	{
		nCols *= nRows;
		nRows = 1;
	}

	uchar* p;
	for (int i = 0; i < nRows; ++i)
	{
		p = I.ptr<uchar>(i);
		for (int j = 0; j < nCols; ++j)
		{
			x[i * nCols + j] = p[j];
		}
	}
}

在C#中声明外部函数

[DllImport("C:\\Users\\boron\\source\\repos\\CVUtilityDll\\debug\\CVUtilityDll.dll"
		, CallingConvention = CallingConvention.Cdecl)]
static extern void InitializeCamera();

[DllImport("C:\\Users\\boron\\source\\repos\\CVUtilityDll\\debug\\CVUtilityDll.dll"
		, CallingConvention = CallingConvention.Cdecl)]
static extern void ReleaseCamera();

[DllImport("C:\\Users\\boron\\source\\repos\\CVUtilityDll\\debug\\CVUtilityDll.dll"
		, CallingConvention = CallingConvention.Cdecl)]
static extern void GetOneFrame(IntPtr a);

创建一个PictureBox,用来显示传回的图片,在一个函数中创建BitMap对象用来接收数据,不断调用GetOneFrame来获取图像,并显示在PictureBox上

InitializeCamera();
Bitmap bmp = new Bitmap(640, 480, PixelFormat.Format24bppRgb);
while (Visible)
{
		BitmapData bmd = bmp.LockBits(new Rectangle(0, 0, 640, 480),
				ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
		GetOneFrame(bmd.Scan0);
		bmp.UnlockBits(bmd);
		pictureBox1.Image = bmp;
		Application.DoEvents();
}
ReleaseCamera();

至于如何设置环境不再赘述,可直接参考我前面写的文章。相关代码下载链接如下

https://download.csdn.net/download/boron1987/15120306

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值