Commit d8ebd795b7071ec43795d24513decfbb0fb7bf5d

Authored by Pierre Lassalle
1 parent 7f113d8b
Exists in master

Final streaming version of the grm, good luck Rémi ;)

Applications/CMakeLists.txt 0 → 100644
... ... @@ -0,0 +1,19 @@
  1 +#=========================================================================
  2 +
  3 +# Program: Large Scale Generic Region Merging Library (LSGRM)
  4 +# Language: C++
  5 +# author: Lassalle Pierre
  6 +
  7 +
  8 +
  9 +# Copyright (c) Centre National d'Etudes Spatiales. All rights reserved
  10 +
  11 +# See grmlib-copyright.txt for details.
  12 +
  13 +# This software is distributed WITHOUT ANY WARRANTY; without even
  14 +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15 +# PURPOSE. See the above copyright notices for more information.
  16 +
  17 +#=========================================================================
  18 +add_executable(Test lsgrmProto.cxx)
  19 +target_link_libraries(Test OTBLSGRM)
... ...
Applications/lsgrmProto.cxx 0 → 100644
... ... @@ -0,0 +1,61 @@
  1 +#include <iostream>
  2 +#include "lsrmBaatzSegmenter.h"
  3 +#include "lsgrmController.h"
  4 +
  5 +int main(int argc, char *argv[])
  6 +{
  7 + if(argc != 8)
  8 + {
  9 + // img/test.tif tiles/ 125 125 4 tmp/
  10 + std::cerr << "[input image] [tile directory] [tile width] [tile height] [number of first iterations] [temporary directory] [output directory]"
  11 + << std::endl;
  12 + return 1;
  13 + }
  14 +
  15 + /* Parse command line arguments */
  16 + const std::string imagePath = argv[1];
  17 + std::string tileDir = argv[2]; // May be corrected if badly written.
  18 + const unsigned int tileWidth = atoi(argv[3]);
  19 + const unsigned int tileHeight = atoi(argv[4]);
  20 + const unsigned int niter = atoi(argv[5]);
  21 + std::string tmpDir = argv[6]; // May be corrected if badly written.
  22 + std::string outDir = argv[7];
  23 +
  24 + /*
  25 + To add:
  26 + internal memory available
  27 + If we have to do the image division
  28 + if we have to clean up the directory
  29 + the output directory in case the global graph cannot fit in memory
  30 +
  31 + */
  32 +
  33 + using ImageType = otb::VectorImage<float, 2>;
  34 + using SegmenterType = lsrm::BaatzSegmenter<ImageType>;
  35 + using ControllerType = lsgrm::Controller<SegmenterType>;
  36 +
  37 +
  38 +
  39 + ControllerType controller;
  40 + controller.SetInputImage(imagePath);
  41 + controller.SetTileDirectory(tileDir);
  42 + controller.SetTemporaryDirectory(tmpDir);
  43 + controller.SetOutputGraphDirectory(outDir);
  44 +
  45 + // Memory configuration
  46 + controller.SetInternalMemoryAvailable(512ul);
  47 + controller.SetTileWidth(500);
  48 + controller.SetTileHeight(500);
  49 + controller.SetNumberOfFirstIterations(6);
  50 +
  51 + // Specific parameters
  52 + lsrm::BaatzParam params;
  53 + params.m_SpectralWeight = 0.7;
  54 + params.m_ShapeWeight = 0.3;
  55 + controller.SetSpecificParameters(params);
  56 + controller.SetThreshold(60*60);
  57 +
  58 + controller.RunSegmentation();
  59 +
  60 + return 0;
  61 +}
... ...
CMakeLists.txt 0 → 100644
... ... @@ -0,0 +1,42 @@
  1 +#=========================================================================
  2 +
  3 +# Program: Large Scale Generic Region Merging Library (GRM)
  4 +# Language: C++
  5 +# author: Lassalle Pierre
  6 +
  7 +
  8 +
  9 +# Copyright (c) Centre National d'Etudes Spatiales. All rights reserved
  10 +
  11 +# See grmlib-copyright.txt for details.
  12 +
  13 +# This software is distributed WITHOUT ANY WARRANTY; without even
  14 +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15 +# PURPOSE. See the above copyright notices for more information.
  16 +
  17 +#=========================================================================
  18 +project(LSGRM)
  19 +
  20 +cmake_minimum_required(VERSION 2.8)
  21 +
  22 +find_package(OTB)
  23 +IF(OTB_FOUND)
  24 + include(${OTB_USE_FILE})
  25 +ELSE(OTB_FOUND)
  26 + message(FATAL_ERROR
  27 + "Cannot build OTB project without OTB. Please set OTB_DIR.")
  28 +ENDIF(OTB_FOUND)
  29 +
  30 +#Activate c++11
  31 +include(CheckCXXCompilerFlag)
  32 +CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
  33 +if(COMPILER_SUPPORTS_CXX11)
  34 + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fpermissive -Wall -Wmaybe-uninitialized")
  35 +else()
  36 + message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
  37 +endif()
  38 +
  39 +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/Code)
  40 +
  41 +add_subdirectory(Code)
  42 +add_subdirectory(Applications)
