使用opencv在MFC图片中显示视频时,GUI无法单击

时间:2015-03-27 10:12:07

标签: c++ opencv mfc

我正在使用MFC开发GUI,允许使用opencv显示视频。 GUI允许在GUI中自动调整控件的大小。它适用于视频显示。但是,视频打开时我有问题。当视频打开时,我无法单击该GUI中的任何控件或最小化按钮。我也无法在场景中单击或移动该GUI。如果我想关闭GUI,我必须在visual studio中Shift+ F5。我的代码会发生什么。 youtube中显示了这个问题。我想将我的代码显示如下。感谢

void CDialogResizeDlg::OnBnClickedButton1()
{
    // TODO: Add your control notification handler code here
        cv::VideoCapture cap(0);
    //VideoCapture cap("C:/Users/lsf-admin/Pictures/Camera Roll/video000.mp4");
    cv::vector<cv::Rect> faces;
    cv::Mat frame;
    cv::Mat graySacleFrame;
    cv::Mat original;
    if (!cap.isOpened())
    {

        return exit(1);
    }

    while (true)
    {
        cap >> frame;
        if (!frame.empty()){

        //clone from original frame
        original = frame.clone();
        }
        CDC* vDC;
        vDC = GetDlgItem(IDC_VIDEO)->GetDC();
        CRect rect;
        GetDlgItem(IDC_VIDEO)->GetClientRect(&rect);
        IplImage* image2=cvCloneImage(&(IplImage)original);
        DisplayIplImageToPictureBox(image2, vDC, rect); //img is IplImage* variable.
        ReleaseDC(vDC);
        if (cv::waitKey(30) >= 0) break;
    }
} 

您可以在here下载我的源代码(visual 2012+ opencv 2.4.10) enter image description here

3 个答案:

答案 0 :(得分:1)

您正在尝试在主应用程序主题中打开视频。这就是为什么您的Window消息处理(WindowProc())被阻止而GUI没有响应的原因。您应该在单独的帖子中打开视频。您可以使用AfxBeginThread()来执行此操作。所以它不会阻止主应用程序线程。另外请不要致电exit(1);如果您想要关闭GUI应用程序,请拨打WM_QUIT消息:

::PostQuitMessage(0);

在您的情况下,我只会显示错误消息并返回:

if (!cap.isOpened())
{
  AfxMessageBox(_T("Failed to load video file"));
  return;
}

答案 1 :(得分:0)

感谢Andrew Komiagin建议解决问题的方法。让我看看我的实现。我希望它可以帮助某人

首先,您必须添加Dlg标头中定义的内容

public:
static UINT StartThread (LPVOID param);

//structure for passing to the controlling function
typedef struct THREADSTRUCT
{
    CDialogResizeDlg*    _this;
        //you can add here other parameters you might be interested on
} THREADSTRUCT;

其次,您将线程功能中的视频显示写为

UINT CDialogResizeDlg::StartThread (LPVOID param)
{

THREADSTRUCT*    ts = (THREADSTRUCT*)param;

//here is the time-consuming process 
//which interacts with your dialog
AfxMessageBox ("Thread is started!");
// TODO: Add your control notification handler code here
cv::VideoCapture cap(0);
//VideoCapture cap("C:/Users/lsf-admin/Pictures/Camera Roll/video000.mp4");
cv::vector<cv::Rect> faces;
cv::Mat frame;
cv::Mat graySacleFrame;
cv::Mat original;
if (!cap.isOpened())
{

    AfxMessageBox(_T("Failed to load video file"));
    //return;
    //return exit(1);
}

while (true)
{
    cap >> frame;
    if (!frame.empty()){

    //clone from original frame
    original = frame.clone();
    }
    CDC* vDC;
    vDC =ts->_this->GetDlgItem(IDC_VIDEO)->GetDC();
    CRect rect;
    ts->_this->GetDlgItem(IDC_VIDEO)->GetClientRect(&rect);
    IplImage* image2=cvCloneImage(&(IplImage)original);
    ts->_this->DisplayIplImageToPictureBox(image2, vDC, rect); //img is IplImage* variable.
    ts->_this->ReleaseDC(vDC);
    if (cv::waitKey(30) >= 0) break;
}

//you can also call AfxEndThread() here
return 1;

}

Finnaly,你在onClick甚至

中调用上述函数
void CDialogResizeDlg::OnBnClickedButton1()
{
    THREADSTRUCT *_param = new THREADSTRUCT;
    _param->_this = this;
    AfxBeginThread (StartThread, _param);
}

现在有效。但是,它只能在1分钟内完成。之后,它有如下错误记忆问题 它image2没有免费。您可以致电cvReleaseImage(&image2);将其释放。

答案 2 :(得分:0)

为了不使用线程的小目的和快速结果:您可以在 mfc 项目中添加此功能。

bool peek_and_pump(void)
{
    MSG msg;

#if defined(_AFX) || defined(_AFXDLL)
    while(::PeekMessage(&msg,NULL,0,0,PM_NOREMOVE))
    {
        if(!AfxGetApp()->PumpMessage())
        {
            ::PostQuitMessage(0);
            return false;
        }
    }
    long lIdle = 0;
    while(AfxGetApp()->OnIdle(lIdle++))
        ;
#else
    if(::PeekMessage(&msg,NULL,0,0,PM_REMOVE))
    {
        ::TranslateMessage(&msg);
        ::DispatchMessage(&msg);
    }
#endif

    return true;
}

例如在 while(true){} 中调用此函数。

注意:使用此解决方案,您将在鼠标单击时停止循环。

但值得一试。