《OpenCV3和Qt5计算机视觉应用开发》学习笔记第5章

本章将开始学习Qt的图形视图框架中大多数最重要的类,QGraphicsScene、QGraphicsItem、QGraphicsView。在本章中将学习使用QGraphicsScene在场景中绘制图形,使用QGraphicsItem及其子类管理图形对象元素,使用QGraphicsView查看QGraphicsScene,同时开发放大、缩小以及其他图像编辑和查看的功能。最后完善第3章中的Computer_Vision项目。

场景,即QGraphicsScene,用于管理对象元素或QGraphicsItem(及其子类)的实例,包含它们,并将事件(如鼠标单击等)传递给对象元素。
视图,即QGraphicsView控件,用于可视化和显示QGraphicsScene的内容,还负责将事件传递给QGraphicsScene。这里需要重点注意,QGraphicsScene和QGraphicsView各有不同的坐标系统。可以想到,如果放大、缩小或经历不同的类似变换,场景中的某个位置将不会相
同。QGraphicsScene和QGraphicsView都提供了转换位置值的函数,以便相互适应。

对象元素,即QGraphicsItem子类的实例,是QGraphicsScene包含的对象元素。这些对象元素可以是线、矩形、图像、文本等。

下面我们从一个简单的Graphics_Viewer例子开始。
1.首先我们新建一个Graphics_Viewer项目,托一个QGraphicsView控件,对界面进行网格布局。
在MainWindow类中添加两个函数用于托拽图片


void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
    QStringList acceptedFileTypes;
    acceptedFileTypes.append("jpg");
    acceptedFileTypes.append("png");
    acceptedFileTypes.append("bmp");

    if (event->mimeData()->hasUrls() && event->mimeData()->urls().count() == 1)
    {

        QFileInfo file(event->mimeData()->urls().at(0).toLocalFile());
        if(acceptedFileTypes.contains(file.suffix().toLower()))
        {
            event->acceptProposedAction();
        }
    }
}

void MainWindow::dropEvent(QDropEvent *event)
{
    QPoint viewPos = ui->graphicsView->mapFromParent(event->pos());
    QPointF sceneDropPos = ui->graphicsView->mapToScene(viewPos);

    QFileInfo file(event->mimeData()->urls().at(0).toLocalFile());
    QPixmap pixmap;
    if(pixmap.load(file.absoluteFilePath()))
    {
        QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap);
        item->setPos(sceneDropPos);
        item->setFlag(QGraphicsItem::ItemIsSelectable);
        item->setAcceptedMouseButtons(Qt::LeftButton);
        scene.addItem(item);
    }
    else
    {
        QMessageBox::critical(this, tr("Error"), tr("The image file cannot be read!"));
    }
}

2.自定义一个QEnhancedGraphicsView继承QGraphicsView,添该类添加滚动鼠标放大缩小功能void wheelEvent(QWheelEvent *event);

重写mousePressEvent(QMouseEvent *event);函数添加右键菜单功能。
右键菜单包含
void clearAll(bool);         
void clearSelected(bool);    
void noEffect(bool);         
void blurEffect(bool);       
void dropShadowEffect(bool);
void colorizeEffect(bool);   
void customEffect(bool);     


QGraphicsEffect是Qt中所有图形效果的基类。它的子类包括 QGraphicsBlurEffect, QGraphicsColorizeEffect, QGraphicsDropShadowEffect, QGraphicsOpacityEffect
当然也可以对其进行子类化,创建自己的图形效果或滤波器,现在自定义一个QCustomGraphicsEffect继承QGraphicsEffect,重写draw函数,把图片转成灰度图

void QCustomGraphicsEffect::draw(QPainter *painter)
{
    QImage image;
    image = sourcePixmap().toImage();
    image = image.convertToFormat(QImage::Format_Grayscale8);

    for(int i = 0; i < image.sizeInBytes(); i++)
    {
        image.bits()[i] = image.bits()[i] < 100 ? 0 : 255;
    }
    painter->drawPixmap(0,0,QPixmap::fromImage(image));
}

完整的代码如下

工程 文件


QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = Graphics_Viewer
TEMPLATE = app

# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

#win环境配置
win32:{
    CONFIG(debug, debug|release){
        DESTDIR += $$PWD/../bin/win64d
        LIBS += -L$$PWD/../lib/win64d -lopencv_world480d
    }else{
        DESTDIR += $$PWD/../bin/win64
        LIBS += -L$$PWD/../lib/win64 -lopencv_world480
    }
}

INCLUDEPATH += ../Include

SOURCES += \
        main.cpp \
        mainwindow.cpp \
    qcustomgraphicseffect.cpp \
    qenhancedgraphicsview.cpp

HEADERS += \
        mainwindow.h \
    qcustomgraphicseffect.h \
    qenhancedgraphicsview.h

FORMS += \
        mainwindow.ui
qcustomgraphicseffect.h文件
#ifndef QCUSTOMGRAPHICSEFFECT_H
#define QCUSTOMGRAPHICSEFFECT_H

#include <QObject>
#include <QGraphicsEffect>
#include <QPainter>

