【2012年终总结】之一 opencv + ds采集摄像头视频 MFC点点滴滴

 

1、MFC单文档多文档程序 不让MFC来更新菜单

1 在CMainFrame::CMainFrame中添加

2 

3 m_bAutoMenuEnable = FALSE;

标题栏图标的更改

1 //cuihao, 标题栏图标;

2 CCameraMonitorApp *pApp = (CCameraMonitorApp*)AfxGetApp();

3 HICON hIcon = pApp->LoadIcon(IDI_ICON3);

4 SetIcon(hIcon, TRUE);

5 SetIcon(hIcon, FALSE);

 

 ------------------------------------------------------------------------------------------------------------------------

使菜单可用/不可用, 通过菜单项的位置来让菜单可用或不可用

1 GetMenu()->GetSubMenu(2)->EnableMenuItem(1, MF_BYPOSITION | MF_GRAYED | MF_DISABLED);

2 

3 GetMenu()->GetSubMenu(3)->EnableMenuItem(2, MF_BYPOSITION | MF_ENABLED);

 

 

更改菜单项的Caption或者ID

如果只想要修改菜单的文字则ID要和原来的一样,原来的菜单ID也为ID_OF_MENUITEM, 修改后的caption为strNewStringCaption

1 GetMenu()->GetSubMenu(1)->ModifyMenu(2, MF_BYPOSITION | MF_STRING, ID_OF_MENUITEM, strNewStringCaption);

 

  ------------------------------------------------------------------------------------------------------------------------

 修改MFC单文档多文档的窗口标题栏

 1 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)

 2 {

 3 if( !CFrameWnd::PreCreateWindow(cs) )

 4 return FALSE;

 5 // TODO: 在此处通过修改

 6 //cuihao, CREATESTRUCT cs 来修改窗口类或样式

 7 cs.style &= ~FWS_ADDTOTITLE;

 8 cs.lpszName = _T("视频监控"); 

 9 

10 return TRUE;

11 }

12 

13  

 

MFC单文档多文档,让程序一开始最大化运行

1 void CMainFrame::ActivateFrame(int nCmdShow)

2 {

3 // TODO: 在此添加专用代码和/或调用基类;

4 

5 nCmdShow = SW_SHOWMAXIMIZED; //cuihao,最大化运行;

6 

7 CFrameWnd::ActivateFrame(nCmdShow);

8 }

 

  ------------------------------------------------------------------------------------------------------------------------

 

 

 如果MFC文档有多个view类,那么获取当前有焦点的view类

1 CView* CFrameWnd::GetActiveView( ) const;

 

如果要获取指定的view类的指针,那么可以:先获得该view类的句柄,然后通过句柄获得指针

1 CWnd* FromHandle(HWND hWnd);

 

如果要遍历所有view类,如下

1 virtual POSITION GetFirstViewPosition() const;

2 virtual CView* GetNextView(POSITION& rPosition) const;

 

  ------------------------------------------------------------------------------------------------------------------------

 改变窗口的位置、大小,Z序

SetWindowPos

eg.  

//最大化视频;

 1 void CMainFrame::OnMenuMaxvideo()

 2 {

 3 // TODO: 在此添加命令处理程序代码;

 4 

 5 static bool bModify[MAX_CAMERAS_NUM] = {false};

 6 

 7 int nCode = CCameraMonitorView::m_nCurrentCode; 

 8 

 9 CCameraMonitorView* pView = NULL; 

10 pView = (CCameraMonitorView*)FromHandle(CCameraMonitorView::m_hWndCameraMonitor);

11 if (NULL == pView)

12 {

13 AfxMessageBox(_T("pView is NULL, CMainFrame::OnMenuMaxvideo"));

14 return;

15 }

16 

17 //最大化;

18 if (false == bModify[nCode])

19 { 

20 CRect rectMax;

21 pView->GetWindowRect(&rectMax);

22 int x = rectMax.TopLeft().x;

23 int y = rectMax.TopLeft().y;

24 int cx = rectMax.Width();

25 int cy = rectMax.Height();

26 BOOL ret = pView->GetDlgItem(videoPicturesCtrl[nCode])->SetWindowPos(&wndTopMost, 0, 0, cx, cy, SWP_SHOWWINDOW |SWP_NOZORDER);

27 

28 HideAllNonActiveWindows(nCode, true); //隐藏其他视频窗口,如果不隐藏则最大化视频显示时其他视频窗口会被刷出来,很难看;

29 

30 }

31 

32 //还原;

33 else

34 {

35 int x = CCameraMonitorView::m_rectVideos[nCode].left;

36 int y = CCameraMonitorView::m_rectVideos[nCode].top;

37 int cx = CCameraMonitorView::m_rectVideos[nCode].Width();

38 int cy = CCameraMonitorView::m_rectVideos[nCode].Height();

39 BOOL ret = pView->GetDlgItem(videoPicturesCtrl[nCode])->SetWindowPos(NULL, x, y, cx, cy, SWP_NOZORDER | SWP_SHOWWINDOW);

40 

41 HideAllNonActiveWindows(nCode, false);

42 }

43 

44 bModify[nCode] = !bModify[nCode]; 

45 Invalidate(TRUE); //刷新窗口;

46 

47 }

 

  ------------------------------------------------------------------------------------------------------------------------

 Windows自定义消息函数

   afx_msg LRESULT OnUpdateMenuCommand(WPARAM wParam, LPARAM lParam);

 

