opencv+directshow实现4个摄像头同步采集图像

时间:2022-05-05 04:00:37

基于网上许多人说到opencv打不开4个摄像头,事实果真如此么,记得哦:opencv是开源的,所以本作者我利用vs2013自己配置了一下opencv与directshow的开发环境,具体要怎么配置我就不详细讲了,上网搜一下就能找得到了,下面我详细讲一下如何将mfc和多线程与opencv和directshow结合实现4个摄像头同步采集图像,本作者正读大二,能力有限,有更好的方法也告诉我一下哈。


一.先在mfc上把界面先布局好如下图

opencv+directshow实现4个摄像头同步采集图像


将布局好的界面稍微改一下相关的属性值

opencv+directshow实现4个摄像头同步采集图像


1-1将显示摄像头区域的ID分别改为:
IDC_Camera1
IDC_Camera2
IDC_Camera3
IDC_Camera3


1-2将控制摄像头开关和关闭界面的控件ID分别改为:
IDC_Capture1
IDC_Capture2
IDC_Capture3
IDC_Capture4
IDCANCEL


二.在对话框的头文件里添加4个线程句柄和打开4个摄像头和一个关闭界面的响应函数:
opencv+directshow实现4个摄像头同步采集图像

//创建4个线程句柄
protected:
HANDLE h1;
HANDLE h2;
HANDLE h3;
HANDLE h4;
// 创建打开摄像头和关闭界面的映射函数
public:
afx_msg void OnBnClickedCancel();
afx_msg void OnBnClickedCapture1();
afx_msg void OnBnClickedCapture2();
afx_msg void OnBnClickedCapture3();
afx_msg void OnBnClickedCapture4();

三.在对话框的.cpp文件里的OnInitDialog()函数内初始化句柄

3.1定义一些全局变量来获取图片的句柄
opencv+directshow实现4个摄像头同步采集图像


//定义一些全局变量来获取图片的句柄
CRect rect1;
CRect rect2;
CRect rect3;
CRect rect4;

CDC* pDC1;
CDC* pDC2;
CDC* pDC3;
CDC* pDC4;

HDC hDC1;
HDC hDC2;
HDC hDC3;
HDC hDC4;

CWnd* pwnd1;
CWnd* pwnd2;
CWnd* pwnd3;
CWnd* pwnd4;

3.2OnInitDialog()函数内初始化句柄
opencv+directshow实现4个摄像头同步采集图像

//句柄的初始化
pwnd1 = GetDlgItem(IDC_Camera1);
pDC1 = pwnd1->GetDC();
hDC1 = pDC1->GetSafeHdc();
pwnd1->GetClientRect(&rect1);

pwnd2 = GetDlgItem(IDC_Camera2);
pDC2 = pwnd2->GetDC();
hDC2 = pDC2->GetSafeHdc();
pwnd2->GetClientRect(&rect2);

pwnd3 = GetDlgItem(IDC_Camera3);
pDC3 = pwnd3->GetDC();
hDC3 = pDC3->GetSafeHdc();
pwnd3->GetClientRect(&rect3);

pwnd4 = GetDlgItem(IDC_Camera4);
pDC4 = pwnd4->GetDC();
hDC4 = pDC4->GetSafeHdc();
pwnd4->GetClientRect(&rect4);

四.在对话框源文件里填加4个互斥对象并添加对应的响应函数:
opencv+directshow实现4个摄像头同步采集图像


    HANDLE hMutex1; //互斥对象1
CCameraDS camera1;//摄像头1
unsigned long _stdcall ThreadProc1(void* IpParameter){
while (1){
WaitForSingleObject(hMutex1, INFINITE);//等待互斥对象所以权
if (CCameraDS::CameraCount() >= 1)
{
camera1.OpenCamera(0, false, 320, 240);//打开第一个摄像头
while (1)
{
IplImage *pFrame1 = camera1.QueryFrame();//获取每一帧
CvvImage m_CvvImage;
m_CvvImage.CopyOf(pFrame1, 1);
if (true)
{
m_CvvImage.DrawToHDC(hDC1, &rect1);//将获取到的图像画到控件上
}
}
}
else
{
AfxMessageBox("无法打开摄像头1");
return -1;
}
Sleep(100);
ReleaseMutex(hMutex1);
}
return 0;

}
void CDirectshow_4CameraDlg::OnBnClickedCapture1()
{
CString Text;
GetDlgItem(IDC_Capture1)->GetWindowText(Text); //获取按键文本
if (Text == "摄像头1") //判断是否要打开摄像头
{
h1 = CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);//创建一个线程
hMutex1 = CreateEvent(NULL, FALSE, TRUE, "event1");
hMutex1 = CreateMutex(NULL, false, "hMutex1");
GetDlgItem(IDC_Capture1)->SetWindowText("关闭摄像头1");
}
else //当按键文本为"关闭摄像头1"时,执行关闭摄像头
{
TerminateThread(h1, 0); //终止线程1
camera1.CloseCamera(); //关闭摄像头
GetDlgItem(IDC_Capture1)->SetWindowText("摄像头1");//修改按键文本
}
}
//以下内容相同,省略注释
//摄像头2
HANDLE hMutex2;
CCameraDS camera2;
unsigned long _stdcall ThreadProc2(void* IpParameter){
while (1){
WaitForSingleObject(hMutex2, INFINITE);
if (CCameraDS::CameraCount() >= 2){
camera2.OpenCamera(1, false, 320, 240);
while (1)
{
IplImage *pFrame2 = camera2.QueryFrame();
CvvImage m_CvvImage2;
m_CvvImage2.CopyOf(pFrame2, 1);
if (true)
{
m_CvvImage2.DrawToHDC(hDC2, &rect2);
}
}
}
else
{
AfxMessageBox("无法打开摄像头2");
return -1;
}
Sleep(100);
ReleaseMutex(hMutex2);
}
return 0;
}