... ...
Code/CMakeLists.txt 0 → 100644
... ... @@ -0,0 +1,22 @@
  1 +#=========================================================================
  2 +
  3 +# Program: Large Scale Generic Region Merging Library (GRM)
  4 +# Language: C++
  5 +# author: Lassalle Pierre
  6 +
  7 +
  8 +
  9 +# Copyright (c) Centre National d'Etudes Spatiales. All rights reserved
  10 +
  11 +# See grmlib-copyright.txt for details.
  12 +
  13 +# This software is distributed WITHOUT ANY WARRANTY; without even
  14 +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15 +# PURPOSE. See the above copyright notices for more information.
  16 +
  17 +#=========================================================================add_library(OTBGRM
  18 +add_library(OTBLSGRM
  19 + lsrmNeighborhood.cpp
  20 + lpContour.cpp)
  21 +
  22 +target_link_libraries(OTBLSGRM ${OTB_LIBRARIES})
... ...
Code/lpContour.cpp 0 → 100644
... ... @@ -0,0 +1,377 @@
  1 +#include "lpContour.h"
  2 +
  3 +namespace lp
  4 +{
  5 +
  6 + void ContourOperations::MergeContour(Contour& mergedContour,
  7 + BoundingBox& mergedBBox,
  8 + Contour& contour1,
  9 + Contour& contour2,
  10 + BoundingBox& bbox1,
  11 + BoundingBox& bbox2,
  12 + const CellIndex cid1,
  13 + const CellIndex cid2,
  14 + const std::size_t gridSizeX)
  15 + {
  16 + // First step consists of building the bounding box resulting from the fusion
  17 + // of the bounding boxes bbox1 and bbox2
  18 + mergedBBox = MergeBoundingBoxes(bbox1, bbox2);
  19 +
  20 + // Create the associate matrix indicating where the cells are located
  21 + // inside the bbox
  22 + std::vector<bool> cellMatrix(mergedBBox.m_W*mergedBBox.m_H, false);
  23 +
  24 + // Fill the cell matrix with the cells from both contours
  25 + {
  26 + CellLists borderCells;
  27 +
  28 + // Fill with the cells of contour 1
  29 + GenerateBorderCells(borderCells, contour1, cid1, gridSizeX);
  30 + for(auto& cell: borderCells)
  31 + cellMatrix[GridToBBox(cell, mergedBBox, gridSizeX)] = true;
  32 + borderCells.clear();
  33 +
  34 +
  35 + // Fill with the cells of contour 2
  36 + GenerateBorderCells(borderCells, contour2, cid2, gridSizeX);
  37 + for(auto& cell: borderCells)
  38 + cellMatrix[GridToBBox(cell, mergedBBox, gridSizeX)] = true;
  39 + }
  40 +
  41 + // Create the new contour
  42 + CreateNewContour(mergedContour, GridToBBox(cid1, mergedBBox, gridSizeX), cellMatrix, mergedBBox.m_W, mergedBBox.m_H);
  43 + }
  44 +
  45 + void ContourOperations::CreateNewContour(Contour& newContour,
  46 + const CellIndex cidx,
  47 + const std::vector<bool>& cellMatrix,
  48 + const std::size_t bboxWidth,
  49 + const std::size_t bboxHeight)
  50 + {
  51 + // The first move is always 1
  52 + Push1(newContour);
  53 +
  54 + // Previous move
  55 + short prevMove = 1;
  56 +
  57 + // Local pixel id
  58 + CellIndex currIdx = cidx;
  59 +
  60 + // Table containing id neighbors
  61 + long int neighbors[8];
  62 +
  63 + for(;;)
  64 + {
  65 +
  66 + // Compute neighbor'ids
  67 + EIGHTNeighborhood(neighbors, currIdx, bboxWidth, bboxHeight);
  68 +
  69 + if(prevMove == 1)
  70 + {
  71 + if(neighbors[1] != -1 && cellMatrix[neighbors[1]])
  72 + {
  73 + Push0(newContour);
  74 + currIdx = currIdx + 1 - bboxWidth;
  75 + prevMove = 0;
  76 + }
  77 + else if(neighbors[2] != -1 && cellMatrix[neighbors[2]])
  78 + {
  79 + Push1(newContour);
  80 + currIdx++;
  81 + prevMove = 1;
  82 + }
  83 + else
  84 + {
  85 + Push2(newContour);
  86 + prevMove = 2;
  87 + }
  88 + }
  89 + else if(prevMove == 2)
  90 + {
  91 + if(neighbors[3] != -1 && cellMatrix[neighbors[3]])
  92 + {
  93 + Push1(newContour);
  94 + currIdx = currIdx + bboxWidth + 1;
  95 + prevMove = 1;
  96 + }
  97 + else if(neighbors[4] != -1 && cellMatrix[neighbors[4]])
  98 + {
  99 + Push2(newContour);
  100 + currIdx += bboxWidth;
  101 + prevMove = 2;
  102 + }
  103 + else
  104 + {
  105 + Push3(newContour);
  106 + prevMove = 3;
  107 + }
  108 + }
  109 + else if(prevMove == 3)
  110 + {
  111 +
  112 + if(neighbors[5] != -1 && cellMatrix[neighbors[5]])
  113 + {
  114 + Push2(newContour);
  115 + currIdx = currIdx - 1 + bboxWidth;
  116 + prevMove = 2;
  117 + }
  118 + else if(neighbors[6] != -1 && cellMatrix[neighbors[6]])
  119 + {
  120 + Push3(newContour);
  121 + currIdx -= 1;
  122 + prevMove = 3;
  123 + }
  124 + else
  125 + {
  126 + Push0(newContour);
  127 + prevMove = 0;
  128 + }
  129 + }
  130 + else
  131 + {
  132 + assert(prevMove == 0);
  133 +
  134 + if(neighbors[7] != -1 && cellMatrix[neighbors[7]])
  135 + {
  136 + Push3(newContour);
  137 + currIdx = currIdx - bboxWidth - 1;
  138 + prevMove = 3;
  139 + }
  140 + else if(neighbors[0] != -1 && cellMatrix[neighbors[0]])
  141 + {
  142 + Push0(newContour);
  143 + currIdx -= bboxWidth;
  144 + prevMove = 0;
  145 + }
  146 + else
  147 + {
  148 + if(currIdx == cidx)
  149 + break;
  150 + else
  151 + {
  152 + Push1(newContour);
  153 + prevMove = 1;
  154 + }
  155 + }
  156 + }
  157 + }
  158 + }
  159 +
  160 + void ContourOperations::GenerateBorderCells(CellLists& borderCells,
  161 + const Contour& contour,
  162 + const CellIndex startCellId,
  163 + const std::size_t gridSizeX)
  164 + {
  165 + // Add the first pixel to the border list
  166 + borderCells.insert(startCellId);
  167 +
  168 + if(contour.size() > 8)
  169 + {
  170 +
  171 + // Intialize the first move at prev
  172 + short curr, prev = GetMove10(GetMove2(0, contour));
  173 +
  174 + // Declare the current pixel index
  175 + CellIndex idx = startCellId;
  176 +
  177 + // Explore the contour
  178 + for(ContourIndex cidx = 1; cidx < contour.size() / 2; cidx++)
  179 + {
  180 + curr = GetMove10(GetMove2(cidx, contour));
  181 + assert(curr >= 0 && curr < 4);
  182 +
  183 + if(curr == 0)
  184 + {
  185 + // Impossible case is prev = 2;
  186 + assert(prev != 2);
  187 +
  188 + //*
  189 + //*
  190 + if(prev == 0)
  191 + {
  192 + idx -= gridSizeX;
  193 + borderCells.insert(idx);
  194 + }
  195 +
  196 + // *
  197 + // **
  198 + if(prev == 1)
  199 + {
  200 + idx = idx + 1 - gridSizeX;
  201 + borderCells.insert(idx);
  202 + }
  203 + }else if(curr == 1)
  204 + {
  205 + // Impossible case
  206 + assert(prev != 3);
  207 +
  208 + // **
  209 + if(prev == 1)
  210 + {
  211 + idx++;
  212 + borderCells.insert(idx);
  213 + }
  214 +
  215 + //*
  216 + //**
  217 + if (prev == 2)
  218 + {
  219 + idx = idx + 1 + gridSizeX;
  220 + borderCells.insert(idx);
  221 + }
  222 +
  223 + }else if(curr == 2)
  224 + {
  225 + // Impossible case
  226 + assert(prev != 0);
  227 +
  228 + // *
  229 + // *
  230 + if(prev == 2)
  231 + {
  232 + idx += gridSizeX;
  233 + borderCells.insert(idx);
  234 + }
  235 +
  236 + // **
  237 + // *
  238 + if(prev == 3)
  239 + {
  240 + idx = idx - 1 + gridSizeX;
  241 + borderCells.insert(idx);
  242 + }
  243 + }else
  244 + {
  245 + // Impossible case
  246 + assert(prev != 1);
  247 +
  248 + if(prev == 0)
  249 + {
  250 + idx = idx - 1 - gridSizeX;
  251 + borderCells.insert(idx);
  252 + }
  253 +
  254 + if(prev == 3)
  255 + {
  256 + idx--;
  257 + borderCells.insert(idx);
  258 + }
  259 + }
  260 +
  261 + prev = curr;
  262 + }
  263 + }
  264 + }
  265 +
  266 + CellIndex ContourOperations::BBoxToGrid(const CellIndex bboxId,
  267 + const BoundingBox& bbox,
  268 + const std::size_t gridSizeX)
  269 + {
  270 + CellIndex bbX = bboxId % bbox.m_W;
  271 + CellIndex bbY = bboxId / bbox.m_W;
  272 +
  273 + CellIndex gridX = bbox.m_UX + bbX;
  274 + CellIndex gridY = bbox.m_UY + bbY;
  275 +
  276 + CellIndex gridId = gridY * gridSizeX + gridX;
  277 +
  278 + return gridId;
  279 + }
  280 +
  281 + CellIndex ContourOperations::GridToBBox(const CellIndex gridId,
  282 + const BoundingBox& bbox,
  283 + const std::size_t gridSizeX)
  284 + {
  285 + CellIndex gridX = gridId % gridSizeX;
  286 + CellIndex gridY = gridId / gridSizeX;
  287 +
  288 + CellIndex bbX = gridX - bbox.m_UX;
  289 + CellIndex bbY = gridY - bbox.m_UY;
  290 +
  291 + CellIndex bbId = bbY * bbox.m_W + bbX;
  292 +
  293 + return bbId;
  294 + }
  295 +
  296 + void ContourOperations::EIGHTNeighborhood(long int * neighborhood,
  297 + const CellIndex id,
  298 + const std::size_t width,
  299 + const std::size_t height)
  300 + {
  301 + const unsigned int x = id % width;
  302 + const unsigned int y = id / width;
  303 +
  304 + /* top */
  305 + neighborhood[0] = ( y > 0 ? (id - width) : -1 );
  306 +
  307 + /* top right */
  308 + neighborhood[1] = ( (y > 0 && x < (width - 1) ) ? (id - width + 1) : -1 );
  309 +
  310 + /* right */
  311 + neighborhood[2] = ( x < (width - 1) ? (id + 1) : -1 );
  312 +
  313 + /* bottom right */
  314 + neighborhood[3] = ( (x < (width - 1) && y < (height - 1) ) ? (id + 1 + width) : -1);
  315 +
  316 + /* bottom */
  317 + neighborhood[4] = ( y < (height - 1) ? (id + width) : -1 );
  318 +
  319 + /* bottom left */
  320 + neighborhood[5] = ( (y < (height - 1) && x > 0) ? (id + width - 1) : -1 );
  321 +
  322 + /* left */
  323 + neighborhood[6] = ( x > 0 ? (id - 1) : -1 );
  324 +
  325 + /* top left */
  326 + neighborhood[7] = ( (x > 0 && y > 0) ? (id -width - 1) : - 1);
  327 + }
  328 +
  329 + BoundingBox ContourOperations::MergeBoundingBoxes(const BoundingBox& bb1,
  330 + const BoundingBox& bb2)
  331 + {
  332 + std::size_t min_ux, min_uy, max_xw, max_yh;
  333 + BoundingBox bb;
  334 +
  335 + min_ux = std::min(bb1.m_UX, bb2.m_UX);
  336 + min_uy = std::min(bb1.m_UY, bb2.m_UY);
  337 + max_xw = std::max(bb1.m_UX + bb1.m_W, bb2.m_UX + bb2.m_W);
  338 + max_yh = std::max(bb1.m_UY + bb1.m_H, bb2.m_UY + bb2.m_H);
  339 +
  340 + bb.m_UX = min_ux;
  341 + bb.m_UY = min_uy;
  342 + bb.m_W = max_xw - min_ux;
  343 + bb.m_H = max_yh - min_uy;
  344 +
  345 + return bb;
  346 + }
  347 +
  348 + Move ContourOperations::GetMove2(ContourIndex idx, const Contour& contour)
  349 + {
  350 + return Move(2*contour[2*idx] + contour[idx*2 +1]);
  351 + }
  352 +
  353 + short ContourOperations::GetMove10(const Move& m)
  354 + {
  355 + return (m[0]*2 + m[1]);
  356 + }
  357 +
  358 + void ContourOperations::Push0(Contour& contour)
  359 + {
  360 + contour.push_back(0); contour.push_back(0);
  361 + }
  362 +
  363 + void ContourOperations::Push1(Contour& contour)
  364 + {
  365 + contour.push_back(1); contour.push_back(0);
  366 + }
  367 +
  368 + void ContourOperations::Push2(Contour& contour)
  369 + {
  370 + contour.push_back(0); contour.push_back(1);
  371 + }
  372 +
  373 + void ContourOperations::Push3(Contour& contour)
  374 + {
  375 + contour.push_back(1); contour.push_back(1);
  376 + }
  377 +} // end of namespace lp
