2016-11-22 56 views
0

逃脫我有一個QThread的運行,試圖圖像從相機解碼:Qt的顯示實時圖像,從大量的信號

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類的一部分:

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響應變慢。

有沒有辦法解決這個問題?謝謝。

+0

如何定義'camera_queue_'和'display_queue_'? –

+0

@AlgirdasPreidžius我已更新帖子。 – Johnnylin

回答

0
  1. 您不希望每次圖像到達時都改變圖形場景。您也可以使用QLabel及其setPixmap方法或簡單的自定義小部件。

  2. 不需要顯示隊列:您只對最近的幀感興趣。如果UI線程滯後於攝像頭線程,則需要刪除過時的幀。

  3. 你,重新考慮是否camera_queue需要是併發隊列,因爲你從一個線程只能訪問它,以及是否需要該隊列的。

典型圖像生產者 - 消費者將工作如下:有相機的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縮放圖像。

+0

感謝您的詳細解答。你能分享一個完整的邏輯演示代碼嗎? – Johnnylin

+0

我已經鏈接了兩個完整的例子。如果你正在尋找別的東西,請告訴我。 –

+0

DecodedImage結構是一個自定義結構,它包含一個QImage以及其他信息。我可以使用信號發送並享受隱式共享嗎? – Johnnylin

0

互斥方法應該比發射Qt信號更快。我曾經嘗試過使用STL condition_variable跳過Qt信號,它對我來說工作得很好。

+0

如何在這裏替換imageReady信號? – Johnnylin

+0

而不是發出imageReady(); – Seph

+0

而不是:發出imageReady();使用互斥鎖,更改condition_variable等待的值並使用cv.notify_one();或cv.notify_all();如果有多個線程在等待。 – Seph