【问题标题】:GUI cannot click when Display video in MFC picture using opencv使用opencv在MFC图片中显示视频时GUI无法点击
【发布时间】:2015-03-27 10:12:06
【问题描述】:

我正在使用 MFC 开发一个允许使用 opencv 显示视频的 GUI。 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)

【问题讨论】:

    标签: c++ opencv mfc


    【解决方案1】:

    您正试图在主应用程序线程中打开视频。这就是您的 Window 消息处理 (WindowProc()) 被阻止且 GUI 没有响应的原因。您应该在单独的线程中打开您的视频。你可以使用AfxBeginThread() 来做到这一点。所以它不会阻塞主应用程序线程。另外请不要拨打exit(1); 如果您想关闭GUI 应用程序,您应该拨打WM_QUIT 发送消息:

    ::PostQuitMessage(0);
    

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

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

    【讨论】:

    • 感谢您的回答。但是,我没有 AfxBeginThread 方面的专家。您能否编辑我的申请并上传完整的答案。对我来说更好理解。
    • 我不得不说你的代码需要重大的重构。如果您出于教育原因自己做,那就更好了。我们可以在 stackoverflow 帮助您选择正确的方向。阅读 AfxBeginThread() 上的 MSDN 以继续前进。
    • 谢谢。我解决了。我想添加我的实现。我希望它可以帮助某人
    • 但是,我只在 1 分钟内运行它。之后,它显示内存问题。有参数需要免费吗?
    • 您需要对 OpenCV 的东西进行适当的异常处理。在 OpenCV 调用周围使用 try/catch。详情请参阅 OpenCV 文档。
    【解决方案2】:

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

    首先,你必须添加Dlg头中定义的theread

    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;
    

    }

    最后,你甚至在 onClick 中调用了上面的函数

    void CDialogResizeDlg::OnBnClickedButton1()
    {
        THREADSTRUCT *_param = new THREADSTRUCT;
        _param->_this = this;
        AfxBeginThread (StartThread, _param);
    }
    

    现在可以了。但是,它只能在 1 分钟内起作用。之后,它有如下错误内存问题 它是image2 没有免费。您可以拨打cvReleaseImage(&amp;image2);释放它。

    【讨论】:

      【解决方案3】:

      不使用线程的小目的和快速结果:您可以在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){} 中调用此函数。

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

      但值得一试。

      【讨论】:

        猜你喜欢
        • 2016-07-21
        • 2012-11-11
        • 1970-01-01
        • 2012-01-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-04
        相关资源
        最近更新 更多