Continuous image stream QThread



  • Hi, my application continiuosly grab images in a while loop in the thread, and then emiting them to main thread. The main problem is that everythings goes well I can display image in separate window(not qt), if thread doesn't emit images. If thread starts to emit images camera start to lag and discarded some images.

    Camera thread looks as follow:

    class CameraObject : public QObject
    {
        Q_OBJECT
    public:
        explicit CameraObject()
        { // init camera, setup camera parameters 
         ...}
    
        ~CameraObject();
    
    public slots:
        Q_INVOKABLE void StateChanged(const bool &newState)
        {state = newState;}
    
        void ContinuousShot();
    
    signals:
        Q_INVOKABLE void NewImage(const QImage &im);
    
    private:
        //bool variable to check state
        // start and stop stream
        bool state;
        // camera object
        Camera_t *camera;
        QMutex mutex;
        int64_t width = 2048;
        int64_t height = 2048;
    };
    

    Method ContinuousShot:

    void  CameraObject : : ContinuousShot()   
    {
    try
        {
            // Create a pylon image.
            CPylonImage PylonImage;
            //camera -> Open();
            if( !camera->IsGrabbing())
            {
                camera->StartGrabbing(GrabStrategy_OneByOne);
            }
            // pointer to results
            while( camera->IsGrabbing() )
            {
                // smart pointer to grab results
                Pylon::CBaslerUsbGrabResultPtr  ptrGrabResult;
    
                if( !state )
                {
                  camera->StopGrabbing();
                }
                else
                {
                    // retrieving results from camera to smart pointer
                    if( camera->RetrieveResult(waitTime, ptrGrabResult, 
                                           TimeoutHandling_ThrowException))
                    {
                        // pylon image
                        Pylon::CPylonImage image;
    
                        cout<< "Number of skiped images"<<endl;
                        cout<< ptrGrabResult->GetNumberOfSkippedImages()<<endl;
    
                        if( ptrGrabResult.IsValid() && ptrGrabResult->GrabSucceeded())
                        {
                            // from smart pointer to image
                            image.AttachGrabResultBuffer( ptrGrabResult);
                            // converting to QImage
                            mutex.lock();
                            QImage qimage;
                            // grayscale image
                            qimage = QImage((uchar*) image.GetBuffer(), width, height, 
                                                                           QImage::Format_Indexed8);
                            //Pylon::DisplayImage(1,  image);
                            // emiting New Image
                            emit NewImage(qimage);
                            mutex.unlock();
                          }
                    }
                    else
                    {
                        cout<<("Results can't be retrived.");
                    }
                // end of else
                }
            // end of while
            }
        // end of try   
        }
        catch(GenICam::GenericException &e)
        {
           cout<<(e.GetDescription())<<endl;
        }
    }
    

    The main Thread (main window)

    namespace Ui {
    class ImageWindow;
    }
    
    class ImageWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit ImageWindow(QWidget *parent = 0) :QMainWindow(parent),
        ui(new Ui::ImageWindow)
    {
        // camera
        camera = new CameraObject;
        camera->moveToThread( &CameraThread);
    
        // handle results
        connect(camera, &CameraObject::NewImage,
                this, &ImageWindow::NewImage,Qt::QueuedConnection);
    
        // star cContinuousshoot
        connect(this, &ImageWindow::StartContinuousShot,
                camera, &CameraObject::ContinuousShot,Qt::QueuedConnection);
    
        // state changed
        connect(this, &ImageWindow::StateChanged,
                camera, &CameraObject::StateChanged,Qt::QueuedConnection);
    
        connect(&CameraThread, &QThread::finished,
               camera, &QObject::deleteLater);
    
         CameraThread.start();
    }
    
        ~ImageWindow();
    private slots:
    
        void on_StartButton_clicked()
        {
         emit StateChanged(true);
         emit StartContinuousShot();
        }
    
        void on_StopButton_clicked()
        {
         emit StateChanged(false);
        }
    
        void NewImage(const QImage &image)
        {
         qDebug()<<"New Image";
         Q_UNUSED(image);
        }
    
    signals:
       // user click button
       void StateChanged(const bool &click);
       // StartStream
       void StartContinuousShot();
    
    private:
        Ui::ImageWindow *ui;
        // Camera obj
        CameraObject *camera;
        QThread CameraThread;
    };
    

    I will be glad to any suggestions or to any help. Sorry for so long piece of code.


  • Lifetime Qt Champion

    Hi,

    You should benchmark your code to see where you are losing time.



  • Hi, after testing. I get that converting time is from 0.015 - 0.02 miliseconds, showing - from 1.45 to 1.5 miliseconds and emiting is from 0.04 to 0.05 miliseconds, retriving the results is from 0.02 miliseconds to 26 miliseconds(due to the documentation of camera, thread will wait until waitTime expirece or new data appear). However if I will comment display line, camera still will discard some data.

    void CameraObject::ContinuousShot()
    {
    ...
    t = (double)getTickCount();
    if( camera->RetrieveResult(waitTime, ptrGrabResult, 
                                           TimeoutHandling_ThrowException)){
    
    t = 1000*((double)getTickCount() - t)/getTickFrequency();
    cout<<"Time to retrive results: "<<t<<" miliseconds"<<endl;
    cout<<"\n";
    ...
    
    t = (double)getTickCount();
    qimage = QImage((uchar*)image.GetBuffer(),
                                      width,
                                       height,
                                       QImage::Format_Indexed8);
    t = 1000*((double)getTickCount() - t)/getTickFrequency();
    cout<<"Time to convert image: "<<t<<" miliseconds"<<endl;
    cout<<"\n";
    
    t = (double)getTickCount();
    Pylon::DisplayImage(1, image);
    t = 1000*((double)getTickCount() - t)/getTickFrequency();
    cout<<"Time to show image: "<<t<<" miliseconds"<<endl;
    cout<<"\n";
    
    
    // emiting New Image
    qDebug()<<"In emmitting id thread "<<QThread::currentThreadId();
     
    t = (double)getTickCount();
    emit NewImage(qimage);
    t = 1000*((double)getTickCount() - t)/getTickFrequency();
    cout<<"Time emit image: "<<t<<" miliseconds"<<endl;
    cout<<"\n";
    }
    

  • Lifetime Qt Champion

    Isn't there a callback alternative that doesn't need to block the thread ?



  • Unfortunately the most expensive operations Camera.Open() and Camera.Close happens in the constructor and destructor, in addition camera is a singleton so it can be only one instance of camera object. Thus I don't see approach to do it in calback way. However, after deleting macro Q_INVOKABLE, camera do not discard images anymore. But still I don't know the reason why it was happening. Thank you for the replies and help.


  • Lifetime Qt Champion

    I missed the fact that you put a Q_INVOKABLE in front of your signal. I don't know what kind of impact it can have.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.