Commit de96e0d9fcc58c8fed74d3c72f8d2405cd0eca8b

Authored by Pierre Lassalle
1 parent 3b980eec
Exists in master

New criteria

Applications/CMakeLists.txt
... ... @@ -17,3 +17,9 @@
17 17 #=========================================================================
18 18 add_executable(RegionMergingSegmentation RegionMergingSegmentation.cxx)
19 19 target_link_libraries(RegionMergingSegmentation OTBGRM)
  20 +
  21 +add_executable(SpringSegmentation SpringSegmentation.cxx)
  22 +target_link_libraries(SpringSegmentation OTBGRM)
  23 +
  24 +add_executable(FullLambdaScheduleSegmentation FullLambdaScheduleSegmentation.cxx)
  25 +target_link_libraries(FullLambdaScheduleSegmentation OTBGRM)
... ...
Applications/FullLambdaScheduleSegmentation.cxx 0 → 100644
... ... @@ -0,0 +1,58 @@
  1 +#include <iostream>
  2 +#include <otbImage.h>
  3 +#include <otbVectorImage.h>
  4 +#include <otbImageFileReader.h>
  5 +#include <otbImageFileWriter.h>
  6 +#include "lsrmFullLambdaScheduleSegmenter.h"
  7 +
  8 +int main(int argc, char *argv[])
  9 +{
  10 + if(argc != 5)
  11 + {
  12 + std::cerr << "Usage: ./" << argv[0] << "\n"
  13 + << "\t[input image path] : (.jpg, .png, .tif)\n"
  14 + << "\t[output clustered image] : (.jpg, .png, .tif)\n"
  15 + << "\t[output label image] : (.tif)\n"
  16 + << "\t[lambda threshold] : unlimited positive value"
  17 + << std::endl;
  18 + return 1;
  19 + }
  20 +
  21 + const char * inFileName = argv[1];
  22 + const char * clusterFileName = argv[2];
  23 + const char * labelFileName = argv[3];
  24 + const float lambda = atof(argv[4]);
  25 +
  26 + typedef float PixelType;
  27 + typedef unsigned long int LabelPixelType;
  28 + typedef unsigned char ClusterPixelType;
  29 + typedef otb::VectorImage<PixelType, 2> InputImageType;
  30 + typedef otb::Image<LabelPixelType, 2> LabelImageType;
  31 + typedef otb::VectorImage<ClusterPixelType, 2> ClusterImageType;
  32 + typedef otb::ImageFileReader<InputImageType> InputImageReaderType;
  33 + typedef otb::ImageFileWriter<LabelImageType> LabelImageWriterType;
  34 + typedef otb::ImageFileWriter<ClusterImageType> ClusterImageWriterType;
  35 + typedef lsrm::FullLambdaScheduleSegmenter<InputImageType> SegmenterType;
  36 +
  37 + auto imgReader = InputImageReaderType::New();
  38 + imgReader->SetFileName(inFileName);
  39 + imgReader->Update();
  40 +
  41 +
  42 + SegmenterType segmenter;
  43 + segmenter.SetThreshold(lambda);
  44 + segmenter.SetInput(imgReader->GetOutput());
  45 + segmenter.Update();
  46 +
  47 + auto labelWriter = LabelImageWriterType::New();
  48 + labelWriter->SetFileName(labelFileName);
  49 + labelWriter->SetInput(segmenter.GetLabeledClusteredOutput());
  50 + labelWriter->Update();
  51 +
  52 + auto clusterWriter = ClusterImageWriterType::New();
  53 + clusterWriter->SetFileName(clusterFileName);
  54 + clusterWriter->SetInput(segmenter.GetClusteredImageOutput());
  55 + clusterWriter->Update();
  56 +
  57 + return 0;
  58 +}
