IPLProcessProperty 是 ImagePlay 框架中用于处理图像处理算法属性的基类系统。它提供了一套完整的属性管理机制,支持多种数据类型和 GUI 控件类型。
主要功能
-
属性管理:为图像处理算法提供可配置的参数
-
序列化/反序列化:支持属性的保存和加载
-
GUI 集成:与用户界面控件绑定
-
事件通知:属性变化时通知相关组件
//#############################################################################
//
// This file is part of ImagePlay.
//
// ImagePlay is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ImagePlay is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ImagePlay. If not, see <http://www.gnu.org/licenses/>.
//
//#############################################################################
#ifndef IPLPROCESSPROPERTY_H
#define IPLPROCESSPROPERTY_H
#include "IPLProcess.h"
#include "IPLColor.h"
#include "IPLPoint.h"
#include <cstring>
#include <string>
#include <map>
#include <sstream>
#include <vector>
#include <memory>
class IPLProcess;
// we need a base class in order to use the template in std::map
class IPLSHARED_EXPORT IPLProcessProperty
{
public:
struct SerializedData
{
std::string type;
std::string widget;
std::string widgetName;
std::string value;
};
struct DeserialationFailed : public std::runtime_error
{ DeserialationFailed(): std::runtime_error("") {} };
int position() const { return _position; }
const char* name() const { return _name; }
const char* title() const { return _title; }
const char* description() const { return _description; }
IPLProcessWidgetType widget() const { return _widget; }
virtual const char* type() const = 0;
virtual SerializedData serialize() const = 0;
virtual void deserialize(const SerializedData &data) = 0;
virtual IPLProcessProperty *clone() const = 0;
virtual void resetValue() = 0;
protected:
IPLProcessProperty(int position,
const char *name,
const char *title,
const char *description,
IPLProcess *process,
IPLProcessWidgetType widget = IPL_WIDGET_DEFAULT);
int _position; //!< Position in GUI
const char* _name; //!< ID for GUI
const char* _title; //!< Short title for GUI
const char* _description; //!< Short help for GUI
IPLProcess* _process;
IPLProcessWidgetType _widget;
};
// templates are not possible because of serialization issues
// INT
class IPLSHARED_EXPORT IPLProcessPropertyInt : public IPLProcessProperty
{
public:
IPLProcessPropertyInt(IPLProcess* process, int position, const char* name, const char* title, const char* description, int value, IPLProcessWidgetType widget = IPL_WIDGET_DEFAULT, int min=0, int max=0);
int min() const { return _min; }
int max() const { return _max; }
int value() const { return _value; }
void setValue(int value);
void resetValue() { setValue(_default); }
virtual const char *type() const { return "int"; }
virtual SerializedData serialize() const;
virtual void deserialize(const SerializedData &data);
IPLProcessProperty *clone() const;
private:
int _min; //!< min value, may be used in GUI
int _max; //!< max value, may be used in GUI
int _value; //!< current value
int _default; //!< default value
};
// UNSIGNED INT
class IPLSHARED_EXPORT IPLProcessPropertyUnsignedInt: public IPLProcessProperty
{
public:
IPLProcessPropertyUnsignedInt(IPLProcess* process, int position, const char* name, const char* title, const char* description, unsigned int value, IPLProcessWidgetType widget = IPL_WIDGET_DEFAULT, unsigned int min=0, unsigned int max=0);
unsigned int min() const { return _min; }
unsigned int max() const { return _max; }
unsigned int value() const { return _value; }
void setValue(unsigned int value);
void resetValue() { setValue(_default); }
virtual const char *type() const { return "uint"; }
virtual SerializedData serialize() const;
virtual void deserialize(const SerializedData &data);
IPLProcessProperty *clone() const;
private:
unsigned int _min; //!< min value, may be used in GUI
unsigned int _max; //!< max value, may be used in GUI
unsigned int _value; //!< current value
unsigned int _default; //!< default value
};
// DOUBLE
class IPLSHARED_EXPORT IPLProcessPropertyDouble : public IPLProcessProperty
{
public:
IPLProcessPropertyDouble(IPLProcess* process, int position, const char* name, const char* title, const char* description, double value, IPLProcessWidgetType widget = IPL_WIDGET_DEFAULT, double min=0.0, double max=0.0);
double min() const { return _min; }
double max() const { return _max; }
double value() const { return _value; }
void setValue(double value);
void resetValue() { setValue(_default); }
virtual const char *type() const { return "double"; }
virtual SerializedData serialize() const;
virtual void deserialize(const SerializedData &data);
IPLProcessProperty *clone() const;
private:
double _min; //!< min value, may be used in GUI
double _max; //!< max value, may be used in GUI
double _value; //!< current value
double _default; //!< default value
};
// DOUBLE
class IPLSHARED_EXPORT IPLProcessPropertyFloat : public IPLProcessProperty
{
public:
IPLProcessPropertyFloat(IPLProcess* process, int position, const char* name, const char* title, const char* description, float value, IPLProcessWidgetType widget = IPL_WIDGET_DEFAULT, float min=0.0f, float max=0.0f);
float min() const { return _min; }
float max() const { return _max; }
float value() const { return _value; }
void setValue(float value);
void resetValue() { setValue(_default); }
virtual const char *type() const { return "float"; }
virtual SerializedData serialize() const;
virtual void deserialize(const SerializedData &data);
IPLProcessProperty *clone() const;
private:
float _min; //!< min value, may be used in GUI
float _max; //!< max value, may be used in GUI
float _value; //!< current value
float _default; //!< default value
};
// BOOL
class IPLSHARED_EXPORT IPLProcessPropertyBool : public IPLProcessProperty
{
public:
IPLProcessPropertyBool(IPLProcess* process, int position, const char* name, const char* title, const char* description, bool value, IPLProcessWidgetType widget = IPL_WIDGET_DEFAULT);
bool value() const { return _value; }
void setValue(bool value);
void resetValue() { setValue(_default); }
virtual const char *type() const { return "bool"; }
virtual SerializedData serialize() const;
virtual void deserialize(const SerializedData &data);
IPLProcessProperty *clone() const;
protected:
bool _value; //!< current value
bool _default; //!< default value
};
// BOOL ONE SHOT
class IPLSHARED_EXPORT IPLProcessPropertyBoolOneShot : public IPLProcessPropertyBool
{
public:
IPLProcessPropertyBoolOneShot(IPLProcess* process, int position, const char* name, const char* title, const char* description, bool value, IPLProcessWidgetType widget = IPL_WIDGET_DEFAULT);
bool value() { bool ret = _value; _value = false; return ret; }
};
// STRING
class IPLSHARED_EXPORT IPLProcessPropertyString : public IPLProcessProperty
{
public:
IPLProcessPropertyString(IPLProcess* process, int position, const char* name, const char* title, const char* description, const std::string &value, IPLProcessWidgetType widget = IPL_WIDGET_DEFAULT);
std::string value() const { return _value; }
void setValue(const std::string &value);
void setValue(std::string &&value);
void resetValue() { setValue(_default); }
virtual const char *type() const { return "string"; }
virtual SerializedData serialize() const;
virtual void deserialize(const SerializedData &data);
IPLProcessProperty *clone() const;
private:
std::string _value; //!< current value
std::string _default; //!< default value
};
// VECTOR<INT>
class IPLSHARED_EXPORT IPLProcessPropertyVectorInt : public IPLProcessProperty
{
public:
IPLProcessPropertyVectorInt(IPLProcess* process, int position, const char* name, const char* title, const char* description, const std::vector<int> &value, IPLProcessWidgetType widget = IPL_WIDGET_DEFAULT);
const std::vector<int> &value() const { return _value; }
void setValue(const std::vector<int> &value);
void setValue(std::vector<int> &&value);
void resetValue() { setValue(_default); }
virtual const char *type() const { return "vector<int>"; }
virtual SerializedData serialize() const;
virtual void deserialize(const SerializedData &data);
IPLProcessProperty *clone() const;
private:
std::vector<int> _value; //!< current value
std::vector<int> _default; //!< default value
};
// VECTOR<DOUBLE>
class IPLSHARED_EXPORT IPLProcessPropertyVectorDouble : public IPLProcessProperty
{
public:
IPLProcessPropertyVectorDouble(IPLProcess* process, int position, const char* name, const char* title, const char* description, const std::vector<double> &value, IPLProcessWidgetType widget = IPL_WIDGET_DEFAULT);
const std::vector<double> &value() const { return _value; }
void setValue(const std::vector<double> &value);
void setValue(std::vector<double> &&value);
void resetValue() { setValue(_default); }
virtual const char *type() const { return "vector<double>"; }
virtual SerializedData serialize() const;
virtual void deserialize(const SerializedData &data);
IPLProcessProperty *clone() const;
private:
std::vector<double> _value; //!< current value
std::vector<double> _default; //!< default value
};
// COLOR
class IPLSHARED_EXPORT IPLProcessPropertyColor : public IPLProcessProperty
{
public:
IPLProcessPropertyColor(IPLProcess* process, int position, const char* name, const char* title, const char* description, const IPLColor &value, IPLProcessWidgetType widget = IPL_WIDGET_DEFAULT);
const IPLColor &value() const { return _value; }
void setValue(const IPLColor &value);
void setValue(IPLColor &&value);
void resetValue() { setValue(_default); }
virtual const char *type() const { return "color"; }
virtual SerializedData serialize() const;
virtual void deserialize(const SerializedData &data);
IPLProcessProperty *clone() const;
private:
IPLColor _value; //!< current value
IPLColor _default; //!< default value
};
// POINT
class IPLSHARED_EXPORT IPLProcessPropertyPoint : public IPLProcessProperty
{
public:
IPLProcessPropertyPoint(IPLProcess* process, int position, const char* name, const char* title, const char* description, const IPLPoint &value, IPLProcessWidgetType widget = IPL_WIDGET_DEFAULT);
const IPLPoint &value() const { return _value; }
void setValue(const IPLPoint &value);
void setValue(IPLPoint &&value);
void resetValue() { setValue(_default); }
virtual const char *type() const { return "point"; }
virtual SerializedData serialize() const;
virtual void deserialize(const SerializedData &data);
IPLProcessProperty *clone() const;
private:
IPLPoint _value; //!< current value
IPLPoint _default; //!< default value
};
//! IPLProcessPropertyMap
typedef std::map<std::string, std::shared_ptr<IPLProcessProperty>> IPLProcessPropertyMap;
#endif // IPLPROCESSPROPERTY_H
//#############################################################################
//
// This file is part of ImagePlay.
//
// ImagePlay is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ImagePlay is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ImagePlay. If not, see <http://www.gnu.org/licenses/>.
//
//#############################################################################
#include "IPLProcessProperty.h"
#include <array>
#include <cctype>
#include <regex>
template<class T>
inline std::string serializeValue(const T &value)
{
std::ostringstream buffer;
buffer << value;
return buffer.str();
}
template<>
inline std::string serializeValue<bool>(const bool &value)
{
std::ostringstream buffer;
buffer << (value ? "true" : "false");
return buffer.str();
}
template<>
inline std::string serializeValue<std::vector<int>>(const std::vector<int> &value)
{
std::ostringstream buffer;
buffer << "[";
if (value.size() > 0) buffer << value[0];
for (int i = 1; i < (int) value.size(); ++i) buffer << "," << value[i];
buffer << "]";
return buffer.str();
}
template<>
inline std::string serializeValue<std::vector<double>>(const std::vector<double> &value)
{
std::ostringstream buffer;
buffer << "[";
if (value.size() > 0) buffer << value[0];
for (int i = 1; i < (int) value.size(); ++i) buffer << "," << value[i];
buffer << "]";
return buffer.str();
}
template<>
inline std::string serializeValue<IPLColor>(const IPLColor &value)
{
std::ostringstream buffer;
buffer << "[" << value.red() << "," << value.green() << "," << value.blue() << "]";
return buffer.str();
}
template<>
inline std::string serializeValue<IPLPoint>(const IPLPoint &value)
{
std::ostringstream buffer;
buffer << "[" << value.x() << "," << value.y() << "]";
return buffer.str();
}
template<class T>
inline IPLProcessProperty::SerializedData serializeProperty(const char *type, IPLProcessWidgetType widget, const T &value)
{
IPLProcessProperty::SerializedData result;
result.type = serializeValue(type);
result.widget = serializeValue(widget);
result.widgetName = serializeValue(widgetName(widget));
result.value = serializeValue(value);
return result;
}
inline void deserializeValue(const std::string &data, bool &value)
{
/*if (data.length() != 4)
{
value = false;
return;
}*/
//static const unsigned char nonAsciiMap = 1<<7;
std::string lowercase(data);
//tolower is undefined (i.e. might crash) for non-ASCII characters. Since we don't want to parse those, just xor them out
//std::transform(lowercase.begin(), lowercase.end(), lowercase.begin(), [](char c) { return c ^ nonAsciiMap; });
std::transform(lowercase.begin(), lowercase.end(), lowercase.begin(), tolower); //Transform to lower case
value = (lowercase.compare("true") == 0 || lowercase.compare("1") == 0);
}
inline void deserializeValue(const std::string &data, int &value)
{
int result = 0;
if (sscanf(data.c_str(),"%d",&result) < 1)
throw IPLProcessProperty::DeserialationFailed();
value = result;
}
inline void deserializeValue(const std::string &data, IPLProcessWidgetType &value)
{
int tmp;
deserializeValue(data,tmp);
value = (IPLProcessWidgetType) tmp;
}
inline void deserializeValue(const std::string &data, unsigned int &value)
{
unsigned int result = 0;
if (sscanf(data.c_str(),"%u",&result) < 1)
throw IPLProcessProperty::DeserialationFailed();
value = result;
}
inline void deserializeValue(const std::string &data, float &value)
{
float result = 0;
if (sscanf(data.c_str(),"%f",&result) < 1)
throw IPLProcessProperty::DeserialationFailed();
value = result;
}
inline void deserializeValue(const std::string &data, double &value)
{
double result = 0;
if (sscanf(data.c_str(),"%lf",&result) < 1)
throw IPLProcessProperty::DeserialationFailed();
value = result;
}
inline void deserializeValue(const std::string &data, std::vector<int> &value)
{
std::vector<int> result;
std::smatch match;
auto pos = data.begin();
while(std::regex_search(pos,data.end(),match,std::regex("[0-9]|-")))
{
pos += match.position();
int charsParsed = 0;
int element = 0;
if (sscanf(&(*pos),"%d%n",&element,&charsParsed) > 0)
result.push_back(element);
pos += charsParsed;
}
value.swap(result);
}
inline void deserializeValue(const std::string &data, std::vector<double> &value)
{
std::vector<double> result;
std::smatch match;
auto pos = data.begin();
while(std::regex_search(pos,data.end(),match,std::regex("[0-9]|-")))
{
pos += match.position();
int charsParsed = 0;
double element = 0;
if (sscanf(&(*pos),"%f%n",&element,&charsParsed) > 0)
result.push_back(element);
pos += charsParsed;
}
value.swap(result);
}
inline void deserializeValue(const std::string &data, IPLColor &value)
{
std::array<float,3> color;
int i = 0;
std::smatch match;
auto pos = data.begin();
while(i < (int) color.size() && std::regex_search(pos,data.end(),match,std::regex("[-0-9.]")))
{
pos += match.position();
int charsParsed = 0;
float element = 0;
if (sscanf(&(*pos),"%f%n",&element,&charsParsed) > 0)
color[i++] = element;
pos += charsParsed;
}
value = IPLColor(color[0], color[1], color[2]);
}
inline void deserializeValue(const std::string &data, IPLPoint &value)
{
std::array<double,2> point;
int i = 0;
std::smatch match;
auto pos = data.begin();
while(i < (int) point.size() && std::regex_search(pos,data.end(),match,std::regex("[-0-9.]")))
{
pos += match.position();
int charsParsed = 0;
float element = 0;
if (sscanf(&(*pos),"%f%n",&element,&charsParsed) > 0)
point[i++] = element;
pos += charsParsed;
}
value = IPLPoint(point[0], point[1]);
}
inline void deserializeValue(const std::string &data, std::string &value)
{
value = data;
}
template<class T>
inline void deserializeProperty(IPLProcessProperty::SerializedData data, IPLProcessWidgetType &widget, T &value)
{
deserializeValue(data.widget,widget);
deserializeValue(data.value,value);
}
IPLProcessProperty::IPLProcessProperty(int position, const char* name, const char *title, const char *description, IPLProcess *process, IPLProcessWidgetType widget):
_position(position),
_name(name),
_title(title),
_description(description),
_process(process),
_widget(widget)
{}
IPLProcessPropertyInt::IPLProcessPropertyInt(IPLProcess *process, int position, const char* name, const char* title, const char *description, int value, IPLProcessWidgetType widget, int min, int max):
IPLProcessProperty(position,name,title,description,process,widget),
_value(value),
_default(value),
_min(min),
_max(max)
{}
void IPLProcessPropertyInt::setValue(int value)
{
_value = value;
_process->requestUpdate();
_process->processPropertyEvents(new IPLEvent(_name));
_process->notifyPropertyChangedEventHandler();
}
IPLProcessProperty::SerializedData IPLProcessPropertyInt::serialize() const
{
return serializeProperty(type(),_widget,_value);
}
void IPLProcessPropertyInt::deserialize(const SerializedData &data)
{
deserializeProperty(data,_widget,_value);
}
IPLProcessProperty *IPLProcessPropertyInt::clone() const
{
return new IPLProcessPropertyInt(*this);
}
IPLProcessPropertyUnsignedInt::IPLProcessPropertyUnsignedInt(IPLProcess *process, int position, const char* name, const char* title, const char *description, unsigned int value, IPLProcessWidgetType widget, unsigned int min, unsigned int max):
IPLProcessProperty(position,name,title,description,process,widget),
_value(value),
_default(value),
_min(min),
_max(max)
{}
void IPLProcessPropertyUnsignedInt::setValue(unsigned int value)
{
_value = value;
_process->requestUpdate();
_process->processPropertyEvents(new IPLEvent(_name));
_process->notifyPropertyChangedEventHandler();
}
IPLProcessProperty::SerializedData IPLProcessPropertyUnsignedInt::serialize() const
{
return serializeProperty(type(),_widget,_value);
}
void IPLProcessPropertyUnsignedInt::deserialize(const SerializedData &data)
{
deserializeProperty(data,_widget,_value);
}
IPLProcessProperty *IPLProcessPropertyUnsignedInt::clone() const
{
return new IPLProcessPropertyUnsignedInt(*this);
}
IPLProcessPropertyDouble::IPLProcessPropertyDouble(IPLProcess *process, int position, const char* name, const char* title, const char *description, double value, IPLProcessWidgetType widget, double min, double max):
IPLProcessProperty(position,name,title,description,process, widget),
_value(value),
_default(value),
_min(min),
_max(max)
{}
void IPLProcessPropertyDouble::setValue(double value)
{
_value = value;
_process->requestUpdate();
_process->processPropertyEvents(new IPLEvent(_name));
_process->notifyPropertyChangedEventHandler();
}
IPLProcessProperty::SerializedData IPLProcessPropertyDouble::serialize() const
{
return serializeProperty(type(),_widget,_value);
}
void IPLProcessPropertyDouble::deserialize(const SerializedData &data)
{
deserializeProperty(data,_widget,_value);
}
IPLProcessProperty *IPLProcessPropertyDouble::clone() const
{
return new IPLProcessPropertyDouble(*this);
}
IPLProcessPropertyFloat::IPLProcessPropertyFloat(IPLProcess *process, int position, const char* name, const char* title, const char *description, float value, IPLProcessWidgetType widget, float min, float max):
IPLProcessProperty(position,name,title,description,process,widget),
_value(value),
_default(value),
_min(min),
_max(max)
{}
void IPLProcessPropertyFloat::setValue(float value)
{
_value = value;
_process->requestUpdate();
_process->processPropertyEvents(new IPLEvent(_name));
_process->notifyPropertyChangedEventHandler();
}
IPLProcessProperty::SerializedData IPLProcessPropertyFloat::serialize() const
{
return serializeProperty(type(),_widget,_value);
}
void IPLProcessPropertyFloat::deserialize(const SerializedData &data)
{
deserializeProperty(data,_widget,_value);
}
IPLProcessProperty *IPLProcessPropertyFloat::clone() const
{
return new IPLProcessPropertyFloat(*this);
}
IPLProcessPropertyBool::IPLProcessPropertyBool(IPLProcess *process, int position, const char* name, const char* title, const char *description, bool value, IPLProcessWidgetType widget):
IPLProcessProperty(position,name,title,description,process,widget),
_value(value),
_default(value)
{}
void IPLProcessPropertyBool::setValue(bool value)
{
_value = value;
_process->requestUpdate();
_process->processPropertyEvents(new IPLEvent(_name));
_process->notifyPropertyChangedEventHandler();
}
IPLProcessProperty::SerializedData IPLProcessPropertyBool::serialize() const
{
return serializeProperty(type(),_widget,_value);
}
void IPLProcessPropertyBool::deserialize(const SerializedData &data)
{
deserializeProperty(data,_widget,_value);
}
IPLProcessProperty *IPLProcessPropertyBool::clone() const
{
return new IPLProcessPropertyBool(*this);
}
IPLProcessPropertyBoolOneShot::IPLProcessPropertyBoolOneShot(IPLProcess *process, int position, const char* name, const char* title, const char *description, bool value, IPLProcessWidgetType widget):
IPLProcessPropertyBool(process, position,name,title,description,process,widget)
{}
IPLProcessPropertyString::IPLProcessPropertyString(IPLProcess *process, int position, const char* name, const char* title, const char *description, const std::string &value, IPLProcessWidgetType widget):
IPLProcessProperty(position,name,title,description,process,widget),
_value(value),
_default(value)
{}
void IPLProcessPropertyString::setValue(const std::string &value)
{
_value = value;
_process->requestUpdate();
_process->processPropertyEvents(new IPLEvent(_name));
_process->notifyPropertyChangedEventHandler();
}
void IPLProcessPropertyString::setValue(std::string &&value)
{
_value = std::move(value);
_process->requestUpdate();
_process->processPropertyEvents(new IPLEvent(_name));
_process->notifyPropertyChangedEventHandler();
}
IPLProcessProperty::SerializedData IPLProcessPropertyString::serialize() const
{
return serializeProperty(type(),_widget,_value);
}
void IPLProcessPropertyString::deserialize(const SerializedData &data)
{
deserializeProperty(data,_widget,_value);
}
IPLProcessProperty *IPLProcessPropertyString::clone() const
{
return new IPLProcessPropertyString(*this);
}
IPLProcessPropertyVectorInt::IPLProcessPropertyVectorInt(IPLProcess *process, int position, const char* name, const char* title, const char *description, const std::vector<int> &value, IPLProcessWidgetType widget):
IPLProcessProperty(position,name,title,description,process,widget),
_value(value)
{
_default = value;
}
void IPLProcessPropertyVectorInt::setValue(const std::vector<int> &value)
{
_value = value;
_process->requestUpdate();
_process->processPropertyEvents(new IPLEvent(_name));
_process->notifyPropertyChangedEventHandler();
}
void IPLProcessPropertyVectorInt::setValue(std::vector<int> &&value)
{
_value = std::move(value);
_process->requestUpdate();
_process->processPropertyEvents(new IPLEvent(_name));
_process->notifyPropertyChangedEventHandler();
}
IPLProcessProperty::SerializedData IPLProcessPropertyVectorInt::serialize() const
{
return serializeProperty(type(),_widget,_value);
}
void IPLProcessPropertyVectorInt::deserialize(const SerializedData &data)
{
deserializeProperty(data,_widget,_value);
}
IPLProcessProperty *IPLProcessPropertyVectorInt::clone() const
{
return new IPLProcessPropertyVectorInt(*this);
}
IPLProcessPropertyVectorDouble::IPLProcessPropertyVectorDouble(IPLProcess *process, int position, const char* name, const char* title, const char *description, const std::vector<double> &value, IPLProcessWidgetType widget):
IPLProcessProperty(position,name,title,description,process,widget),
_value(value),
_default(value)
{}
void IPLProcessPropertyVectorDouble::setValue(const std::vector<double> &value)
{
_value = value;
_process->requestUpdate();
_process->processPropertyEvents(new IPLEvent(_name));
_process->notifyPropertyChangedEventHandler();
}
void IPLProcessPropertyVectorDouble::setValue(std::vector<double> &&value)
{
_value = std::move(value);
_process->requestUpdate();
_process->processPropertyEvents(new IPLEvent(_name));
_process->notifyPropertyChangedEventHandler();
}
IPLProcessProperty::SerializedData IPLProcessPropertyVectorDouble::serialize() const
{
return serializeProperty(type(),_widget,_value);
}
void IPLProcessPropertyVectorDouble::deserialize(const SerializedData &data)
{
deserializeProperty(data,_widget,_value);
}
IPLProcessProperty *IPLProcessPropertyVectorDouble::clone() const
{
return new IPLProcessPropertyVectorDouble(*this);
}
IPLProcessPropertyColor::IPLProcessPropertyColor(IPLProcess *process, int position, const char* name, const char* title, const char *description, const IPLColor &value, IPLProcessWidgetType widget):
IPLProcessProperty(position,name,title,description,process,widget),
_value(value),
_default(value)
{}
void IPLProcessPropertyColor::setValue(const IPLColor &value)
{
_value = value;
_process->requestUpdate();
_process->processPropertyEvents(new IPLEvent(_name));
_process->notifyPropertyChangedEventHandler();
}
void IPLProcessPropertyColor::setValue(IPLColor &&value)
{
_value = std::move(value);
_process->requestUpdate();
_process->processPropertyEvents(new IPLEvent(_name));
_process->notifyPropertyChangedEventHandler();
}
IPLProcessProperty::SerializedData IPLProcessPropertyColor::serialize() const
{
return serializeProperty(type(),_widget,_value);
}
void IPLProcessPropertyColor::deserialize(const SerializedData &data)
{
deserializeProperty(data,_widget,_value);
}
IPLProcessProperty *IPLProcessPropertyColor::clone() const
{
return new IPLProcessPropertyColor(*this);
}
IPLProcessPropertyPoint::IPLProcessPropertyPoint(IPLProcess *process, int position, const char* name, const char* title, const char *description, const IPLPoint &value, IPLProcessWidgetType widget):
IPLProcessProperty(position,name,title,description,process,widget),
_value(value),
_default(value)
{}
void IPLProcessPropertyPoint::setValue(const IPLPoint &value)
{
_value = value;
_process->requestUpdate();
_process->processPropertyEvents(new IPLEvent(_name));
_process->notifyPropertyChangedEventHandler();
}
void IPLProcessPropertyPoint::setValue(IPLPoint &&value)
{
_value = std::move(value);
_process->requestUpdate();
_process->processPropertyEvents(new IPLEvent(_name));
_process->notifyPropertyChangedEventHandler();
}
IPLProcessProperty::SerializedData IPLProcessPropertyPoint::serialize() const
{
return serializeProperty(type(),_widget,_value);
}
void IPLProcessPropertyPoint::deserialize(const SerializedData &data)
{
deserializeProperty(data,_widget,_value);
}
IPLProcessProperty *IPLProcessPropertyPoint::clone() const
{
return new IPLProcessPropertyPoint(*this);
}
类结构
基类 IPLProcessProperty
所有属性类的基类,定义了通用接口:
class IPLProcessProperty { public: struct SerializedData { std::string type; std::string widget; std::string widgetName; std::string value; }; // 基础信息访问 int position() const; const char* name() const; const char* title() const; const char* description() const; IPLProcessWidgetType widget() const; // 必须实现的纯虚函数 virtual const char* type() const = 0; virtual SerializedData serialize() const = 0; virtual void deserialize(const SerializedData &data) = 0; virtual IPLProcessProperty *clone() const = 0; virtual void resetValue() = 0; };
派生属性类
框架提供了多种数据类型的属性类:
-
IPLProcessPropertyInt - 整型属性
-
IPLProcessPropertyUnsignedInt - 无符号整型属性
-
IPLProcessPropertyDouble - 双精度浮点属性
-
IPLProcessPropertyFloat - 单精度浮点属性
-
IPLProcessPropertyBool - 布尔属性
-
IPLProcessPropertyBoolOneShot - 一次性布尔属性(点击后自动复位)
-
IPLProcessPropertyString - 字符串属性
-
IPLProcessPropertyVectorInt - 整型向量属性
-
IPLProcessPropertyVectorDouble - 双精度浮点向量属性
-
IPLProcessPropertyColor - 颜色属性
-
IPLProcessPropertyPoint - 点坐标属性
核心实现细节
序列化机制
每个属性类都实现了 serialize()
和 deserialize()
方法,用于将属性值转换为字符串表示和反向转换。
// 序列化模板函数 template<class T> inline std::string serializeValue(const T &value) { std::ostringstream buffer; buffer << value; return buffer.str(); } // 特化版本的序列化 template<> inline std::string serializeValue<bool>(const bool &value) { return value ? "true" : "false"; } // 向量类型的序列化 template<> inline std::string serializeValue<std::vector<int>>(const std::vector<int> &value) { std::ostringstream buffer; buffer << "["; if (value.size() > 0) buffer << value[0]; for (int i = 1; i < (int) value.size(); ++i) buffer << "," << value[i]; buffer << "]"; return buffer.str(); }
反序列化机制
反序列化使用正则表达式和 sscanf 来解析字符串值:
inline void deserializeValue(const std::string &data, bool &value) { std::string lowercase(data); std::transform(lowercase.begin(), lowercase.end(), lowercase.begin(), tolower); value = (lowercase.compare("true") == 0 || lowercase.compare("1") == 0); } inline void deserializeValue(const std::string &data, std::vector<int> &value) { std::vector<int> result; std::smatch match; auto pos = data.begin(); while(std::regex_search(pos,data.end(),match,std::regex("[0-9]|-"))) { pos += match.position(); int charsParsed = 0; int element = 0; if (sscanf(&(*pos),"%d%n",&element,&charsParsed) > 0) result.push_back(element); pos += charsParsed; } value.swap(result); }
属性变更通知
当属性值变化时,会触发以下操作:
-
请求处理流程更新
-
发送属性变化事件
-
通知属性变化处理器
void IPLProcessPropertyInt::setValue(int value) { _value = value; _process->requestUpdate(); // 请求更新 _process->processPropertyEvents(new IPLEvent(_name)); // 发送事件 _process->notifyPropertyChangedEventHandler(); // 通知处理器 }
使用示例
创建属性
// 在图像处理算法中创建属性 class MyImageProcessor : public IPLProcessor { public: MyImageProcessor() { // 添加整型属性,范围0-100,默认值50,使用滑块控件 addProperty("threshold", "Threshold", "Image binarization threshold", 50, IPL_WIDGET_SLIDER, 0, 100); // 添加布尔属性,默认false,使用复选框 addProperty("invert", "Invert", "Invert output", false, IPL_WIDGET_CHECKBOX); // 添加颜色属性 addProperty("color", "Color", "Selection color", IPLColor(255,0,0), IPL_WIDGET_COLOR); } };
访问属性值
void MyImageProcessor::process() { // 获取阈值属性值 int threshold = getProperty("threshold")->value(); // 获取反转标志 bool invert = getProperty("invert")->value(); // 获取颜色值 IPLColor color = getProperty("color")->value(); // 处理图像... }
设计特点
-
类型安全:每种数据类型有对应的属性类,避免类型混淆
-
可扩展性:易于添加新的属性类型
-
GUI 集成:支持多种控件类型 (滑块、复选框、颜色选择器等)
-
默认值支持:所有属性都保存默认值,可随时重置
-
克隆支持:支持深度复制属性对象
总结
IPLProcessProperty 系统是 ImagePlay 框架中处理算法参数的核心组件,它提供了:
-
多种数据类型的属性支持
-
完整的序列化/反序列化能力
-
与 GUI 控件的紧密集成
-
属性变更通知机制
-
类型安全和可扩展的设计
这套系统使得图像处理算法的参数可以方便地在 GUI 中配置、保存和加载,大大简化了算法开发和用户交互的实现。