opencv+MFC做个视频监控软件

终于到了不写博客不行的地步了,菜鸡的技术终于要袒露出来了,唉,话不多说直入正题。

第一次写博客,结构有点乱,各位凑合着看吧。

1.核心功能:显示摄像头画面

先来张图直观理解下
第一个画面是外接的一个USB摄像头传上来的图像,第二个是本菜鸡笔记本上的摄像头传上来的图片(渣渣像素无力吐槽)


打开摄像头并上传图像用opencv来做的话非常简单

UINT CShowThreeDlg::ShowImg(LPVOID lpParam)
{
	CShowThreeDlg *pDlg= (CShowThreeDlg*)lpParam;
	VideoCapture capture;  // 创建个VideoCapture类的实例
 	capture.open();        // 打开USB设备
 	
 	if (!capture.isOpened())  // 判断是否打开成功
 		return false;
	while (true)  
	{  
		Mat img;
		capture >> img;

		if(img.empty())    
			return false;    

		CRect drect;
		pDlg->GetDlgItem(IDC_SHOW3_PIC);
		pDlg->GetClientRect(&drect);    

		CClientDC dc(pDlg);  
		HDC hDC =dc.GetSafeHdc();  

		//内存中的图像数据拷贝到屏幕上  
		BYTE *bitBuffer        = NULL;  
		BITMAPINFO *bitMapinfo = NULL;  

		int ichannels =img.channels();    // 获取并判断通道数
		if( ichannels == 1)  
		{  
			bitBuffer  = new BYTE[40+4*256];   
		}  
		else if( ichannels == 3)  
		{  
			bitBuffer  = new BYTE[sizeof(BITMAPINFO)];   
		}  
		else  
		{  
			return false;  
		}  


		if(bitBuffer == NULL)  
		{     
			return false;  
		}  

		bitMapinfo = (BITMAPINFO *)bitBuffer;  
		bitMapinfo->bmiHeader.biSize             = sizeof(BITMAPINFOHEADER);  
		bitMapinfo->bmiHeader.biHeight           = -img.rows;  //如果高度为正的,位图的起始位置在左下角。如果高度为负,起始位置在左上角。  
		bitMapinfo->bmiHeader.biWidth            = img.cols;  
		bitMapinfo->bmiHeader.biPlanes           = 1;      // 目标设备的级别,必须为1     
		bitMapinfo->bmiHeader.biBitCount		 = ichannels *8;// 每个像素所需的位数,必须是1(双色), 4(16色),8(256色)或24(真彩色)之一  
		bitMapinfo->bmiHeader.biCompression      = BI_RGB; //位图压缩类型,必须是 0(不压缩), 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一  
		bitMapinfo->bmiHeader.biSizeImage        = 0;      // 位图的大小,以字节为单位  
		bitMapinfo->bmiHeader.biXPelsPerMeter    = 0;      // 位图水平分辨率,每米像素数  
		bitMapinfo->bmiHeader.biYPelsPerMeter    = 0;      // 位图垂直分辨率,每米像素数  
		bitMapinfo->bmiHeader.biClrUsed          = 0;      // 位图实际使用的颜色表中的颜色数  
		bitMapinfo->bmiHeader.biClrImportant     = 0;      // 位图显示过程中重要的颜色数  

		if(ichannels == 1)  
		{  
			for(int i=0; i<256; i++)  
			{   //颜色的取值范围 (0-255)  
				bitMapinfo->bmiColors[i].rgbBlue  =bitMapinfo->bmiColors[i].rgbGreen =bitMapinfo->bmiColors[i].rgbRed = (BYTE) i;  
			}  

			bitMapinfo->bmiHeader.biClrUsed = 256;    // 位图实际使用的颜色表中的颜色数  
		}  
		SetStretchBltMode(hDC, COLORONCOLOR);  

		StretchDIBits(hDC,  
			0,  
			0,  
			drect.right,        //显示窗口宽度  
			drect.bottom,       //显示窗口高度  
			0,  
			0,  
			img.cols,          //图像宽度  
			img.rows,          //图像高度  
			img.data,             
			bitMapinfo,           
			DIB_RGB_COLORS,   
			SRCCOPY  
			);  

		delete []bitBuffer; 

		waitKey(30);    //延时30 

		if (pDlg->m_bCloseShow == TRUE)
		{
			pDlg = NULL;
			capture.release();
			return TRUE;
		}
	}
	return TRUE;
}



void CShowThreeDlg::OnRButtonUp(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
//	CAddNewShow dlg;
//	dlg.DoModal();

	hThread = AfxBeginThread(ShowImg,
		this);//创建一个新线程ShowImg
	CFormView::OnRButtonUp(nFlags, point);
}

以上就是整个图像显示的流程了,写到线程里面让他努力干活吧,我们继续去搞事情
2.附加功能:截图

既然都已经显示出来了那么顺手就把截图给做出来吧,反正挺简单的

先来张效果图
很简单,按下空格,然后获取当前显示的那一帧图像,然后保存下来
if (pDlg->m_bWabei == TRUE)  // 截图存图  后续界面上补个提示
		{
			Mat frame;
			const char* path;
			path=".\\image\\test.bmp";  // 路径自己设,可以弄个for循环来实现多张截图
			capture.read(frame);        // 当前帧图像读取到Mat类型里
			imwrite(path,frame);        // 图像保存
			pDlg->m_bWabei = FALSE;     // 截图标志状态改回来   构造函数里就初始为false 
		}

这段放到显示图像后面(放到waitKey(30);    //延时30 后面就挺好的) ,m_bWabei是个状态标志,用来判断什么时候截图

重载PreTranslateMessage,截获按键消息
BOOL CShowThreeDlg::PreTranslateMessage(MSG* pMsg)
{
	// TODO: 在此添加专用代码和/或调用基类
	if (pMsg->message == WM_KEYDOWN)  
	{  
		if (pMsg->wParam == VK_ESCAPE)
		{
			m_bCloseShow = TRUE;

			return TRUE;
		}
		if (pMsg->wParam == VK_SPACE)  
		{
			m_bWabei = TRUE;   // 按下空格键的时候标志置为true,然后线程里截图
		}
	} 

	return CFormView::PreTranslateMessage(pMsg);
}
撤了,接女票下班了,先写到这,有空补接下来的功能大笑
阅读更多
文章标签: opencv mfc
个人分类: C++
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