Reputation: 115
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
Upvotes: 0
Views: 1368
Reputation: 115
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
Upvotes: 1