在 QGraphicsView/QGraphicsScene 上显示一系列图像

Posted

技术标签:

【中文标题】在 QGraphicsView/QGraphicsScene 上显示一系列图像【英文标题】:Display a sequence of images on a QGraphicsView/QGraphicsScene 【发布时间】:2015-05-26 11:49:27 【问题描述】:

我正在开发一个应用程序,我必须在其中显示一系列图像并在其上绘制一些矩形。这就是为什么我必须选择在 QGraphicsScene/QGraphicsView 中显示我的图像。

在向您展示我的代码之前,我将详细介绍我开发的一些功能:

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); 

=> 是否对图像(img)进行线性变换,对所有图像,或图像的指定部分(x1->x2,y1->y2),有上(Tolmax)和下(Tolmin) ) 容差

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

=> 是否在图像的指定部分 (x1->x2, y1->y2) 或整个图像上均衡化 16 位灰度图像。

ZonePoints getZonePoints(); 

=> 函数用于获取将在其上进行转换的图像区域(点来自鼠标位置),返回一个 ZonePoints 对象(int xmin, xma, ymin, ymax)

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

=> 将 OpenCV 16 位灰度图像 (​​Mat) 转换为 RGB32 QPixmap 图像

我有一个文件夹,其中包含许多标记为“ImageRaw_00000.png”到“ImageRaw_02999.png”的图像。我的图像是 16 位灰度的,我使用 OpenCV 打开它们(因为 Qt 无法读取 16 位图像),我想对其进行一些处理(使用 OpenCV),将它们转换为 QPixmap,在其上添加一个矩形(代表区域)并显示它们。

我还需要同时显示 2 个图像(第一个我对“getZonePoints”给出的区域进行转换,第二个我显示一个与区域点对应的矩形)。我的应用程序如下所示:PrintScreen of the application

这是我目前所拥有的:

类声明:

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; 
;

类定义:

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; 
     

我已经完成了一个与我没有使用 Qt 的行为相同的工作应用程序,我使用 OpenCV 进行图像处理和显示。我尝试使用相同的技术:

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

但它不起作用。仅显示最后一个图像和矩形。我猜该技术与 Qt 相似,但我找不到代码示例

提前谢谢你

【问题讨论】:

【参考方案1】:

我找到了一种方法来做我想做的事,最后它真的很简单。 我使用了计时器和信号/槽机制。

我的新班级声明如下:

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; 
;

类定义:

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);

这很好用,我只需要创建一个“停止”插槽,以防我想停止视频,这很好

【讨论】:

谢谢你 - 我提出了一个类似的问题,发现我做对了,但计时器做错了!

以上是关于在 QGraphicsView/QGraphicsScene 上显示一系列图像的主要内容,如果未能解决你的问题,请参考以下文章

NOIP 2015 & SDOI 2016 Round1 & CTSC 2016 & SDOI2016 Round2游记

秋的潇洒在啥?在啥在啥?

上传的数据在云端的怎么查看,保存在啥位置?

在 React 应用程序中在哪里转换数据 - 在 Express 中还是在前端使用 React?

存储在 plist 中的数据在模拟器中有效,但在设备中无效

如何在保存在 Mongoose (ExpressJS) 之前在模型中格式化数据