Qt显示实时图像,逃离大量信号

时间:2016-11-22 16:25:54

标签: c++ qt tbb

我正在运行QThread,试图从相机解码图像:

struct ImageQueue
{
    enum {NumItems = 5};
    tbb::concurrent_bounded_queue<DecodedImage> camera_queue_; // decoded image
    tbb::concurrent_bounded_queue<DecodedImage> display_queue_; // widget display image
    ImageQueue(int camid){camera_queue_.set_capacity(NumItems);display_queue_.set_capacity(NumItems)}
};

std::shared_ptr<ImageQueue> camera_queue;

void Worker::process()
{

    while(1)
    {
        if(quit_)
            break;

        DecodedImage tmp_img;
        camera_queue->camera_queue_.pop(tmp_img);
        camera_queue->display_queue_.push(tmp_img);
        emit imageReady();

    }

    emit finished();
}

此线程是Camera Class的一部分:

void Camera::Start()
{
        work_ = new Worker();
        work_->moveToThread(workerThread_);
        QObject::connect(workerThread_, &QThread::finished, work_, &QObject::deleteLater);
        QObject::connect(this, &Camera::operate, work_, &Worker::process);
        QObject::connect(this, &Camera::stopDecode, work_, &Worker::stop);
        QObject::connect(work_, &Worker::imageReady, this, &Camera::DisplayImage);
        workerThread_->start();
        emit operate();
}

在小部件显示方面:

class CVImageWidget : public QGraphicsView
{
    Q_OBJECT
public:
    void display(DecodedImage& tmp_img);
    ~CVImageWidget();
private:
    QGraphicsScene *scene_;
};

CVImageWidget widget;


void Camera::DisplayImage()
{
    if(camera_queue != nullptr)
    {
        DecodedImage tmp_img;
        camera_queue->display_queue_.pop(tmp_img);
        widget->display(tmp_img);
    }
}


void CVImageWidget::display(DecodedImage& tmp_img)
{
    if(!tmp_img.isNull())
    {
        scene_->clear();
        scene_->addPixmap(QPixmap::fromImage(tmp_img));
    }
}

我的问题是:

有没有办法让我免受巨大的imageReady信号的影响?我使用此信号显示图像,因为图像必须在主线程中显示,否则图像将不会显示。但是大量的信号会使GUI响应变慢。

有没有办法解决这个问题?谢谢。

2 个答案:

答案 0 :(得分:0)

互斥方法应该比发出Qt信号更快。我曾经尝试使用STL condition_variable跳过Qt信号,它对我来说效果很好。

答案 1 :(得分:0)

  1. 每次图像到达时,您都不希望改变图形场景。您也可以使用QLabel及其setPixmap方法或简单的自定义小部件。

  2. 不需要显示队列:您只对最近的帧感兴趣。如果UI线程滞后于相机线程,则需要删除过时的帧。

  3. 如果camera_queue需要是并发队列,您必须重新考虑,因为您只从一个线程访问它,以及您是否需要该队列。

  4. 典型的图像生成者 - 消费者将按如下方式工作:Camera类与相机接口,并在每次获得新帧时发出hasFrame(const DecodedImage &)信号。不需要队列:任何侦听对象线程的事件队列都已经是并发队列。

    显示小部件只接受要显示的图像:

    class Display : public QWidget {
      Q_OBJECT
      DecodedImage m_image;
    protected:
      void paintEvent(QPaintEvent *event) {
        QPainter painter{this};
        painter.drawImage(0, 0, m_image);
      }
    public:
      Display(QWidget *parent = nullptr) : QWidget{parent} {}
      QSize sizeHint() const override { return m_image.size(); }
      Q_SLOT void setImage(const QImage & image) {
        auto oldSize = m_image.size();
        m_image = image;
        if (oldSize != m_image.size())
          updateGeometry();
        update();
      }
    };
    

    然后,您将图像源连接到显示小部件,然后您就完成了。 paintEvent或其他GUI线程操作可以按照您的意愿进行,即使相机生成的图像比显示器消耗它们的速度快得多,每次小部件获取时,您仍然会显示最新的图像重塑自己的机会。请参阅this answer以了解该事实。请参阅this answer,了解适用于固定管道OpenGL后端的类似演示,并使用GPU缩放图像。