Commit 84788f22 authored by Pierre Lassalle's avatar Pierre Lassalle

Add the GRM Remote Module

parent ff8510c6
# Check compiler version
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
# require at least gcc 4.8
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8)
message(FATAL_ERROR "GCC version must be at least 4.8!")
endif()
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# require at least clang 3.2
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.2)
message(FATAL_ERROR "Clang version must be at least 3.2!")
endif()
else()
message(WARNING "You are using an unsupported compiler! Compilation has only been tested with Clang and GCC.")
endif()
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
if(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fpermissive")
else()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()
set(GRM_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/)
include_directories(${GRM_INCLUDE_DIR})
project(GRM)
set(GRM_LIBRARIES GRM)
otb_module_impl()
/*=========================================================================
Program: Generic Region Merging Library
Language: C++
author: Lassalle Pierre
contact: lassallepierre34@gmail.com
Copyright (c) Centre National d'Etudes Spatiales. All rights reserved
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
Template Model to help the developper to add a new criterion
This file as well as his corresponding txx file has to be added
src folder.
=========================================================================*/
#ifndef __GRM_MYSEGMENTER_H
#define __GRM_MYSEGMENTER_H
#include "grmSegmenter.h"
namespace grm
{
struct MySpecificNode : Node<MySpecificNode>
{
// Specific Attributes for your criterion.
};
struct MySpecificParams
{
// Specific user-defined parameters for your criterion.
};
template<class TImage>
class MySegmenter : public Segmenter< TImage, MySpecificNode, MySpecificParams>
{
public:
/* Some convenient typedefs (put them all) */
typedef Segmenter<TImage, MySpecificNode, MySpecificParams> Superclass;
typedef TImage ImageType;
typedef MySpecificParams ParameterType;
typedef typename Superclass::GraphType GraphType;
typedef MySpecificNode NodeType;
typedef typename Superclass::EdgeType EdgeType;
typedef typename Superclass::NodePointerType NodePointerType;
typedef typename Superclass::GraphOperatorType GraphOperatorType;
typedef GraphToOtbImage<GraphType> IOType;
// Mandatory functions to be defined by the developer.
void InitFromImage();
float ComputeMergingCost(NodePointerType n1, NodePointerType n2);
void UpdateSpecificAttributes(NodePointerType n1, NodePointerType n2);
};
} // end of namespace grm
#include "GRMSegmenterTemplate.txx"
#endif
/*=========================================================================
Program: Generic Region Merging Library
Language: C++
author: Lassalle Pierre
contact: lassallepierre34@gmail.com
Copyright (c) Centre National d'Etudes Spatiales. All rights reserved
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
Template Model to help the developper to add a new criterion
This file as well as his corresponding txx file has to be added
src folder.
=========================================================================*/
#ifndef __GRM_MYSEGMENTER_TXX
#define __GRM_MYSEGMENTER_TXX
#include <otbImageFileReader.h>
#include <itkImageRegionIterator.h>
/*
Important to read:
The graph of segments can be accessed like this: this->m_Graph
The number of segments in the graph: this->m_Graph.size()
To access to the segment pointer at the position idx: this->m_Graph.m_Nodes[idx]
For each segment pointer you can used the following attributes:
this->m_Graph.m_Nodes[idx]->m_Perimeter // Perimeter of the segment.
this->m_Graph.m_Nodes[idx]->m_Area // Number of pixels contained in the segment.
this->m_Graph.m_Nodes[idx]->m_Bbox // Bounding box of the segment:
this->m_Graph.m_Nodes[idx]->m_Bbox.m_UX : upper left x coordinate
this->m_Graph.m_Nodes[idx]->m_Bbox.m_UY : upper left y coordinate
this->m_Graph.m_Nodes[idx]->m_Bbox.m_W : width
this->m_Graph.m_Nodes[idx]->m_Bbox.m_UX : height
this->m_Graph.m_Nodes[idx]->m_Contour: moves along the contour of the segment:
To generate the set of the coordinates of the border pixels:
lp::CellLists borderPixels; // (std::unordered_set<long unsigned int>)
lp::ContourOperations::GenerateBorderCells(borderPixels, this->m_Graph.m_Nodes[idx]->m_Contour, this->m_Graph.m_Nodes[idx]->m_Id, this->m_ImageWidth);
this->m_Graph.m_Nodes[idx]->m_Edges // std::vector<EdgeType> containing edges to adjacent segment
Given an edge e:
e.GetRegion() : access to the adjacent segment pointer.
e.m_Boundary : lenght of the border between the current segment and the adjacent segment.
e.m_Cost: merging cost between the current segment and the adjacent segment.
*/
namespace grm
{
template<class TImage>
void
MySegmenter<TImage>::InitFromImage()
{
typedef itk::ImageRegionIterator<TImage> ImageIterator;
this->m_ImageWidth = this->m_InputImage->GetLargestPossibleRegion().GetSize()[0];
this->m_ImageHeight =this->m_InputImage->GetLargestPossibleRegion().GetSize()[1];
this->m_NumberOfComponentsPerPixel = this->m_InputImage->GetNumberOfComponentsPerPixel();
std::size_t idx = 0;
ImageIterator it(this->m_InputImage, this->m_InputImage->GetLargestPossibleRegion());
for(it.GoToBegin(); !it.IsAtEnd(); ++it)
{
// Initialize your specific attributes for each pixel of the image.
for(std::size_t b = 0; b < this->m_NumberOfComponentsPerPixel; ++b)
{
// Initialize your specific attributes if they depend on spectral values of pixels.
}
++idx;
}
}
template<class TImage>
float
MySegmenter<TImage>::ComputeMergingCost(NodePointerType n1, NodePointerType n2)
{
// Determine how to compute the merging cost between the two adjacent segments.
}
template<class TImage>
void
MySegmenter<TImage>::UpdateSpecificAttributes(NodePointerType n1, NodePointerType n2)
{
// Determine how to update your specif attributes when segment n2 is merged into segment n1.
// This means that you have to update the specific attributes of segment n1 according to
// the specific attributes of segments n1 and n2.
}
} // end of namespace grm
#endif
Summary
=======
This module provides the GRM OTB application to perform multiscale region-merging segmentation on satellite images.
Three local homogeneity criteria are available: the Baatz & Schäpe criterion, the Full Lambda Schedule criterion and
the simple Euclidean Distance criterion.
This application uses the GRM (Generic Region Merging) library which allows to add quickly a new local homogeneity criterion.
Look at the template header file: GRMSegmenterTemplate.h to see which format you must respect to add a new criterion.
Licence
=======
Copyright (c) Centre National d'Études Spatiales. All rights reserved.
This is free software under the GPL v3 licence. See http://www.gnu.org/licenses/gpl-3.0.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Contact
=======
Author: Lassalle Pierre
email: lassallepierre34@gmail.com
website: http://pierre33.github.io/
OTB_CREATE_APPLICATION(NAME GRM
SOURCES otbGRM.cxx
LINK_LIBRARIES ${${otb-module}_LIBRARIES}
)
OTB_CREATE_APPLICATION(NAME GRMSegmentation
SOURCES otbGRM.cxx
LINK_LIBRARIES ${${otb-module}_LIBRARIES}
)
/*=======================================================================
Program: ORFEO Toolbox
Language: C++
Date: $Date$
Version: $Revision$
Author: Lassalle Pierre
Contact: lassallepierre34@gmail.com
Website: http://pierre33.github.io/
Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
See OTBCopyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=======================================================================*/
#include "otbImage.h"
#include "otbVectorImage.h"
#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"
#include "grmSpringSegmenter.h"
#include "grmFullLambdaScheduleSegmenter.h"
#include "grmBaatzSegmenter.h"
#include "otbWrapperApplication.h"
namespace otb
{
namespace Wrapper
{
class otbGRM : public Application
{
public:
typedef otbGRM Self;
typedef itk::SmartPointer<Self> Pointer;
typedef FloatVectorImageType ImageType;
typedef UInt32ImageType LabelImageType;
itkNewMacro(Self);
itkTypeMacro(otbGRM, otb::Application);
private:
void DoInit()
{
SetName("otbGRM");
SetDescription("This application allows to use the Generic Region Merging library (GRM) and provides currently 3 homogeneity criteria: Euclidean Distance, Full Lambda Schedule and Baatz & Schape criterion.");
AddParameter(ParameterType_InputImage, "in", "Input Image");
AddParameter(ParameterType_OutputFilename, "out", "Ouput Label Image");
AddParameter(ParameterType_Choice, "criterion", "Homogeneity criterion to use");
AddChoice("bs", "Baatz & Schape");
AddChoice("ed", "Euclidean Distance");
AddChoice("fls", "Full Lambda Schedule");
AddParameter(ParameterType_Float, "threshold", "Threshold for the criterion");
AddParameter(ParameterType_Int, "niter", "Number of iterations");
SetDefaultParameterFloat("niter", 0);
MandatoryOff("niter");
AddParameter(ParameterType_Int, "speed", "Activate it to boost the segmentation speed");
SetDefaultParameterFloat("speed", 0);
MandatoryOff("speed");
// For Baatz & Schape
AddParameter(ParameterType_Float, "cw", "Weight for the spectral homogeneity");
SetDefaultParameterFloat("cw", 0.5);
MandatoryOff("cw");
AddParameter(ParameterType_Float, "sw", "Weight for the spatial homogeneity");
SetDefaultParameterFloat("sw", 0.5);
MandatoryOff("sw");
}
void DoUpdateParameters()
{
}
void DoExecute()
{
// Mandatory parameters
// Input Image
ImageType::Pointer image = GetParameterImage("in");
image->Update();
// Output label file name.
const std::string labelImageFileName = GetParameterString("out");
// Criterion selected
const std::string selectedCriterion = GetParameterString("criterion");
// Threshold
float threshold = GetParameterFloat("threshold");
const unsigned int niter = GetParameterInt("niter");
const int speed = GetParameterInt("speed");
typedef otb::ImageFileWriter<LabelImageType> LabelImageWriter;
if(selectedCriterion == "bs")
{
const float cw = GetParameterFloat("cw");
const float sw = GetParameterFloat("sw");
grm::BaatzParam params;
params.m_SpectralWeight = cw;
params.m_ShapeWeight = sw;
grm::BaatzSegmenter<ImageType> segmenter;
segmenter.SetParam(params);
segmenter.SetThreshold(threshold*threshold);
segmenter.SetInput(image);
if(niter > 0)
segmenter.SetNumberOfIterations(niter);
if(speed > 0)
segmenter.SetDoFastSegmentation(true);
segmenter.Update();
LabelImageWriter::Pointer labelWriter = LabelImageWriter::New();
labelWriter->SetFileName(labelImageFileName);
labelWriter->SetInput(segmenter.GetLabeledClusteredOutput());
labelWriter->Update();
}
else if(selectedCriterion == "ed")
{
grm::SpringSegmenter<ImageType> segmenter;
segmenter.SetThreshold(threshold);
segmenter.SetInput(image);
if(niter > 0)
segmenter.SetNumberOfIterations(niter);
if(speed > 0)
segmenter.SetDoFastSegmentation(true);
segmenter.Update();
LabelImageWriter::Pointer labelWriter = LabelImageWriter::New();
labelWriter->SetFileName(labelImageFileName);
labelWriter->SetInput(segmenter.GetLabeledClusteredOutput());
labelWriter->Update();
}
else if(selectedCriterion == "fls")
{
grm::FullLambdaScheduleSegmenter<ImageType> segmenter;
segmenter.SetThreshold(threshold);
segmenter.SetInput(image);
if(niter > 0)
segmenter.SetNumberOfIterations(niter);
if(speed > 0)
segmenter.SetDoFastSegmentation(true);
segmenter.Update();
LabelImageWriter::Pointer labelWriter = LabelImageWriter::New();
labelWriter->SetFileName(labelImageFileName);
labelWriter->SetInput(segmenter.GetLabeledClusteredOutput());
labelWriter->Update();
}
}
};
} // end of namespace Wrapper
} // end of namespace otb
/*=======================================================================
Program: ORFEO Toolbox
Language: C++
Date: $Date$
Version: $Revision$
Author: Lassalle Pierre
Contact: lassallepierre34@gmail.com
Website: http://pierre33.github.io/
Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
See OTBCopyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=======================================================================*/
#include "otbImage.h"
#include "otbVectorImage.h"
#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"
#include "grmSpringSegmenter.h"
#include "grmFullLambdaScheduleSegmenter.h"
#include "grmBaatzSegmenter.h"
#include "otbWrapperApplication.h"
namespace otb
{
namespace Wrapper
{
class otbGRM : public Application
{
public:
typedef otbGRM Self;
typedef itk::SmartPointer<Self> Pointer;
typedef FloatVectorImageType ImageType;
typedef UInt32ImageType LabelImageType;
itkNewMacro(Self);
itkTypeMacro(otbGRM, otb::Application);
private:
void DoInit()
{
SetName("otbGRM");
SetDescription("This application allows to use the Generic Region Merging library (GRM) and provides currently 3 homogeneity criteria: Euclidean Distance, Full Lambda Schedule and Baatz & Schape criterion.");
AddParameter(ParameterType_InputImage, "in", "Input Image");
AddParameter(ParameterType_OutputFilename, "out", "Ouput Label Image");
AddParameter(ParameterType_Choice, "criterion", "Homogeneity criterion to use");
AddChoice("bs", "Baatz & Schape");
AddChoice("ed", "Euclidean Distance");
AddChoice("fls", "Full Lambda Schedule");
AddParameter(ParameterType_Float, "threshold", "Threshold for the criterion");
AddParameter(ParameterType_Int, "niter", "Number of iterations");
SetDefaultParameterFloat("niter", 0);
MandatoryOff("niter");
AddParameter(ParameterType_Int, "speed", "Activate it to boost the segmentation speed");
SetDefaultParameterFloat("speed", 0);
MandatoryOff("speed");
// For Baatz & Schape
AddParameter(ParameterType_Float, "cw", "Weight for the spectral homogeneity");
SetDefaultParameterFloat("cw", 0.5);
MandatoryOff("cw");
AddParameter(ParameterType_Float, "sw", "Weight for the spatial homogeneity");
SetDefaultParameterFloat("sw", 0.5);
MandatoryOff("sw");
}
void DoUpdateParameters()
{
}
void DoExecute()
{
// Mandatory parameters
// Input Image
ImageType::Pointer image = GetParameterImage("in");
image->Update();
// Output label file name.
const std::string labelImageFileName = GetParameterString("out");
// Criterion selected
const std::string selectedCriterion = GetParameterString("criterion");
// Threshold
float threshold = GetParameterFloat("threshold");
const unsigned int niter = GetParameterInt("niter");
const int speed = GetParameterInt("speed");
typedef otb::ImageFileWriter<LabelImageType> LabelImageWriter;
if(selectedCriterion == "bs")
{
const float cw = GetParameterFloat("cw");
const float sw = GetParameterFloat("sw");
grm::BaatzParam params;
params.m_SpectralWeight = cw;
params.m_ShapeWeight = sw;
grm::BaatzSegmenter<ImageType> segmenter;
segmenter.SetParam(params);
segmenter.SetThreshold(threshold*threshold);
segmenter.SetInput(image);
if(niter > 0)
segmenter.SetNumberOfIterations(niter);
if(speed > 0)
segmenter.SetDoFastSegmentation(true);
segmenter.Update();
LabelImageWriter::Pointer labelWriter = LabelImageWriter::New();
labelWriter->SetFileName(labelImageFileName);
labelWriter->SetInput(segmenter.GetLabeledClusteredOutput());
labelWriter->Update();
}
else if(selectedCriterion == "ed")
{
grm::SpringSegmenter<ImageType> segmenter;
segmenter.SetThreshold(threshold);
segmenter.SetInput(image);
if(niter > 0)
segmenter.SetNumberOfIterations(niter);
if(speed > 0)
segmenter.SetDoFastSegmentation(true);
segmenter.Update();
LabelImageWriter::Pointer labelWriter = LabelImageWriter::New();
labelWriter->SetFileName(labelImageFileName);
labelWriter->SetInput(segmenter.GetLabeledClusteredOutput());
labelWriter->Update();
}
else if(selectedCriterion == "fls")
{
grm::FullLambdaScheduleSegmenter<ImageType> segmenter;
segmenter.SetThreshold(threshold);
segmenter.SetInput(image);
if(niter > 0)
segmenter.SetNumberOfIterations(niter);
if(speed > 0)
segmenter.SetDoFastSegmentation(true);
segmenter.Update();
LabelImageWriter::Pointer labelWriter = LabelImageWriter::New();
labelWriter->SetFileName(labelImageFileName);
labelWriter->SetInput(segmenter.GetLabeledClusteredOutput());
labelWriter->Update();
}
}
};
} // end of namespace Wrapper
} // end of namespace otb
author: Lassalle Pierre
Copyright (c) Centre National d'Études Spatiales. All rights reserved.
This work has been funded by CNES, CS Systèmes d'Information,
Université Paul Sabatier Toulouse III, and CNRS,
in the frame of the PHD thesis of Pierre Lassalle.
set(DOCUMENTATION "GRM OTB Application for region merging segmentation of very high resolution satellite scenes.")
# define the dependencies of the include module and the tests
otb_module(otbGRM
DEPENDS
OTBCommon
OTBApplicationEngine
OTBStreaming
OTBExtendedFilename
OTBImageIO
TEST_DEPENDS
OTBTestKernel
OTBCommandLine
DESCRIPTION
"${DOCUMENTATION}"
)
set(${otb-module}_SRC
grmBaatzSegmenter.txx
grmFullLambdaScheduleSegmenter.txx
grmGraphOperations.txx
grmGraphToOtbImage.txx
grmNeighborhood.cxx
grmSpringSegmenter.txx
lpContour.cxx
)
add_library(${otb-module} ${${otb-module}_SRC})
target_link_libraries(${otb_module} ${OTBCommon_LIBRARIES})
otb_module_target(${otb-module})
/*=========================================================================
Program: Generic Region Merging Library
Language: C++
author: Lassalle Pierre
contact: lassallepierre34@gmail.com
Copyright (c) Centre National d'Etudes Spatiales. All rights reserved
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#ifndef __GRM_BAATZ_SEGMENTER_H
#define __GRM_BAATZ_SEGMENTER_H
#include "grmSegmenter.h"
namespace grm
{
struct BaatzNode : Node<BaatzNode>
{
std::vector<float> m_Means;
std::vector<float> m_SquareMeans;
std::vector<float> m_SpectralSum;
std::vector<float> m_Std;
};
struct BaatzParam
{
float m_SpectralWeight;
float m_ShapeWeight;
};
template<class TImage>
class BaatzSegmenter : public Segmenter< TImage, BaatzNode, BaatzParam>
{
public:
/* Some convenient typedefs */
typedef Segmenter<TImage, BaatzNode, BaatzParam> Superclass;
typedef TImage ImageType;
typedef BaatzParam ParameterType;
typedef typename Superclass::GraphType GraphType;
typedef BaatzNode NodeType;
typedef typename Superclass::EdgeType EdgeType;
typedef typename Superclass::NodePointerType NodePointerType;
typedef typename Superclass::GraphOperatorType GraphOperatorType;
typedef GraphToOtbImage<GraphType> IOType;
float ComputeMergingCost(NodePointerType n1, NodePointerType n2);
void UpdateSpecificAttributes(NodePointerType n1, NodePointerType n2);
void InitFromImage();
};
} // end of namespace grm
#include "grmBaatzSegmenter.txx"
#endif
/*=========================================================================
Program: Generic Region Merging Library
Language: C++
author: Lassalle Pierre
contact: lassallepierre34@gmail.com
Copyright (c) Centre National d'Etudes Spatiales. All rights reserved
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#ifndef __GRM_BAATZ_SEGMENTER_TXX
#define __GRM_BAATZ_SEGMENTER_TXX
#include <otbImageFileReader.h>
#include <itkImageRegionIterator.h>