四小时学习opencv+qt系列(第三天)

    技术2022-07-11  126

    四小时学习opencv+qt系列(第三天)

    一、接口是一个什么也不做的类,只列出应用程序所需要的所有插件的草图,一定要在一开始的时候将所有必须的函数都包含在插件接口中。首先建立一个.h文件,命名为cvplugininterface.h,内容如下

    #ifndef CVPLUGININTERFACE_H #define CVPLUGININTERFACE_H #include <QObject> #include <QString> #include "opencv2/opencv.hpp" class CvPluginInterface { public: virtual ~CvPluginInterface() {} virtual QString description() = 0; virtual void processImage(const cv::Mat &inputImage, cv::Mat &outputImage) = 0; }; #define CVPLUGININTERFACE_IID "com.amin.cvplugininterface" Q_DECLARE_INTERFACE(CvPluginInterface, CVPLUGININTERFACE_IID) #endif // CVPLUGININTERFACE_H

    分析:

    ifndef define endif 确保了在处理过程中对每个头文件只进行一次包含和处理。 virtual ~CvPluginInterface() {}是虚析构函数,避免内存泄漏。 description()返回所有插件的描数及其相关有用信息。 processImage函数将cv::Mat &inputImage作为输入,并返回1最为输出。 Q_DECLARE_INTERFACE(CvPluginInterface, CVPLUGININTERFACE_IID)使用Q_DECLARE_INTERFACE将类宏定义为接口

    二、插件,创建median_filter_plugin插件

    1.项目建好了以后,把cvplugininterface.h放到工程目录下并右键添加现有文件把他加进来。此时的工程目录结构如下:

    2.此时要告诉qt这是一个插件而并非只是库,在.pro文件中添加:

    CONFIG += plugin

    将opencv的路径添加进去:(debug下)

    LIBS += -LD:/opencv4.2/opencv/newbuild/newbuild/install/x64/vc14/lib/ -lopencv_world420d INCLUDEPATH += D:/opencv4.2/opencv/newbuild/newbuild/install/include/ D:/opencv4.2/opencv/newbuild/newbuild/install/include/opencv2/

    3.修改median_filter_plugin.h如下

    #ifndef MEDIAN_FILTER_PLUGIN_H #define MEDIAN_FILTER_PLUGIN_H #include "median_filter_plugin_global.h" #include "cvplugininterface.h" class MEDIAN_FILTER_PLUGINSHARED_EXPORT Median_filter_plugin: public QObject, public CvPluginInterface { Q_OBJECT Q_PLUGIN_METADATA(IID "com.amin.cvplugininterface") Q_INTERFACES(CvPluginInterface) public: Median_filter_plugin(); ~Median_filter_plugin(); QString description(); void processImage(const cv::Mat &inputImage, cv::Mat &outputImage); }; #endif // MEDIAN_FILTER_PLUGIN_H

    4.此时编译可能会提示使用未定义的类class MEDIAN_FILTER_PLUGINSHARED_EXPORT,这里将median_filter_plugin_global.h修改如下就好了

    #ifndef MEDIAN_FILTER_PLUGIN_GLOBAL_H #define MEDIAN_FILTER_PLUGIN_GLOBAL_H #include <QtCore/qglobal.h> #if defined(MEDIAN_FILTER_PLUGIN_LIBRARY) # define MEDIAN_FILTER_PLUGINSHARED_EXPORT Q_DECL_EXPORT #else # define MEDIAN_FILTER_PLUGINSHARED_EXPORT Q_DECL_IMPORT #endif #endif // MEDIAN_FILTER_PLUGIN_GLOBAL_H

    5.接下来修改median_filter_plugin.cpp如下:这里就是类析构函数的实现以及description()和processImage函数。

    #include "median_filter_plugin.h" Median_filter_plugin::Median_filter_plugin() { } Median_filter_plugin::~Median_filter_plugin() { } QString Median_filter_plugin::description() { return "This plugin applies median blur filters to any image." " This plugin's goal is to make us more familiar with the" " concept of plugins in general."; } void Median_filter_plugin::processImage(const cv::Mat &inputImage, cv::Mat &outputImage) { cv::medianBlur(inputImage, outputImage, 5); }

    6.接下来Build就行了。可以看到生成的目录里:

    三、接下插件加载器和用户

    1.新建工程Plugin_User,基类那里选择QMainWindow

    2.ui界面:

    3.将之前的cvplugininterface.h添加到工程中。

    4.mainwindow.h

    #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QDir> #include <QFileDialog> #include <QMessageBox> #include <QPluginLoader> #include <QFileInfoList> #include "opencv2/opencv.hpp" #include "cvplugininterface.h" namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private slots: void on_inputImgButton_pressed(); void on_helpButton_pressed(); void on_filterButton_pressed(); private: Ui::MainWindow *ui; void getPluginsList(); }; #endif // MAINWINDOW_H

    mainwindow.cpp

    #include "mainwindow.h" #include "ui_mainwindow.h" #define FILTERS_SUBFOLDER "/filter_plugins/" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); getPluginsList(); } MainWindow::~MainWindow() { delete ui; } void MainWindow::getPluginsList() { QDir filtersDir(qApp->applicationDirPath() + FILTERS_SUBFOLDER); QFileInfoList filters = filtersDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files, QDir::Name); foreach(QFileInfo filter, filters) { if(QLibrary::isLibrary(filter.absoluteFilePath())) { QPluginLoader pluginLoader(filter.absoluteFilePath(), this); if(dynamic_cast<CvPluginInterface*>(pluginLoader.instance())) { ui->filtersList->addItem(filter.fileName()); pluginLoader.unload(); // we can unload for now } 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(filter.fileName())); } } else { QMessageBox::warning(this, tr("Warning"), QString(tr("Make sure only plugins exist in plugins folder.<br>" "%1 is not a plugin.")).arg(filter.fileName())); } } if(ui->filtersList->count() <= 0) { QMessageBox::critical(this, tr("No Plugins"), tr("This application cannot work without plugins!" "<br>Make sure that filter_plugins folder exists " "in the same folder as the application<br>and that " "there are some filter plugins inside it")); this->setEnabled(false); } } void MainWindow::on_inputImgButton_pressed() { QString fileName = QFileDialog::getOpenFileName(this, tr("Open Input Image"), QDir::currentPath(), tr("Images") + " (*.jpg *.png *.bmp)"); if(QFile::exists(fileName)) { ui->inputImgEdit->setText(fileName); } } void MainWindow::on_helpButton_pressed() { if(ui->filtersList->currentRow() >= 0) { QPluginLoader pluginLoader(qApp->applicationDirPath() + FILTERS_SUBFOLDER + ui->filtersList->currentItem()->text()); CvPluginInterface *plugin = dynamic_cast<CvPluginInterface*>(pluginLoader.instance()); if(plugin) { QMessageBox::information(this, tr("Plugin Description"), plugin->description()); } else { QMessageBox::warning(this, tr("Warning"), QString(tr("Make sure plugin %1 exists and is usable.")).arg(ui->filtersList->currentItem()->text())); } } else { QMessageBox::warning(this, tr("Warning"), QString(tr("First select a filter plugin from the list."))); } } void MainWindow::on_filterButton_pressed() { if(ui->filtersList->currentRow() >= 0 && !ui->inputImgEdit->text().isEmpty()) { QPluginLoader pluginLoader(qApp->applicationDirPath() + FILTERS_SUBFOLDER + ui->filtersList->currentItem()->text()); CvPluginInterface *plugin = dynamic_cast<CvPluginInterface*>(pluginLoader.instance()); if(plugin) { if(QFile::exists(ui->inputImgEdit->text())) { using namespace cv; Mat inputImage, outputImage; inputImage = imread(ui->inputImgEdit->text().toStdString()); plugin->processImage(inputImage, outputImage); imshow(tr("Filtered Image").toStdString(), outputImage); } else { QMessageBox::warning(this, tr("Warning"), QString(tr("Make sure %1 exists.")).arg(ui->inputImgEdit->text())); } } else { QMessageBox::warning(this, tr("Warning"), QString(tr("Make sure plugin %1 exists and is usable.")).arg(ui->filtersList->currentItem()->text())); } } else { QMessageBox::warning(this, tr("Warning"), QString(tr("First select a filter plugin from the list."))); } }

    主要代码分析:(这里只对获取插件的函数进行分析,其余函数简单就不分析了,下面的代码不能直接加到工程中,添加了一些注释,直接移植可能会报错,完整代码参照上面的)

    void MainWindow::getPluginsList() { QDir filtersDir(qApp->applicationDirPath() + FILTERS_SUBFOLDER);//获取插件的路径 //提取QFileInfoList QFileInfoList filters = filtersDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files, QDir::Name); //通过foreach遍历文件夹列表,检索每一个文件 foreach(QFileInfo filter, filters) { if(QLibrary::isLibrary(filter.absoluteFilePath()))//确保只检索插件 { QPluginLoader pluginLoader(filter.absoluteFilePath(), this); if(dynamic_cast<CvPluginInterface*>(pluginLoader.instance()))//不让任何一个库文件作为插件被接受 { ui->filtersList->addItem(filter.fileName()); pluginLoader.unload(); // we can unload for now } //插件类型不正确弹出的警告 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(filter.fileName())); } } else { //确保插件文件夹中只存在插件 QMessageBox::warning(this, tr("Warning"), QString(tr("Make sure only plugins exist in plugins folder.<br>" "%1 is not a plugin.")).arg(filter.fileName())); } } //如果空则没有可用插件 if(ui->filtersList->count() <= 0) { QMessageBox::critical(this, tr("No Plugins"), tr("This application cannot work without plugins!" "<br>Make sure that filter_plugins folder exists " "in the same folder as the application<br>and that " "there are some filter plugins inside it")); this->setEnabled(false); } }

    接下来是插件的加载,在build的目录下新建filter_plugins文件夹,在其中放入我们之前生产的dll,可以测试使用了,效果如下图:

    Processed: 0.021, SQL: 9