2016-11-22 8 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(); 
} 

И эта нить является частью класса камеры:

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)); 
    } 
} 

Мой вопрос:

Есть ли способ спасти меня от массивного изображения? Я использую этот сигнал для отображения изображения, потому что изображение должно отображаться в основном потоке, иначе изображение не будет отображаться. Но огромное количество сигналов заставит реакцию GUI замедляться.

Есть ли способ исправить это? Благодарю.

+0

Как определяются 'camera_queue_' и' display_queue_'? –

+0

@ AlgirdasPreidžius Я обновил сообщение. – Johnnylin

ответ

0
  1. Вы не хотите изменять графическую сцену каждый раз, когда изображение прибывает. Вы также можете использовать метод QLabel и его метод setPixmap или простой пользовательский виджет.

  2. Нет необходимости в очереди отображения: вас интересует только последний кадр. Если поток пользовательского интерфейса отстает от потока камеры, вы хотите удалить устаревшие кадры.

  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 или другими потоками графического интерфейса могут занять столько, сколько хотите, даже если камера производит изображения намного быстрее, чем может их потреблять, вы все равно будете показывать самое последнее изображение каждый раз, когда виджет получит возможность перекрасить себя. См. this answer для демонстрации этого факта. См. this answer для аналогичной демонстрации, которая работает на базовом сервере OpenGL с фиксированным контуром и использует графический процессор для масштабирования изображения.

+0

Спасибо за подробный ответ.Можете ли вы поделиться полным демо-кодом этой логики? – Johnnylin

+0

Я привел два полных примера. Если вы ищете что-то еще, дайте мне знать. –

+0

Структура DecodedImage - это самонастраиваемая структура, содержащая QImage, а также другую информацию. Могу ли я использовать сигнал для отправки, а также пользоваться неявным совместным использованием? – Johnnylin

0

Мьютексный подход должен быть быстрее, чем излучать сигналы Qt. Я однажды попытался пропустить сигналы Qt, используя STL condition_variable, и это сработало для меня отлично.

+0

Как вы можете заменить здесь сигнал ImageReady? – Johnnylin

+0

вместо emit imageReady(); – Seph

+0

Вместо: emit imageReady(); использовать мьютекс, изменить значение, при котором condition_variable ждет и использует cv.notify_one(); или cv.notify_all(); если ожидалось несколько потоков. – Seph

 Смежные вопросы

  • Нет связанных вопросов^_^