ImFusion SDK 4.3
Extending ImageMath

How to extend the ImageMath plugin.

+ Collaboration diagram for Extending ImageMath:

How to extend the ImageMath plugin.

Extending ImageMath

There are various ways to extend the functionality of the ImageMathPlugin. These are just a few:

  1. Define local operators, unary or binary, and directly use them in your expression.
  2. Add operators to the files BinaryOps.h or UnaryOps.h and add them to the BinaryOpTpl class. This adds your operator on a global level and makes it easy to use for everyone else too.
  3. For anything that is not an unary or binary operator you can consider to implement your own operator by implementing the ExprBaseTpl interface.

Local binary or unary operators:

You can define binary and unary operators locally. We support a functor as well as a lambda function style.

// define your own operators (unary or binary). Functor style. See UnaryOps.h and BinaryOps.h for all supported operators and feel free to add yours.
// exponential function
struct unaryExp
{
template <typename OperandT>
IMFUSION_STRONG_INLINE auto operator()(OperandT operand) const -> decltype(std::exp(std::declval<OperandT>()))
{
return std::exp(operand);
}
std::string evalString(const std::string& operandStr) const
{
str.reserve(5 + operandStr.size());
str += "exp(";
str += operandStr;
str += ")";
return str;
}
};
// usage
makeArray(res) = makeArray(img1).unaryOp<unaryExp>();
// add
struct add
{
template <typename LhsT, typename RhsT>
IMFUSION_STRONG_INLINE auto operator()(LhsT lhs, RhsT rhs) const -> decltype(std::declval<LhsT>() + std::declval<RhsT>())
{
return lhs + rhs;
}
std::string evalString(const std::string& lhsStr, const std::string& rhsStr) const
{
std::string str;
str.reserve(5 + lhsStr.size() + rhsStr.size());
str += "(";
str += lhsStr;
str += ")+(";
str += rhsStr;
str += ")";
return str;
}
};
// usage
makeArray(res) = makeArray(img1).binaryOp<add>(makeArray(img2));
// define your own operators (unary or binary). Lambda style
auto eval = [](float operand) { return std::exp(operand)); };
auto evalString = [](const std::string& operandStr) {
std::string str;
str.reserve(5 + operandStr.size());
str += "exp(";
str += operandStr;
str += ")";
return str;
};
makeArray(res) = makeArray(si).unaryOp(eval, evalString);
T declval(T... args)
T exp(T... args)
auto makeArray(TypedImage< T > &img, bool ignoreShiftAndScale, MagFilter magFilter, Wrap wrap, const vec4f &borderColor)
Convenience function to create an array leaf (needed as until c++17 there is no template type deducti...
Definition Array.h:657
T reserve(T... args)
T size(T... args)

Global binary or unary operators:

In this case you want to add the operators (see above for examples) to the files BinaryOps.h or UnaryOps.h. Afterwards add the operators to the ExprBaseTpl by adding the operator using either the ADD_UNARY_OP or the ADD_BINARY_OP macro.

Implement your own operator:

This example implements a convert to gray operator:

template <typename OperandT>
class ConvertToGray : public ExprBaseTpl<ConvertToGray<OperandT>>, public GlExprInterface , public ExprInterface
{
public:
// result type of this expression
using expr_type = typename OperandT::expr_type;
// has_variable in order to check at compile
static constexpr bool has_variable = OperandT::has_variable;
// imf_img_type in order to check at compile
using imf_img_type = typename OperandT::imf_img_type;
ConvertToGray(const OperandT& operand)
: m_operand(operand)
, m_channelIndices(indices)
, m_outDesc(m_operand.imgDesc())
, m_opDesc(m_operand.imgDesc())
{
m_outDesc.channels = 1;
}
OperandT& operand() { return m_operand; }
template <typename ImgT>
auto convertToMemImgExpr() const
{
return ConvertToGray<decltype(m_operand.template convertToMemImgExpr<ImgT>())>(m_operand.template convertToMemImgExpr<ImgT>());
}
auto convertToSharedImgExpr(std::size_t index) const
{
return ConvertToGray<decltype(m_operand.convertToSharedImgExpr(index))>(m_operand.convertToSharedImgExpr(index));
}
template <typename SubOperandT>
auto substituteVariable(const SubOperandT& operand) const
{
static_assert(has_variable);
return ConvertToGray<decltype(m_operand.substituteVariable(operand))>(m_operand.substituteVariable(operand));
}
const ImageDescriptor& imgDesc() const override { return m_outDesc; }
int numImgs() const override { return m_operand.numImgs(); }
IMFUSION_STRONG_INLINE expr_type eval(const std::size_t i, const vec4i& coord) const
{
IMFUSION_ASSERT(coord[3] == 1);
const auto slicedI = m_opDesc.index(coord[0], coord[1], coord[2], coord[3]);
const auto numChannels = m_opDesc.channels;
expt_type outVal = 0.0;
for(int i = 0; i < numChannels; ++i)
outVal += m_operand.eval(slicedI + i, slicedCoord);
return outVal;
}
std::string evalString(bool tagAndAssign = true) const
{
IMFUSION_ASSERT(m_opDesc.channels <= 4);
if (tagAndAssign)
internal::tagAndAssignNamesHelper(*this);
const auto opStr = m_operand.evalString(false);
std::stringstream ss;
ss << "vec4(";
const auto numChannels = m_opDesc.channels;
for(int i = 0; i < numChannels; ++i)
{
ss << "(" << m_operand.evalString(false) << ").";
switch(i)
{
case 1: ss << "r"; break;
case 2: ss << "g"; break;
case 3: ss << "b"; break;
case 4: ss << "a"; break;
}
if(i < numChannels - 1)
ss << " + ";
}
ss << ")";
return ss.str();
}
void tagAndAssignNames(std::unordered_map<internal::TaggingIndex, const void*>& taggedLeaves,
std::unordered_map<std::type_index, int>& countPerLeafType,
const std::string& prefix) const
{
m_operand.tagAndAssignNames(taggedLeaves, countPerLeafType, prefix);
}
void getUniformDefinitionList(std::string& definitionList, const std::string& prefix) const
{
m_operand.getUniformDefinitionList(definitionList, prefix);
}
void getVariableDefinitionList(std::string& definitionList, const std::string& prefix) const
{
m_operand.getVariableDefinitionList(definitionList, prefix);
}
int setArguments(GlProgram& p, const std::string& prefix) const { return m_operand.setArguments(p, prefix); }
DeviceStrategy deviceStrategy() const override
{
return m_operand.deviceStrategy();
}
private:
OperandT m_operand;
ImageDescriptor m_outDesc;
const ImageDescriptor m_opDesc;
};
#define IMFUSION_ASSERT(...)
ImFusion assertion macro, supports two overloads:
Definition Assert.h:102
DeviceStrategy
Computing device strategy.
Definition Types.h:18
T str(T... args)
Search Tab / S to search, Esc to close