void CDirectshow_4CameraDlg::OnBnClickedCapture2()
{
CString Text;
GetDlgItem(IDC_Capture2)->GetWindowText(Text);
if (Text == "摄像头2")
{
h2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);
hMutex2 = CreateEvent(NULL, FALSE, TRUE, "event2");
hMutex2 = CreateMutex(NULL, false, "hMutex2");
GetDlgItem(IDC_Capture2)->SetWindowText("关闭摄像头2");
}
else
{
TerminateThread(h2, 0);
camera2.CloseCamera();
GetDlgItem(IDC_Capture2)->SetWindowText("摄像头2");
}
}

//摄像头3
HANDLE hMutex3;
CCameraDS camera3;
unsigned long _stdcall ThreadProc3(void* IpParameter){
while (1){
WaitForSingleObject(hMutex3, INFINITE);
if (CCameraDS::CameraCount() >= 3){
camera3.OpenCamera(2, false, 320, 240);
while (1)
{
IplImage *pFrame3 = camera3.QueryFrame();
CvvImage m_CvvImage3;
m_CvvImage3.CopyOf(pFrame3, 1);
if (true)
{
m_CvvImage3.DrawToHDC(hDC3, &rect3);
}
}
}
else
{
AfxMessageBox("无法打开摄像头3");
return -1;
}
Sleep(100);
ReleaseMutex(hMutex3);
}
return 0;
}


void CDirectshow_4CameraDlg::OnBnClickedCapture3()
{
CString Text;
GetDlgItem(IDC_Capture3)->GetWindowText(Text);
if (Text == "摄像头3")
{
h3 = CreateThread(NULL, 0, ThreadProc3, NULL, 0, NULL);
hMutex3 = CreateEvent(NULL, FALSE, TRUE, "event3");
hMutex3 = CreateMutex(NULL, false, "hMutex3");
GetDlgItem(IDC_Capture3)->SetWindowText("关闭摄像头3");
}
else
{
TerminateThread(h3, 0);
camera3.CloseCamera();
GetDlgItem(IDC_Capture3)->SetWindowText("摄像头3");
}
}

//摄像头4
HANDLE hMutex4;
CCameraDS camera4;
unsigned long _stdcall ThreadProc4(void* IpParameter){
while (1){
WaitForSingleObject(hMutex4, INFINITE);
if (CCameraDS::CameraCount() >= 4){
CCameraDS camera4;
camera4.OpenCamera(3, false, 320, 240);
while (1)
{
IplImage *pFrame4 = camera4.QueryFrame();
CvvImage m_CvvImage4;
m_CvvImage4.CopyOf(pFrame4, 1);
if (true)
{
m_CvvImage4.DrawToHDC(hDC4, &rect4);
}
}
}
else
{
AfxMessageBox("无法打开摄像头4");
return -1;
}
Sleep(100);
ReleaseMutex(hMutex4);
}
return h4 = CreateThread(NULL, 0, ThreadProc4, NULL, 0, NULL);
hMutex4 = CreateEvent(NULL, FALSE, TRUE, "event4");
hMutex4 = CreateMutex(NULL, false, "hMutex4");
GetDlgItem(IDC_Capture4)->SetWindowText("关闭摄像头4");
}
else
{
TerminateThread(h4, 0);
camera4.CloseCamera();
GetDlgItem(IDC_Capture4)->SetWindowText("摄像头4");
}
}
pture4)->SetWindowText("关闭摄像头4");
}
else
{
TerminateThread(h4, 0);
camera4.CloseCamera();
GetDlgItem(IDC_Capture4)->SetWindowText("摄像头4");
}
}

void CDirectshow_4CameraDlg::OnBnClickedCancel()
{
switch (CCameraDS::CameraCount()) //判断需要终止多少个线程
{
case 1:
{
TerminateThread(h1, 0);
break;
}
case 2:
{
TerminateThread(h1, 0);
TerminateThread(h2, 0);
break;
}
case 3:
{
TerminateThread(h1, 0);
TerminateThread(h2, 0);
TerminateThread(h3, 0);
break;
}
case 4:
{
TerminateThread(h1, 0);
TerminateThread(h2, 0);
TerminateThread(h3, 0);
TerminateThread(h4, 0);
break;
}
}
CDialogEx::OnCancel();
}

五.验证效果
opencv+directshow实现4个摄像头同步采集图像

六.总结
opencv+directshow打开4个摄像头的方法除了用互斥对象实现多线程同步外还可以用事件对象实现多线程同步

转载请标明出处:http://blog.csdn.net/lwqbrell/article/details/53954795