class QCustomGraphicsEffect : public QGraphicsEffect
{
    Q_OBJECT
public:
    explicit QCustomGraphicsEffect(QObject *parent = nullptr);

protected:
    void draw(QPainter *painter);

signals:

public slots:
};

#endif // QCUSTOMGRAPHICSEFFECT_H

qcustomgraphicseffect.cpp文件

#include "qcustomgraphicseffect.h"

QCustomGraphicsEffect::QCustomGraphicsEffect(QObject *parent)
    : QGraphicsEffect(parent)
{

}

void QCustomGraphicsEffect::draw(QPainter *painter)
{
    QImage image;
    image = sourcePixmap().toImage();
    image = image.convertToFormat(QImage::Format_Grayscale8);

    for(int i = 0; i < image.sizeInBytes(); i++)
    {
        image.bits()[i] = image.bits()[i] < 100 ? 0 : 255;
    }
    painter->drawPixmap(0,0,QPixmap::fromImage(image));
}
qenhancedgraphicsview.h文件
#ifndef QENHANCEDGRAPHICSVIEW_H
#define QENHANCEDGRAPHICSVIEW_H

#include <QWidget>
#include <QGraphicsView>
#include <QWheelEvent>
#include <QMouseEvent>
#include <QtMath>
#include <QContextMenuEvent>
#include <QMenu>
#include <QGraphicsItem>
#include <QDebug>
#include <QGraphicsEffect>
#include "qcustomgraphicseffect.h"

class QEnhancedGraphicsView : public QGraphicsView
{
    Q_OBJECT
public:
    explicit QEnhancedGraphicsView(QWidget *parent = nullptr);

protected:
    void wheelEvent(QWheelEvent *event);
    void mousePressEvent(QMouseEvent *event);

signals:

private slots:
    void clearAll(bool);
    void clearSelected(bool);
    void noEffect(bool);
    void blurEffect(bool);
    void dropShadowEffect(bool);
    void colorizeEffect(bool);
    void customEffect(bool);

private:
    QPointF sceneMousePos;

};

#endif // QENHANCEDGRAPHICSVIEW_H

qenhancedgraphicsview.cpp文件

#include "qenhancedgraphicsview.h"

QEnhancedGraphicsView::QEnhancedGraphicsView(QWidget *parent)
    : QGraphicsView(parent)
{

}

void QEnhancedGraphicsView::wheelEvent(QWheelEvent *event)
{
    if (event->orientation() == Qt::Vertical)
    {
        double angleDeltaY = event->angleDelta().y();
        double zoomFactor = qPow(1.0015, angleDeltaY);
        scale(zoomFactor, zoomFactor);
        if(angleDeltaY > 0)
        {
            this->centerOn(sceneMousePos);
            sceneMousePos = this->mapToScene(event->pos());
        }
        this->viewport()->update();
        event->accept();
    }
    else
    {
        event->ignore();
    }
}

void QEnhancedGraphicsView::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::RightButton)
    {
        QMenu menu;
        QAction *clearAllAction = menu.addAction("Clear All");
        connect(clearAllAction, SIGNAL(triggered(bool)), this, SLOT(clearAll(bool)));

        QAction *clearSelectedAction = menu.addAction("Clear Selected");
        connect(clearSelectedAction, SIGNAL(triggered(bool)), this, SLOT(clearSelected(bool)));

        QAction *noEffectAction = menu.addAction("No Effect");
        connect(noEffectAction, SIGNAL(triggered(bool)), this, SLOT(noEffect(bool)));

        QAction *blurEffectAction = menu.addAction("Blur Effect");
        connect(blurEffectAction, SIGNAL(triggered(bool)), this, SLOT(blurEffect(bool)));

        QAction *dropShadEffectAction = menu.addAction("Drop Shadow Effect");
        connect(dropShadEffectAction, SIGNAL(triggered(bool)), this, SLOT(dropShadowEffect(bool)));

        QAction *colorizeEffectAction = menu.addAction("Colorize Effect");
        connect(colorizeEffectAction, SIGNAL(triggered(bool)), this, SLOT(colorizeEffect(bool)));

        QAction *customEffectAction = menu.addAction("Custom Effect");
        connect(customEffectAction, SIGNAL(triggered(bool)), this, SLOT(customEffect(bool)));

        menu.exec(event->globalPos());
        event->accept();
    }
    else
    {
        QGraphicsView::mousePressEvent(event);
    }
}

void QEnhancedGraphicsView::clearAll(bool)
{
    scene()->clear();
}

void QEnhancedGraphicsView::clearSelected(bool)
{
    while(scene()->selectedItems().count() > 0)
    {
        delete scene()->selectedItems().at(0);
        scene()->selectedItems().removeAt(0);
    }
}

void QEnhancedGraphicsView::noEffect(bool)
{
    foreach(QGraphicsItem *item, scene()->selectedItems())
    {
        item->setGraphicsEffect(Q_NULLPTR);
    }
}

void QEnhancedGraphicsView::blurEffect(bool)
{
    foreach(QGraphicsItem *item, scene()->selectedItems())
    {
        item->setGraphicsEffect(new QGraphicsBlurEffect(this));
    }
}

