0
votes

I am developing an application in which I have to display a sequence of images and draw some rectangles on it. That's why I have to chosen to display my images in a QGraphicsScene/QGraphicsView.

Before showing you my code I will detail some of the functions I have developed :

void equalizeHist_16U_linear(Mat &img, int Tolmin, int Tolmax); 
and void equalizeHist_16U_linear(Mat &img, int Tolmin, int Tolmax, int x1, int x2, int y1, int y2); 

=> Does the linear transformation of an image (img), on all the image,or a specified part of the image (x1->x2, y1->y2),with an upper (Tolmax) and lower (Tolmin) tolerance

void equalizeHist_16U(Mat &img); and void equalizeHist_16U(Mat &img, int x1, int x2, int y1, int y2); 

=> Does the egalisation of a 16bits grayscale image, on a specified part of the image (x1->x2, y1->y2) or on all the image.

ZonePoints getZonePoints(); 

=> Function used to get the zone of the image on which transformations will be done (the points comes from mouse positions), returns a ZonePoints object (int xmin, xma, ymin, ymax)

QPixmap convert16uc1(const cv::Mat& source); 

=> Converts an OpenCV 16bits grayscale image (Mat) to a RGB32 QPixmap imgage

I have a folder containing numerous images labelled "ImageRaw_00000.png" to "ImageRaw_02999.png". My images are 16bits grayscale, I open them using OpenCV (as Qt cannot read 16bits images), I want to do some process on it (with OpenCV), convert them to QPixmap, add a rectangle (which represents the zone) on it and display them.

I also need to display 2 images at the same time (on the first I do the transformation on the zone given by "getZonePoints", on the second I display a rectangle corresponding to the zone points). My application looks like this : PrintScreen of the application

This is what I have so far :

Class declaration :

class FenetrePrinc : public QMainWindow 
{ 
    Q_OBJECT 
public: 
    explicit FenetrePrinc(QWidget *parent = 0); 
    ~FenetrePrinc();

    void compute_hist_16U(Mat &img, long* hist, bool cumul); 
    void equalizeHist_16U(Mat &img, int x1, int x2, int y1, int y2); 
    void equalizeHist_16U(Mat &img); 
    void equalizeHist_16U_linear(Mat &img, int Tolmin, int Tolmax, int x1, int x2, int y1, int y2); 
    void equalizeHist_16U_linear(Mat &img, int Tolmin, int Tolmax); 
    QPixmap convert16uc1(const cv::Mat& source);

public slots:

    virtual void openFile(); 
    virtual void start();

private:

    QString filename; 
    QGraphicsScene *scene_src, *scene_dst; 
    QGraphicsItem *item_rect; 
    QGraphicsItem *img_src, *img_dst; 
    VideoCapture sequence;

    Mat src, dst;

    bool transfo_lineaire; 
    bool coupling; 
    int Tolmin, Tolmax; 
    int impsec; 
    ZonePoints zpoints; 
};

Class definition :

FenetrePrinc::FenetrePrinc(QWidget *parent) : QMainWindow(parent), ui(new Ui::FenetrePrinc) 
{ 
    scene_src = new QGraphicsScene(); 
    img_src = scene_src->addPixmap(QPixmap("vide.jpg")); 
    img_src->setZValue(1); 
    ui->view_src->setScene(scene_src);

    scene_dst = new QGraphicsScene(); 
    img_dst = scene_dst->addPixmap(QPixmap("vide.jpg")); 
    img_dst->setZValue(1); 
    ui->view_dst->setScene(scene_dst); 
}

void FenetrePrinc::openFile()
{ 
    filename = QFileDialog::getOpenFileName(this, tr("Open Video file"), "C:/", tr("Image Files (*.png)"));

    sequence.open(filename.toStdString());

    if(!sequence.isOpened()) 
        ui->buttonStart->setEnabled(false); 
    else 
        ui->buttonStart->setEnabled(true); 
}

void FenetrePrinc::start() 
{ 
    char key; 
    for(;;) 
    { 
        sequence >> src; 
        sequence >> dst; 
        if(src.empty() || dst.empty()) 
        { 
            cout << "End of sequence" << endl; 
            break; 
        } zpoints = getZonePoints();

        key = (char)waitKey(1000);

        if(transfo_lineaire) 
        { 
            equalizeHist_16U_linear(src, Tolmin, Tolmax, zpoints.xmin, zpoints.xmax, zpoints.ymin, zpoints.ymax); 
            equalizeHist_16U_linear(dst, Tolmin, Tolmax); 
        } 
        else 
        { 
            equalizeHist_16U(src, zpoints.xmin, zpoints.xmax, zpoints.ymin, zpoints.ymax); 
            equalizeHist_16U(dst); 
        }

        scene_src->removeItem(img_src); 
        img_src = scene_src->addPixmap( convert16uc1(src)); 
        img_src->setZValue(1);

        scene_dst->removeItem(img_dst); 
        img_dst = scene_dst->addPixmap( convert16uc1(dst)); 
        img_dst->setZValue(1);

        scene_dst->removeItem(item_rect); 
        item_rect = scene_dst->addRect(zpoints.xmin, zpoints.ymin, zpoints.xmax-zpoints.xmin+1, zpoints.ymax-zpoints.ymin+1, QPen(Qt::red, 2, Qt::SolidLine)); 
        item_rect->setZValue(2);

        if(key == 'q' || key == 'Q' || key == 27) 
        break; 
    } 
}

