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

8 篇文章 18 订阅

四小时学习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,可以测试使用了,效果如下图:
在这里插入图片描述

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

visual_eagle

欢迎交流学习

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值