void QEnhancedGraphicsView::dropShadowEffect(bool)
{
    foreach(QGraphicsItem *item, scene()->selectedItems())
    {
        item->setGraphicsEffect(new QGraphicsDropShadowEffect(this));
    }
}

void QEnhancedGraphicsView::colorizeEffect(bool)
{
    foreach(QGraphicsItem *item, scene()->selectedItems())
    {
        item->setGraphicsEffect(new QGraphicsColorizeEffect(this));
    }
}

void QEnhancedGraphicsView::customEffect(bool)
{
    foreach(QGraphicsItem *item, scene()->selectedItems())
    {
        item->setGraphicsEffect(new QCustomGraphicsEffect(this));
    }
}
mainwindow.h文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include <QGraphicsScene>
#include <QGraphicsItem>
#include <QPixmap>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QMimeData>
#include <QFileInfo>
#include <QMessageBox>
#include <QDebug>

#include "qcustomgraphicseffect.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

protected:
    void dragEnterEvent(QDragEnterEvent *event);
    void dropEvent(QDropEvent *event);

private:
    Ui::MainWindow *ui;
    QGraphicsScene scene;

};

#endif // MAINWINDOW_H

mainwindow.cpp文件

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->setAcceptDrops(true);
    ui->graphicsView->setAcceptDrops(false);
    ui->graphicsView->setScene(&scene);

    ui->graphicsView->setInteractive(true);
    ui->graphicsView->setDragMode(QGraphicsView::RubberBandDrag);
    ui->graphicsView->setRubberBandSelectionMode(Qt::ContainsItemShape);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
    QStringList acceptedFileTypes;
    acceptedFileTypes.append("jpg");
    acceptedFileTypes.append("png");
    acceptedFileTypes.append("bmp");

    if (event->mimeData()->hasUrls() && event->mimeData()->urls().count() == 1)
    {

        QFileInfo file(event->mimeData()->urls().at(0).toLocalFile());
        if(acceptedFileTypes.contains(file.suffix().toLower()))
        {
            event->acceptProposedAction();
        }
    }
}

void MainWindow::dropEvent(QDropEvent *event)
{
    QPoint viewPos = ui->graphicsView->mapFromParent(event->pos());
    QPointF sceneDropPos = ui->graphicsView->mapToScene(viewPos);

    QFileInfo file(event->mimeData()->urls().at(0).toLocalFile());
    QPixmap pixmap;
    if(pixmap.load(file.absoluteFilePath()))
    {
        QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap);
        item->setPos(sceneDropPos);
        //设置对象可选中,可托动
        item->setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable);
        item->setAcceptedMouseButtons(Qt::LeftButton);
        scene.addItem(item);
    }
    else
    {
        QMessageBox::critical(this, tr("Error"), tr("The image file cannot be read!"));
    }
}

main.cpp文件

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}

运行效果:

 computer_vision项目添加插件,该项目分两个子项目,一个是插件项目,一个是应用项目,具体代码如下:

computer_vision.pro

TEMPLATE = subdirs
SUBDIRS += \
    mainapp \
    template_plugin

插件项目

template_plugin.pro


QT       += widgets

TARGET = Template_Plugin
TEMPLATE = lib

CONFIG += plugin

DEFINES += TEMPLATE_PLUGIN_LIBRARY

# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

#win环境配置
win32:{
    CONFIG(debug, debug|release){
        #插件生成目录
        DESTDIR += $$PWD/../../bin/win64d/cvplugins
        LIBS += -L$$PWD/../../lib/win64d -lopencv_world480d
    }else{
        DESTDIR += $$PWD/../../bin/win64/cvplugins
        LIBS += -L$$PWD/../../lib/win64 -lopencv_world480
    }
}

INCLUDEPATH += ../../Include


INCLUDEPATH += ../cvplugininterface

SOURCES += \
        template_plugin.cpp

HEADERS += \
        template_plugin.h \
        template_plugin_global.h

unix {
    target.path = /usr/lib
    INSTALLS += target
}

win32: {
    include("c:/dev/opencv/opencv.pri")
}

unix: !macx{
    CONFIG += link_pkgconfig
    PKGCONFIG += opencv
}

unix: macx{
INCLUDEPATH += "/usr/local/include"
LIBS += -L"/usr/local/lib" \
    -lopencv_world
}

FORMS += \
    plugin.ui
cvplugininterface.h文件
#ifndef CVPLUGIN_H
#define CVPLUGIN_H

#include <QObject>
#include <QWidget>
#include <QString>

#include "opencv2/opencv.hpp"

class CvPluginInterface
{
public:
    virtual ~CvPluginInterface() {}
    virtual QString title() = 0;
    virtual QString version() = 0;
    virtual QString description() = 0;
    virtual QString help() = 0;
    virtual void setupUi(QWidget *parent) = 0;
    virtual void processImage(const cv::Mat &inputImage, cv::Mat &outputImage) = 0;
};

