Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Image display on thread in qt



  • I am trying to display my image. Here detect_images is a vector of vector contains Mat images, this myfunction is running on a thread triggered with QtConcurrent and trying to display on the thread itself. I am getting a black empty window displayed but not image.

    What wrong i was doing here and can we display image on thread.

    void MainWindow::myfunction(string name, int buf_id)
    {
        cv::putText(detect_images[buf_id][0],"4",cv::Point(40, detect_images[buf_id][0].rows / 2),cv::FONT_HERSHEY_DUPLEX,1.0,CV_RGB(118, 185, 0),2);
        string path = res_path+name;
        cv::imwrite(path, detect_images[buf_id][0]);                                            //writing images into folder
    
        QPixmap pixmap;                                                                                                          //display images
        QImage qimg(detect_images[buf_id][0].data, detect_images[buf_id][0].cols, detect_images[buf_id][0].rows, detect_images[buf_id][0].step, QImage::Format_RGB888);
        pixmap = QPixmap::fromImage(qimg.rgbSwapped());
        ui->label->setPixmap(pixmap);
        ui->label->setScaledContents(true);
        ui->label->show();
        qApp->processEvents();
        QThread::currentThread()->msleep(1000);
    
        detect_images[buf_id].clear();
        free_buff.push(buf_id);
    }


  • @rahult said in Image display on thread in qt:

    What wrong i was doing here and can we display image on thread.

    UI element must be updated in UI thread. This is what you are doing wrong!
    You can do it like this:

    // I suppose ui is a member of MainWindow class
    QTimer::singleShot(0, this, [this, pixmap](){
        ui->label->setPixmap(pixmap);
        ui->label->setScaledContents(true);
        ui->label->show();
    });
    


  • @KroMignon Thank you and yes ui is a member of MainWindow class

    I have added the snippet in my code. This myfunction will be called on a thread for sequence of images.

    void MainWindow::myfunction(string name, int buf_id)
    {
        cv::putText(detect_images[buf_id][0],"4",cv::Point(40, detect_images[buf_id][0].rows / 2),cv::FONT_HERSHEY_DUPLEX,1.0,CV_RGB(118, 185, 0),2);
        string path = res_path+name;
        cv::imwrite(path, detect_images[buf_id][0]);
    //    display_images.push(detect_images[buf_id][0]);
    
        QPixmap pixmap;
        QImage qimg(detect_images[buf_id][0].data, detect_images[buf_id][0].cols, detect_images[buf_id][0].rows, detect_images[buf_id][0].step, QImage::Format_RGB888);
        pixmap = QPixmap::fromImage(qimg.rgbSwapped());
    
        QTimer::singleShot(0, this, [this, pixmap](){
            ui->label->setPixmap(pixmap);
            ui->label->setScaledContents(true);
            ui->label->show();
        });
    
        QThread::currentThread()->msleep(100);
    )
    

    i could see only the last image is displayed



  • @KroMignon said in Image display on thread in qt:

    UI element must be updated in UI thread. This is what you are doing wrong!

    Out of curiosity i wanted to know...... as you said UI element must be updated in UI thread, i am maintaining a common buffer where i push the resultant images into it and wanted to display it on main thread. Below is how i followed, even though i get the same black empty window issue.
    Here i am calling function1 from my main() where my UI is declared, display_images is a queue globally declared.

    void MainWindow::display_func()
    {
        qDebug() << display_images.size();
        while(display_images.size())   
        {
            Mat img = display_images.front();
            QPixmap pixmap;
            QImage qimg(img.data, img.cols, img.rows, img.step, QImage::Format_RGB888);
            pixmap = QPixmap::fromImage(qimg.rgbSwapped());
            ui->label->setPixmap(pixmap);
            ui->label->setScaledContents(true);
            ui->label->show();
            qApp->processEvents();
            QThread::currentThread()->msleep(100);
            display_images.pop();
        }
    }
    
    void MainWindow::function1(int buf_id)
    {
        DIR *dir;
        struct dirent *ent;
        cv::Mat img;
        string img_path;
        dir = opendir(img_paths.c_str());
        while(1)
        {
            if(pro_buf.size() <= max_in_images)
            {
                if((ent = readdir(dir)) == NULL)
                {
                    closedir(dir);
                    terminate_th = 1;
                    break;
                }
                if(ent->d_name[0] == '.')
                {
                    continue;
                }
                img_path = img_paths + ent->d_name;
                img = cv::imread(img_path.c_str(), 1);
    
                pro_buf.push(img);
            }
            display_func();
        }
        return;
    }
    
    void MainWindow::myfunction(string name, int buf_id)
    {
        cv::putText(detect_images[buf_id][0],"4",cv::Point(40, detect_images[buf_id][0].rows / 2),cv::FONT_HERSHEY_DUPLEX,1.0,CV_RGB(118, 185, 0),2);
        string path = res_path+name;
        cv::imwrite(path, detect_images[buf_id][0]);
        display_images.push(detect_images[buf_id][0]);
        detect_images[buf_id].clear();
        free_buff.push(buf_id);
    }
    

  • Lifetime Qt Champion

    Hi,

    How exactly are you using threads in your application.

    From the code you are showing you seem to call UI related function within MainWindow trying to force the event loop to run and then blocking it.

    If you want to show your images one after the other, you should use a QTimer with a slot displaying the next image and stop the QTimer once your done. You can also use a single shot version within your slot to call it again and not do that after your buffer is empty.

    As for the black image, beside the threading issues you may have, are you sure that your images are not black before converting them to QPixmap ?


Log in to reply