... ...
Code/lpContour.h 0 → 100644
... ... @@ -0,0 +1,97 @@
  1 +#ifndef __LP_CONTOUR_H
  2 +#define __LP_CONTOUR_H
  3 +#include <cassert>
  4 +#include <iostream>
  5 +#include <bitset>
  6 +#include <vector>
  7 +#include <utility>
  8 +#include <unordered_set>
  9 +#include <unordered_map>
  10 +#include <boost/dynamic_bitset.hpp>
  11 +
  12 +namespace lp
  13 +{
  14 + /* Move along a contour: 4 possibles: top (0), right(1), bottom (2), left(3). */
  15 + using Move = std::bitset<2>;
  16 + /* A contour is a list of moves represented by a pair of bits*/
  17 + using Contour = boost::dynamic_bitset<>;
  18 +
  19 + using ContourIndex = boost::dynamic_bitset<>::size_type;
  20 +
  21 + /* Index of a cell in the grid */
  22 + using CellIndex = std::size_t;
  23 +
  24 + /* List of cell indices */
  25 + using CellLists = std::unordered_set<CellIndex>;
  26 +
  27 + struct BoundingBox
  28 + {
  29 + std::size_t m_UX;
  30 + std::size_t m_UY;
  31 + std::size_t m_W;
  32 + std::size_t m_H;
  33 + };
  34 +
  35 + class ContourOperations
  36 + {
  37 + public:
  38 + /* Methods to fill a contour. */
  39 + static void Push0(Contour& contour); // Push a move to the top.
  40 + static void Push1(Contour& contour); // Push a move to the right.
  41 + static void Push2(Contour& contour); // Push a move to the bottom.
  42 + static void Push3(Contour& contour); // Push a move to the left.
  43 +
  44 + /* Methods to access to elements of a contour. */
  45 + static Move GetMove2(ContourIndex idx, const Contour& contour); // Retrieve a move
  46 + static short GetMove10(const Move& m); // Transform the move into a 10 base number (0,1,2 or 3).
  47 +
  48 + /* Main methods */
  49 + static void MergeContour(Contour& mergedContour,
  50 + BoundingBox& mergedBoundingBox,
  51 + Contour& contour1,
  52 + Contour& contour2,
  53 + BoundingBox& bbox1,
  54 + BoundingBox& bbox2,
  55 + const CellIndex cid1,
  56 + const CellIndex cid2,
  57 + const std::size_t gridSizeX);
  58 +
  59 + static void GenerateBorderCells(CellLists& borderCells, // From a contour, the smallest id of the cell
  60 + const Contour& contour, // belonging to the shape and the size of the grid,
  61 + const CellIndex startCellId, // this method returns the ids of the border cells
  62 + const std::size_t gridSizeX); // of the shape.
  63 +
  64 + static void CreateNewContour(Contour& newContour,
  65 + const CellIndex startCellId,
  66 + const std::vector<bool>& cellMatrix,
  67 + const std::size_t bboxWidth,
  68 + const std::size_t bboxHeight);
  69 +
  70 + /* Utilities methods */
  71 + static BoundingBox MergeBoundingBoxes(const BoundingBox& bb1, // Given 2 bounding boxes return the bounding
  72 + const BoundingBox& bb2); // which is the union.
  73 +
  74 + static void EIGHTNeighborhood(long int * neighborhood, // return 8-neighbors of cell id.
  75 + const CellIndex id,
  76 + const std::size_t width,
  77 + const std::size_t height);
  78 +
  79 + static CellIndex BBoxToGrid(const CellIndex bboxId,
  80 + const BoundingBox& bbox,
  81 + const std::size_t gridSizeX);
  82 +
  83 + static CellIndex GridToBBox(const CellIndex gridId, // Return the coordinates of the cell
  84 + const BoundingBox& bbox, // in the bounding box reference.
  85 + const std::size_t gridSizeX);
  86 + };
  87 +} // end of namespace lp
  88 +#endif
  89 +
  90 +
  91 +
  92 +
  93 +
  94 +
  95 +
  96 +
  97 +