I had done an working application with the same behavior in which I did not used Qt, I used OpenCV for the image processing and the display. I tried to use the same technique :

Mat img; 
VideoCapture sequence; 
sequence.open(filename.toStdString()); 
for(;;) 
{ 
    sequence >> img; 
    ... //Process images 
    ... //Display images 
} 

But it does not work. Only the last image and rectangle is displayed. I guess the technique is similar with Qt but I cannot find examples of code

Thank you in advance

1

1 Answers

1
votes

I found a way to do what I want, in the end it is really simple. I used a timer and signal/slot mechanism.

My new class declaration is the following :

class FenetrePrinc : public QMainWindow 
{ 
    Q_OBJECT 
public: 
    explicit FenetrePrinc(QWidget *parent = 0); 
    ~FenetrePrinc();

    void compute_hist_16U(Mat &img, long* hist, bool cumul); 
    void equalizeHist_16U(Mat &img, int x1, int x2, int y1, int y2); 
    void equalizeHist_16U(Mat &img); 
    void equalizeHist_16U_linear(Mat &img, int Tolmin, int Tolmax, int x1, int x2, int y1, int y2); 
    void equalizeHist_16U_linear(Mat &img, int Tolmin, int Tolmax); 
    QPixmap convert16uc1(const cv::Mat& source);

public slots:

    virtual void openFile(); 
    virtual void start();
    virtual void tick();              //Added a 'tick()' slot

private:

    QString filename; 
    QGraphicsScene *scene_src, *scene_dst; 
    QGraphicsItem *item_rect; 
    QGraphicsItem *img_src, *img_dst; 
    VideoCapture sequence, sequence2;  //Declared a 2nd sequence
                                       //If there's only 1 sequence, both images will be the same
    Mat src, dst;
    QTimer *timer            //Added a QTimer

    bool transfo_lineaire; 
    bool coupling; 
    int Tolmin, Tolmax; 
    int impsec; 
    ZonePoints zpoints; 
};

Class definition :

FenetrePrinc::FenetrePrinc(QWidget *parent) : QMainWindow(parent), ui(new Ui::FenetrePrinc) 
{ 
    scene_src = new QGraphicsScene(); 
    img_src = scene_src->addPixmap(QPixmap("vide.jpg")); 
    img_src->setZValue(1); 
    ui->view_src->setScene(scene_src);

    scene_dst = new QGraphicsScene(); 
    img_dst = scene_dst->addPixmap(QPixmap("vide.jpg")); 
    img_dst->setZValue(1); 
    ui->view_dst->setScene(scene_dst); 

    timer = new QTimer(this);     //timer instantiation
}

void FenetrePrinc::openFile()
{ 
    filename = QFileDialog::getOpenFileName(this, tr("Open Video file"), "C:/", tr("Image Files (*.png)"));

    sequence.open(filename.toStdString());
    sequence2.open(filename.toStdString());

    if(!sequence.isOpened()) 
        ui->buttonStart->setEnabled(false); 
    else 
        ui->buttonStart->setEnabled(true); 
}

void FenetrePrinc::start() 
{ 
    connect(timer, SIGNAL(timeout()), this, SLOT(tick()));
    timer->start(1000/impsec);
}

void FenetrePrinc::tick()
{
    char key;
    int i=0;

    sequence >> src;
    sequence2 >> dst;
    if(src.empty() || dst.empty())
    {
        stop_timer();
    }
    zpoints = mgaze->getZonePoints();
    zpoints = mgaze->applyOFFSET(zpoints);
    zpoints = mgaze->fixZonePoints(zpoints);

    if(transfo_lineaire)
    {
        equalizeHist_16U_linear(src, Tolmin, Tolmax, zpoints.xmin, zpoints.xmax, zpoints.ymin, zpoints.ymax);
        equalizeHist_16U_linear(dst, Tolmin, Tolmax);
    }
    else
    {
        equalizeHist_16U(src, zpoints.xmin, zpoints.xmax, zpoints.ymin, zpoints.ymax);
        equalizeHist_16U(dst);
    }

    scene_src->removeItem(img_src);
    img_src = scene_src->addPixmap(convert16uc1(src));
    img_src->setZValue(1);

    scene_dst->removeItem(img_dst);
    img_dst = scene_dst->addPixmap(convert16uc1(dst));
    img_dst->setZValue(1);

    scene_dst->removeItem(item_rect);
    item_rect = scene_dst->addRect(zpoints.xmin, zpoints.ymin, zpoints.xmax-zpoints.xmin+1, zpoints.ymax-zpoints.ymin+1, QPen(Qt::red, 2, Qt::SolidLine));
    item_rect->setZValue(2);
}

This works well, I just have to create a 'stop' slot in case I want to stop the video and that'll be good