#define CVPLUGININTERFACE_IID "com.computervision.cvplugininterface"
Q_DECLARE_INTERFACE(CvPluginInterface, CVPLUGININTERFACE_IID)

#endif // CVPLUGIN_H
template_plugin_global.h文件
#ifndef TEMPLATE_PLUGIN_GLOBAL_H
#define TEMPLATE_PLUGIN_GLOBAL_H

#include <QtCore/qglobal.h>

#if defined(TEMPLATE_PLUGIN_LIBRARY)
#  define TEMPLATE_PLUGINSHARED_EXPORT Q_DECL_EXPORT
#else
#  define TEMPLATE_PLUGINSHARED_EXPORT Q_DECL_IMPORT
#endif

#endif // TEMPLATE_PLUGIN_GLOBAL_H

template_plugin.h文件

#ifndef TEMPLATE_PLUGIN_H
#define TEMPLATE_PLUGIN_H

#include "template_plugin_global.h"
#include "cvplugininterface.h"

namespace Ui {
    class PluginGui;
}

//继承CvPluginInterface类,重写title(), version(), description(), help(), setupUi(QWidget *parent), processImage函数
class TEMPLATE_PLUGINSHARED_EXPORT Template_Plugin: public QObject, public CvPluginInterface
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "com.computervision.cvplugininterface")
    Q_INTERFACES(CvPluginInterface)
public:
    Template_Plugin();
    ~Template_Plugin();

    QString title();
    QString version();
    QString description();
    QString help();
    void setupUi(QWidget *parent);
    void processImage(const cv::Mat &inputImage, cv::Mat &outputImage);

signals:
    void updateNeeded();
    void errorMessage(QString msg);
    void infoMessage(QString msg);

private:
    Ui::PluginGui *ui;

};

#endif // TEMPLATE_PLUGIN_H

template_plugin.cpp文件

#include "template_plugin.h"

#include "ui_plugin.h"

Template_Plugin::Template_Plugin()
{
    // Insert initialization codes here ...
}

Template_Plugin::~Template_Plugin()
{
    // Insert cleanup codes here ...
}

QString Template_Plugin::title()
{
    return this->metaObject()->className();
}

QString Template_Plugin::version()
{
    return "1.0.0";
}

QString Template_Plugin::description()
{
    return "A <b>Template</b> plugin";
}

QString Template_Plugin::help()
{
    return "This is a <b>Template</b> plugin. Clone and use it to create new plugins.";
}

void Template_Plugin::setupUi(QWidget *parent)
{
    ui = new Ui::PluginGui;
    ui->setupUi(parent);

    // Connect signals for GUI elemnts manually here since they won't be connected by name in a plugin
    // ...
    // emit updateNeeded(); should be added whenever parameters on the plugin GUI change
}

void Template_Plugin::processImage(const cv::Mat &inputImage, cv::Mat &outputImage)
{
    // Replace the following line with the actual image processing task
    inputImage.copyTo(outputImage);

    // Otherwise, if the process doesn't affect the output image, update plugin GUI here ...
}

plugin.ui文件

app项目

mainapp.app


QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = Computer_Vision
TEMPLATE = app

# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

#win环境配置
win32:{
    CONFIG(debug, debug|release){
        DESTDIR += $$PWD/../../bin/win64d
        LIBS += -L$$PWD/../../lib/win64d -lopencv_world480d
    }else{
        DESTDIR += $$PWD/../../bin/win64
        LIBS += -L$$PWD/../../lib/win64 -lopencv_world480
    }
}

INCLUDEPATH += ../../Include

INCLUDEPATH += ../cvplugininterface

SOURCES += \
        main.cpp \
        mainwindow.cpp \
    qenhancedgraphicsview.cpp

HEADERS += \
        mainwindow.h \
    qenhancedgraphicsview.h

FORMS += \
        mainwindow.ui

win32: {
    include("c:/dev/opencv/opencv.pri")
}

unix: !macx{
    CONFIG += link_pkgconfig
    PKGCONFIG += opencv
}

unix: macx{
INCLUDEPATH += /usr/local/include
LIBS += -L"/usr/local/lib" \
    -lopencv_world
}

# Add more language entries here, following the same naming rule
TRANSLATIONS = language_tr.ts
qenhancedgraphicsview.h文件
#ifndef QENHANCEDGRAPHICSVIEW_H
#define QENHANCEDGRAPHICSVIEW_H

#include <QWidget>
#include <QGraphicsView>
#include <QWheelEvent>
#include <QMouseEvent>
#include <QtMath>
#include <QContextMenuEvent>
#include <QMenu>
#include <QGraphicsItem>
#include <QDebug>
#include <QGraphicsEffect>

class QEnhancedGraphicsView : public QGraphicsView
{
    Q_OBJECT
public:
    explicit QEnhancedGraphicsView(QWidget *parent = nullptr);

protected:
    void wheelEvent(QWheelEvent *event);

signals:

public slots:

private:
    QPointF sceneMousePos;

};

#endif // QENHANCEDGRAPHICSVIEW_H

 qenhancedgraphicsview.cpp文件

#include "qenhancedgraphicsview.h"

