Qt显示实时图像,从大量信号中逃脱

Qt showing live image, escape from massive signals

我有一个 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();
}

并且此线程是相机的一部分 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响应变慢。

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

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

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

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

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

典型的图像生产者-消费者的工作方式如下:Camera class 与相机接口,并在每次获得新帧时发出 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 线程操作可以根据您的意愿进行,即使相机生成图像的速度比显示器消耗图像的速度快得多,您仍然会每次显示最新的图像小部件有机会重新绘制自己。有关在固定管道 OpenGL 后端上运行并使用 GPU 缩放图像的类似演示,请参阅 for a demonstration of that fact. See