其中WPARAM为unsigned int,  LPARAM为long

与之前相关的给窗口发送消息的函数为SendMessage

SendMessage(



HWND  hWnd,         //目的窗口句柄



UINT    nMessageID, //消息



WPARAM wParam,  //unsigned int 参数



LPARAM   lParam    //long类型参数



)

 

其中nMessageID的定义为: #define MY_MESSAGE  WM_USER +  一个数字

WM_USER的定义为: #define  WM_USER  0X0400, 加上一个数字就能避免和系统消息冲突

 

添加消息映射

ON_MESSAGE(UPDATEUI_MESSAGE, CMainFrame::OnUpdateMenuCommand)

 

 

 有时候在不同的情况下要让目的窗口发生不同的变化,这个时候可以使用wParam和lParam这两个参数来传递给目的窗口不同的参数,

这里有个实例就是让wParam中的某些位的区别 以及 lParam的区别来区分不同的消息类型,从而让目的窗口发生不同的变化

eg.

  1 /////////////////////////////////////////////////////////////////////////////////////////////

  2 //

  3 //说明:::SendMessage(窗口句柄, 消息, wParam, lParam)

  4 // wParam == 0 :线程失败,没有进入实质的采集过程;

  5 // wParam == 0x****0001, lParam == 0x0000 00001 :线程成功,进入实质的采集过程;

  6 // wParam == 0x****0001, lParam == 0x0000 0000 :线程成功,进入实质采集过程,但是创建视频文件写入器失败

  7 // wParam == 0x****0001, lParam == 0x0000 00002 :线程成功,写视频异常;

  8 // wParam == 0x****0002, lParam == 0x0000 00000 :

  9 // 0x**** == code

 10 /////////////////////////////////////////////////////////////////////////////////////////////

 11 

 12 

 13 if (false == camera.OpenCamera(code, false, width, height))

 14 { 

 15 wParam = (code << 16) & 0xffff0000;

 16 wParam |= 0x00000000;

 17 

 18 ::SendMessage(hViewWnd, UPDATEUI_MESSAGE, wParam, 0); //失败,发送消息给主线程;

 19 ::SendMessage(hWndMainFrame, UPDATEUI_MESSAGE, wParam, 0);

 20 

 21 g_bIsRunningArr[min(code, MAX_CAMERAS_NUM)] = false;

 22 CString strInfo(_T("打开摄像头 "));

 23 strInfo += chCode;

 24 strInfo += _T(" 失败!");

 25 MessageBox(NULL, strInfo, _T("提示信息"), MB_OKCANCEL);

 26 return 0;

 27 }

 28 

 29 

 30 

 31 

 32 

 33 

 34 

 35 

 36 LRESULT CMainFrame::OnUpdateMenuCommand( WPARAM wParam, LPARAM lParam )

 37 {

 38 /////////////////////////////////////////////////////////////////////////////////////////////

 39 //

 40 //说明:::SendMessage(窗口句柄, 消息, wParam, lParam)

 41 // wParam == 0 :线程失败,没有进入实质的采集过程;

 42 // wParam == 0x****0001, lParam == 0x0000 00001 :线程成功,进入实质的采集过程;

 43 // wParam == 0x****0001, lParam == 0x0000 0000 :线程成功,进入实质采集过程,但是创建视频文件写入器失败

 44 // wParam == 0x****0001, lParam == 0x0000 00002 :线程成功,写视频异常;

 45 // wParam == 0x****0002, lParam == 0x0000 00000 :线程退出

 46 // 0x**** == code

 47 // wParam == 111(十进制), lParam == 0 :开始采集按钮事件 出错;

 48 /////////////////////////////////////////////////////////////////////////////////////////////

 49 

 50 WORD wLowState = 0; //状态代码;

 51 WORD wHICode = 0; //摄像头ID;

 52 

 53 wLowState = wParam & 0x0000ffff; //取低位两个字节;

 54 wHICode = (wParam >> 16) & 0x0000ffff; //取高位两个字节;

 55 

 56 const WCHAR strStartCapture[] = _T("开始采集");

 57 const WCHAR strEndCapture[] = _T("停止采集");

 58 const WCHAR strStartRecord[] = _T("开始录像");

 59 const WCHAR strEndRecord[] = _T("停止录像");

 60 

 61 int nCode = CCameraMonitorView::m_nCurrentCode; //获得当前摄像头code;

 62 

 63 //获得【视频】菜单;

 64 CMenu *pMenuVideo = NULL;

 65 pMenuVideo = GetMenu()->GetSubMenu(2);

 66 if (pMenuVideo == NULL)

 67 {

 68     AfxMessageBox(_T("pMenuVideo is NULL, CMainFrame::OnUpdateMenuCommand"));

 69     return -1;

 70 } 

 71 //如果当前摄像头code == 返回的摄像头code,则立即更新UI 

 72 if (nCode == wHICode && nCode != 0)

 73 {

 74     //线程在进入采集while之前失败;

 75     if (0 == wParam && 0 ==lParam)

 76     {

 77         //【开始采集】按钮可用,caption为【开始采集】,【开始录像】按钮不可用;

 78        pMenuVideo->ModifyMenu(0, MF_BYPOSITION, ID_MENU_STARTCAPTURE, strStartCapture);

 79     pMenuVideo->EnableMenuItem(0, MF_BYPOSITION | MF_ENABLED);

 80 

 81     pMenuVideo->EnableMenuItem(1, MF_BYPOSITION | MF_GRAYED | MF_DISABLED); 

 82   }

 83 

 84   //线程进入实质的采集过程;

 85   else if (1 == wLowState && 1 == lParam)

 86   {

 87     //【开始采集】按钮可用,caption为【停止采集】,【开始录像】按钮可用,caption为【开始录像】;

 88 

 89     pMenuVideo->ModifyMenu(0, MF_BYPOSITION | MF_STRING, ID_MENU_STARTCAPTURE, strEndCapture);

 90     pMenuVideo->EnableMenuItem(0, MF_BYPOSITION | MF_ENABLED);

 91 

 92     pMenuVideo->ModifyMenu(1, MF_BYPOSITION | MF_STRING, ID_MENU_RECORD, strStartRecord);

 93     pMenuVideo->EnableMenuItem(1, MF_BYPOSITION | MF_ENABLED);

 94 

 95 }

 96 

 97   //进入实质采集过程,但是创建视频写入器失败;

 98   else if (1 == wLowState && 0 == lParam)

 99   {

100     //【开始采集】按钮不变, 【开始录像】按钮caption变为【开始录像】,可用;

101     pMenuVideo->ModifyMenu(1, MF_BYPOSITION | MF_STRING, ID_MENU_RECORD, strStartRecord); 

102     pMenuVideo->EnableMenuItem(1, MF_ENABLED);

103   }

104 

105   //进入实质采集过程,写视频文件异常;

106   else if (1 == wLowState && 2 == lParam)

107   { 

108     //【开始采集】按钮不变, 【开始录像】按钮caption变为【开始录像】,可用;

109     pMenuVideo->ModifyMenu(1, MF_BYPOSITION | MF_STRING, ID_MENU_RECORD, strStartRecord); 

110     pMenuVideo->EnableMenuItem(1, MF_ENABLED);

111   }

112 

113   //线程退出;

114   else if (2 == wLowState && 0 == lParam)

115   {

116     //【开始采集】按钮变味【开始采集】, 【开始录像】不可用;

122    }

123 

124 }

125 

126 //开始采集 出错;

127 if (111 == wParam && 0 == lParam)

128 {

129   //【开始采集】可用;

130   pMenuVideo->EnableMenuItem(0, MF_BYPOSITION | MF_ENABLED);

131 }

132 else if (112 == wParam && 0 == lParam)

133 {

134   // GetDlgItem(IDC_BTN_RECORD)->EnableWindow(TRUE);

135   //SetDlgItemText(IDC_BTN_RECORD, _T("停止录像"));

136   pMenuVideo->EnableMenuItem(1, MF_ENABLED);

137   pMenuVideo->ModifyMenu(1, MF_BYPOSITION | MF_STRING, ID_MENU_RECORD, strEndRecord);

138 }

139 else if (113 == wParam && 0 == lParam)

140 {

141 

153 }

154 else if (114 == wParam && 0 == lParam)

155 { 

} 166 else if (115 == wParam && 0 == lParam) 167 {

} 171 else if (116 == wParam && 0 == lParam) 172 {

} 176 else if (117 == wParam && 0 == lParam) 177 { 179 } 181 182 return 0; 183 }

 

 

 

  ------------------------------------------------------------------------------------------------------------------------

 

 ------------------------------------------------------------------------------------------------------------------------

 【打开文件】对话框

