使用OpenCV从网络摄像头捕获视频时,QT GUI冻结 [英] QT GUI freezes when capturing video from webcam using OpenCV

查看:179
本文介绍了使用OpenCV从网络摄像头捕获视频时,QT GUI冻结的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Opencv进行一些实时视频处理.

I am using Opencv for some real-time video processing.

作为前端,我正在使用QT框架.

As a front-end I am using QT framework.

在我的GUI上,有一个输入图像窗口(映射到Label)和一个输出图像窗口(映射到另一个Label)以及3个按钮.一种是开始输入视频捕获,第二种是处理视频(代码尚未写入),第三种是退出.

On my GUI, I have an input image window (mapped to a Label) and an output image window (mapped to another Label) and 3 push buttons. One to Start input video capture, the second to process the video (code not written yet), and third to Exit.

我目前能够流式传输视频并将其显示在前端.但是,这锁定了我的GUI,无法退出.

I am currently able to stream my video and display it on the Front-end. But this locks my GUI and am unable to Exit.

我尝试使用QTimers(使用来自此和QT论坛的建议),但我的GUI仍然保持锁定状态.

I tried using QTimers (using suggestions from this and the QT forum), but my GUI still remains locked.

如果有人能指出我正确的方向,将不胜感激.

Would appreciate if someone can point my in the right direction.

下面是代码:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>   // for cvtColor
#include <iostream>
#include <QTimer>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_buttonCaptureVideo_clicked();

    void on_buttonExit_clicked();

public slots:
    virtual void doNextFrame() {repaint();}

private:
    Ui::MainWindow *ui;
    CvCapture *capture;          // OpenCV Video Capture Variable
    IplImage *frame;            // Variable to capture a frame of the input video
    cv::Mat source_image;     // Variable pointing to the same input frame
    cv::Mat dest_image;      // Variable to output a frame of the processed video
    QTimer *imageTimer;
};

#endif // MAINWINDOW_H

mainwindow.cpp

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
    cvReleaseImage(&frame);
    cvReleaseCapture(&capture);
}

void MainWindow::on_buttonCaptureVideo_clicked()
{
    // Set to 25 frames per second

    const int imagePeriod = 1000/25;   // ms

    imageTimer = new QTimer(this);

    imageTimer->setInterval(imagePeriod);

    connect(imageTimer, SIGNAL(timeout()), this, SLOT(doNextFrame()));

    // Use the default camera
    capture = cvCreateCameraCapture(-1);

    while(capture)
    {
    // Capture a frame
    frame = cvQueryFrame(capture);

    // Point to the same frame
    source_image = frame;

    // Resize Image
    cv::resize(source_image, source_image, cv::Size(128,128) , 0, 0);

    // Change to RGB format
    cv::cvtColor(source_image,source_image,CV_BGR2RGB);

    // Convert to QImage
    QImage qimg = QImage((const unsigned char*) source_image.data, source_image.cols, source_image.rows, QImage::Format_RGB888); // convert to QImage

    // Display on Input Label
    ui->labelInputVideo->setPixmap(QPixmap::fromImage(qimg));

    // Resize the label to fit the image
    ui->labelInputVideo->resize(ui->labelInputVideo->pixmap()->size());

    }
}

void MainWindow::on_buttonExit_clicked()
{

    connect(ui->buttonExit, SIGNAL(clicked()), qApp, SLOT(closeAllWindows()));
}

推荐答案

单击按钮时,

while(capture) { ... }

循环将永远运行,因为capture永远不会设置为NULL. 这意味着代码流永远不会离开循环,因此主线程无法处理其他任何事情,例如重新粉刷.

loop will run forever, as capture will never be set to NULL. This means the code flow never leaves your loop and thus the main thread cannot process anything else, like e.g. repainting.

QTimer将发出其timeout()信号,但它们将作为事件放置在Qt的事件队列中.只要您的on_buttonCaptureVideo_clicked()方法正在运行,这些事件就不会被处理.

The QTimer will emit its timeout() signals, but they will be placed as Events in Qt's Event Queue. As long as your on_buttonCaptureVideo_clicked() method is running, those Events will not be processed.

以下是我的工作建议:

此代码:

// Set to 25 frames per second  
const int imagePeriod = 1000/25;   // ms        
imageTimer = new QTimer(this);        
imageTimer->setInterval(imagePeriod);        
connect(imageTimer, SIGNAL(timeout()), this, SLOT(doNextFrame()));   
// Use the default camera            
capture = cvCreateCameraCapture(-1);  

属于MainWindow的构造函数,因为您只想设置一次.当用户第二次,第三次等单击该按钮时,无需再次执行此操作.

belongs into the constructor of MainWindow as you want to set that up one time only. There is no need to do it again when the user clicks the button the second, third, etc time.

while循环中的代码应放入doNextFrame()插槽(没有while构造).

The code which is within your while loop should go into the doNextFrame() slot (without the while construct).

然后您的按钮将只可用

imageTimer->start();

,然后例如做

imageTimer->stop();

再次单击它.

示例代码:

void MainWindow::on_buttonCaptureVideo_clicked()
{
    if( imageTimer->isActive() )
    {
        imageTimer->stop();
    }
    else
    {
        imageTimer->start();
    }
}


如果这样做,会发生什么?


What will happen if you do that?

单击该按钮时,将从GUI线程调用on_buttonCaptureVideo_clicked()单击的插槽,计时器将启动,该方法几乎立即返回.
现在,GUI线程是免费的,并且能够处理重绘等.
从那时起,计时器将每40ms发送一次timeout()信号.只要GUI线程空闲,它将处理此信号并调用您的doNextFrame插槽.
该插槽将捕获下一帧,并在完成后返回.完成后,GUI线程将能够再次处理其他事件(例如重新绘制).
再次单击该按钮,计时器将停止,并且不会发送新的timeout()事件.如果单击按钮后仍然看到几帧,则可能意味着计时器事件的发送速度比处理事件的速度快.

When you click the button, your on_buttonCaptureVideo_clicked() clicked slot will be called from the GUI thread, the timer will be started, and the method will return almost instantly.
Now the GUI thread is free and able to handle repaints etc.
From that point on, the timer will be sending timeout() signals every 40ms. Whenever the GUI thread is free, it will handle this signal and call your doNextFrame slot.
This slot will capture the next frame and return when it is done. When it is done, the GUI thread will be able to process other Events (e.g. repaint) again.
As soon as you click the button again, the timer will stop, and no new timeout() events will be sent. If you still see a couple of frames after the button has been clicked, this could mean that the timer events were sent faster than they could be processed.

这篇关于使用OpenCV从网络摄像头捕获视频时,QT GUI冻结的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