... ...
Code/lsgrmController.h 0 → 100644
... ... @@ -0,0 +1,74 @@
  1 +#ifndef __LSGRM_CONTROLLER_H
  2 +#define __LSGRM_CONTROLLER_H
  3 +#include "lsrmGetInternalMemory.h"
  4 +#include "lsgrmSplitter.h"
  5 +#include "lsgrmGraphOperations.h"
  6 +
  7 +namespace lsgrm
  8 +{
  9 + template<class TSegmenter>
  10 + class Controller
  11 + {
  12 + public:
  13 +
  14 + /* Some convenient typedefs */
  15 + using SegmenterType = TSegmenter;
  16 + using ImageType = typename SegmenterType::ImageType;
  17 + using SegmentationParameterType = typename SegmenterType::ParameterType;
  18 +
  19 + /* Default constructor and destructor. */
  20 + Controller();
  21 + ~Controller();
  22 +
  23 + void RunSegmentation();
  24 +
  25 + void SetImageDivision(bool f);
  26 + void SetInputImage(const std::string& str);
  27 + void SetTileDirectory(const std::string& str);
  28 + void SetTemporaryDirectory(const std::string& str);
  29 + void SetOutputGraphDirectory(const std::string& str);
  30 + void SetTileWidth(const unsigned int v);
  31 + void SetTileHeight(const unsigned int v);
  32 + void SetNumberOfFirstIterations(const unsigned int v);
  33 + void SetSpecificParameters(const SegmentationParameterType& params);
  34 + void SetThreshold(const float& t);
  35 + void SetInternalMemoryAvailable(long long unsigned int v); // expecting a value in Mbytes.
  36 +
  37 + private:
  38 +
  39 + void GetAutomaticConfiguration();
  40 + void RetrieveProblemConfiguration();
  41 +
  42 +
  43 + /* Parameters given by the user */
  44 + long long unsigned int m_Memory; // RAM available for the computation.
  45 + std::string m_InputImage; // Input image path (if the image needs to be divided).
  46 + std::string m_TileDirectory; // Directory containing tiles (if the process of dividing is not activated
  47 + // then the directory must contain the tiles and the info.txt file.)
  48 + std::string m_TemporaryDirectory; // Directory used to store intermediate files during the process.
  49 + std::string m_OutputGraphDirectory;
  50 + std::string m_OutputLabelImage; // Output label image path.
  51 +
  52 + bool m_ImageDivisionActivated; // The input image must be divided.
  53 + bool m_CleanTemporaryDirectory; // Clean the temporary directory.
  54 +
  55 + /* Specific segmentation parameters */
  56 + SegmentationParameterType m_SpecificParameters;
  57 + float m_Threshold;
  58 +
  59 + /* Internal attribute members.*/
  60 + unsigned int m_ImageWidth;
  61 + unsigned int m_ImageHeight;
  62 + unsigned int m_ImageBands;
  63 + unsigned int m_NbTilesX;
  64 + unsigned int m_NbTilesY;
  65 + unsigned int m_NumberOfFirstIterations;
  66 + unsigned int m_Margin;
  67 + unsigned int m_TileWidth;
  68 + unsigned int m_TileHeight;
  69 + std::vector<ProcessingTile> m_Tiles;
  70 + };
  71 +} // end of namespace lsgrm
  72 +
  73 +#include "lsgrmController.txx"
  74 +#endif
