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

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

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

#ifndef CVPLUGININTERFACE_H
#define CVPLUGININTERFACE_H

#include 
#include 
#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插件

四小时学习opencv+qt系列(第三天)_第1张图片
四小时学习opencv+qt系列(第三天)_第2张图片
四小时学习opencv+qt系列(第三天)_第3张图片

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

四小时学习opencv+qt系列(第三天)_第4张图片

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 

#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就行了。可以看到生成的目录里:

四小时学习opencv+qt系列(第三天)_第5张图片

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

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

2.ui界面:

四小时学习opencv+qt系列(第三天)_第6张图片

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

4.mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 
#include 
#include 
#include 
#include 
#include 
#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(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
" "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.
" "%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!" "
Make sure that filter_plugins folder exists " "in the same folder as the application
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(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(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(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
" "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.
" "%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!" "
Make sure that filter_plugins folder exists " "in the same folder as the application
and that " "there are some filter plugins inside it")); this->setEnabled(false); } }

接下来是插件的加载,在build的目录下新建filter_plugins文件夹,在其中放入我们之前生产的dll,可以测试使用了,效果如下图:
四小时学习opencv+qt系列(第三天)_第7张图片

你可能感兴趣的:(Qt,opencv)