创建插件工程
开发环境要求
| 工具 | 版本要求 |
|---|---|
| Visual Studio | 2019 或更高 |
| C++ 标准 | C++14 |
| 编译器 | MSVC (v142+) |
| 依赖库 | OpenCV 3.4.1(可选) |
快速开始
1. 创建项目结构
mkdir Plugin.MyPlugin
cd Plugin.MyPlugin
mkdir Tools
mkdir Include
2. 引用 ToolBase 头文件
从 ToolBank 工程中复制以下文件到项目:
MainUI.Plugin.ToolBase/Base/
├── ToolBaseNative.h # 插件基类
├── ToolFactory.h # 注册工厂
├── Macro.h # 宏定义和类型
├── Variable.h # 变量基类
├── DataType.h # 数据类型定义
├── ProjectControl.h # 项目控制器
├── ProjectArgument.h # 参数定义
├── ProjectVariables.h # 变量池
└── Variable/
├── Image.h
├── Point2D.h
├── Point3D.h
├── Line2D.h
├── Rectangle2D.h
├── Circle2D.h
├── Polygon2D.h
└── Region.h
3. 创建算子类
每个算子需要继承 ToolBaseNative 类。
头文件示例
// Tools/MyFilter.h
#pragma once
#include <ToolBaseNative.h>
namespace DLJ
{
namespace VT
{
class MyFilter : public ToolBaseNative
{
public:
MyFilter();
#pragma region DoNotChange
public:
// 工厂创建函数
static ToolBaseNative* Create() { return new MyFilter; }
// 返回算子名称
const std::string& GetName() const { return Name; }
// 返回算子分类
const ToolCategory GetCategory() const { return ToolCategory::Image; }
// 实现算子逻辑
ECode Apply(ProjectControl& ctx) override;
ECode parseInputVariable();
ECode setOutputVariable();
protected:
static const string Name;
#pragma endregion
public:
// 自定义实现
ECode do_Filter();
private:
// 输入变量
DLJ_IN_V(Image) m_InputImage; // 单值输入
DLJ_IN_V(double) m_KernelSize; // 单值输入
DLJ_IN_V(int) m_Iterations; // 列表输入
// 输出变量
DLJ_OUT_S(Image) m_OutputImage; // 单值输出
};
} // namespace VT
} // namespace DLJ
源文件示例
// Tools/MyFilter.cpp
#include "MyFilter.h"
namespace DLJ
{
namespace VT
{
// 注册算子:名称 -> 创建函数
const std::string MyFilter::Name = ToolFactory::Register(
"MyFilter", // 算子显示名
MyFilter::Create // 创建函数指针
);
// 构造函数:定义输入输出
MyFilter::MyFilter()
{
// 输入参数
setupInput("InputImage", IMAGE, "InputImage", "",
&m_InputImage, VAR_MODE::ALLOW_SINGLE,
u8"输入图像");
setupInput("KernelSize", DOUBLE, "3.0", "",
&m_KernelSize, VAR_MODE::ALLOW_EMPTY,
u8"卷积核大小");
setupInput("Iterations", INTEGER, "1", "",
&m_Iterations, VAR_MODE::ALLOW_MANY,
u8"迭代次数,支持列表");
// 输出参数
setupOutput("OutputImage", IMAGE, "OutputImage",
&m_OutputImage, u8"滤波后图像");
// 完成设置
SetupDone();
}
// Apply 函数:执行流程
ECode MyFilter::Apply(ProjectControl& ctx)
{
// 1. 解析输入
auto err = parseInputVariable();
if (err != ECode::ALL_OK) return err;
// 2. 执行算法
err = do_Filter();
if (err != ECode::ALL_OK) return err;
// 3. 输出结果
err = setOutputVariable();
if (err != ECode::ALL_OK) return err;
return err;
}
// 解析输入
ECode MyFilter::parseInputVariable()
{
auto err = ParseInputs();
if (err == ECode::ALL_OK)
{
// 自定义参数校验
if (m_KernelSize.empty())
{
SET_ERROR("KernelSize 不能为空");
return ECode::LOGIC_ERROR;
}
}
return err;
}
// 设置输出
ECode MyFilter::setOutputVariable()
{
return Outputs();
}
// 实际算法实现
ECode MyFilter::do_Filter()
{
// 获取输入
cv::Mat src = m_InputImage[0].m_Image;
double kernel = m_KernelSize[0];
// 执行滤波(示例)
cv::Mat dst;
cv::GaussianBlur(src, dst, cv::Size(0, 0), kernel);
// 设置输出
m_OutputImage = Image(dst);
return ECode::ALL_OK;
}
} // namespace VT
} // namespace DLJ
4. 配置 DLL 导出
在项目属性中:
- C/C++ → 预处理器:添加
DLJ_TOOLS和TOOL_PLUGIN - 链接器 → 输入:确保以下库
ToolBaseNative.libToolFactory.libopencv_world341.lib(可选)
- C/C++ → 代码生成:运行库设置为
/MD或/MDd
5. 实现 DLL 导出
在项目中创建一个导出文件,确保所有算子可被加载:
// Tools/Export.cpp
#define DLJ_TOOLS
#include <ToolFactory.h>
extern "C" {
__declspec(dllexport) int RegisterAllTools()
{
// 注册所有算子(通过静态构造自动注册)
return 0;
}
__declspec(dllexport) int DeregisterAllTools()
{
ToolFactory::ClearAll();
return 0;
}
__declspec(dllexport) const char** GetAllToolsNames(int* toolsCount)
{
auto names = ToolFactory::GetFactoryNames();
*toolsCount = (int)names.size();
static std::vector<const char*> result;
result.clear();
for (auto& name : names)
result.push_back(name.c_str());
return result.data();
}
} // extern "C"
算子分类
使用 ToolCategory 枚举指定算子分类:
| 分类 | 枚举值 | 说明 |
|---|---|---|
| 图像处理 | ToolCategory::Image | 滤波、变换、形态学等 |
| 区域操作 | ToolCategory::Region | ROI 处理、轮廓分析等 |
| 数学运算 | ToolCategory::Math | 数值计算、表达式等 |
| 变量定义 | ToolCategory::Variable | 定义变量/常量 |
| 控制流 | ToolCategory::ControlFlow | IF/ELSE/LOOP 等 |
| 文件读写 | ToolCategory::FileIO | 文件/数据库操作 |
| 自定义 | ToolCategory::CustomTools | 用户自定义分类 |
输入输出模式
VAR_MODE 定义
enum VAR_MODE
{
ALLOW_EMPTY = 0, // 允许空值/单值/列表
ALLOW_SINGLE, // 仅允许单值
ALLOW_MANY, // 允许单值或列表
OUT_IS_EMPTY // 输出空值模式
};
变量类型宏
// 输入变量
DLJ_IN_V(T) // 输入,向量类型
DLJ_IN_S(T) // 输入,单值类型
// 输出变量
DLJ_OUT_V(T) // 输出,向量类型
DLJ_OUT_S(T) // 输出,单值类型
构建与测试
编译
# Release x64 模式
MSBuild Plugin.MyPlugin.sln /p:Configuration=Release /p:Platform=x64
本地测试
- 将编译生成的 DLL 复制到 ToolBank 插件目录
- 启动 ToolBank
- 在"插件管理"中确认插件已加载
- 在程序编辑器中添加算子并测试
调试技巧
查看算子信息
// 在构造函数中添加调试日志
DLJ_PUSH_CALLSTACK("MyFilter 构造函数被调用");
参数验证
// 使用宏验证输入
DLJ_ASSERT_VECTOR_SIZE(m_InputImage, >, 0); // 至少一个图像
DLJ_ASSERT_vA_OPTR_vB(m_KernelSize, >=, 1.0); // 核大小 >= 1.0
运行时错误
SET_ERROR("自定义错误信息");
return ECode::LOGIC_ERROR;
常见问题
| 问题 | 解决方案 |
|---|---|
| 算子无法注册 | 检查 ToolFactory::Register 是否在静态初始化时调用 |
| DLL 加载失败 | 检查依赖库是否都在可执行目录中 |
| 输入参数为空 | 检查 VAR_MODE 设置和 ParseInputs() 调用 |
| 输出变量为空 | 确保 Outputs() 在 Apply 中被调用 |
参考示例
可参考 ToolBank 工程中的现有插件实现:
Plugin.CV- 图像处理类插件Plugin.DL- 深度学习类插件Plugin.Finance- 金融数据处理插件