... ...
Applications/SpringSegmentation.cxx 0 → 100644
... ... @@ -0,0 +1,58 @@
  1 +#include <iostream>
  2 +#include <otbImage.h>
  3 +#include <otbVectorImage.h>
  4 +#include <otbImageFileReader.h>
  5 +#include <otbImageFileWriter.h>
  6 +#include "lsrmSpringSegmenter.h"
  7 +
  8 +int main(int argc, char *argv[])
  9 +{
  10 + if(argc != 5)
  11 + {
  12 + std::cerr << "Usage: ./" << argv[0] << "\n"
  13 + << "\t[input image path] : (.jpg, .png, .tif)\n"
  14 + << "\t[output clustered image] : (.jpg, .png, .tif)\n"
  15 + << "\t[output label image] : (.tif)\n"
  16 + << "\t[distance threshold] : unlimited positive value"
  17 + << std::endl;
  18 + return 1;
  19 + }
  20 +
  21 + const char * inFileName = argv[1];
  22 + const char * clusterFileName = argv[2];
  23 + const char * labelFileName = argv[3];
  24 + const float distThreshold = atof(argv[4]);
  25 +
  26 + typedef float PixelType;
  27 + typedef unsigned long int LabelPixelType;
  28 + typedef unsigned char ClusterPixelType;
  29 + typedef otb::VectorImage<PixelType, 2> InputImageType;
  30 + typedef otb::Image<LabelPixelType, 2> LabelImageType;
  31 + typedef otb::VectorImage<ClusterPixelType, 2> ClusterImageType;
  32 + typedef otb::ImageFileReader<InputImageType> InputImageReaderType;
  33 + typedef otb::ImageFileWriter<LabelImageType> LabelImageWriterType;
  34 + typedef otb::ImageFileWriter<ClusterImageType> ClusterImageWriterType;
  35 + typedef lsrm::SpringSegmenter<InputImageType> SegmenterType;
  36 +
  37 + auto imgReader = InputImageReaderType::New();
  38 + imgReader->SetFileName(inFileName);
  39 + imgReader->Update();
  40 +
  41 +
  42 + SegmenterType segmenter;
  43 + segmenter.SetThreshold(distThreshold);
  44 + segmenter.SetInput(imgReader->GetOutput());
  45 + segmenter.Update();
  46 +
  47 + auto labelWriter = LabelImageWriterType::New();
  48 + labelWriter->SetFileName(labelFileName);
  49 + labelWriter->SetInput(segmenter.GetLabeledClusteredOutput());
  50 + labelWriter->Update();
  51 +
  52 + auto clusterWriter = ClusterImageWriterType::New();
  53 + clusterWriter->SetFileName(clusterFileName);
  54 + clusterWriter->SetInput(segmenter.GetClusteredImageOutput());
  55 + clusterWriter->Update();
  56 +
  57 + return 0;
  58 +}
... ...
Code/lsrmBaatzSegmenter.txx
... ... @@ -9,8 +9,6 @@ namespace lsrm
9 9 template<class TImage>
10 10 BaatzSegmenter<TImage>::BaatzSegmenter() : Superclass()
11 11 {
12   - this->m_DoBFSegmentation = true;
13   - this->m_NumberOfIterations = 75;
14 12 }
15 13  
16 14 template<class TImage>
... ...
Code/lsrmFullLambdaScheduleSegmenter.h 0 → 100644
... ... @@ -0,0 +1,37 @@
  1 +#ifndef __LSRM_FULL_LAMBDA_SCHEDULE_SEGMENTER_H
  2 +#define __LSRM_FULL_LAMBDA_SCHEDULE_SEGMENTER_H
  3 +#include "lsrmSegmenter.h"
  4 +
  5 +namespace lsrm
  6 +{
  7 + struct FLSNode : Node<FLSNode>
  8 + {
  9 + std::vector<float> m_Means;
  10 + };
  11 +
  12 + struct FLSParam{};
  13 +
  14 + template<class TImage>
  15 + class FullLambdaScheduleSegmenter : public Segmenter< TImage, FLSNode, FLSParam>
  16 + {
  17 + public:
  18 + /* Some convenient typedefs */
  19 + typedef Segmenter<TImage, FLSNode, FLSParam> Superclass;
  20 + typedef TImage ImageType;
  21 + typedef typename Superclass::GraphType GraphType;
  22 + typedef typename Superclass::NodePointerType NodePointerType;
  23 + typedef typename Superclass::GraphOperatorType GraphOperatorType;
  24 + typedef GraphToOtbImage<GraphType> IOType;
  25 +
  26 + FullLambdaScheduleSegmenter();
  27 +
  28 + void Update();
  29 +
  30 + float ComputeMergingCost(NodePointerType n1, NodePointerType n2);
  31 + void UpdateSpecificAttributes(NodePointerType n1, NodePointerType n2);
  32 + void InitFromImage();
  33 + };
  34 +} // end of namespace lsrm
  35 +#include "lsrmFullLambdaScheduleSegmenter.txx"
  36 +#endif
  37 +
