Commit 91852f09 authored by remicres's avatar remicres

ENH: remove image file readers

parent b6e5a13d
#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"
// GRM
#include <iostream>
#include "lsrmBaatzSegmenter.h"
#include "lsgrmController.h"
int main(int argc, char *argv[])
namespace otb
{
namespace Wrapper
{
class LSGRM : public Application
{
public:
/** Standard class typedefs. */
typedef LSGRM Self;
typedef Application Superclass;
typedef itk::SmartPointer<Self> Pointer;
typedef itk::SmartPointer<const Self> ConstPointer;
/** Standard macro */
itkNewMacro(Self);
itkTypeMacro(LSGRM, Application);
private:
void DoInit()
{
SetName("GenericRegionMerging");
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_OutputImage, "out", "Ouput Label Image");
// AddParameter(ParameterType_Choice, "criterion", "Homogeneity criterion to use");
// AddChoice("criterion.bs", "Baatz & Schape");
// AddChoice("criterion.ed", "Euclidean Distance");
// AddChoice("criterion.fls", "Full Lambda Schedule");
AddParameter(ParameterType_Float, "threshold", "Threshold for the criterion");
AddParameter(ParameterType_Int, "niter", "Number of iterations");
SetDefaultParameterInt("niter", 0);
MandatoryOff("niter");
AddParameter(ParameterType_Int, "speed", "Activate it to boost the segmentation speed");
SetDefaultParameterInt("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");
// For large scale
AddParameter(ParameterType_Directory, "tmpdir", "temporary directory for tiles and graphs");
AddParameter(ParameterType_Int, "tsizex", "tile width");
AddParameter(ParameterType_Int, "tsizey", "tile height");
AddParameter(ParameterType_Int, "nfirstiter", "number of first iterations");
}
void DoUpdateParameters()
{
}
void DoExecute()
{
/*
To add:
internal memory available
If we have to do the image division
if we have to clean up the directory
the output directory in case the global graph cannot fit in memory
*/
using ImageType = otb::VectorImage<float, 2>;
using SegmenterType = lsrm::BaatzSegmenter<ImageType>;
using ControllerType = lsgrm::Controller<SegmenterType>;
ControllerType controller;
controller.SetInputImage(GetParameterFloatVectorImage("in"));
controller.SetTileDirectory(GetParameterAsString("tmpdir"));
controller.SetTemporaryDirectory(GetParameterAsString("tmpdir"));
controller.SetOutputGraphDirectory(GetParameterAsString("tmpdir"));
// Memory configuration
controller.SetInternalMemoryAvailable(0); // 0 = automatic
controller.SetTileWidth(GetParameterInt("tsizex"));
controller.SetTileHeight(GetParameterInt("tsizey"));
controller.SetNumberOfFirstIterations(GetParameterInt("nfirstiter"));
// MPI configuration
#ifdef OTB_USE_MPI
if (myrank==0)
std::cout << "Number of MPI process : " << nprocs << std::endl;
controller.SetNumberOfProcess(nprocs);
controller.SetProcessRank(myrank);
#endif
// Specific parameters
lsrm::BaatzParam params;
params.m_SpectralWeight = GetParameterFloat("cw");
params.m_ShapeWeight = GetParameterFloat("sw");
controller.SetSpecificParameters(params);
float thres = GetParameterFloat("threshold");
controller.SetThreshold(thres*thres);
controller.RunSegmentation();
}
void AfterExecuteAndWriteOutputs()
{
}
}; // app class
} // end of namespace wrapper
} // end of namespace otb
OTB_APPLICATION_EXPORT(otb::Wrapper::LSGRM)
int myrank, nprocs;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
if (myrank==0)
std::cout << "Number of MPI process : " << nprocs << std::endl;
if(argc != 8)
{
// img/test.tif tiles/ 125 125 4 tmp/
std::cerr << "[input image] [tile directory] [tile width] [tile height] [number of first iterations] [temporary directory] [output directory]"
<< std::endl;
return 1;
}
/* Parse command line arguments */
const std::string imagePath = argv[1];
std::string tileDir = argv[2]; // May be corrected if badly written.
const unsigned int tileWidth = atoi(argv[3]);
const unsigned int tileHeight = atoi(argv[4]);
const unsigned int niter = atoi(argv[5]);
std::string tmpDir = argv[6]; // May be corrected if badly written.
std::string outDir = argv[7];
/*
To add:
internal memory available
If we have to do the image division
if we have to clean up the directory
the output directory in case the global graph cannot fit in memory
*/
using ImageType = otb::VectorImage<float, 2>;
using SegmenterType = lsrm::BaatzSegmenter<ImageType>;
using ControllerType = lsgrm::Controller<SegmenterType>;
ControllerType controller;
controller.SetInputImage(imagePath);
controller.SetTileDirectory(tileDir);
controller.SetTemporaryDirectory(tmpDir);
controller.SetOutputGraphDirectory(outDir);
// Memory configuration
controller.SetInternalMemoryAvailable(4096ul);
controller.SetTileWidth(tileWidth);
controller.SetTileHeight(tileHeight);
controller.SetNumberOfFirstIterations(niter);
// MPI configuration
controller.SetNumberOfProcess(nprocs);
controller.SetProcessRank(myrank);
// Specific parameters
lsrm::BaatzParam params;
params.m_SpectralWeight = 0.7;
params.m_ShapeWeight = 0.3;
controller.SetSpecificParameters(params);
controller.SetThreshold(60*60);
controller.RunSegmentation();
MPI_Finalize();
return 0;
}
......@@ -2,7 +2,7 @@
namespace lp
{
void ContourOperations::MergeContour(Contour& mergedContour,
BoundingBox& mergedBBox,
Contour& contour1,
......
......@@ -85,6 +85,7 @@ namespace lp
const std::size_t gridSizeX);
};
} // end of namespace lp
#include "lpContour.cpp"
#endif
......
......@@ -23,7 +23,7 @@ namespace lsgrm
void RunSegmentation();
void SetImageDivision(bool f);
void SetInputImage(const std::string& str);
void SetInputImage(ImageType * inputImage);
void SetTileDirectory(const std::string& str);
void SetTemporaryDirectory(const std::string& str);
void SetOutputGraphDirectory(const std::string& str);
......@@ -33,18 +33,14 @@ namespace lsgrm
void SetSpecificParameters(const SegmentationParameterType& params);
void SetThreshold(const float& t);
void SetInternalMemoryAvailable(long long unsigned int v); // expecting a value in Mbytes.
void SetNumberOfProcess(int n) {m_NumberOfProcess = n;} ;
void SetProcessRank(int i) {m_ProcessRank = i;} ;
private:
void GetAutomaticConfiguration();
void RetrieveProblemConfiguration();
/* Parameters given by the user */
long long unsigned int m_Memory; // RAM available for the computation.
std::string m_InputImage; // Input image path (if the image needs to be divided).
ImageType * m_InputImage; // Input image
std::string m_TileDirectory; // Directory containing tiles (if the process of dividing is not activated
// then the directory must contain the tiles and the info.txt file.)
std::string m_TemporaryDirectory; // Directory used to store intermediate files during the process.
......@@ -59,17 +55,13 @@ namespace lsgrm
float m_Threshold;
/* Internal attribute members.*/
unsigned int m_ImageWidth;
unsigned int m_ImageHeight;
unsigned int m_ImageBands;
unsigned int m_NbTilesX;
unsigned int m_NbTilesY;
unsigned int m_NumberOfFirstIterations;
unsigned int m_Margin;
unsigned int m_TileWidth;
unsigned int m_TileHeight;
int m_NumberOfProcess;
int m_ProcessRank;
std::vector<ProcessingTile> m_Tiles;
};
} // end of namespace lsgrm
......
#ifndef __LSGRM_CONTROLLER_TXX
#define __LSGRM_CONTROLLER_TXX
#include "lsgrmController.h"
namespace lsgrm
{
template<class TSegmenter>
Controller<TSegmenter>::Controller()
{
m_Memory = 0;
m_ImageDivisionActivated = true;
}
template<class TSegmenter>
Controller<TSegmenter>::~Controller()
{
}
template<class TSegmenter>
void Controller<TSegmenter>::RunSegmentation()
{
// Rajouter un if pour vérifier si l'utilisateur a enclenché la procédure automatique
if(m_Memory < 1)
{
this->GetAutomaticConfiguration();
std::cout << m_Memory << " bytes, tile dimension " << m_TileWidth << " X " << m_TileHeight
<< ", margin" << m_Margin << " niter " << m_NumberOfFirstIterations << std::endl;
}
// Divide the input image if necessary
if(m_ImageDivisionActivated && (m_ProcessRank == 0))
{
std::cout << "Splitting tiles in " << m_TileDirectory << std::endl;
boost::timer t; t.restart();
SplitOTBImage<ImageType>(m_InputImage, m_TileDirectory, m_TileWidth,
m_TileHeight, m_Margin, m_NumberOfFirstIterations);
ShowTime(t);
}
MPI_Barrier(MPI_COMM_WORLD);
// Retrieve the problem configuration
RetrieveProblemConfiguration();
// Print values
std::cout << m_Memory << " bytes, tile dimension " << m_TileWidth << " X " << m_TileHeight
<< ", margin " << m_Margin << " niter " << m_NumberOfFirstIterations << std::endl;
// Boolean indicating if there are remaining fusions
bool isFusion = false;
// Run first partial segmentation
MPI_Barrier(MPI_COMM_WORLD);
boost::timer t; t.restart();
auto accumulatedMemory = RunFirstPartialSegmentation<TSegmenter>(m_SpecificParameters,
m_Threshold,
m_NumberOfFirstIterations,
3,
m_Tiles,
m_TileDirectory,
m_NbTilesX,
m_NbTilesY,
m_Margin,
m_TileWidth,
m_TileHeight,
m_ImageWidth,
m_ImageHeight,
m_TemporaryDirectory,
isFusion,
m_ProcessRank,
m_NumberOfProcess);
// Gathering useful variables
GatherUsefulVariables(accumulatedMemory, isFusion, m_ProcessRank, m_NumberOfProcess);
// Time monitoring
if (m_ProcessRank == 0)
ShowTime(t);
while(accumulatedMemory > m_Memory && isFusion)
{
isFusion = false;
accumulatedMemory = RunPartialSegmentation<TSegmenter>(m_SpecificParameters,
m_Threshold,
3,
m_Tiles,
m_TemporaryDirectory,
m_NbTilesX,
m_NbTilesY,
m_TileWidth,
m_TileHeight,
m_ImageWidth,
m_ImageHeight,
m_ImageBands,
isFusion,
m_ProcessRank,
m_NumberOfProcess);
// Gathering useful variables
GatherUsefulVariables(accumulatedMemory, isFusion, m_ProcessRank, m_NumberOfProcess);
}
// Time monitoring
if (m_ProcessRank == 0)
ShowTime(t);
if(accumulatedMemory <= m_Memory && m_ProcessRank == 0)
{
// Merge all the graphs
MergeAllGraphsAndAchieveSegmentation<TSegmenter>(m_SpecificParameters,
m_Threshold,
m_Tiles,
m_TemporaryDirectory,
m_NbTilesX,
m_NbTilesY,
m_TileWidth,
m_TileHeight,
m_ImageWidth,
m_ImageHeight,
m_ImageBands,
isFusion,
m_OutputGraphDirectory,
m_ProcessRank,
m_NumberOfProcess);
ShowTime(t);
}
else
{
// That means there are no more possible fusions but we can not store the ouput graph
// Todo do not clean up temporary directory before copying resulting graph to the output directory
// In the output directory add an info file to give the number of tiles.
}
}
template<class TSegmenter>
void Controller<TSegmenter>::RetrieveProblemConfiguration()
{
// Open the lsgrm info file
std::ifstream in(m_TileDirectory + "info.txt");
assert(in.good());
std::string line;
std::vector<std::string> tokens;
std::getline(in, line);
boost::split(tokens, line, boost::is_any_of(":"));
m_ImageWidth = static_cast<unsigned int>(atoi(tokens[1].c_str()));
std::getline(in, line);
boost::split(tokens, line, boost::is_any_of(":"));
m_ImageHeight = static_cast<unsigned int>(atoi(tokens[1].c_str()));
std::getline(in, line);
boost::split(tokens, line, boost::is_any_of(":"));
m_ImageBands = static_cast<unsigned int>(atoi(tokens[1].c_str()));
std::getline(in, line);
boost::split(tokens, line, boost::is_any_of(":"));
m_NbTilesX = static_cast<unsigned int>(atoi(tokens[1].c_str()));
std::getline(in, line);
boost::split(tokens, line, boost::is_any_of(":"));
m_NbTilesY = static_cast<unsigned int>(atoi(tokens[1].c_str()));
std::getline(in, line);
boost::split(tokens, line, boost::is_any_of(":"));
m_TileWidth = static_cast<unsigned int>(atoi(tokens[1].c_str()));
std::getline(in, line);
boost::split(tokens, line, boost::is_any_of(":"));
m_TileHeight = static_cast<unsigned int>(atoi(tokens[1].c_str()));
std::getline(in, line);
boost::split(tokens, line, boost::is_any_of(":"));
m_Margin = static_cast<unsigned int>(atoi(tokens[1].c_str()));
std::getline(in, line);
boost::split(tokens, line, boost::is_any_of(":"));
m_NumberOfFirstIterations = static_cast<unsigned int>(atoi(tokens[1].c_str()));
m_Tiles.assign(m_NbTilesX * m_NbTilesY, ProcessingTile());
std::vector<std::string> subtokens;
unsigned int i = 0;
for(unsigned int row = 0; row < m_NbTilesY; ++row)
{
for(unsigned int col = 0; col < m_NbTilesX; ++col)
{
std::getline(in, line);
boost::split(tokens, line, boost::is_any_of(":"));
boost::split(subtokens, tokens[1], boost::is_any_of(","));
/* Margin at the top ? */
if( row > 0 )
{
m_Tiles[i].rows[0] = row * m_TileHeight;
m_Tiles[i].tileNeighbors[0] = i - m_NbTilesX;
m_Tiles[i].margin[0] = true;
}else
{
m_Tiles[i].rows[0] = 0;
m_Tiles[i].tileNeighbors[0] = -1;
m_Tiles[i].margin[0] = false;
}
/* Margin at the right ? */
if( col < m_NbTilesX - 1 )
{
m_Tiles[i].columns[1] = col * m_TileWidth + static_cast<unsigned int>(atoi(subtokens[2].c_str())) - 1;
m_Tiles[i].tileNeighbors[2] = i+1;
m_Tiles[i].margin[1] = true;
}
else
{
m_Tiles[i].columns[1] = m_ImageWidth - 1;
m_Tiles[i].tileNeighbors[2] = -1;
m_Tiles[i].margin[1] = false;
}
/* Margin at the bottom */
if( row < m_NbTilesY - 1)
{
m_Tiles[i].rows[1] = row * m_TileHeight + static_cast<unsigned int>(atoi(subtokens[3].c_str())) - 1;
m_Tiles[i].tileNeighbors[4] = i + m_NbTilesX;
m_Tiles[i].margin[2] = true;
}
else
{
m_Tiles[i].rows[1] = m_ImageHeight - 1;
m_Tiles[i].tileNeighbors[4] = -1;
m_Tiles[i].margin[2] = false;
}
/* Margin at the left */
if( col > 0 )
{
m_Tiles[i].columns[0] = col * m_TileWidth;
m_Tiles[i].tileNeighbors[6] = i-1;
m_Tiles[i].margin[3] = true;
}
else
{
m_Tiles[i].columns[0] = 0;
m_Tiles[i].tileNeighbors[6] = -1;
m_Tiles[i].margin[3] = false;
}
/* Is there a neighbor at the rop right */
if(row > 0 && col < m_NbTilesX - 1)
m_Tiles[i].tileNeighbors[1] = i - m_NbTilesX + 1;
else
m_Tiles[i].tileNeighbors[1] = -1;
/* Is there a neighbor at the bottom right */
if(col < m_NbTilesX - 1 && row < m_NbTilesY - 1)
m_Tiles[i].tileNeighbors[3] = i + m_NbTilesX + 1;
else
m_Tiles[i].tileNeighbors[3] = -1;
/* Is there a neighbor at the bottom left */
if(row < m_NbTilesY - 1 && col > 0)
m_Tiles[i].tileNeighbors[5] = i + m_NbTilesX - 1;
else
m_Tiles[i].tileNeighbors[5] = -1;
/* Is there a neighbor at the top left */
if(col > 0 && row > 0)
m_Tiles[i].tileNeighbors[7] = i - m_NbTilesX - 1;
else
m_Tiles[i].tileNeighbors[7] = -1;
i++;
}
}
in.close();
}
template<class TSegmenter>
void Controller<TSegmenter>::GetAutomaticConfiguration()
{
m_Memory = getMemorySize();
assert(m_Memory > 0);
m_Memory /= 2; // For safety and can prevent out of memory troubles
// Compute the size of an initial segment
using NodeType = typename TSegmenter::NodeType;
using NodePointer = typename TSegmenter::NodePointerType;
using EdgeType = typename TSegmenter::EdgeType;
long long unsigned int sizePerNode = sizeof(NodePointer) + sizeof(NodeType) + 1 + 4 *(sizeof(EdgeType) + sizeof(float)); // last term is specific to BS.
long unsigned int maximumNumberOfNodes = std::ceil(m_Memory / sizePerNode);
unsigned int tileDimension = std::sqrt(maximumNumberOfNodes);
// Compute the stability margin. The naive strategy consider a margin value and a stable size equal.
unsigned int niter = 1;
unsigned int maxMargin = tileDimension/2;
unsigned int currMargin = static_cast<unsigned int>(pow(2, niter + 1) - 2);
unsigned int prevMargin = currMargin;
while(currMargin < maxMargin)
{
prevMargin = currMargin;
niter++;
currMargin = static_cast<unsigned int>(pow(2, niter + 1) - 2);
}
m_TileWidth = tileDimension - prevMargin;
m_TileHeight = m_TileWidth;
m_Margin = prevMargin;
m_NumberOfFirstIterations = niter - 1;
}
template <class TSegmenter>
void Controller<TSegmenter>::SetInternalMemoryAvailable(long long unsigned int v) // expecting a value in Mbytes.
{
assert(v > 0);
m_Memory = v * 1024ul * 1024ul;
}
template<class TSegmenter>
void Controller<TSegmenter>::SetImageDivision(bool f)
{
m_ImageDivisionActivated = f;
}
template<class TSegmenter>
void Controller<TSegmenter>::SetInputImage(const std::string& str)
{
m_InputImage = str;
}
template<class TSegmenter>
void Controller<TSegmenter>::SetOutputGraphDirectory(const std::string& str)
{
m_OutputGraphDirectory = str;
}
template<class TSegmenter>
void Controller<TSegmenter>::SetTileDirectory(const std::string& str)
{
m_TileDirectory = str;
}
template<class TSegmenter>
void Controller<TSegmenter>::SetTemporaryDirectory(const std::string& str)
{
m_TemporaryDirectory = str;
}
template<class TSegmenter>
void Controller<TSegmenter>::SetTileWidth(const unsigned int v)
{
m_TileWidth = v;
}
template<class TSegmenter>
void Controller<TSegmenter>::SetTileHeight(const unsigned int v)
{
m_TileHeight = v;
}
template<class TSegmenter>
void Controller<TSegmenter>::SetNumberOfFirstIterations(const unsigned int v)
{
m_NumberOfFirstIterations = v;
m_Margin = static_cast<unsigned int>(pow(2, m_NumberOfFirstIterations + 1) - 2);// 2^{n+1}-2
}
template<class TSegmenter>
void Controller<TSegmenter>::SetSpecificParameters(const SegmentationParameterType& params)
{
m_SpecificParameters = params;
}
template<class TSegmenter>
void Controller<TSegmenter>::SetThreshold(const float& t)
{
m_Threshold = t;
}
} // end of namespace lsgrm
template<class TSegmenter>
Controller<TSegmenter>::Controller()
{