由于以前设计的插件系统,参数设置都是 手动的,搞得比较麻烦。
我花了一周的时间写了一个自动化设置的版本,主要有如下改进:
1.使用变量注册的方式,支持扩展任意变量
2.变量支持任意数据类型存储,默认提供了 45种数据类型,包括特殊类型
3.变量支持 自动 read/write/get/set,不需要手动参与。
4.用工具类 实现 委托 和 继承 2种接口模式。
5.删除OpenCV依赖,将 cv::FileStorage 彻底从插件系统删除,使用 boost.property_tree.ptree替换
整个插件系统,仅依赖 boost静态库。
6.将 类型从 int值改为 string类型,提高了 通用能力。
比如 自适应高斯二值化,使用 接口继承的写法:
struct KImgBinAdaptGauss : public KPlugImg
{
Mat _dst;
KImgBinAdaptGauss()
{
defVar("blockSize").setType(VariableTypeInt).setDisplay("块尺寸").setValue(3);
defVar("subtractParam").setType(VariableTypeDouble).setDisplay("减法常量").setValue(5);
}
virtual bool exec(const KArbitType& src, KArbitType& dst) override
{
cv::adaptiveThreshold(a2m(src), _dst, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY, gInt(“blockSize”), gDouble(“subtractParam”));
dst = _dst;
return true;
}
virtual KParamTypeList inputTypes() const override
{
return { ParamMat8U1C };
}
virtual KParamTypeList outputTypes() const override
{
return { ParamMatBin };
}
};
使用 委托 实现的方法:
KPLUG_AUTO_DEFINE(KImgBinAdaptGauss, PLUG_IMG_BINARY_LOCAL, “自适应高斯”)
{
defVar(“blockSize”).setType(VariableTypeInt).setDisplay(“块尺寸”).setValue(3);
defVar(“subtractParam”).setType(VariableTypeDouble).setDisplay(“减法常量”).setValue(5);
setCallbackExec([&](const KArbitType & src, KArbitType & dst)->bool {
Mat _dst;
cv::adaptiveThreshold(a2m(src), _dst, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY, gInt("blockSize"), gDouble("subtractParam"));
dst = _dst;
});
setCallbackInputTypes({ ParamMat8U1C });
setCallbackOutputTypes({ ParamMatBin });
}
这两种写法,一个是 面向对象代码方式,一个是 函数式代码方式。
编译出来的插件是相同的。
改进插件接口
对应关系
参数自动保存为 json格式:
改进插件接口
保存的参数
通过简化的接口,不需要操心参数的 read/write/set过程,自动get就行了。
变量接口
struct KLIB_DECL KVar
{
//
KVar();
KVar(const string& _name);
KVar(const string& _name, const KVarType& _type);
KVar(const string& _name, const KVarType& _type, const KArbitType& _value);
~KVar();
//
//基本属性
KVar& setName(const string& _name); //变量名字
string getName()const;
KVar& setDisplay(const string& _display);//变量中文名字
string getDisplay()const;
KVar& setType(const KVarType& _type);
KVar& setTypeString(const string& _type);
KVarType getType()const;
string getTypeString()const;
KVar& setValue(const KArbitType& _value);
KVar& setValueString(const string& value);
const KArbitType& getValue()const;
string getValueString()const;
KVar& setDefValue(const KArbitType& _value);
KArbitType getDefValue()const;
string getDefValueString()const;
//
//扩展属性
KVar& setMinValue(double _value); //默认 0
double getMinValue()const;
KVar& setMaxValue(double _value); //默认 0
double getMaxValue()const;
KVar& setSingleStep(double _value); //默认为1/当为double时候0.01
double getSingleStep()const;
KVar& setDecimals(int prec); //默认小数点2位
int getDecimals()const;
KVar& setFileFilter(const string& _filter); //默认"*.*"
string getFileFilter()const;
KVar& setItems(const vector<string>& _items); //默认 空
vector<string> getItems()const;
//底层接口
KVar& _setItem(const string& _name, const KArbitType& _value);
KArbitType _getItem(const string& _name)const;
//value 值的拦截器
KVar& setValueSetter(KVarSetter _func);
KVar& setValueGetter(KVarGetter _func);
//
static vector<string> type_available();
private:
struct KVarImpl;
boost::shared_ptr pImpl;
};
调用接口
struct KLIB_DECL KPlugBase
{
//
//变量描述/设置/获取
virtual KVarList getVarList()const;
virtual bool setVar(const string& name, const KArbitType& value);
virtual const KArbitType& getVar(const string& name)const;
//
//参数类型输入/输出类型/执行接口, 调用成功,返回为true
virtual KParamTypeList inputTypes()const;
virtual KParamTypeList outputTypes()const;
virtual bool exec(const KArbitType& src, KArbitType& dst);
virtual KArbitType formatResult()const;
//
//序列化接口
virtual string getAlgName()const; //用于设置 load/save的节点参数
void load(const string& filename, const string& objname = string());
void load(KSer& fs, const string& objname = string());
virtual void read(const KSer& fn);
void save(const string& filename) const;
void save(KSer& fs, const string& name = string()) const;
virtual void write(KSer& fs) const;
protected: //禁止直接构造
KPlugBase();
virtual ~KPlugBase();//虚析构
};
然后实现了一个
改进插件接口
自动实现 参数设置等接口
这一版本的插件系统,应该比较有扩展性和稳定性。
“磨刀不误砍柴工”,底层架构好了,系统就能灵活扩展了。