... ...
Code/lsrmFullLambdaScheduleSegmenter.txx 0 → 100644
... ... @@ -0,0 +1,104 @@
  1 +#ifndef __LSRM_FULL_LAMBDA_SCHEDULE_SEGMENTER_TXX
  2 +#define __LSRM_FULL_LAMBDA_SCHEDULE_SEGMENTER_TXX
  3 +
  4 +namespace lsrm
  5 +{
  6 + template<class TImage>
  7 + FullLambdaScheduleSegmenter<TImage>::FullLambdaScheduleSegmenter() : Superclass()
  8 + {
  9 + }
  10 +
  11 + template<class TImage>
  12 + void
  13 + FullLambdaScheduleSegmenter<TImage>::InitFromImage()
  14 + {
  15 + typedef itk::ImageRegionIterator<TImage> ImageIterator;
  16 +
  17 + this->m_ImageWidth = this->m_InputImage->GetLargestPossibleRegion().GetSize()[0];
  18 + this->m_ImageHeight =this->m_InputImage->GetLargestPossibleRegion().GetSize()[1];
  19 + this->m_NumberOfComponentsPerPixel = this->m_InputImage->GetNumberOfComponentsPerPixel();
  20 +
  21 + std::size_t idx = 0;
  22 + ImageIterator it(this->m_InputImage, this->m_InputImage->GetLargestPossibleRegion());
  23 + for(it.GoToBegin(); !it.IsAtEnd(); ++it)
  24 + {
  25 + this->m_Graph.m_Nodes[idx]->m_Means.reserve(this->m_NumberOfComponentsPerPixel);
  26 +
  27 + for(std::size_t b = 0; b < this->m_NumberOfComponentsPerPixel; ++b)
  28 + {
  29 + this->m_Graph.m_Nodes[idx]->m_Means.push_back(it.Get()[b]);
  30 + }
  31 + ++idx;
  32 + }
  33 + }
  34 +
  35 + template<class TImage>
  36 + float
  37 + FullLambdaScheduleSegmenter<TImage>::ComputeMergingCost(NodePointerType n1, NodePointerType n2)
  38 + {
  39 + float eucDist = 0.0;
  40 + const float a1 = static_cast<float>(n1->m_Area);
  41 + const float a2 = static_cast<float>(n2->m_Area);
  42 + const float a_sum = a1 + a2;
  43 +
  44 + for(unsigned int b = 0; b < this->m_NumberOfComponentsPerPixel; b++)
  45 + {
  46 + eucDist += (n1->m_Means[b] - n2->m_Means[b])*(n1->m_Means[b] - n2->m_Means[b]);
  47 + }
  48 +
  49 + // Retrieve the length of the boundary between n1 and n2
  50 + auto toN2 = GraphOperatorType::FindEdge(n1, n2);
  51 +
  52 + float cost = (((a1*a2)/a_sum)*eucDist) / (static_cast<float>(toN2->m_Boundary));
  53 +
  54 + return cost;
  55 + }
  56 +
  57 + template<class TImage>
  58 + void
  59 + FullLambdaScheduleSegmenter<TImage>::UpdateSpecificAttributes(NodePointerType n1, NodePointerType n2)
  60 + {
  61 + const float a1 = static_cast<float>(n1->m_Area);
  62 + const float a2 = static_cast<float>(n2->m_Area);
  63 + const float a_sum = a1 + a2;
  64 +
  65 + for(unsigned int b = 0; b < this->m_NumberOfComponentsPerPixel; ++b)
  66 + {
  67 + n1->m_Means[b] = (a1 * n1->m_Means[b] + a2 * n2->m_Means[b]) / a_sum;
  68 + }
  69 + }
  70 +
  71 + template<class TImage>
  72 + void
  73 + FullLambdaScheduleSegmenter<TImage>::Update()
  74 + {
  75 + GraphOperatorType::InitNodes(this->m_InputImage, this->m_Graph, *this, FOUR);
  76 + bool prev_merged = false;
  77 +
  78 + if(this->m_NumberOfIterations > 0)
  79 + {
  80 + prev_merged =
  81 + GraphOperatorType::PerfomAllIterationsWithLMBFAndConstThreshold(this->m_Graph, *this,
  82 + this->m_Threshold, this->m_NumberOfIterations,
  83 + this->m_ImageWidth, this->m_ImageHeight);
  84 +
  85 + if(prev_merged && this->m_DoBFSegmentation)
  86 + {
  87 + prev_merged =
  88 + GraphOperatorType::PerfomAllIterationsWithBFAndConstThreshold(this->m_Graph, *this,
  89 + this->m_Threshold, this->m_NumberOfIterations,
  90 + this->m_ImageWidth, this->m_ImageHeight);
  91 + }
  92 + }
  93 + else
  94 + {
  95 + assert(this->m_DoBFSegmentation == true);
  96 + prev_merged =
  97 + GraphOperatorType::PerfomAllIterationsWithBFAndConstThreshold(this->m_Graph, *this,
  98 + this->m_Threshold, this->m_NumberOfIterations,
  99 + this->m_ImageWidth, this->m_ImageHeight);
  100 + }
  101 + }
  102 +}
  103 +
  104 +#endif