GetModuleFileName :  获得包含路径的全文件名称
PathRemoveFileSpec: 获得去掉文加名及后缀的文件路径

上面这两个函数可能需要头文件<shlapi.h>

 

 

 1 void CMainFrame::OnMenuOpenfile()

 2 {

 3 // TODO: 在此添加命令处理程序代码; 

 4 

 5 static TCHAR szPath[MAX_PATH - 1] = {0};

 6 static bool bOnlyOnce = false;

 7 if (false == bOnlyOnce)

 8 {

 9 bOnlyOnce = true;

10 GetModuleFileName(NULL, szPath, sizeof(szPath));

11 PathRemoveFileSpec(szPath);

12 }

13 

14 CString strFileName;

15 

16 CFileDialog dlg(TRUE);

17 dlg.m_ofn.lpstrTitle = _T("打开avi视频文件");

18 dlg.m_ofn.lpstrFilter = _T("Avi Files(*.avi)\0 *.avi\0All Files(*.*)\0 *.*\0\0");    //文件过滤器

19 dlg.m_ofn.lpstrInitialDir = szPath;

20 

21 if (IDOK == dlg.DoModal())

22 { 

23 strFileName = dlg.GetPathName();

24 

25 //CString 2 TCHAR*

26 int iLen = strFileName.GetLength(); 

27 memset(szPath, 0, sizeof(szPath)); 

28 lstrcpy(szPath, strFileName.GetBuffer(iLen)); //得到szPath;

29 strFileName.ReleaseBuffer();

30 

31 //CString 2 char* 

32 char* pVideoFileName = (char*)malloc((iLen * 2 + 1) * sizeof(char));//CString的长度中汉字算一个长度; 

33 memset(pVideoFileName, 0, 2 * iLen + 1); 

34 USES_CONVERSION; 

35 strcpy((LPSTR)pVideoFileName,OLE2A(strFileName.LockBuffer())); //得到pVideoFileName;

36 

37 if (NULL == pVideoFileName)

38 {

39 assert(pVideoFileName != NULL);

40 AfxMessageBox(_T("视频文件打开失败!"));

41 return;

42 }

43 else

44 {

45 PalyVideo(pVideoFileName); //播放视频;

46 free(pVideoFileName);

47 }

48 

49 

50 PathRemoveFileSpec(szPath); //去掉文件名只保留路径;

51 }

52 }

 

 

 ------------------------------------------------------------------------------------------------------------------------

 MFC静态控件默认不响应键盘鼠标事件,需要激活SS_NOTIFY,可在控件属性里或者用该代码如下

