text: #include "stromx/cvimgproc/BilateralFilter.h"
  
  #include "stromx/cvimgproc/Locale.h"
  #include "stromx/cvimgproc/Utility.h"
  #include <stromx/cvsupport/Image.h>
  #include <stromx/cvsupport/Matrix.h>
  #include <stromx/cvsupport/Utilities.h>
  #include <stromx/runtime/DataContainer.h>
  #include <stromx/runtime/DataProvider.h>
  #include <stromx/runtime/Id2DataComposite.h>
  #include <stromx/runtime/Id2DataPair.h>
  #include <stromx/runtime/ReadAccess.h>
  #include <stromx/runtime/VariantComposite.h>
  #include <stromx/runtime/WriteAccess.h>
  #include <opencv2/imgproc/imgproc.hpp>
  
  namespace stromx
  {
      namespace cvimgproc
      {
          const std::string BilateralFilter::PACKAGE(STROMX_CVIMGPROC_PACKAGE_NAME);
          const runtime::Version BilateralFilter::VERSION(STROMX_CVIMGPROC_VERSION_MAJOR, STROMX_CVIMGPROC_VERSION_MINOR, STROMX_CVIMGPROC_VERSION_PATCH);
          const std::string BilateralFilter::TYPE("BilateralFilter");
          
          BilateralFilter::BilateralFilter()
            : runtime::OperatorKernel(TYPE, PACKAGE, VERSION, setupInitParameters()),
              m_d(9),
              m_sigmaColor(50.0),
              m_sigmaSpace(50.0),
              m_dataFlow()
          {
          }
          
          const runtime::DataRef BilateralFilter::getParameter(unsigned int id) const
          {
              switch(id)
              {
              case PARAMETER_D:
                  return m_d;
              case PARAMETER_SIGMA_COLOR:
                  return m_sigmaColor;
              case PARAMETER_SIGMA_SPACE:
                  return m_sigmaSpace;
              case PARAMETER_DATA_FLOW:
                  return m_dataFlow;
              default:
                  throw runtime::WrongParameterId(id, *this);
              }
          }
          
          void BilateralFilter::setParameter(unsigned int id, const runtime::Data& value)
          {
              try
              {
                  switch(id)
                  {
                  case PARAMETER_D:
                      {
                          const runtime::UInt32 & castedValue = runtime::data_cast<runtime::UInt32>(value);
                          if(! castedValue.variant().isVariant(runtime::Variant::UINT_32))
                          {
                              throw runtime::WrongParameterType(parameter(id), *this);
                          }
                          cvsupport::checkNumericValue(castedValue, m_dParameter, *this);
                          m_d = castedValue;
                      }
                      break;
                  case PARAMETER_SIGMA_COLOR:
                      {
                          const runtime::Float64 & castedValue = runtime::data_cast<runtime::Float64>(value);
                          if(! castedValue.variant().isVariant(runtime::Variant::FLOAT_64))
                          {
                              throw runtime::WrongParameterType(parameter(id), *this);
                          }
                          cvsupport::checkNumericValue(castedValue, m_sigmaColorParameter, *this);
                          m_sigmaColor = castedValue;
                      }
                      break;
                  case PARAMETER_SIGMA_SPACE:
                      {
                          const runtime::Float64 & castedValue = runtime::data_cast<runtime::Float64>(value);
                          if(! castedValue.variant().isVariant(runtime::Variant::FLOAT_64))
                          {
                              throw runtime::WrongParameterType(parameter(id), *this);
                          }
                          cvsupport::checkNumericValue(castedValue, m_sigmaSpaceParameter, *this);
                          m_sigmaSpace = castedValue;
                      }
                      break;
                  case PARAMETER_DATA_FLOW:
                      {
                          const runtime::Enum & castedValue = runtime::data_cast<runtime::Enum>(value);
                          if(! castedValue.variant().isVariant(runtime::Variant::ENUM))
                          {
                              throw runtime::WrongParameterType(parameter(id), *this);
                          }
                          cvsupport::checkEnumValue(castedValue, m_dataFlowParameter, *this);
                          m_dataFlow = castedValue;
                      }
                      break;
                  default:
                      throw runtime::WrongParameterId(id, *this);
                  }
              }
              catch(runtime::BadCast&)
              {
                  throw runtime::WrongParameterType(parameter(id), *this);
              }
          }
          
          const std::vector<const runtime::Parameter*> BilateralFilter::setupInitParameters()
          {
              std::vector<const runtime::Parameter*> parameters;
              
              m_dataFlowParameter = new runtime::EnumParameter(PARAMETER_DATA_FLOW);
              m_dataFlowParameter->setAccessMode(runtime::Parameter::NONE_WRITE);
              m_dataFlowParameter->setTitle(L_("Data flow"));
              m_dataFlowParameter->add(runtime::EnumDescription(runtime::Enum(MANUAL), L_("Manual")));
              m_dataFlowParameter->add(runtime::EnumDescription(runtime::Enum(ALLOCATE), L_("Allocate")));
              parameters.push_back(m_dataFlowParameter);
              
              return parameters;
          }
          
          const std::vector<const runtime::Parameter*> BilateralFilter::setupParameters()
          {
              std::vector<const runtime::Parameter*> parameters;
              
              switch(int(m_dataFlow))
              {
              case(MANUAL):
                  {
                      m_dParameter = new runtime::NumericParameter<runtime::UInt32>(PARAMETER_D);
                      m_dParameter->setAccessMode(runtime::Parameter::ACTIVATED_WRITE);
                      m_dParameter->setTitle(L_("Pixel neigbourhood diameter"));
                      parameters.push_back(m_dParameter);
                      
                      m_sigmaColorParameter = new runtime::NumericParameter<runtime::Float64>(PARAMETER_SIGMA_COLOR);
                      m_sigmaColorParameter->setAccessMode(runtime::Parameter::ACTIVATED_WRITE);
                      m_sigmaColorParameter->setTitle(L_("Sigma color"));
                      parameters.push_back(m_sigmaColorParameter);
                      
                      m_sigmaSpaceParameter = new runtime::NumericParameter<runtime::Float64>(PARAMETER_SIGMA_SPACE);
                      m_sigmaSpaceParameter->setAccessMode(runtime::Parameter::ACTIVATED_WRITE);
                      m_sigmaSpaceParameter->setTitle(L_("Sigma space"));
                      parameters.push_back(m_sigmaSpaceParameter);
                      
                  }
                  break;
              case(ALLOCATE):
                  {
                      m_dParameter = new runtime::NumericParameter<runtime::UInt32>(PARAMETER_D);
                      m_dParameter->setAccessMode(runtime::Parameter::ACTIVATED_WRITE);
                      m_dParameter->setTitle(L_("Pixel neigbourhood diameter"));
                      parameters.push_back(m_dParameter);
                      
                      m_sigmaColorParameter = new runtime::NumericParameter<runtime::Float64>(PARAMETER_SIGMA_COLOR);
                      m_sigmaColorParameter->setAccessMode(runtime::Parameter::ACTIVATED_WRITE);
                      m_sigmaColorParameter->setTitle(L_("Sigma color"));
                      parameters.push_back(m_sigmaColorParameter);
                      
                      m_sigmaSpaceParameter = new runtime::NumericParameter<runtime::Float64>(PARAMETER_SIGMA_SPACE);
                      m_sigmaSpaceParameter->setAccessMode(runtime::Parameter::ACTIVATED_WRITE);
                      m_sigmaSpaceParameter->setTitle(L_("Sigma space"));
                      parameters.push_back(m_sigmaSpaceParameter);
                      
                  }
                  break;
              }
              
              return parameters;
          }
          
          const std::vector<const runtime::Input*> BilateralFilter::setupInputs()
          {
              std::vector<const runtime::Input*> inputs;
              
              switch(int(m_dataFlow))
              {
              case(MANUAL):
                  {
                      m_srcDescription = new runtime::Input(INPUT_SRC, runtime::Variant::IMAGE);
                      m_srcDescription->setTitle(L_("Source"));
                      inputs.push_back(m_srcDescription);
                      
                      m_dstDescription = new runtime::Input(INPUT_DST, runtime::Variant::IMAGE);
                      m_dstDescription->setTitle(L_("Destination"));
                      inputs.push_back(m_dstDescription);
                      
                  }
                  break;
              case(ALLOCATE):
                  {
                      m_srcDescription = new runtime::Input(INPUT_SRC, runtime::Variant::IMAGE);
                      m_srcDescription->setTitle(L_("Source"));
                      inputs.push_back(m_srcDescription);
                      
                  }
                  break;
              }
              
              return inputs;
          }
          
          const std::vector<const runtime::Output*> BilateralFilter::setupOutputs()
          {
              std::vector<const runtime::Output*> outputs;
              
              switch(int(m_dataFlow))
              {
              case(MANUAL):
                  {
                      runtime::Output* dst = new runtime::Output(OUTPUT_DST, runtime::Variant::IMAGE);
                      dst->setTitle(L_("Destination"));
                      outputs.push_back(dst);
                      
                  }
                  break;
              case(ALLOCATE):
                  {
                      runtime::Output* dst = new runtime::Output(OUTPUT_DST, runtime::Variant::IMAGE);
                      dst->setTitle(L_("Destination"));
                      outputs.push_back(dst);
                      
                  }
                  break;
              }
              
              return outputs;
          }
          
          void BilateralFilter::initialize()
          {
              runtime::OperatorKernel::initialize(setupInputs(), setupOutputs(), setupParameters());
          }
          
          void BilateralFilter::execute(runtime::DataProvider & provider)
          {
              switch(int(m_dataFlow))
              {
              case(MANUAL):
                  {
                      runtime::Id2DataPair srcInMapper(INPUT_SRC);
                      runtime::Id2DataPair dstInMapper(INPUT_DST);
                      
                      provider.receiveInputData(srcInMapper && dstInMapper);
                      
                      const runtime::Data* srcData = 0;
                      runtime::Data* dstData = 0;
                      
                      runtime::ReadAccess srcReadAccess;
                      runtime::DataContainer inContainer = dstInMapper.data();
                      runtime::WriteAccess writeAccess(inContainer);
                      dstData = &writeAccess.get();
                      
                      if(srcInMapper.data() == inContainer)
                      {
                          throw runtime::InputError(INPUT_SRC, *this, "Can not operate in place.");
                      }
                      else
                      {
                          srcReadAccess = runtime::ReadAccess(srcInMapper.data());
                          srcData = &srcReadAccess.get();
                      }
                      
                      if(! srcData->variant().isVariant(m_srcDescription->variant()))
                      {
                          throw runtime::InputError(INPUT_SRC, *this, "Wrong input data variant.");
                      }
                      if(! dstData->variant().isVariant(m_dstDescription->variant()))
                      {
                          throw runtime::InputError(INPUT_DST, *this, "Wrong input data variant.");
                      }
                      
                      const runtime::Image* srcCastedData = runtime::data_cast<runtime::Image>(srcData);
                      runtime::Image * dstCastedData = runtime::data_cast<runtime::Image>(dstData);
                      
                      dstCastedData->initializeImage(srcCastedData->width(), srcCastedData->height(), srcCastedData->stride(), dstCastedData->data(), srcCastedData->pixelType());
                      
                      cv::Mat srcCvData = cvsupport::getOpenCvMat(*srcCastedData);
                      cv::Mat dstCvData = cvsupport::getOpenCvMat(*dstCastedData);
                      int dCvData = int(m_d);
                      double sigmaColorCvData = double(m_sigmaColor);
                      double sigmaSpaceCvData = double(m_sigmaSpace);
                      
                      cv::bilateralFilter(srcCvData, dstCvData, dCvData, sigmaColorCvData, sigmaSpaceCvData);
                      
                      runtime::DataContainer dstOutContainer = inContainer;
                      runtime::Id2DataPair dstOutMapper(OUTPUT_DST, dstOutContainer);
                      
                      provider.sendOutputData(dstOutMapper);
                  }
                  break;
              case(ALLOCATE):
                  {
                      runtime::Id2DataPair srcInMapper(INPUT_SRC);
                      
                      provider.receiveInputData(srcInMapper);
                      
                      const runtime::Data* srcData = 0;
                      
                      runtime::ReadAccess srcReadAccess;
                      
                      srcReadAccess = runtime::ReadAccess(srcInMapper.data());
                      srcData = &srcReadAccess.get();
                      
                      if(! srcData->variant().isVariant(m_srcDescription->variant()))
                      {
                          throw runtime::InputError(INPUT_SRC, *this, "Wrong input data variant.");
                      }
                      
                      const runtime::Image* srcCastedData = runtime::data_cast<runtime::Image>(srcData);
                      
                      cv::Mat srcCvData = cvsupport::getOpenCvMat(*srcCastedData);
                      cv::Mat dstCvData;
                      int dCvData = int(m_d);
                      double sigmaColorCvData = double(m_sigmaColor);
                      double sigmaSpaceCvData = double(m_sigmaSpace);
                      
                      cv::bilateralFilter(srcCvData, dstCvData, dCvData, sigmaColorCvData, sigmaSpaceCvData);
                      
                      runtime::Image* dstCastedData = new cvsupport::Image(dstCvData);
                      runtime::DataContainer dstOutContainer = runtime::DataContainer(dstCastedData);
                      runtime::Id2DataPair dstOutMapper(OUTPUT_DST, dstOutContainer);
                      
                      dstCastedData->initializeImage(dstCastedData->width(), dstCastedData->height(), dstCastedData->stride(), dstCastedData->data(), srcCastedData->pixelType());
                      provider.sendOutputData(dstOutMapper);
                  }
                  break;
              }
          }
          
      } // cvimgproc
  } // stromx
  
  