... ...
Code/lsrmGraphOperations.txx~ 0 → 100644
... ... @@ -0,0 +1,465 @@
  1 +#ifndef __LSRM_GRAPH_OPERATIONS_TXX
  2 +#define __LSRM_GRAPH_OPERATIONS_TXX
  3 +#include <otbImageFileReader.h>
  4 +
  5 +namespace lsrm
  6 +{
  7 + template<class TSegmenter>
  8 + void GraphOperations<TSegmenter>::InitNodes(ImageType * inputImg,
  9 + GraphType& graph,
  10 + SegmenterType& seg,
  11 + CONNECTIVITY mask)
  12 + {
  13 + unsigned int width, height;
  14 +
  15 + {
  16 + width = inputImg->GetLargestPossibleRegion().GetSize()[0];
  17 + height = inputImg->GetLargestPossibleRegion().GetSize()[1];
  18 + }
  19 +
  20 + const long unsigned int num_nodes = width * height;
  21 +
  22 + graph.m_Nodes.reserve(num_nodes);
  23 +
  24 + for(long unsigned int i = 0;
  25 + i < num_nodes;
  26 + ++i)
  27 + {
  28 + NodePointerType n(new NodeType);
  29 + n->m_Id = i;
  30 + n->m_Valid = true;
  31 + n->m_Expired = false;
  32 + n->m_IsMerged = true; // force to compute costs for the first iteration
  33 + n->m_Perimeter = 4;
  34 + n->m_Area = 1;
  35 + n->m_Bbox.m_UX = i % width;
  36 + n->m_Bbox.m_UY = i / width;
  37 + n->m_Bbox.m_W = 1;
  38 + n->m_Bbox.m_H = 1;
  39 + n->m_Pixels.push_back(i);
  40 + graph.m_Nodes.push_back(n);
  41 + }
  42 +
  43 + if(mask == FOUR)
  44 + {
  45 + for(auto& r : graph.m_Nodes)
  46 + {
  47 + long int neighborhood[4];
  48 + FOURNeighborhood(neighborhood, r->m_Id, width, height);
  49 + for(short j = 0; j < 4; ++j)
  50 + {
  51 + if(neighborhood[j] > -1)
  52 + r->m_Edges.push_back(EdgeType( graph.m_Nodes[neighborhood[j]], 0, 1));
  53 + }
  54 + }
  55 + }
  56 + else
  57 + {
  58 + for(auto& r : graph.m_Nodes)
  59 + {
  60 + long int neighborhood[8];
  61 + EIGHTNeighborhood(neighborhood, r->m_Id, width, height);
  62 + for(short j = 0; j < 8; ++j)
  63 + {
  64 + if(neighborhood[j] > -1)
  65 + {
  66 + if(j % 2 > 0)
  67 + r->m_Edges.push_back(EdgeType( graph.m_Nodes[neighborhood[j]], 0, 0));
  68 + else
  69 + r->m_Edges.push_back(EdgeType( graph.m_Nodes[neighborhood[j]], 0, 1));
  70 + }
  71 + }
  72 + }
  73 + }
  74 + seg.InitFromImage();
  75 + }
  76 +
  77 + template<class TSegmenter>
  78 + void GraphOperations<TSegmenter>::UpdateMergingCosts(GraphType& graph,
  79 + SegmenterType& seg)
  80 + {
  81 + float min_cost;
  82 + long unsigned int min_id;
  83 + std::size_t idx, min_idx;
  84 +
  85 + for(auto& r : graph.m_Nodes)
  86 + {
  87 + for(auto& edge : r->m_Edges)
  88 + edge.m_CostUpdated = false;
  89 + }
  90 +
  91 + for(auto& r : graph.m_Nodes)
  92 + {
  93 + min_cost = std::numeric_limits<float>::max();
  94 + min_id = 0;
  95 + idx = 0;
  96 + min_idx = 0;
  97 +
  98 + r->m_Expired = false;
  99 + r->m_Valid = true;
  100 +
  101 + for(auto& edge : r->m_Edges)
  102 + {
  103 + auto neighborR = edge.GetRegion();
  104 +
  105 + // Compute the cost if necessary
  106 + if(!edge.m_CostUpdated && (neighborR->m_IsMerged || r->m_IsMerged))
  107 + {
  108 + auto edgeFromNeighborToR = FindEdge(neighborR, r);
  109 + edge.m_Cost = seg.ComputeMergingCost(r, neighborR);
  110 + edgeFromNeighborToR->m_Cost = edge.m_Cost;
  111 + edge.m_CostUpdated = true;
  112 + edgeFromNeighborToR->m_CostUpdated = true;
  113 + }
  114 +
  115 + // Check if the cost of the edge is the minimum
  116 + if(min_cost > edge.m_Cost)
  117 + {
  118 + min_cost = edge.m_Cost;
  119 + min_id = neighborR->m_Id;
  120 + min_idx = idx;
  121 + }
  122 + else if(min_cost == edge.m_Cost)
  123 + {
  124 + if(min_id > neighborR->m_Id)
  125 + {
  126 + min_id = neighborR->m_Id;
  127 + min_idx = idx;
  128 + }
  129 + }
  130 + ++idx;
  131 + }
  132 +
  133 + assert(min_idx < r->m_Edges.size());
  134 + std::swap(r->m_Edges[0], r->m_Edges[min_idx]);
  135 +
  136 + }
  137 +
  138 + // Reset the merge flag for all the regions.
  139 + for(auto& r : graph.m_Nodes)
  140 + r->m_IsMerged = false;
  141 + }
  142 +
  143 + template<class TSegmenter>
  144 + typename GraphOperations<TSegmenter>::NodePointerType
  145 + GraphOperations<TSegmenter>::CheckLMBF(NodePointerType a, float t)
  146 + {
  147 + if(a->m_Valid)
  148 + {
  149 + float cost = a->m_Edges.front().m_Cost;
  150 +
  151 + if(cost < t)
  152 + {
  153 + NodePointerType b = a->m_Edges.front().GetRegion();
  154 +
  155 + if( b->m_Valid)
  156 + {
  157 + NodePointerType best_b = b->m_Edges.front().GetRegion();
  158 +
  159 + if(a == best_b)
  160 + {
  161 + if(a->m_Id < b->m_Id)
  162 + return a;
  163 + else
  164 + return b;
  165 + }
  166 + else
  167 + return NodePointerType();
  168 + }
  169 + else
  170 + return NodePointerType();
  171 + }
  172 + else
  173 + return NodePointerType();
  174 + }
  175 + else
  176 + return NodePointerType();
  177 + }
  178 +
  179 + template<class TSegmenter>
  180 + typename GraphOperations<TSegmenter>::NodePointerType
  181 + GraphOperations<TSegmenter>::CheckBF(NodePointerType a, float t)
  182 + {
  183 + if(a->m_Valid)
  184 + {
  185 + float cost = a->m_Edges.front().m_Cost;
  186 +
  187 + if( cost < t )
  188 + {
  189 + NodePointerType b = a->m_Edges.front().GetRegion();
  190 +
  191 + if(b->m_Valid)
  192 + {
  193 + if( a->m_Id < b->m_Id )
  194 + return a;
  195 + else
  196 + return b;
  197 + }
  198 + else
  199 + return NodePointerType();
  200 + }
  201 + else
  202 + return NodePointerType();
  203 + }
  204 + else
  205 + return NodePointerType();
  206 + }
  207 +
  208 + template<class TSegmenter>
  209 + typename GraphOperations<TSegmenter>::EdgeIterator
  210 + GraphOperations<TSegmenter>::FindEdge(NodePointerType n, NodePointerType target)
  211 + {
  212 + return std::find_if(n->m_Edges.begin(), n->m_Edges.end(),[&](EdgeType& e)->bool{
  213 + return e.GetRegion() == target;
  214 + });
  215 + }
  216 +
  217 + template<class TSegmenter>
  218 + void
  219 + GraphOperations<TSegmenter>::UpdateNeighbors(NodePointerType a, NodePointerType b)
  220 + {
  221 + unsigned int boundary;
  222 +
  223 + /* Explore the neighbors of b */
  224 + for (auto& edge : b->m_Edges)
  225 + {
  226 + // Retrieve the edge targeting node b.
  227 + auto neigh_b = edge.GetRegion();
  228 + auto toB = FindEdge(neigh_b, b);
  229 +
  230 + /* If the edge tageting to node b is the first then
  231 + the corresponding node is not valid anymore. */
  232 + if(toB == neigh_b->m_Edges.begin())
  233 + neigh_b->m_Valid = false;
  234 +
  235 + /* Keep in memory the boundary between node b
  236 + and node neigh_b */
  237 + boundary = edge.m_Boundary;
  238 +
  239 + /*
  240 + We can remove safely the edge from node neigh_b
  241 + targeting to node b
  242 + */
  243 + neigh_b->m_Edges.erase(toB);
  244 +
  245 + if(neigh_b != a)
  246 + {
  247 + /* Retrieve the edge targeting to node a. */
  248 + auto toA = FindEdge(neigh_b, a);
  249 +
  250 + if( toA == neigh_b->m_Edges.end() )
  251 + {
  252 + /* No edge exists between node a and node neigh_b. */
  253 +
  254 + /* Add an edge from node neigh_b targeting node a. */
  255 + neigh_b->m_Edges.push_back(EdgeType(a, 0, boundary));
  256 +
  257 + /* Add an edge from node a targeting node neigh_b. */
  258 + a->m_Edges.push_back(EdgeType(neigh_b, 0, boundary));
  259 + }
  260 + else
  261 + {
  262 + /* An edge exists between node a and node neigh_b. */
  263 +
  264 + /* Increment the boundary of the edge from node neigh_b
  265 + targeting to node a. */
  266 + toA->m_Boundary += boundary;
  267 +
  268 + /* Increment the boundary of the edge from node a
  269 + targeting to node neigh_b. */
  270 + auto toNeighB = FindEdge(a, neigh_b);
  271 + toNeighB->m_Boundary += boundary;
  272 + }
  273 + }
  274 +
  275 + }
  276 +
  277 + }
  278 +
  279 + template<class TSegmenter>
  280 + void
  281 + GraphOperations<TSegmenter>::UpdateInternalAttributes(NodePointerType a,
  282 + NodePointerType b,
  283 + const unsigned int width,
  284 + const unsigned int height)
  285 + {
  286 + /* Step 1: update the bounding box */
  287 + a->m_Bbox = MergeBoundingBoxes(a->m_Bbox, b->m_Bbox);
  288 +
  289 + /* Update the list of pixels */
  290 + auto begin = std::make_move_iterator(b->m_Pixels.begin());
  291 + auto end = std::make_move_iterator(b->m_Pixels.end());
  292 + a->m_Pixels.insert(a->m_Pixels.end(), begin, end);
  293 +
  294 + /* Step 2 : update perimeter and area attributes */
  295 + EdgeIterator toB = FindEdge(a, b);
  296 + a->m_Perimeter += (b->m_Perimeter - 2 * toB->m_Boundary);
  297 + a->m_Area += b->m_Area;
  298 +
  299 + /* Step 2: update the neighborhood */
  300 + UpdateNeighbors(a,b);
  301 +
  302 + /* Step 3: update the node' states */
  303 + a->m_Valid = false;
  304 + b->m_Valid = false;
  305 + b->m_Expired = true;
  306 + a->m_IsMerged = true;
  307 + }
  308 +
  309 + template<class TSegmenter>
  310 + void
  311 + GraphOperations<TSegmenter>::RemoveExpiredNodes(GraphType& graph)
  312 + {
  313 + NodeIterator nit = std::remove_if(graph.m_Nodes.begin(), graph.m_Nodes.end(), [](NodePointerType r)->bool{
  314 + return r->m_Expired;
  315 + });
  316 + graph.m_Nodes.erase(nit, graph.m_Nodes.end());
  317 + }
  318 +
  319 + template<class TSegmenter>
  320 + bool
  321 + GraphOperations<TSegmenter>::PerfomOneIterationWithLMBF(GraphType& graph,
  322 + SegmenterType& seg,
  323 + const float threshold,
  324 + const unsigned int width,
  325 + const unsigned int height)
  326 + {
  327 + bool merged = false;
  328 +
  329 + /* Update the costs of merging between adjacent nodes */
  330 + UpdateMergingCosts(graph, seg);
  331 +
  332 + for(auto& region : graph.m_Nodes)
  333 + {
  334 +
  335 + auto res_node = CheckLMBF(region, threshold);
  336 +
  337 + if(res_node)
  338 + {
  339 + seg.UpdateSpecificAttributes(res_node, res_node->m_Edges.front().GetRegion());
  340 + UpdateInternalAttributes(res_node, res_node->m_Edges.front().GetRegion(),
  341 + width, height);
  342 + merged = true;
  343 + }
  344 + }
  345 +
  346 + RemoveExpiredNodes(graph);
  347 +
  348 + if(graph.m_Nodes.size() < 2)
  349 + return false;
  350 +
  351 + return merged;
  352 + }
  353 +
  354 + template<class TSegmenter>
  355 + bool
  356 + GraphOperations<TSegmenter>::PerfomOneIterationWithBF(GraphType& graph,
  357 + SegmenterType& seg,
  358 + const float threshold,
  359 + const unsigned int width,
  360 + const unsigned int height)
  361 + {
  362 + bool merged = false;
  363 +
  364 + /* Update the costs of merging between adjacent nodes */
  365 + UpdateMergingCosts(graph, seg);
  366 +
  367 + for(auto& region : graph.m_Nodes)
  368 + {
  369 + NodePointerType res_node = CheckBF(region, threshold);
  370 +
  371 + if(res_node)
  372 + {
  373 + seg.UpdateSpecificAttributes(res_node, res_node->m_Edges.front().GetRegion());
  374 + UpdateInternalAttributes(res_node, res_node->m_Edges.front().GetRegion(),
  375 + width, height);
  376 + merged = true;
  377 + }
  378 + }
  379 +
  380 + RemoveExpiredNodes(graph);
  381 +
  382 + if(graph.m_Nodes.size() < 2)
  383 + return false;
  384 +
  385 + return merged;
  386 + }
  387 +
  388 + template<class TSegmenter>
  389 + bool
  390 + GraphOperations<TSegmenter>::PerfomAllIterationsWithLMBFAndConstThreshold(GraphType& graph,
  391 + SegmenterType& seg,
  392 + const float threshold,
  393 + const unsigned int numberOfIterations,
  394 + const unsigned int width,
  395 + const unsigned int height)
  396 + {
  397 + bool merged = true;
  398 + unsigned int iterations = 0;
  399 +
  400 + while(merged &&
  401 + iterations < numberOfIterations &&
  402 + graph.m_Nodes.size() > 1)
  403 + {
  404 + std::cout << "." << std::flush;
  405 + ++iterations;
  406 +
  407 + merged = PerfomOneIterationWithLMBF(graph, seg, threshold,
  408 + width, height);
  409 + }
  410 + std::cout << std::endl;
  411 +
  412 + if(graph.m_Nodes.size() < 2)
  413 + return false;
  414 +
  415 + return merged;
  416 + }
  417 +
  418 + template<class TSegmenter>
  419 + bool
  420 + GraphOperations<TSegmenter>::PerfomAllIterationsWithBFAndConstThreshold(GraphType& graph,
  421 + SegmenterType& seg,
  422 + const float threshold,
  423 + const unsigned int numberOfIterations,
  424 + const unsigned int width,
  425 + const unsigned int height)
  426 + {
  427 + bool merged = true;
  428 + unsigned int maxNumberOfIterations;
  429 + if(numberOfIterations < 1)
  430 + maxNumberOfIterations = 75;
  431 + else
  432 + maxNumberOfIterations = numberOfIterations;
  433 +
  434 + unsigned int iterations = 0;
  435 +
  436 + while(merged &&
  437 + iterations < maxNumberOfIterations &&
  438 + graph.m_Nodes.size() > 1)
  439 + {
  440 + std::cout << "." << std::flush;
  441 + ++iterations;
  442 +
  443 + merged = PerfomOneIterationWithBF(graph, seg, threshold,
  444 + width, height);
  445 + }
  446 + std::cout << std::endl;
  447 +
  448 + if(graph.m_Nodes.size() < 2)
  449 + return false;
  450 +
  451 + return merged;
  452 + }
  453 +
  454 +
  455 +} // end of namespace lsrm
  456 +
  457 +#endif
  458 +
  459 +
  460 +
  461 +
  462 +
  463 +
  464 +
  465 +