... ...
Code/lsgrmController.txx 0 → 100644
... ... @@ -0,0 +1,358 @@
  1 +#ifndef __LSGRM_CONTROLLER_TXX
  2 +#define __LSGRM_CONTROLLER_TXX
  3 +
  4 +namespace lsgrm
  5 +{
  6 +
  7 + template<class TSegmenter>
  8 + Controller<TSegmenter>::Controller()
  9 + {
  10 + m_Memory = 0;
  11 + m_ImageDivisionActivated = true;
  12 + }
  13 +
  14 + template<class TSegmenter>
  15 + Controller<TSegmenter>::~Controller()
  16 + {
  17 + }
  18 +
  19 + template<class TSegmenter>
  20 + void Controller<TSegmenter>::RunSegmentation()
  21 + {
  22 + // Rajouter un if pour vérifier si l'utilisateur a enclenché la procédure automatique
  23 + if(m_Memory < 1)
  24 + {
  25 + this->GetAutomaticConfiguration();
  26 + std::cout << m_Memory << " bytes, tile dimension " << m_TileWidth << " X " << m_TileHeight
  27 + << ", margin" << m_Margin << " niter " << m_NumberOfFirstIterations << std::endl;
  28 + }
  29 +
  30 + // Divide the input image if necessary
  31 + if(m_ImageDivisionActivated)
  32 + SplitOTBImage<ImageType>(m_InputImage, m_TileDirectory, m_TileWidth,
  33 + m_TileHeight, m_Margin, m_NumberOfFirstIterations);
  34 +
  35 + // Retrieve the problem configuration
  36 + RetrieveProblemConfiguration();
  37 +
  38 + // Print values
  39 + std::cout << m_Memory << " bytes, tile dimension " << m_TileWidth << " X " << m_TileHeight
  40 + << ", margin" << m_Margin << " niter " << m_NumberOfFirstIterations << std::endl;
  41 +
  42 + // Boolean indicating if there are remaining fusions
  43 + bool isFusion = false;
  44 +
  45 + // Run first partial segmentation
  46 + auto accumulatedMemory = RunFirstPartialSegmentation<TSegmenter>(m_SpecificParameters,
  47 + m_Threshold,
  48 + m_NumberOfFirstIterations,
  49 + 3,
  50 + m_Tiles,
  51 + m_TileDirectory,
  52 + m_NbTilesX,
  53 + m_NbTilesY,
  54 + m_Margin,
  55 + m_TileWidth,
  56 + m_TileHeight,
  57 + m_ImageWidth,
  58 + m_ImageHeight,
  59 + m_TemporaryDirectory,
  60 + isFusion);
  61 +
  62 + std::cout << "Accumulated memory " << accumulatedMemory << " bytes, there is fusion "<< isFusion << std::endl;
  63 +
  64 + while(accumulatedMemory > m_Memory && isFusion)
  65 + {
  66 + isFusion = false;
  67 + accumulatedMemory = RunPartialSegmentation<TSegmenter>(m_SpecificParameters,
  68 + m_Threshold,
  69 + 3,
  70 + m_Tiles,
  71 + m_TemporaryDirectory,
  72 + m_NbTilesX,
  73 + m_NbTilesY,
  74 + m_TileWidth,
  75 + m_TileHeight,
  76 + m_ImageWidth,
  77 + m_ImageHeight,
  78 + m_ImageBands,
  79 + isFusion);
  80 + std::cout << "Accumulated memory " << accumulatedMemory << " bytes, there is fusion "
  81 + << isFusion << std::endl;
  82 + }
  83 +
  84 + if(accumulatedMemory <= m_Memory)
  85 + {
  86 + // Merge all the graphs
  87 + MergeAllGraphsAndAchieveSegmentation<TSegmenter>(m_SpecificParameters,
  88 + m_Threshold,
  89 + m_Tiles,
  90 + m_TemporaryDirectory,
  91 + m_NbTilesX,
  92 + m_NbTilesY,
  93 + m_TileWidth,
  94 + m_TileHeight,
  95 + m_ImageWidth,
  96 + m_ImageHeight,
  97 + m_ImageBands,
  98 + isFusion,
  99 + m_OutputGraphDirectory);
  100 + }
  101 + else
  102 + {
  103 + // That means there are no more possible fusions but we can not store the ouput graph
  104 + // Todo do not clean up temporary directory before copying resulting graph to the output directory
  105 + // In the output directory add an info file to give the number of tiles.
  106 + }
  107 + }
  108 +
  109 + template<class TSegmenter>
  110 + void Controller<TSegmenter>::RetrieveProblemConfiguration()
  111 + {
  112 + // Open the lsgrm info file
  113 + std::ifstream in(m_TileDirectory + "info.txt");
  114 + assert(in.good());
  115 +
  116 +
  117 + std::string line;
  118 + std::vector<std::string> tokens;
  119 +
  120 + std::getline(in, line);
  121 + boost::split(tokens, line, boost::is_any_of(":"));
  122 + m_ImageWidth = static_cast<unsigned int>(atoi(tokens[1].c_str()));
  123 +
  124 + std::getline(in, line);
  125 + boost::split(tokens, line, boost::is_any_of(":"));
  126 + m_ImageHeight = static_cast<unsigned int>(atoi(tokens[1].c_str()));
  127 +
  128 + std::getline(in, line);
  129 + boost::split(tokens, line, boost::is_any_of(":"));
  130 + m_ImageBands = static_cast<unsigned int>(atoi(tokens[1].c_str()));
  131 +
  132 + std::getline(in, line);
  133 + boost::split(tokens, line, boost::is_any_of(":"));
  134 + m_NbTilesX = static_cast<unsigned int>(atoi(tokens[1].c_str()));
  135 +
  136 + std::getline(in, line);
  137 + boost::split(tokens, line, boost::is_any_of(":"));
  138 + m_NbTilesY = static_cast<unsigned int>(atoi(tokens[1].c_str()));
  139 +
  140 + std::getline(in, line);
  141 + boost::split(tokens, line, boost::is_any_of(":"));
  142 + m_TileWidth = static_cast<unsigned int>(atoi(tokens[1].c_str()));
  143 +
  144 + std::getline(in, line);
  145 + boost::split(tokens, line, boost::is_any_of(":"));
  146 + m_TileHeight = static_cast<unsigned int>(atoi(tokens[1].c_str()));
  147 +
  148 + std::getline(in, line);
  149 + boost::split(tokens, line, boost::is_any_of(":"));
  150 + m_Margin = static_cast<unsigned int>(atoi(tokens[1].c_str()));
  151 +
  152 + std::getline(in, line);
  153 + boost::split(tokens, line, boost::is_any_of(":"));
  154 + m_NumberOfFirstIterations = static_cast<unsigned int>(atoi(tokens[1].c_str()));
  155 +
  156 + m_Tiles.assign(m_NbTilesX * m_NbTilesY, ProcessingTile());
  157 + std::vector<std::string> subtokens;
  158 + unsigned int i = 0;
  159 + for(unsigned int row = 0; row < m_NbTilesY; ++row)
  160 + {
  161 + for(unsigned int col = 0; col < m_NbTilesX; ++col)
  162 + {
  163 + std::getline(in, line);
  164 + boost::split(tokens, line, boost::is_any_of(":"));
  165 + boost::split(subtokens, tokens[1], boost::is_any_of(","));
  166 +
  167 + /* Margin at the top ? */
  168 + if( row > 0 )
  169 + {
  170 + m_Tiles[i].rows[0] = row * m_TileHeight;
  171 + m_Tiles[i].tileNeighbors[0] = i - m_NbTilesX;
  172 + m_Tiles[i].margin[0] = true;
  173 + }else
  174 + {
  175 + m_Tiles[i].rows[0] = 0;
  176 + m_Tiles[i].tileNeighbors[0] = -1;
  177 + m_Tiles[i].margin[0] = false;
  178 + }
  179 +
  180 + /* Margin at the right ? */
  181 + if( col < m_NbTilesX - 1 )
  182 + {
  183 + m_Tiles[i].columns[1] = col * m_TileWidth + static_cast<unsigned int>(atoi(subtokens[2].c_str())) - 1;
  184 + m_Tiles[i].tileNeighbors[2] = i+1;
  185 + m_Tiles[i].margin[1] = true;
  186 + }
  187 + else
  188 + {
  189 + m_Tiles[i].columns[1] = m_ImageWidth - 1;
  190 + m_Tiles[i].tileNeighbors[2] = -1;
  191 + m_Tiles[i].margin[1] = false;
  192 + }
  193 +
  194 + /* Margin at the bottom */
  195 + if( row < m_NbTilesY - 1)
  196 + {
  197 + m_Tiles[i].rows[1] = row * m_TileHeight + static_cast<unsigned int>(atoi(subtokens[3].c_str())) - 1;
  198 + m_Tiles[i].tileNeighbors[4] = i + m_NbTilesX;
  199 + m_Tiles[i].margin[2] = true;
  200 + }
  201 + else
  202 + {
  203 + m_Tiles[i].rows[1] = m_ImageHeight - 1;
  204 + m_Tiles[i].tileNeighbors[4] = -1;
  205 + m_Tiles[i].margin[2] = false;
  206 + }
  207 +
  208 + /* Margin at the left */
  209 + if( col > 0 )
  210 + {
  211 + m_Tiles[i].columns[0] = col * m_TileWidth;
  212 + m_Tiles[i].tileNeighbors[6] = i-1;
  213 + m_Tiles[i].margin[3] = true;
  214 + }
  215 + else
  216 + {
  217 + m_Tiles[i].columns[0] = 0;
  218 + m_Tiles[i].tileNeighbors[6] = -1;
  219 + m_Tiles[i].margin[3] = false;
  220 + }
  221 +
  222 + /* Is there a neighbor at the rop right */
  223 + if(row > 0 && col < m_NbTilesX - 1)
  224 + m_Tiles[i].tileNeighbors[1] = i - m_NbTilesX + 1;
  225 + else
  226 + m_Tiles[i].tileNeighbors[1] = -1;
  227 +
  228 + /* Is there a neighbor at the bottom right */
  229 + if(col < m_NbTilesX - 1 && row < m_NbTilesY - 1)
  230 + m_Tiles[i].tileNeighbors[3] = i + m_NbTilesX + 1;
  231 + else
  232 + m_Tiles[i].tileNeighbors[3] = -1;
  233 +
  234 + /* Is there a neighbor at the bottom left */
  235 + if(row < m_NbTilesY - 1 && col > 0)
  236 + m_Tiles[i].tileNeighbors[5] = i + m_NbTilesX - 1;
  237 + else
  238 + m_Tiles[i].tileNeighbors[5] = -1;
  239 +
  240 + /* Is there a neighbor at the top left */
  241 + if(col > 0 && row > 0)
  242 + m_Tiles[i].tileNeighbors[7] = i - m_NbTilesX - 1;
  243 + else
  244 + m_Tiles[i].tileNeighbors[7] = -1;
  245 +
  246 + i++;
  247 + }
  248 + }
  249 +
  250 + in.close();
  251 + }
  252 +
  253 + template<class TSegmenter>
  254 + void Controller<TSegmenter>::GetAutomaticConfiguration()
  255 + {
  256 + m_Memory = getMemorySize();
  257 + assert(m_Memory > 0);
  258 +
  259 + m_Memory /= 2; // For safety and can prevent out of memory troubles
  260 +
  261 + // Compute the size of an initial segment
  262 + using NodeType = typename TSegmenter::NodeType;
  263 + using NodePointer = typename TSegmenter::NodePointerType;
  264 + using EdgeType = typename TSegmenter::EdgeType;
  265 +
  266 + long long unsigned int sizePerNode = sizeof(NodePointer) + sizeof(NodeType) + 1 + 4 *(sizeof(EdgeType) + sizeof(float)); // last term is specific to BS.
  267 + long unsigned int maximumNumberOfNodes = std::ceil(m_Memory / sizePerNode);
  268 + unsigned int tileDimension = std::sqrt(maximumNumberOfNodes);
  269 +
  270 + // Compute the stability margin. The naive strategy consider a margin value and a stable size equal.
  271 + unsigned int niter = 1;
  272 + unsigned int maxMargin = tileDimension/2;
  273 + unsigned int currMargin = static_cast<unsigned int>(pow(2, niter + 1) - 2);
  274 + unsigned int prevMargin = currMargin;
  275 +
  276 + while(currMargin < maxMargin)
  277 + {
  278 + prevMargin = currMargin;
  279 + niter++;
  280 + currMargin = static_cast<unsigned int>(pow(2, niter + 1) - 2);
  281 + }
  282 +
  283 + m_TileWidth = tileDimension - prevMargin;
  284 + m_TileHeight = m_TileWidth;
  285 + m_Margin = prevMargin;
  286 + m_NumberOfFirstIterations = niter - 1;
  287 + }
  288 +
  289 + template <class TSegmenter>
  290 + void Controller<TSegmenter>::SetInternalMemoryAvailable(long long unsigned int v) // expecting a value in Mbytes.
  291 + {
  292 + assert(v > 0);
  293 + m_Memory = v * 1024ul * 1024ul;
  294 + }
  295 +
  296 + template<class TSegmenter>
  297 + void Controller<TSegmenter>::SetImageDivision(bool f)
  298 + {
  299 + m_ImageDivisionActivated = f;
  300 + }
  301 +
  302 + template<class TSegmenter>
  303 + void Controller<TSegmenter>::SetInputImage(const std::string& str)
  304 + {
  305 + m_InputImage = str;
  306 + }
  307 +
  308 + template<class TSegmenter>
  309 + void Controller<TSegmenter>::SetOutputGraphDirectory(const std::string& str)
  310 + {
  311 + m_OutputGraphDirectory = str;
  312 + }
  313 +
  314 + template<class TSegmenter>
  315 + void Controller<TSegmenter>::SetTileDirectory(const std::string& str)
  316 + {
  317 + m_TileDirectory = str;
  318 + }
  319 +
  320 + template<class TSegmenter>
  321 + void Controller<TSegmenter>::SetTemporaryDirectory(const std::string& str)
  322 + {