QEnhancedGraphicsView::QEnhancedGraphicsView(QWidget *parent)
    : QGraphicsView(parent)
{

}

void QEnhancedGraphicsView::wheelEvent(QWheelEvent *event)
{
    if (event->orientation() == Qt::Vertical)
    {
        double angleDeltaY = event->angleDelta().y();
        double zoomFactor = qPow(1.0015, angleDeltaY);
        scale(zoomFactor, zoomFactor);
        if(angleDeltaY > 0)
        {
            this->centerOn(sceneMousePos);
            sceneMousePos = this->mapToScene(event->pos());
        }
        this->viewport()->update();
        event->accept();
    }
    else
    {
        event->ignore();
    }
}
mainwindow.h文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QSettings>
#include <QCloseEvent>
#include <QMessageBox>
#include <QDir>
#include <QFileInfoList>
#include <QLibrary>
#include <QPluginLoader>
#include <QDebug>
#include <QFileDialog>
#include <QLabel>
#include <QGraphicsScene>
#include <QPushButton>
#include <QGraphicsProxyWidget>
#include <QTranslator>
#include <QThread>
#include <QThreadPool>
#include <QRunnable>
#include <QMutex>
#include <QWaitCondition>

#include "cvplugininterface.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

protected:
    void closeEvent(QCloseEvent *event);
    void changeEvent(QEvent *event);

private slots:
    void onPluginActionTriggered(bool);
    void onLanguageActionTriggered(bool);
    void onThemeActionTriggered(bool);
    void onCurrentPluginUpdateNeeded();
    void onCurrentPluginErrorMessage(QString msg);
    void onCurrentPluginInfoMessage(QString msg);

    void on_actionAboutQt_triggered();

    void on_actionExit_triggered();

    void on_actionOpenImage_triggered();

    void on_viewOriginalCheck_toggled(bool checked);

    void on_actionSaveImage_triggered();

    void on_action_Camera_triggered();

private:
    Ui::MainWindow *ui;

    void loadSettings();
    void saveSettings();

    QString currentThemeFile;
    QString currentLanguageFile;
    QString currentPluginFile;

    void populatePluginsMenu();
    void populateLanguagesMenu();
    void populateThemesMenu();

    QPointer<QPluginLoader> currentPlugin;
    QPointer<QWidget> currentPluginGui;
    QGraphicsScene scene;
    QTranslator translator;
    QGraphicsPixmapItem originalPixmap, processedPixmap;
    cv::Mat originalMat, processedMat;
    QImage originalImage, processedImage;

};

#endif // MAINWINDOW_H

mainwindow.cpp文件

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

#define PLUGINS_SUBFOLDER                   "/cvplugins/"
//#define PLUGINS_SUBFOLDER                   "/filter_plugins/"
#define LANGUAGES_SUBFOLDER                 "/languages/"
#define THEMES_SUBFOLDER                    "/themes/"
#define FILE_ON_DISK_DYNAMIC_PROPERTY       "absolute_file_path"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    loadSettings(); // First thing's first, load settings

    //加载插件菜单
    populatePluginsMenu();
    //加载多语言菜单
    populateLanguagesMenu();
    //加载主题菜单
    populateThemesMenu();

    ui->graphicsView->setScene(&scene);
    scene.addItem(&originalPixmap);
    scene.addItem(&processedPixmap);

    ui->graphicsView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
}

MainWindow::~MainWindow()
{
    delete currentPlugin;
    delete ui;
}

void MainWindow::loadSettings()
{
    QSettings settings("Packt", "Computer_Vision", this);
    currentThemeFile = settings.value("currentThemeFile", "").toString();
    currentLanguageFile = settings.value("currentLanguageFile", "").toString();
    currentPluginFile = settings.value("currentPluginFile", "").toString();
}

void MainWindow::saveSettings()
{
    QSettings settings("Packt", "Computer_Vision", this);
    settings.setValue("currentThemeFile", currentThemeFile);
    settings.setValue("currentLanguageFile", currentLanguageFile);
    settings.setValue("currentPluginFile", currentPluginFile);
}

void MainWindow::changeEvent(QEvent *event)
{
    if(event->type() == QEvent::LanguageChange)
    {
        ui->retranslateUi(this);
    }
    else
    {
        QMainWindow::changeEvent(event);
    }
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    int result = QMessageBox::warning(this, tr("Exit"), tr("Are you sure you want to exit?"), QMessageBox::Yes, QMessageBox::No);
    if(result == QMessageBox::Yes)
    {
        saveSettings();
        event->accept();
    }
    else
    {
        event->ignore();
    }
}