... ...
Code/lsrmSegmenter.h
... ... @@ -28,7 +28,10 @@ namespace lsrm
28 28  
29 29 /* Default constructor and destructor */
30 30  
31   - Segmenter(){};
  31 + Segmenter(){
  32 + this->m_DoBFSegmentation = true;
  33 + this->m_NumberOfIterations = 75;
  34 + };
32 35 ~Segmenter(){};
33 36  
34 37 /*
... ...
Code/lsrmSpringSegmenter.h 0 → 100644
... ... @@ -0,0 +1,36 @@
  1 +#ifndef __LSRM_SPRING_SEGMENTER_H
  2 +#define __LSRM_SPRING_SEGMENTER_H
  3 +#include "lsrmSegmenter.h"
  4 +
  5 +namespace lsrm
  6 +{
  7 + struct SpringNode : Node<SpringNode>
  8 + {
  9 + std::vector<float> m_Means;
  10 + };
  11 +
  12 + struct SpringParam{};
  13 +
  14 + template<class TImage>
  15 + class SpringSegmenter : public Segmenter< TImage, SpringNode, SpringParam>
  16 + {
  17 + public:
  18 + /* Some convenient typedefs */
  19 + typedef Segmenter<TImage, SpringNode, SpringParam> Superclass;
  20 + typedef TImage ImageType;
  21 + typedef typename Superclass::GraphType GraphType;
  22 + typedef typename Superclass::NodePointerType NodePointerType;
  23 + typedef typename Superclass::GraphOperatorType GraphOperatorType;
  24 + typedef GraphToOtbImage<GraphType> IOType;
  25 +
  26 + SpringSegmenter();
  27 +
  28 + void Update();
  29 +
  30 + float ComputeMergingCost(NodePointerType n1, NodePointerType n2);
  31 + void UpdateSpecificAttributes(NodePointerType n1, NodePointerType n2);
  32 + void InitFromImage();
  33 + };
  34 +} // end of namespace lsrm
  35 +#include "lsrmSpringSegmenter.txx"
  36 +#endif
