otbBandMath.cxx 8.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
20

21 22 23 24
#include "otbWrapperApplication.h"
#include "otbWrapperApplicationFactory.h"

#include "otbBandMathImageFilter.h"
25 26 27 28 29 30
#include "otbMultiToMonoChannelExtractROI.h"
#include "otbObjectList.h"

namespace otb
{

31
namespace Wrapper
32 33
{

34 35
class BandMath : public Application
{
36

37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
public:
  /** Standard class typedefs. */
  typedef BandMath                      Self;
  typedef Application                   Superclass;
  typedef itk::SmartPointer<Self>       Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;

  /** Standard macro */
  itkNewMacro(Self);

  itkTypeMacro(BandMath, otb::Application);

  typedef otb::MultiToMonoChannelExtractROI<FloatVectorImageType::InternalPixelType,
                                            FloatImageType::PixelType>    ExtractROIFilterType;
  typedef otb::ObjectList<ExtractROIFilterType>                           ExtractROIFilterListType;
  typedef otb::BandMathImageFilter<FloatImageType>                             BandMathImageFilterType;


private:
56
  void DoInit() override
57
  {
58 59 60 61 62 63 64 65 66 67 68
    SetName( "BandMath" );

    SetDescription(
      "Outputs a monoband image which is the result of a mathematical operation "
      "on several multi-band images."
    );

    SetDocName( "Band Math" );

    SetDocLongDescription(
      "This application performs a mathematical operation on several multi-band "
69 70
      "images and outputs the result into a monoband image. The given expression"
      " is computed at each pixel position. Evaluation of the "
71
      "mathematical formula is done by the muParser library.\n\n"
72

73
      "The formula can be written using:\n\n"
74
      "* numerical values ( 2.3, -5, 3.1e4, ...)\n"
75
      "* variables containing pixel values (e.g. ``im2b3`` is the pixel value"
76
      " in 2nd image, 3rd band)\n"
77 78 79 80 81 82
      "* binary operators:\n\n"

      "  * ``+`` addition, ``-`` subtraction, ``*`` multiplication, ``/`` division\n"
      "  * ``^`` raise x to the power of y\n"
      "  * ``<`` less than, ``>`` greater than, ``<=`` less or equal, ``>=`` greater or equal\n"
      "  * ``==`` equal, ``!=`` not equal\n"
83
#ifdef OTB_MUPARSER_HAS_CXX_LOGICAL_OPERATORS
84
      "  * ``||`` logical or, ``&&`` logical and\n"
85
      "  * if-then-else operator: ``(condition ? value_true : value_false)``\n"
86
#else
87 88
      "  * ``or`` logical or, ``and`` logical and\n"
      "* if-then-else operator: ``if(condition;value_true;value_false)``\n"
89
#endif
90
      "* functions: ``exp()``, ``log()``, ``sin()``, ``cos()``, ``min()``, ``max()``, ...\n\n"
91 92

      "The full list of features and operators is available on the muParser website [1]."
93
      );
94

95 96
    SetDocLimitations( "None" );
    SetDocAuthors( "OTB-Team" );
97
    SetDocSeeAlso("[1] http://beltoforion.de/article.php?a=muparser");
98
    AddDocTag(Tags::Manip);
99

100
    AddParameter( ParameterType_InputImageList, "il", "Input image list" );
101 102
    SetParameterDescription(
      "il",
103
      "Image list of operands to the mathematical expression."
104
    );
105

106 107 108 109
    AddParameter( ParameterType_OutputImage, "out", "Output Image" );
    SetParameterDescription(
      "out",
      "Output image which is the result of the mathematical expressions on input"
110
      " image list operands.");
111

112 113 114
    AddParameter( ParameterType_String, "exp", "Expression");
    SetParameterDescription(
      "exp",
115
      "The muParser mathematical expression to apply on input images."
116
    );
117

118 119
    AddRAMParameter();

120
    // Doc example parameter settings
121 122 123 124 125 126 127 128 129 130 131
    SetDocExampleParameterValue(
      "il",
      "verySmallFSATSW_r.tif verySmallFSATSW_nir.tif verySmallFSATSW.tif"
    );
    SetDocExampleParameterValue(
      "out",
      "apTvUtBandMathOutput.tif"
    );
    SetDocExampleParameterValue(
      "exp", "'cos( im1b1 ) > cos( im2b1 ) ? im3b1 : im3b2'"
    );
132

133
    SetOfficialDocLink();
134
  }
135

136
  void DoUpdateParameters() override
137 138 139 140 141 142 143 144 145 146 147 148 149
  {
    // Check if the expression is correctly set
    if (HasValue("il"))
      {
      LiveCheck();
      }
  }

  void LiveCheck()
  {
    // Initialize a bandMath Filter first
    m_ChannelExtractorList = ExtractROIFilterListType::New();
    m_Filter               = BandMathImageFilterType::New();
150

151 152 153
    FloatVectorImageListType::Pointer inList   = GetParameterImageList("il");
    unsigned int                      nbInputs = inList->Size();
    unsigned int                      imageId  = 0, bandId = 0;
154

155 156 157 158
    for (unsigned int i = 0; i < nbInputs; i++)
      {
      FloatVectorImageType::Pointer currentImage = inList->GetNthElement(i);
      currentImage->UpdateOutputInformation();
159

160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
      for (unsigned int j = 0; j < currentImage->GetNumberOfComponentsPerPixel(); j++)
        {
        std::ostringstream tmpParserVarName;
        tmpParserVarName << "im" << imageId + 1 << "b" << j + 1;

        m_ExtractROIFilter = ExtractROIFilterType::New();
        m_ExtractROIFilter->SetInput(currentImage);
        m_ExtractROIFilter->SetChannel(j + 1);
        m_ExtractROIFilter->GetOutput()->UpdateOutputInformation();
        m_ChannelExtractorList->PushBack(m_ExtractROIFilter);
        m_Filter->SetNthInput(bandId, m_ChannelExtractorList->Back()->GetOutput(), tmpParserVarName.str());

        bandId++;
        }
      imageId++;
      }
176

177 178 179
    otb::Parser::Pointer dummyParser = otb::Parser::New();
    std::vector<double> dummyVars;
    std::string         success = "The expression is Valid";
OTB Bot's avatar
OTB Bot committed
180
    SetParameterDescription("exp", success);
181
    std::ostringstream  failure;
182

183 184 185
    if (HasValue("exp"))
      {
      // Setup the dummy parser
186
      for (unsigned int i = 0; i < bandId; i++)
187
        {
188
        dummyVars.push_back(1.);
189 190 191 192 193 194 195
        dummyParser->DefineVar(m_Filter->GetNthInputName(i), &(dummyVars.at(i)));
        }
      dummyParser->SetExpr(GetParameterString("exp"));

      // Check the expression
      try
        {
196
        dummyParser->Eval();
197 198 199
        }
      catch(itk::ExceptionObject& err)
        {
200 201
        // Change the parameter description to be able to have the
        // parser errors in the tooltip
OTB Bot's avatar
OTB Bot committed
202
        SetParameterDescription("exp", err.GetDescription());
203 204 205
        }
      }
  }
206

207
  void DoExecute() override
208 209 210
  {
    // Get the input image list
    FloatVectorImageListType::Pointer inList = GetParameterImageList("il");
211

212 213
    // checking the input images list validity
    const unsigned int nbImages = inList->Size();
214

215
    if (nbImages == 0)
216
      {
217 218
       itkExceptionMacro("No input Image set...; please set at least one input image");
      }
219

220 221
    m_ChannelExtractorList = ExtractROIFilterListType::New();
    m_Filter               = BandMathImageFilterType::New();
222

223 224
    unsigned int bandId = 0;
    unsigned int imageId = 0;
225

226 227 228 229 230
    for (unsigned int i = 0; i < nbImages; i++)
      {
      FloatVectorImageType::Pointer currentImage = inList->GetNthElement(i);
      currentImage->UpdateOutputInformation();

OTB Bot's avatar
OTB Bot committed
231
      otbAppLogINFO( << "Image #" << i + 1 << " has "
232 233
                     << currentImage->GetNumberOfComponentsPerPixel()
                     << " components" << std::endl );
234

235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
      for (unsigned int j = 0; j < currentImage->GetNumberOfComponentsPerPixel(); j++)
        {
        std::ostringstream tmpParserVarName;
        tmpParserVarName << "im" << imageId + 1 << "b" << j + 1;

        m_ExtractROIFilter = ExtractROIFilterType::New();
        m_ExtractROIFilter->SetInput(currentImage);
        m_ExtractROIFilter->SetChannel(j + 1);
        m_ExtractROIFilter->GetOutput()->UpdateOutputInformation();
        m_ChannelExtractorList->PushBack(m_ExtractROIFilter);
        m_Filter->SetNthInput(bandId, m_ChannelExtractorList->Back()->GetOutput(), tmpParserVarName.str());

        bandId++;
        }
      imageId++;
250 251
      }

252
    m_Filter->SetExpression(GetParameterString("exp"));
253

254 255 256
    // Set the output image
    SetParameterOutputImage("out", m_Filter->GetOutput());
  }
257

258 259 260 261
  ExtractROIFilterType::Pointer     m_ExtractROIFilter;
  ExtractROIFilterListType::Pointer m_ChannelExtractorList;
  BandMathImageFilterType::Pointer  m_Filter;
};
262

263 264
} // namespace Wrapper
} // namespace otb
265

266
OTB_APPLICATION_EXPORT(otb::Wrapper::BandMath)