//使Picture控件响应鼠标事件

GetDlgItem(IDC_VIDEO0)->ModifyStyle(0, SS_NOTIFY);

GetDlgItem(IDC_VIDEO1)->ModifyStyle(0, SS_NOTIFY); 

GetDlgItem(IDC_VIDEO2)->ModifyStyle(0, SS_NOTIFY);

 

  

 ------------------------------------------------------------------------------------------------------------------------

 获得桌面坐标 GetWindowRect和 客户区坐标GetClientRect

两者的区别仅仅是起点不同,桌面坐标的起点根据实际情况来,客户区的坐标起点是(0, 0),

他们之间通过ClientToScreen和ScreenToClient互相转换

 

 

 ------------------------------------------------------------------------------------------------------------------------

 开启子线程_begingthreadex

函数原型

函数原型:
unsigned long _beginthreadex(

    void *security,

    unsigned stack_size,

    unsigned ( __stdcall *start_address )( void * ),

    void *arglist, /* 这个就是传给线程函数的参数的指针 */

    unsigned initflag,

    unsigned *thrdaddr );

 



线程函数
UINT __stdcall ShowThread(void *p)

 



eg.

 1 UINT retValue = _beginthreadex(NULL, 

 2 0,

 3 ShowThread,  //线程函数

 4 pParams,       //参数

 5 0,

 6 &nThreadID  //线程ID

 7 );

 8 

 9 

10 if (INVALID_HANDLE_VALUE == (HANDLE)retValue)

11 {

12 MessageBox(_T("线程创建可能失败!INVALID_HANDLE_VALUE"));

13 delete pParams;

14 pParams = NULL;

15 return false;

16 }

