otbLSGRM.cxx 9.7 KB
Newer Older
remicres's avatar
remicres committed
1 2 3 4 5 6 7 8 9 10 11 12
#include "itkFixedArray.h"
#include "itkObjectFactory.h"

// Elevation handler
#include "otbWrapperElevationParametersHandler.h"
#include "otbWrapperApplicationFactory.h"

// Application engine
#include "otbStandardFilterWatcher.h"
#include "itkFixedArray.h"
#include "itkImageSource.h"

remicres's avatar
remicres committed
13
// LSGRM
14
#include <iostream>
15 16 17
#include "lsgrmBaatzSegmenter.h"
#include "lsgrmSpringSegmenter.h"
#include "lsgrmFullLambdaScheduleSegmenter.h"
18 19
#include "lsgrmController.h"

20 21 22 23
// Graph to label image (streaming version)
#include "otbStreamingGraphToImageFilter.h"
#include "otbStreamingImageVirtualWriter.h"

24 25 26
// system tools
#include <itksys/SystemTools.hxx>

remicres's avatar
remicres committed
27 28 29 30 31 32 33
namespace otb
{

namespace Wrapper
{

class LSGRM : public Application
34
{
remicres's avatar
remicres committed
35 36
public:
  /** Standard class typedefs. */
37
  typedef LSGRM                         Self;
remicres's avatar
remicres committed
38 39 40 41 42 43 44 45
  typedef Application                   Superclass;
  typedef itk::SmartPointer<Self>       Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;

  /** Standard macro */
  itkNewMacro(Self);
  itkTypeMacro(LSGRM, Application);

46 47 48 49 50 51
  /** Useful typedefs */
  typedef otb::VectorImage<float, 2>                    ImageType;
  typedef lsgrm::BaatzSegmenter<ImageType>              BaatzSegmenterType;
  typedef lsgrm::SpringSegmenter<ImageType>             SpringSegmenterType;
  typedef lsgrm::FullLambdaScheduleSegmenter<ImageType> FLSSegmenterType;

remicres's avatar
remicres committed
52 53
private:

54 55 56 57 58 59 60 61
  /* Tiling mode choice */
  enum TilingMode
  {
    TILING_AUTO,
    TILING_USER,
    TILING_NONE
  };

62 63 64 65 66 67 68 69
  /* Criterion choice */
  enum Criterion
  {
    CRITERION_BAATZ,
    CRITERION_SPRING,
    CRITERION_FLS
  };

remicres's avatar
remicres committed
70 71
  void DoInit()
  {
72

73
    SetName("GenericRegionMerging");
remicres's avatar
remicres committed
74 75
    SetDescription("This application allows to use the Large Scale Generic Region Merging library "
        "(LSGRM) and provides currently 3 homogeneity criteria: Euclidean Distance, "
76 77
        "Full Lambda Schedule and Baatz & Schape criterion.");

78
    // Input and Output images
79 80 81 82
    AddParameter(ParameterType_InputImage, "in", "Input Image");
    AddParameter(ParameterType_OutputImage, "out", "Ouput Label Image");
    SetDefaultOutputPixelType("out", ImagePixelType_uint32);

83 84 85 86 87
    // Criterion choice
    AddParameter(ParameterType_Choice, "criterion", "Homogeneity criterion to use");
    AddChoice("criterion.bs", "Baatz & Schape");
    AddChoice("criterion.ed", "Euclidean Distance");
    AddChoice("criterion.fls", "Full Lambda Schedule");
88

89
    // Generic parameters
90 91 92 93 94
    AddParameter(ParameterType_Float, "threshold", "Threshold for the criterion");
    AddParameter(ParameterType_Int, "niter", "Maximum number of iterations");
    SetDefaultParameterInt("niter", 75);
    MandatoryOff("niter");

95 96 97 98 99 100 101
    // Specific parameters for Baatz & Schape
    AddParameter(ParameterType_Float, "criterion.bs.cw", "Weight for the spectral homogeneity");
    SetDefaultParameterFloat("criterion.bs.cw", 0.5);
    MandatoryOff("criterion.bs.cw");
    AddParameter(ParameterType_Float, "criterion.bs.sw", "Weight for the spatial homogeneity");
    SetDefaultParameterFloat("criterion.bs.sw", 0.5);
    MandatoryOff("criterion.bs.sw");
102 103

    // For large scale
104
    AddParameter(ParameterType_Directory, "tmpdir", "Directory for temporary files");
105
    MandatoryOff("tmpdir");
106 107 108 109 110 111 112
    AddParameter(ParameterType_Choice, "tiling", "Tiling layout for the large scale segmentation");
    AddChoice("tiling.auto", "Automatic tiling layout");
    AddChoice("tiling.user", "User tiling layout");
    AddParameter(ParameterType_Int, "tiling.user.sizex", "Tiles width");
    AddParameter(ParameterType_Int, "tiling.user.sizey", "Tiles height");
    AddParameter(ParameterType_Int, "tiling.user.nfirstiter", "Number of first iterations");
    AddChoice("tiling.none", "No tiling layout");
113 114

    AddParameter(ParameterType_Int, "memory", "Restrict memory use (mb)");
115

116
    MandatoryOff("memory");
remicres's avatar
remicres committed
117 118 119 120 121 122
  }

  void DoUpdateParameters()
  {
  }

123 124 125 126 127 128 129 130 131 132 133
  /*
   * Return a prefix for temporary files
   */
  std::string GetTemporaryFilesPrefix()
  {

    // Get output filename (without extension)
    std::string outfname = GetParameterString("out");
    std::string outbfname = itksys::SystemTools::GetFilenameWithoutExtension(outfname.c_str());

    // Get specified temporary directory
134 135 136
    std::string tmpdir;
    if (HasValue("tmpdir"))
      {
137
        tmpdir= GetParameterAsString("tmpdir");
138 139 140
      }
    else
      {
141
        tmpdir = itksys::SystemTools::GetFilenamePath(outfname);
142 143
      }

144 145
    if (!tmpdir.empty())
      {
146 147 148 149 150 151 152 153 154 155 156 157 158
        // A temporary directory is specified: we check that it ends with a POSIX separator
        if (tmpdir[tmpdir.size()-1] != '/')
          {
            // If not, we add the separator
            tmpdir.append("/");
          }

        // Check that the directory exists
        if (!itksys::SystemTools::FileExists(tmpdir.c_str(),false))
          {
            otbAppLogFATAL("The directory " << tmpdir << " does not exist.");
          }
        otbAppLogINFO("Using temporary directory " << tmpdir);
remicres's avatar
remicres committed
159
      }
160

remicres's avatar
remicres committed
161 162

    // Return the prefix
163 164 165 166
    std::string prefix = tmpdir + outbfname;
    return prefix;
  }

167 168 169
  /*
   * This function sets the generic parameters of a controller and runs the segmentation
   */
remicres's avatar
remicres committed
170
  template<class TSegmenter>
171 172
  void
  SetGenericParametersAndRunSegmentation(const typename TSegmenter::ParamType params){
remicres's avatar
remicres committed
173 174 175 176

    // Instantiate the controller
    typedef typename lsgrm::Controller<TSegmenter> ControlerType;
    typename ControlerType::Pointer controller = ControlerType::New();
177
    using GraphType = typename ControlerType::GraphType;
remicres's avatar
remicres committed
178 179 180 181

    // Set specific parameters
    controller->SetSpecificParameters(params);

182
    // Set input image
183 184
    ImageType::Pointer inputImage = GetParameterFloatVectorImage("in");
    controller->SetInputImage(inputImage);
remicres's avatar
remicres committed
185

186 187 188
    // Set threshold
    float thres = GetParameterFloat("threshold");
    controller->SetThreshold(thres*thres);
remicres's avatar
remicres committed
189

190 191
    // Set number of iterations
    controller->SetNumberOfIterations(GetParameterInt("niter"));
remicres's avatar
remicres committed
192

193 194
    // Set temporary files prefix
    controller->SetTemporaryFilesPrefix(this->GetTemporaryFilesPrefix());
remicres's avatar
remicres committed
195

196
    // Switch tiling mode
197 198
    int inputTilingMode = GetParameterInt("tiling");
    if (inputTilingMode == TILING_AUTO)
199
      {
200 201
        // Automatic mode
        controller->SetTilingModeAuto();
202
      }
203
    else if (inputTilingMode == TILING_USER)
204
      {
205 206 207 208 209
        // User mode
        controller->SetTilingModeUser();
        controller->SetTileWidth(GetParameterInt("tiling.user.sizex"));
        controller->SetTileHeight(GetParameterInt("tiling.user.sizey"));
        controller->SetNumberOfFirstIterations(GetParameterInt("tiling.user.nfirstiter"));
210
      }
211 212
    else if (inputTilingMode == TILING_NONE)
      {
213 214
        // None mode
        controller->SetTilingModeNone();
215 216 217
      }
    else
      {
218
        otbAppLogFATAL("Unknown tiling mode!");
219 220 221 222 223
      }

    // Input RAM value?
    if (HasValue("memory"))
      {
224 225
        otbAppLogINFO("Setting maximum memory to " << GetParameterInt("memory") << " MBytes");
        controller->SetInternalMemoryAvailable(GetParameterInt("memory"));
226
      }
remicres's avatar
remicres committed
227

228
    // Run the segmentation
229
    controller->RunSegmentation();
remicres's avatar
remicres committed
230

231 232 233 234 235 236
    // Prepare the label image source
    typedef lsgrm::StreamingGraphToImageFilter<GraphType, UInt32ImageType> LabelImageSourceType;
    typename LabelImageSourceType::Pointer labelImageSource = LabelImageSourceType::New();
    labelImageSource->SetGraph(controller->GetOutputGraph());
    labelImageSource->SetOutputSize(inputImage->GetLargestPossibleRegion().GetSize());
    labelImageSource->SetOutputOrigin(inputImage->GetOrigin());
237
    labelImageSource->SetOutputSpacing(inputImage->GetSignedSpacing());
238 239 240 241 242 243 244 245 246 247 248
    labelImageSource->SetOutputProjectionRef(inputImage->GetProjectionRef());
    labelImageSource->GenerateOutputInformation();

    m_LabelImageSource = static_cast<itk::ImageSource<UInt32ImageType>*>(labelImageSource);

    SetParameterOutputImage<UInt32ImageType>("out", m_LabelImageSource->GetOutput());

    // TODO: find an intelligent value of RAM
    if (dynamic_cast<OutputImageParameter*>(GetParameterByKey("out")))
      {
      OutputImageParameter* paramDown = dynamic_cast<OutputImageParameter*>(GetParameterByKey("out"));
249
      paramDown->SetRAMValue(1024);
250 251
      }

252 253 254 255 256 257 258 259 260 261 262 263 264 265
    // Get temporary files list
    m_TemporaryFilesList = controller->GetTemporaryFilesList();

  }

  void DoExecute()
  {

    ImageType::Pointer inputImage = GetParameterFloatVectorImage("in");

    // Switch criterion
    int inputCriterion = GetParameterInt("criterion");
    if (inputCriterion == CRITERION_BAATZ)
      {
266 267 268 269
        grm::BaatzParam params;
        params.m_SpectralWeight = GetParameterFloat("criterion.bs.cw");
        params.m_ShapeWeight = GetParameterFloat("criterion.bs.sw");
        SetGenericParametersAndRunSegmentation<BaatzSegmenterType>(params);
270 271 272
      }
    else if (inputCriterion == CRITERION_SPRING)
      {
273 274
        grm::SpringParam params;
        SetGenericParametersAndRunSegmentation<SpringSegmenterType>(params);
275 276 277
      }
    else if (inputCriterion == CRITERION_FLS)
      {
278 279
        grm::FLSParam params;
        SetGenericParametersAndRunSegmentation<FLSSegmenterType>(params);
280 281 282
      }
    else
      {
283
        otbAppLogFATAL("Unknow criterion!")
284
      }
285

remicres's avatar
remicres committed
286 287 288 289
  }

  void AfterExecuteAndWriteOutputs()
  {
remicres's avatar
remicres committed
290 291 292 293 294 295 296

#ifdef OTB_USE_MPI
    // When MPI is activated, only the master thread proceed
    if (otb::MPIConfig::Instance()->GetMyRank() != 0)
      return;
#endif

297 298 299
    // Delete temporary files
    for (unsigned int i = 0 ; i < m_TemporaryFilesList.size() ; i++)
      {
300 301 302 303
        if( remove(m_TemporaryFilesList.at(i).c_str() ) != 0  )
          {
            otbAppLogWARNING( "Error deleting file " << m_TemporaryFilesList.at(i) );
          }
304
      }
remicres's avatar
remicres committed
305 306
  }

307 308
private:
  std::vector<std::string> m_TemporaryFilesList;
309
  itk::ImageSource<UInt32ImageType>::Pointer m_LabelImageSource;
310

remicres's avatar
remicres committed
311 312 313 314 315
}; // app class
} // end of namespace wrapper
} // end of namespace otb

OTB_APPLICATION_EXPORT(otb::Wrapper::LSGRM)