void MainWindow::populatePluginsMenu()
{
    // Load all plugins and populate the menus
    QDir pluginsDir(qApp->applicationDirPath() + PLUGINS_SUBFOLDER);
    //QDir pluginsDir(qApp->applicationDirPath());
    QFileInfoList pluginFiles = pluginsDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files, QDir::Name);
    qDebug() << "MainWindow::populatePluginsMenu=====================pluginFiles.size========" << pluginFiles.size();
    foreach(QFileInfo pluginFile, pluginFiles)
    {
        if(QLibrary::isLibrary(pluginFile.absoluteFilePath()))
        {
            QPluginLoader pluginLoader(pluginFile.absoluteFilePath(), this);
            if(CvPluginInterface *plugin = dynamic_cast<CvPluginInterface*>(pluginLoader.instance()))
            {
                QAction *pluginAction = ui->menu_Plugins->addAction(plugin->title());
                pluginAction->setProperty(FILE_ON_DISK_DYNAMIC_PROPERTY, pluginFile.absoluteFilePath());
                connect(pluginAction, SIGNAL(triggered(bool)), this, SLOT(onPluginActionTriggered(bool)));
                if(currentPluginFile == pluginFile.absoluteFilePath())
                {
                    pluginAction->trigger();
                }
            }
            else
            {
                QMessageBox::warning(this, tr("Warning"),
                                     QString(tr("Make sure %1 is a correct plugin for this application<br>"
                                                "and it's not in use by some other application!")).arg(pluginFile.fileName()));
            }
        }
        else
        {
            QMessageBox::warning(this, tr("Warning"),
                                 QString(tr("Make sure only plugins exist in %1 folder.<br>"
                                            "%2 is not a plugin."))
                                 .arg(PLUGINS_SUBFOLDER)
                                 .arg(pluginFile.fileName()));
        }
    }

    if(ui->menu_Plugins->actions().count() <= 0)
    {
        QMessageBox::critical(this, tr("No Plugins"), QString(tr("This application cannot work without plugins!"
                                                                 "<br>Make sure that %1 folder exists "
                                                                 "in the same folder as the application<br>and that "
                                                                 "there are some filter plugins inside it")).arg(PLUGINS_SUBFOLDER));
        this->setEnabled(false);
    }
}

void MainWindow::populateLanguagesMenu()
{
    QMenu *languagesMenu = new QMenu(this);
    // Add default (english) language
    QAction *defaultLanguageAction = languagesMenu->addAction("English - US");
    defaultLanguageAction->setProperty(FILE_ON_DISK_DYNAMIC_PROPERTY, "");
    connect(defaultLanguageAction, SIGNAL(triggered(bool)), this, SLOT(onLanguageActionTriggered(bool)));

    // Load all languages and populate the menus
    QDir languagesDir(qApp->applicationDirPath() + LANGUAGES_SUBFOLDER);
    QFileInfoList languageFiles = languagesDir.entryInfoList(QStringList() << "*.qm", QDir::NoDotAndDotDot | QDir::Files, QDir::Name);
    foreach(QFileInfo languageFile, languageFiles)
    {
        QAction *languageAction = languagesMenu->addAction(languageFile.baseName());
        languageAction->setProperty(FILE_ON_DISK_DYNAMIC_PROPERTY, languageFile.absoluteFilePath());
        connect(languageAction, SIGNAL(triggered(bool)), this, SLOT(onLanguageActionTriggered(bool)));

        if(currentLanguageFile == languageFile.absoluteFilePath())
        {
            languageAction->trigger();
        }
    }
    ui->actionLanguage->setMenu(languagesMenu);
}

void MainWindow::populateThemesMenu()
{
    QMenu *themesMenu = new QMenu(this);
    // Add default (native) theme
    QAction *defaultThemeAction = themesMenu->addAction("Default");
    defaultThemeAction->setProperty(FILE_ON_DISK_DYNAMIC_PROPERTY, "");
    connect(defaultThemeAction, SIGNAL(triggered(bool)), this, SLOT(onThemeActionTriggered(bool)));

    // Load all themes and populate the menus
    QDir themesDir(qApp->applicationDirPath() + THEMES_SUBFOLDER);
    QFileInfoList themeFiles = themesDir.entryInfoList(QStringList() << "*.thm", QDir::NoDotAndDotDot | QDir::Files, QDir::Name);
    foreach(QFileInfo themeFile, themeFiles)
    {
        QAction *themeAction = themesMenu->addAction(themeFile.baseName());
        themeAction->setProperty(FILE_ON_DISK_DYNAMIC_PROPERTY, themeFile.absoluteFilePath());
        connect(themeAction, SIGNAL(triggered(bool)), this, SLOT(onThemeActionTriggered(bool)));

        if(currentThemeFile == themeFile.absoluteFilePath())
        {
            themeAction->trigger();
        }
    }
    ui->actionTheme->setMenu(themesMenu);
}

void MainWindow::on_actionAboutQt_triggered()
{
    qApp->aboutQt();
}

void MainWindow::on_actionExit_triggered()
{
    close();
}