17 else if (NULL == (HANDLE)retValue)

18 {

19 MessageBox(_T("线程创建可能失败!NULL"));

20 delete pParams;

21 pParams = NULL;

22 return false;

23 }

24 

25 return true;

 

 

 ------------------------------------------------------------------------------------------------------------------------

 TreeView的使用

MFC单文档程序中:选择资源管理器风格, VIEW类的父类选择CTreeView,则生成的程序中有个CLeftView,

CLeftView在程序中动态生成,因此取得该控件的方法是  CTreeCtrl& treeCtrl = GetTreeCtrl();

eg.

 

 1 void CLeftView::UpdateCameraList()

 2 {

 3     m_hWndLeftView = m_hWnd;

 4 

 5   CTreeCtrl& treeCtrl = GetTreeCtrl();

 6 

 7   treeCtrl.DeleteAllItems();

 8 

 9   CImageList Cil1, Cil2;

10   CCameraMonitorApp *pApp = (CCameraMonitorApp*)AfxGetApp();

11   Cil1.Create(16, 16, ILC_COLOR, 2, 2);

12   Cil1.Add(pApp->LoadIcon(IDI_ICON1));

13   Cil1.Add(pApp->LoadIcon(IDI_ICON2));

14 

15   treeCtrl.SetImageList(&Cil1, TVSIL_NORMAL);

16 

17   DWORD dwStyles = GetWindowLong(m_hWnd, GWL_STYLE);

18   dwStyles |= TVS_EDITLABELS | TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT;

19   SetWindowLong(m_hWnd, GWL_STYLE, dwStyles);

20 

21   TCHAR* arrFather[] = {_T("A栋"), _T("B栋"), _T("C栋"), _T("D栋"), _T("E栋"), _T("F栋"), _T("G栋"), _T("H栋"), _T("I栋")};

22   TCHAR* arrSon[3][2] = {{_T("11"), _T("12")}, {_T("21"), _T("22")}, {_T("31"), _T("32")}};  

25 

26    int i = 0;

27    int j = 0;

28 

29   HTREEITEM hRoot, hCur;

30   TV_INSERTSTRUCT TCItem;

31   TCItem.hParent = TVI_ROOT;

32   TCItem.hInsertAfter = TVI_LAST;

33   TCItem.item.pszText = _T("摄像头列表");

34   TCItem.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;

35   TCItem.item.lParam = 0;

36   TCItem.item.iImage = 0;

37   TCItem.item.iSelectedImage = 1;

38 

39   hRoot = treeCtrl.InsertItem(&TCItem); //根节点;

40 

41   CCamerasInfo::GetCameraCountNames(); //获得摄像头数量和名字; 

42   WCHAR wcName[512] = {0};

43 

44   for (i = 0; i < CCamerasInfo::s_nCameraCount; ++ i)

45   {

46     TCItem.hParent = hRoot;

47    TCItem.item.pszText = arrFather[i];

48     TCItem.item.lParam = (i + 1) * 10;

49     hCur = treeCtrl.InsertItem(&TCItem);

50     for (j = 0; j < 1; ++ j)

51     {

52       TCItem.hParent = hCur;

53 

54       //char* 转 wchar_t*

55       MultiByteToWideChar(CP_ACP, 0, (LPCSTR)CCamerasInfo::s_chCameraNameArray[i], 

56       sizeof(CCamerasInfo::s_chCameraNameArray[i]), wcName, sizeof(wcName));

57 

58       TCItem.item.pszText = wcName;

59       TCItem.item.lParam = (i + 1) * 10 + (j + 1);

60       treeCtrl.InsertItem(&TCItem);

61     }

62 

63     treeCtrl.Expand(hCur, TVE_EXPAND);

64   }

65   treeCtrl.Expand(hRoot, TVE_EXPAND);

66 

67 }

 

 

 ------------------------------------------------------------------------------------------------------------------------

 

屏幕坐标至客户区域坐标

 1 //Picture0控件双击事件;

 2 void CCameraMonitorView::OnStnDblclickVideo0()

 3 {

 4     // TODO: 在此添加控件通知处理程序代码;

 5 

 6     CRect rect;

 7     GetDlgItem(IDC_VIDEO0)->GetWindowRect(&rect);

 8     ScreenToClient(&rect);;

 9 

10 

11     CRect rect2;

12     GetDlgItem(IDC_VIDEO0)->GetClientRect(&rect2);

13     GetDlgItem(IDC_VIDEO0)->MapWindowPoints(FromHandle(m_hWnd), rect2);

14  

15 

16 }

 

 

 

 

  

 

  

你可能感兴趣的:(opencv)