... ...
Code/lsrmSpringSegmenter.txx 0 → 100644
... ... @@ -0,0 +1,97 @@
  1 +#ifndef __LSRM_SPRING_SEGMENTER_TXX
  2 +#define __LSRM_SPRING_SEGMENTER_TXX
  3 +#include <otbImageFileReader.h>
  4 +#include <itkImageRegionIterator.h>
  5 +
  6 +namespace lsrm
  7 +{
  8 + template<class TImage>
  9 + SpringSegmenter<TImage>::SpringSegmenter() : Superclass()
  10 + {
  11 + }
  12 +
  13 + template<class TImage>
  14 + void
  15 + SpringSegmenter<TImage>::InitFromImage()
  16 + {
  17 + typedef itk::ImageRegionIterator<TImage> ImageIterator;
  18 +
  19 + this->m_ImageWidth = this->m_InputImage->GetLargestPossibleRegion().GetSize()[0];
  20 + this->m_ImageHeight =this->m_InputImage->GetLargestPossibleRegion().GetSize()[1];
  21 + this->m_NumberOfComponentsPerPixel = this->m_InputImage->GetNumberOfComponentsPerPixel();
  22 +
  23 + std::size_t idx = 0;
  24 + ImageIterator it(this->m_InputImage, this->m_InputImage->GetLargestPossibleRegion());
  25 + for(it.GoToBegin(); !it.IsAtEnd(); ++it)
  26 + {
  27 + this->m_Graph.m_Nodes[idx]->m_Means.reserve(this->m_NumberOfComponentsPerPixel);
  28 +
  29 + for(std::size_t b = 0; b < this->m_NumberOfComponentsPerPixel; ++b)
  30 + {
  31 + this->m_Graph.m_Nodes[idx]->m_Means.push_back(it.Get()[b]);
  32 + }
  33 + ++idx;
  34 + }
  35 + }
  36 +
  37 + template<class TImage>
  38 + float
  39 + SpringSegmenter<TImage>::ComputeMergingCost(NodePointerType n1, NodePointerType n2)
  40 + {
  41 + float eucDist = 0.0;
  42 +
  43 + for(unsigned int b = 0; b < this->m_NumberOfComponentsPerPixel; b++)
  44 + {
  45 + eucDist += (n1->m_Means[b] - n2->m_Means[b])*(n1->m_Means[b] - n2->m_Means[b]);
  46 + }
  47 +
  48 + return (static_cast<float>(std::sqrt(eucDist)));
  49 + }
  50 +
  51 + template<class TImage>
  52 + void
  53 + SpringSegmenter<TImage>::UpdateSpecificAttributes(NodePointerType n1, NodePointerType n2)
  54 + {
  55 + const float a1 = static_cast<float>(n1->m_Area);
  56 + const float a2 = static_cast<float>(n2->m_Area);
  57 + const float a_sum = a1 + a2;
  58 +
  59 + for(unsigned int b = 0; b < this->m_NumberOfComponentsPerPixel; ++b)
  60 + {
  61 + n1->m_Means[b] = (a1 * n1->m_Means[b] + a2 * n2->m_Means[b]) / a_sum;
  62 + }
  63 + }
  64 +
  65 + template<class TImage>
  66 + void
  67 + SpringSegmenter<TImage>::Update()
  68 + {
  69 + GraphOperatorType::InitNodes(this->m_InputImage, this->m_Graph, *this, FOUR);
  70 + bool prev_merged = false;
  71 +
  72 + if(this->m_NumberOfIterations > 0)
  73 + {
  74 + prev_merged =
  75 + GraphOperatorType::PerfomAllIterationsWithLMBFAndConstThreshold(this->m_Graph, *this,
  76 + this->m_Threshold, this->m_NumberOfIterations,
  77 + this->m_ImageWidth, this->m_ImageHeight);
  78 +
  79 + if(prev_merged && this->m_DoBFSegmentation)
  80 + {
  81 + prev_merged =
  82 + GraphOperatorType::PerfomAllIterationsWithBFAndConstThreshold(this->m_Graph, *this,
  83 + this->m_Threshold, this->m_NumberOfIterations,
  84 + this->m_ImageWidth, this->m_ImageHeight);
  85 + }
  86 + }
  87 + else
  88 + {
  89 + assert(this->m_DoBFSegmentation == true);
  90 + prev_merged =
  91 + GraphOperatorType::PerfomAllIterationsWithBFAndConstThreshold(this->m_Graph, *this,
  92 + this->m_Threshold, this->m_NumberOfIterations,
  93 + this->m_ImageWidth, this->m_ImageHeight);
  94 + }
  95 + }
  96 +}
  97 +#endif
... ...
img/test.tif 0 → 100644
No preview for this file type