//加载插件
void MainWindow::onPluginActionTriggered(bool)
{
    if(!currentPlugin.isNull())
    {
        delete currentPlugin;
        delete currentPluginGui;
    }
    qDebug() << "MainWindow::onPluginActionTriggered====================currentPlugin========" << currentPlugin.isNull();
    currentPluginFile = QObject::sender()->property(FILE_ON_DISK_DYNAMIC_PROPERTY).toString();
    currentPlugin = new QPluginLoader(currentPluginFile, this);
    currentPluginGui = new QWidget(this);
    ui->pluginLayout->addWidget(currentPluginGui);
    CvPluginInterface *currentPluginInstance = dynamic_cast<CvPluginInterface*>(currentPlugin->instance());

    if(currentPluginInstance)
    {
        currentPluginInstance->setupUi(currentPluginGui);
        connect(currentPlugin->instance(), SIGNAL(updateNeeded()), this, SLOT(onCurrentPluginUpdateNeeded()));
        connect(currentPlugin->instance(), SIGNAL(infoMessage(QString)), this, SLOT(onCurrentPluginInfoMessage(QString)));
        connect(currentPlugin->instance(), SIGNAL(errorMessage(QString)), this, SLOT(onCurrentPluginErrorMessage(QString)));

    }
}

void MainWindow::onLanguageActionTriggered(bool)
{
    currentLanguageFile = QObject::sender()->property(FILE_ON_DISK_DYNAMIC_PROPERTY).toString();
    qApp->removeTranslator(&translator);
    if(!currentLanguageFile.isEmpty())
    {
        translator.load(currentLanguageFile);
        qApp->installTranslator(&translator);
        ui->retranslateUi(this);
    }
}

void MainWindow::onThemeActionTriggered(bool)
{
    currentThemeFile = QObject::sender()->property(FILE_ON_DISK_DYNAMIC_PROPERTY).toString();
    QFile themeFile(currentThemeFile);
    if(currentThemeFile.isEmpty())
    {
        qApp->setStyleSheet("");
    }
    else
    {
        themeFile.open(QFile::ReadOnly | QFile::Text);
        QString styleSheet = themeFile.readAll();
        qApp->setStyleSheet(styleSheet);
        themeFile.close();
    }
}

void MainWindow::on_actionOpenImage_triggered()
{
    QString fileName = QFileDialog::getOpenFileName(this,
                                                    tr("Open Input Image"),
                                                    QDir::currentPath(),
                                                    tr("Images") + " (*.jpg *.png *.bmp)");

    using namespace cv;
    originalMat = imread(fileName.toStdString());
    if(!originalMat.empty())
    {
        onCurrentPluginUpdateNeeded();
    }
    else if(!fileName.trimmed().isEmpty())
    {
        QMessageBox::critical(this,
                              tr("Error"),
                              tr("Make sure the image file exists "
                                 "and it is accessible!"));
    }
}

void MainWindow::on_viewOriginalCheck_toggled(bool checked)
{
    originalPixmap.setVisible(checked);
    processedPixmap.setVisible(!checked);
}

void MainWindow::onCurrentPluginUpdateNeeded()
{
    if(!originalMat.empty())
    {
        if(!currentPlugin.isNull())
        {
            CvPluginInterface *currentPluginInstance = dynamic_cast<CvPluginInterface*>(currentPlugin->instance());
            if(currentPluginInstance)
            {
                cv::TickMeter meter;
                meter.start();
                currentPluginInstance->processImage(originalMat, processedMat);
                meter.stop();
                qDebug() << "The process took " << meter.getTimeMilli() << "milliseconds";
            }
        }
        else
        {
            processedMat = originalMat.clone();
        }

        originalImage = QImage(originalMat.data, originalMat.cols, originalMat.rows, originalMat.step, QImage::Format_RGB888);
        originalPixmap.setPixmap(QPixmap::fromImage(originalImage.rgbSwapped()));

        processedImage = QImage(processedMat.data, processedMat.cols, processedMat.rows, processedMat.step, QImage::Format_RGB888);
        processedPixmap.setPixmap(QPixmap::fromImage(processedImage.rgbSwapped()));
    }
}

void MainWindow::on_actionSaveImage_triggered()
{
    if(!ui->viewOriginalCheck->isChecked() && !processedMat.empty())
    {
        QString fileName = QFileDialog::getSaveFileName(this, tr("Save Image"), QDir::currentPath(), "*.jpg;;*.png;;*.bmp");
        if(!fileName.isEmpty())
        {
            cv::imwrite(fileName.toStdString(), processedMat);
        }
    }
    else if(ui->viewOriginalCheck->isChecked() && !originalMat.empty())
    {
        QString fileName = QFileDialog::getSaveFileName(this, tr("Save Image"), QDir::currentPath(), "*.jpg;;*.png;;*.bmp");
        if(!fileName.isEmpty())
        {
            cv::imwrite(fileName.toStdString(), originalMat);
        }
    }
    else
    {
        QMessageBox::warning(this, tr("Warning"), tr("There is nothing to be saved!"));
    }
}

void MainWindow::onCurrentPluginErrorMessage(QString msg)
{
    qDebug() << "Plugin Error Message : " << msg;
}

void MainWindow::onCurrentPluginInfoMessage(QString msg)
{
    qDebug() << "Plugin Info Message : " << msg;
}

void MainWindow::on_action_Camera_triggered()
{

}

main.cpp文件

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    a.setStyle("fusion");
    MainWindow w;
    w.showMaximized();
    return a.exec();
}

