【问题标题】:Qt GUI thread is not responding when camera is streaming相机流式传输时 Qt GUI 线程没有响应
【发布时间】:2021-05-01 11:38:47
【问题描述】:

我正在使用 Basler 相机同时传输图像和分析图像。 该程序在子项目静态库中有摄像头类、图像检测类、图像采集类。用于在另一个 GUI 子项目中显示流的 GUI。但是,当程序运行时,GUI 在摄像机流式传输时一直“无响应”。我做错了什么,我需要在这种情况下实现 QThread 吗?如果我必须使用 QThread,我应该在主 GUI 线程中使用它还是在 Acquisition 中使用它? 从 Basler 相机中获取图像流的相机类:

class ICam: public QObject
    ,public Pylon::CImageEventHandler  {
    Q_OBJECT
    public:
        ICam(QObject *parent = nullptr);
        Mat GetOpencvImage();
        void StartContinuousGrabbing();
    signals:
        void OneImageFinishSignal();
    protected:
        virtual void OnImageGrabbed(Pylon::CInstantCamera& camera, const Pylon::CGrabResultPtr& grabResult);
    private:
        CBaslerUniversalInstantCamera m_camera;
};

void ICam::OnImageGrabbed(Pylon::CInstantCamera& camera, const Pylon::CGrabResultPtr& grabResult)
{
    clock.Lock();
    m_ptr_grab_result = grabResult;//Pass the captured image out
    m_bitmap_image.CopyImage(grabResult);
    clock.Unlock();
    emit OneImageFinishSignal();
}

Mat ICam::GetOpencvImage(){
    return cv::Mat(m_bitmap_image.GetHeight(), m_bitmap_image.GetWidth(), CV_8UC3, (uint8_t *)m_bitmap_image.GetBuffer());
}

void ICam::StartContinuousGrabbing(){
    m_camera.StartGrabbing( Pylon::GrabStrategy_OneByOne, Pylon::GrabLoop_ProvidedByInstantCamera);
}

Detect 类进行图像处理以检测虹膜眼:

class Detect : public QObject
{
    Q_OBJECT
    public:
       explicit Detect(QObject *parent = nullptr);
       cv::Point CalculateIrisOffset(cv::Mat img_input);
 };


cv::Point Detect::CalculateIrisOffset(cv::Mat img_input, bool show) {

    //Some Code to detect the iris

    return center_offset;
}

Acquisition 类包含一个ICam 类的icam 对象和一个Detect 类的detect 对象作为成员属性,它在抓取图像时从icam 对象接收信号,同时向GUI 发送信号以显示图像,调用Detect类的detect函数对图像进行处理:

class Acquisition: public QObject
{
    Q_OBJECT
    public:
        Acquisition (QObject *parent = nullptr);
        void StartContinuousGrabbing();
        Mat GetOpenCVImageFromICam();
    signals:
        void OneImageFinishSignal();
    private slots:
        void OneImageFinishSlot();
    private:
        ICam *icam;
        Detect *detect;
};
Acquisition:: Acquisition(QObject *parent) : QObject(parent)
                                                    ,icam(new ICam())
                                                    ,detect(new Detect())
{
    //connect(this->icam, SIGNAL(OneImageFinishSignal()), this, SIGNAL(OneImageFinishSignal()));
    connect(this->icam, SIGNAL(OneImageFinishSignal()), this, SLOT(OneImageFinishSlot()));
}

void Acquisition::OneImageFinishSlot(){
    cv::Mat img_input= icam-> GetOpencvImage ();
    cv::Point center_iris_offset;
    center_offset = detect->CalculateOffset(img_input, 0);
    emit(OneImageFinishSignal());
}
void Acquisition::StartContinuousGrabbing(){
    this->icam->StartContinuousGrabbing();
}
Mat CDLImageAcquisition::GetOpenCVImageFromICam(){
    return this->icam_->GetOpencvImage();
}

主 GUI 类:

class MainWizard : public QWizard
{
    Q_OBJECT
    public:
        explicit MainWizard(QWidget *parent = nullptr);
    private slots:
        void OneImageFinishSlot();
        void ShowImage(QWidget *object, Mat image);
    private:
        virtual bool eventFilter(QObject *watched, QEvent *event);
        Acquisition *acquisition;
};

MainWizard::MainWizard(QWidget *parent) :
    QWizard(parent),
    ui(new Ui::MainWizard), 
    acquisition(new Acquisition())
{
    ui->setupUi(this);
    ui->dock_cnt_continuous_grab->installEventFilter(this);//Install Qt's event filter
    acquisition ->StartContinuousGrabbing();
    connect(acquisition, SIGNAL(OneImageFinishSignal()), this, SLOT(OneImageFinishSlot()));
}

void MainWizard::OneImageFinishSlot(){
    ui->dock_cnt_continuous_grab->update();

}

bool MainWizard::eventFilter(QObject *watched, QEvent *event)
{
  if (watched == ui->dock_cnt_continuous_grab && event->type() == QEvent::Paint)
  {
      cv::Mat opencv_image = acquisition->GetOpenCVImageFromICam();
      this->ShowImage(ui->dock_cnt_continuous_grab, opencv_image);
  }
  return false;
}

void MainWizard::ShowImage(QWidget *widget, Mat image)
{
    m_mutex_lock.lock();
    QPainter painter(widget);

    QImage img((const unsigned char *)(image.data), image.cols, image.rows, QImage::Format_RGB888);

    QRectF target;
    target.setLeft(0);
    target.setTop(0);
    target.setSize(this->size());

    QRectF source;
    source.setLeft(0);
    source.setTop(0);
    source.setSize(img.size());

    QPixmap pixmap = QPixmap::fromImage(img);
    painter.drawImage(target,img, source);
    painter.drawPixmap(target, pixmap, source);
    m_mutex_lock.unlock();
}

【问题讨论】:

  • 你能附加MainWizard::ShowImage函数吗?
  • 是的,我只是将它附加到 MainWizard 类的末尾。
  • 您不必在仅在 GUI 线程中调用的私有插槽中使用 mutex。捕获事件时,您的事件过滤器未返回 true。你的画家画了image 和pixmap,图像就足够了。
  • 你为什么不直接update dock_cnt_continuous_grab 并在paintEvent 中绘制图像。
  • 谢谢,我按照你说的编辑了代码,但是 GUI 仍然没有响应

标签: c++ qt camera streaming qthread


【解决方案1】:

我终于通过一些更改解决了这个问题。我认为主要问题是抓取帧的大小太大,程序无法同时在 GUI 上分析和显示。初始抓取的图像大小为4000*3096*3。在通过信号发送之前,我将高度和宽度调整了 8 倍,并为图像处理的每个维度再次调整了 2 倍。此外,我发出携带新抓取图像的信号,而不是像以前那样发出空信号。在 GUI 方面,我使用 QGraphicsView 和 QGraphicsItems 而不是绘制事件过滤器。详细代码如下:

class ICam: public QObject
,public Pylon::CImageEventHandler  {
Q_OBJECT
public:
    ICam(QObject *parent = nullptr);
    void StartContinuousGrabbing();
signals:
    void OneImageFinishSignal(Mat img);
protected:
    virtual void OnImageGrabbed(Pylon::CInstantCamera& camera, const Pylon::CGrabResultPtr& grabResult);
private:
    CBaslerUniversalInstantCamera m_camera;
    CPylonImage pylon_image;
    CImageFormatConverter format_converter;// in constructor: format_converter.OutputPixelFormat = PixelType_BGR8packed;
};

void ICam::OnImageGrabbed(Pylon::CInstantCamera& camera, const Pylon::CGrabResultPtr& grabResult)
{
    clock.Lock();
    m_ptr_grab_result = grabResult;//Pass the captured image out
    m_bitmap_image.CopyImage(grabResult);
    format_converter.Convert(pylon_image, grabResult);
    clock.Unlock();

    cv::Mat img_resize;
    resize(opencv_image_, img_resize, cv::Size(opencv_image_.cols/8,
    opencv_image_.rows/8), 0, 0, cv::INTER_AREA);
    //Tell the gui that there is a new image available
    emit OneImageFinishSignal(img_resize.clone());
 }


void ICam::StartContinuousGrabbing(){
    m_camera.StartGrabbing( Pylon::GrabStrategy_OneByOne, Pylon::GrabLoop_ProvidedByInstantCamera);
}

采集类:

class Acquisition: public QObject
{
    Q_OBJECT
    public:
        Acquisition (QObject *parent = nullptr);
    signals:
        void OneImageFinishSignal(Mat img);
    private slots:
        void OneImageFinishSlot(Mat img_input);
    private:
        ICam *icam;
        Detect *detect;
};
Acquisition:: Acquisition(QObject *parent) : QObject(parent)
                                                ,icam(new ICam())
                                                ,detect(new Detect(2))//resize by 2
{

    connect(this->icam, SIGNAL(OneImageFinishSignal()), this, SLOT(OneImageFinishSlot()));
}

void Acquisition::OneImageFinishSlot(Mat img_input){
    cv::Point center_iris_offset;
    center_offset = detect->CalculateOffset(img_input, 0);
    emit OneImageFinishSignal(img_input);
}

主 GUI 类:

class MainWizard : public QWizard
{
    Q_OBJECT
    public:
        explicit MainWizard(QWidget *parent = nullptr);
        QImage PutImage(const Mat& mat);
    private slots:
        void OneImageFinishSlot(Mat img);
    private:
        QGraphicsScene* scene;
        QGraphicsPixmapItem* pixmap_item;
        QMutex m_mutex_lock;
        cv::Mat opencv_image;            
        Acquisition *acquisition;
};

MainWizard::MainWizard(QWidget *parent) :
    QWizard(parent),
    ui(new Ui::MainWizard), 
    acquisition(new Acquisition())
{
    ui->setupUi(this);
    scene = new QGraphicsScene(this);
    pixmap_item = new QGraphicsPixmapItem();
    scene->addItem(pixmap_item);

    acquisition ->StartContinuousGrabbing();
    connect(acquisition, SIGNAL(OneImageFinishSignal(Mat)), this, SLOT(OneImageFinishSlot(Mat)));
}

void MainWizard::OneImageFinishSlot(Mat img){
    m_mutex_lock.lock();
    pixmap_item->setPixmap(QPixmap::fromImage(PutImage(img)));
    scene->update();

    ui->gphv_continuous_grab->setScene(scene);
    ui->gphv_continuous_grab->update();

    m_mutex_lock.unlock();
}


/*Convert openCV image to QImage*/
QImage MainWizard::PutImage(const Mat& mat)
{
    // 8-bits unsigned, NO. OF CHANNELS=1
    if(mat.type()==CV_8UC1){
        // Set the color table (used to translate colour indexes to qRgb values)
        QVector<QRgb> colorTable;
        for (int i=0; i<256; i++)
            colorTable.push_back(qRgb(i,i,i));
        // Copy input Mat
        const uchar *qImageBuffer = (const uchar*)mat.data;
        // Create QImage with same dimensions as input Mat
        QImage img(qImageBuffer, mat.cols, mat.rows, QImage::Format_Indexed8);
        img.setColorTable(colorTable);
        return img;
    }
    // 8-bits unsigned, NO. OF CHANNELS=3
    if(mat.type()==CV_8UC3){
        // Copy input Mat
        const uchar *qImageBuffer = (const uchar*)mat.data;
        // Create QImage with same dimensions as input Mat
        QImage img(qImageBuffer, mat.cols, mat.rows, QImage::Format_RGB888);
        return img.rgbSwapped();
    }else{
        qDebug() << "ERROR: Mat could not be converted to QImage.";
        return QImage();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-19
    • 1970-01-01
    • 2021-08-07
    相关资源
    最近更新 更多