language_tr.ts文件

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="tr_TR">
<context>
    <name>MainWindow</name>
    <message>
        <location filename="mainwindow.ui" line="20"/>
        <source>Computer Vision</source>
        <translation>Computer Vision</translation>
    </message>
    <message>
        <location filename="mainwindow.ui" line="35"/>
        <source>Plugin UI</source>
        <translation>Plugin Arayüzü</translation>
    </message>
    <message>
        <location filename="mainwindow.ui" line="47"/>
        <source>View</source>
        <translation>Görüntü</translation>
    </message>
    <message>
        <location filename="mainwindow.ui" line="72"/>
        <source>&amp;File</source>
        <translation>&amp;Dosya</translation>
    </message>
    <message>
        <location filename="mainwindow.ui" line="85"/>
        <source>&amp;Plugins</source>
        <translation>&amp;Pluginler</translation>
    </message>
    <message>
        <location filename="mainwindow.ui" line="90"/>
        <source>O&amp;ptions</source>
        <translation>&amp;Seçenekler</translation>
    </message>
    <message>
        <location filename="mainwindow.ui" line="97"/>
        <source>&amp;Help</source>
        <translation>&amp;Yardım</translation>
    </message>
    <message>
        <location filename="mainwindow.ui" line="108"/>
        <source>&amp;Open Image</source>
        <translation>&amp;Resim Seç</translation>
    </message>
    <message>
        <location filename="mainwindow.ui" line="113"/>
        <source>Open &amp;Video</source>
        <translation>&amp;Video Seç</translation>
    </message>
    <message>
        <location filename="mainwindow.ui" line="118"/>
        <source>Open &amp;Camera</source>
        <translation>&amp;Kamera</translation>
    </message>
    <message>
        <location filename="mainwindow.ui" line="123"/>
        <source>Open &amp;RTSP</source>
        <translation>&amp;RTSP Seç</translation>
    </message>
    <message>
        <location filename="mainwindow.ui" line="128"/>
        <source>&amp;Save Image</source>
        <translation>Resim Ka&amp;ydet</translation>
    </message>
    <message>
        <location filename="mainwindow.ui" line="133"/>
        <source>E&amp;xit</source>
        <translation>&amp;Çıkış</translation>
    </message>
    <message>
        <location filename="mainwindow.ui" line="138"/>
        <source>&amp;About Qt</source>
        <translation>&amp;Qt Hakkında</translation>
    </message>
    <message>
        <location filename="mainwindow.ui" line="143"/>
        <source>Language</source>
        <translation>Dil</translation>
    </message>
    <message>
        <location filename="mainwindow.ui" line="148"/>
        <source>Theme</source>
        <translation>Stil</translation>
    </message>
    <message>
        <location filename="mainwindow.cpp" line="52"/>
        <source>Exit</source>
        <translation>Çıkış</translation>
    </message>
    <message>
        <location filename="mainwindow.cpp" line="52"/>
        <source>Are you sure you want to exit?</source>
        <translation>Çıkmak istediğinizden emin misiniz?</translation>
    </message>
    <message>
        <location filename="mainwindow.cpp" line="82"/>
        <location filename="mainwindow.cpp" line="89"/>
        <source>Warning</source>
        <translation>Dikkat</translation>
    </message>
    <message>
        <location filename="mainwindow.cpp" line="83"/>
        <source>Make sure %1 is a correct plugin for this application&lt;br&gt;and it&apos;s not in use by some other application!</source>
        <translation>%1 doğru bir plugin değil. Lütfen kontrol ediniz.&lt;br&gt;Başka bir program bu plugin&apos;i kullanıyor olabilir!</translation>
    </message>
    <message>
        <location filename="mainwindow.cpp" line="90"/>
        <source>Make sure only plugins exist in %1 folder.&lt;br&gt;%2 is not a plugin.</source>
        <oldsource>Make sure only plugins exist in plugins folder.&lt;br&gt;%1 is not a plugin.</oldsource>
        <translation>Sadece pluginlerin %1 klasöründe olduğundan emin olunuz.&lt;br&gt;%2 bir plugin değildir.</translation>
    </message>
    <message>
        <location filename="mainwindow.cpp" line="99"/>
        <source>No Plugins</source>
        <translation>Plugin bulunamadı</translation>
    </message>
    <message>
        <location filename="mainwindow.cpp" line="99"/>
        <source>This application cannot work without plugins!&lt;br&gt;Make sure that %1 folder exists in the same folder as the application&lt;br&gt;and that there are some filter plugins inside it</source>
        <translation>Bu program pluginler olmadan çalışmaz.&lt;br&gt;%1 klasörünün programla aynı klasörde olduğundan emin olunuz&lt;br&gt;ve içinde en az bir plugin olduğunu kontrol ediniz</translation>
    </message>
    <message>
        <source>This application cannot work without plugins!&lt;br&gt;Make sure that filter_plugins folder exists in the same folder as the application&lt;br&gt;and that there are some filter plugins inside it</source>
        <translation type="obsolete">Bu program pluginler olmadan çalışmaz.&lt;br&gt;</translation>
    </message>
</context>
</TS>

mainwindow.ui文件

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值