triskele/include/ArrayTree/GraphWalker.tpp
Git Merciol f687310939 modifié : CMakeLists.txt
modifié :         CMakeListsOTB.txt
	modifié :         LICENSE
	modifié :         MakefileNoOTB
	modifié :         Readme.html
	modifié :         Readme.txt
	modifié :         include/Appli/Option.hpp
	modifié :         include/Appli/Selected.hpp
	modifié :         include/Appli/Selected.tpp
	modifié :         include/ArrayTree/ArrayTreeBuilder.hpp
	modifié :         include/ArrayTree/ArrayTreeBuilder.tpp
	modifié :         include/ArrayTree/Border.hpp
	modifié :         include/ArrayTree/Border.tpp
	modifié :         include/ArrayTree/GraphWalker.hpp
	modifié :         include/ArrayTree/GraphWalker.tpp
	modifié :         include/ArrayTree/Leader.hpp
	modifié :         include/ArrayTree/Leader.tpp
	modifié :         include/ArrayTree/Weight.hpp
	modifié :         include/ArrayTree/Weight.tpp
	modifié :         include/ArrayTree/triskeleArrayTreeBase.hpp
	modifié :         include/ArrayTree/triskeleArrayTreeBase.tpp
	modifié :         include/ArrayTree/triskeleSort.hpp
	modifié :         include/ArrayTree/triskeleSort.tpp
	modifié :         include/AttributeProfiles.hpp
	modifié :         include/AttributeProfiles.tpp
	modifié :         include/Attributes/AreaAttributes.hpp
	modifié :         include/Attributes/AreaAttributes.tpp
	modifié :         include/Attributes/AverageAttributes.hpp
	modifié :         include/Attributes/AverageAttributes.tpp
	modifié :         include/Attributes/MoIAttributes.hpp
	modifié :         include/Attributes/MoIAttributes.tpp
	modifié :         include/Attributes/SDAttributes.hpp
	modifié :         include/Attributes/SDAttributes.tpp
	modifié :         include/Attributes/WeightAttributes.hpp
	modifié :         include/Attributes/WeightAttributes.tpp
	modifié :         include/Attributes/XYAttributes.hpp
	modifié :         include/Attributes/XYAttributes.tpp
	modifié :         include/CompAttribute.hpp
	modifié :         include/CompAttribute.tpp
	modifié :         include/IImage.hpp
	modifié :         include/IImage.tpp
	modifié :         include/QuadTree/QuadTreeBuilder.hpp
	modifié :         include/Tree.hpp
	modifié :         include/Tree.tpp
	modifié :         include/TreeBuilder.hpp
	modifié :         include/TreeBuilder.tpp
	modifié :         include/TreeStats.hpp
	modifié :         include/TreeStats.tpp
	modifié :         include/XMLTree/XMLTreeBuilder.hpp
	modifié :         include/triskeleBase.hpp
	modifié :         include/triskeleBase.tpp
	modifié :         include/triskeleDealThreads.hpp
	modifié :         include/triskeleDealThreads.tpp
	modifié :         include/triskeleDebug.hpp
	modifié :         include/triskeleGdalGetType.hpp
	modifié :         otb-module.cmake
	modifié :         src/Appli/Option.cpp
	modifié :         src/Appli/Selected.cpp
	modifié :         src/ArrayTree/triskeleArrayTreeBase.cpp
	modifié :         src/CMakeLists.txt
	modifié :         src/IImage.cpp
	modifié :         src/PerfArrayTreeBuilder.cpp
	modifié :         src/QuadTree/QuadTreeBuilder.cpp
	modifié :         src/TestArrayTreeBuilder.cpp
	modifié :         src/Tree.cpp
	modifié :         src/TreeStats.cpp
	modifié :         src/XMLTree/XMLTreeBuilder.cpp
	modifié :         src/apGenerator.cpp
	modifié :         src/triskeleBase.cpp
	modifié :         src/triskeleDebug.cpp
2018-04-02 19:25:37 +02:00

340 lines
11 KiB
C++

#ifndef _OTB_TRISKELE_ARRAY_TREE_GRAPHWALKER_TPP
#define _OTB_TRISKELE_ARRAY_TREE_GRAPHWALKER_TPP
// ========================================
inline const Size &
GraphWalker::getSize () const {
return border.getSize ();
}
// ========================================
inline
GraphWalker::GraphWalker (const Border &border, const Connectivity &connectivity)
: border (border), connectivity (connectivity) {
DEF_LOG ("GraphWalker::GraphWalker", "size: " << border.getSize ());
BOOST_ASSERT (border.getSize ().width >= DimImg (0));
BOOST_ASSERT (border.getSize ().height >= DimImg (0));
}
// ----------------------------------------
inline DimImg
GraphWalker::vertexMaxCount () const {
return vertexMaxCount (border.getSize ());
}
// ----------------------------------------
inline DimImg
GraphWalker::vertexMaxCount (const Size &tileSize) {
return DimImg (tileSize.width)*DimImg (tileSize.height);
}
// ----------------------------------------
inline DimEdge
GraphWalker::edgeMaxCount () const {
return edgeMaxCount (border.getSize ());
}
// ----------------------------------------
inline DimEdge
GraphWalker::edgeMaxCount (const Size &tileSize) const {
if (!tileSize.width || !tileSize.height)
return 0;
DimEdge miniSquare = DimImg (tileSize.width)*DimImg (tileSize.height-1) + DimImg (tileSize.width-1)*DimImg (tileSize.height);
switch (connectivity) {
case Connectivity::C4 :
return miniSquare;
case Connectivity::C6N :
case Connectivity::C6P :
return miniSquare + DimImg (tileSize.width-1)*DimImg (tileSize.height-1);
default :
BOOST_ASSERT (connectivity == Connectivity::C8);
return miniSquare + 2*DimImg (tileSize.width-1)*DimImg (tileSize.height-1);
};
}
// ----------------------------------------
inline DimEdge
GraphWalker::edgeBoundaryMaxCount (const DimSideImg &side) const {
if (!side)
return 0;
switch (connectivity) {
case Connectivity::C4 :
return side;
case Connectivity::C6N :
case Connectivity::C6P :
return side+side-1;
default :
BOOST_ASSERT (connectivity == Connectivity::C8);
return 3*side-2;
};
}
// ========================================
inline void
GraphWalker::setTiles (const unsigned int &coreCount, const Rect &rect,
vector<Rect> &tiles, vector<Rect> &boundaries, vector<bool> &verticalBoundaries) {
BOOST_ASSERT (coreCount);
DEF_LOG ("GraphWalker::setTiles", "coreCount:" << coreCount << " rect:" << rect);
if (coreCount < 2 || max (rect.width, rect.height) < 4 || min (rect.width, rect.height) < 3) {
LOG ("rect:" << rect);
tiles.push_back (rect);
return;
}
bool vertical = rect.width > rect.height;
bool odd = coreCount & 0x1;
DimImg thin = (vertical ? rect.width : rect.height) / (odd ? coreCount : 2);
Rect tileA (rect);
Rect tileB (rect);
if (vertical) {
tileA.width = thin;
tileB.x += thin;
tileB.width -= thin;
} else {
tileA.height = thin;
tileB.y += thin;
tileB.height -= thin;
}
setTiles ((odd ? 1 : coreCount/2), tileA, tiles, boundaries, verticalBoundaries);
boundaries.push_back (tileB);
verticalBoundaries.push_back (vertical);
setTiles ((odd ? coreCount-1 : coreCount/2), tileB, tiles, boundaries, verticalBoundaries);
}
inline void
GraphWalker::setMaxBounds (const vector<Rect> &tiles, vector<DimImg> &vertexMaxBounds, vector<DimImg> &edgesMaxBounds) const {
unsigned int tileCount = tiles.size ();
vertexMaxBounds.resize (tileCount+1);
edgesMaxBounds.resize (tileCount+1);
DimImg vertexBase = 0, edgesBase = 0;
vertexMaxBounds [0] = edgesMaxBounds [0] = 0;
for (unsigned int i = 0; i < tileCount; ++i) {
Size zoneSize (tiles[i].width, tiles[i].height);
vertexMaxBounds [i+1] = vertexBase += vertexMaxCount (zoneSize); /* -1, but prety LOG */
edgesMaxBounds [i+1] = edgesBase += edgeMaxCount (zoneSize);
}
}
// ========================================
template<typename Funct>
inline DimImg
GraphWalker::forEachVertexIdx (const Funct &lambda /*lambda (DimImg idx)*/) const {
DimImg maxCount = vertexMaxCount ();
DimImg vertexCount = 0;
for (DimImg idx = 0; idx < maxCount; ++idx)
GRAPHWALKER_CALL_LAMBDA_IDX (idx, vertexCount, lambda (idx));
return vertexCount;
}
template<typename Funct>
inline DimImg
GraphWalker::forEachVertexIdx (const Rect &rect, const Funct &lambda /*lambda (DimImg idx)*/) const {
const Size &size (border.getSize ());
DimImg vertexCount = 0;
DimSideImg const lastX = rect.x+rect.width;
DimSideImg const lastY = rect.y+rect.height;
for (DimSideImg y = rect.y; y < lastY; ++y)
for (DimSideImg x = rect.x; x < lastX; ++x) {
const Point p (x, y);
DimImg idx = point2idx (size, p);
GRAPHWALKER_CALL_LAMBDA_IDX (idx, vertexCount, lambda (idx));
}
return vertexCount;
}
template<typename Funct>
inline DimImg
GraphWalker::forEachVertexPt (const Rect &rect, const Funct &lambda /*lambda (Point p)*/) const {
const Size &size (border.getSize ());
DimImg vertexCount = 0;
DimSideImg const lastX = rect.x+rect.width;
DimSideImg const lastY = rect.y+rect.height;
for (DimSideImg y = rect.y; y < lastY; ++y)
for (DimSideImg x = rect.x; x < lastX; ++x) {
const Point p (x, y);
DimImg idx = point2idx (size, p);
GRAPHWALKER_CALL_LAMBDA_IDX (idx, vertexCount, lambda (p));
}
return vertexCount;
}
// ========================================
template<typename Funct>
inline DimEdge
GraphWalker::forEachEdgePt (const Rect &rect, TileItem tileItem, const Funct &lambda /*lambda (Point p0, Point p1)*/) const {
DimImg edgeCount = 0;
if (!rect.width || !rect.height)
return edgeCount;
const DimSideImg firstX = rect.x, endX = rect.x+rect.width;
const DimSideImg firstY = rect.y, endY = rect.y+rect.height;
switch (tileItem) {
case Surface:
{
for (DimSideImg x = firstX+1; x < endX; ++x) {
Point pha1 (x-1, firstY), pha2 (x, firstY);
GRAPHWALKER_CALL_LAMBDA_PTS (pha1, pha2, edgeCount, lambda (pha1, pha2));
}
for (DimSideImg y = firstY+1; y < endY; ++y) {
Point pva1 (firstX, y-1), pva2 (firstX, y);
GRAPHWALKER_CALL_LAMBDA_PTS (pva1, pva2, edgeCount, lambda (pva1, pva2));
for (DimSideImg x = firstX+1; x < endX; ++x) {
Point ph1 (x-1, y), pv1 (x, y-1), p2 (x, y);
GRAPHWALKER_CALL_LAMBDA_PTS (ph1, p2, edgeCount, lambda (ph1, p2));
GRAPHWALKER_CALL_LAMBDA_PTS (pv1, p2, edgeCount, lambda (pv1, p2));
}
}
if (connectivity & Connectivity::C6P)
for (DimSideImg y = firstY+1; y < endY; ++y)
for (DimSideImg x = firstX+1; x < endX; ++x) {
Point p1 (x-1, y-1), p2 (x, y);
GRAPHWALKER_CALL_LAMBDA_PTS (p1, p2, edgeCount, lambda (p1, p2));
}
if (connectivity & Connectivity::C6N)
for (DimSideImg y = firstY+1; y < endY; ++y)
for (DimSideImg x = firstX+1; x < endX; ++x) {
Point p1 (x-1, y), p2 (x, y-1);
GRAPHWALKER_CALL_LAMBDA_PTS (p1, p2, edgeCount, lambda (p1, p2));
}
}
break;
case Horizontal:
{
const DimSideImg y1 = rect.y-1, y2 = rect.y;
for (DimSideImg x = firstX; x < endX; ++x) {
Point p1 (x, y1), p2 (x, y2);
GRAPHWALKER_CALL_LAMBDA_PTS (p1, p2, edgeCount, lambda (p1, p2));
}
if (connectivity & Connectivity::C6P)
for (DimSideImg x = firstX+1; x < endX; ++x) {
Point p1 (x-1, y1), p2 (x, y2);
GRAPHWALKER_CALL_LAMBDA_PTS (p1, p2, edgeCount, lambda (p1, p2));
}
if (connectivity & Connectivity::C6N)
for (DimSideImg x = firstX+1; x < endX; ++x) {
Point p1 (x, y1), p2 (x-1, y2);
GRAPHWALKER_CALL_LAMBDA_PTS (p1, p2, edgeCount, lambda (p1, p2));
}
}
break;
case Vertical:
{
const DimSideImg x1 = rect.x-1, x2 = rect.x;
for (DimSideImg y = firstY; y < endY; ++y) {
Point p1 (x1, y), p2 (x2, y);
GRAPHWALKER_CALL_LAMBDA_PTS (p1, p2, edgeCount, lambda (p1, p2));
}
if (connectivity & Connectivity::C6P)
for (DimSideImg y = firstY+1; y < endY; ++y) {
Point p1 (x1, y-1), p2 (x2, y);
GRAPHWALKER_CALL_LAMBDA_PTS (p1, p2, edgeCount, lambda (p1, p2));
}
if (connectivity & Connectivity::C6N)
for (DimSideImg y = firstY+1; y < endY; ++y) {
Point p1 (x1, y), p2 (x2, y-1);
GRAPHWALKER_CALL_LAMBDA_PTS (p1, p2, edgeCount, lambda (p1, p2));
}
}
break;
default:
BOOST_ASSERT (false);
}
return edgeCount;
}
// ========================================
template <typename WeightT, typename EdgeWeightFunction>
inline WeightT
GraphWalker::getMedian (const EdgeWeightFunction &ef /*ef.getValue (idx)*/) const {
int bits = 8*sizeof (WeightT);
BOOST_ASSERT (bits < 17);
DimEdge dim = 1UL << bits;
vector<DimImg> indices (dim+1, 0);
DimImg *histogram = &indices[1];
forEachVertexIdx ([&histogram, &ef] (const DimImg &idx) {
++histogram[(size_t) ef.getValue (idx)];
});
partial_sum (histogram, histogram+dim, histogram);
return lower_bound (indices.begin (), indices.end (), indices[dim] >> 1) - indices.begin ();
}
// ========================================
template <typename WeightT, typename EdgeWeightFunction>
inline DimEdge
GraphWalker::getEdges (const Rect &rect, TileItem tileItem, Edge<WeightT> *edges, const EdgeWeightFunction &ef /*ef.getWeight (p0, p1)*/) const {
BOOST_ASSERT (rect.width);
BOOST_ASSERT (rect.height);
BOOST_ASSERT (edges);
DimEdge edgeCount = 0;
forEachEdgePt (rect, tileItem,
[&edges, &edgeCount, &ef] (Point const &a, Point const &b) {
Edge<WeightT> &edge = edges[edgeCount++];
edge.points[0] = a;
edge.points[1] = b;
edge.weight = ef.getWeight (a, b);
});
return edgeCount;
}
// ----------------------------------------
template <typename WeightT, typename EdgeWeightFunction>
inline DimEdge
GraphWalker::getSortedEdges (const Rect &rect, TileItem tileItem, Edge<WeightT> *edges, const EdgeWeightFunction &ef /*ef.getWeight (p0, p1) ef.sort ()*/) const {
SMART_DEF_LOG ("GraphWalker::getSortedEdges", "");
DimEdge edgeCount = getEdges (rect, tileItem, edges, ef);
// SMART_LOG (endl << printEdges (edges, border.getSize (), edgeCount));
ef.sort (edges, edgeCount);
SMART_LOG (endl << printEdges (edges, border.getSize (), edgeCount))
return edgeCount;
}
template <typename WeightT, typename EdgeWeightFunction>
// template DimImg
inline DimEdge
GraphWalker::getCountingSortedEdges (const Rect &rect, TileItem tileItem, Edge<WeightT> *edges, const EdgeWeightFunction &ef /*ef.getWeight (p0, p1)*/) const {
SMART_DEF_LOG ("GraphWalker::getCountingSortedEdges", "");
int bits = 8*sizeof (WeightT);
BOOST_ASSERT (bits < 17);
DimEdge dim = 1UL << bits;
vector<DimImg> counters (dim+1, 0);
DimImg *indices = &counters [0];
DimImg *histogram = &indices [1];
DimImg sum = 0;
forEachEdgePt (rect, tileItem,
[&histogram, &ef] (Point const &a, Point const &b) {
++histogram[(size_t) ef.getWeight (a, b)];
});
// get indices by prefix sum
partial_sum (histogram, histogram+dim, histogram);
sum = indices[dim];
if (ef.getDecr ()) {
for (size_t i = 0; i < dim; ++i)
histogram[i] = sum - histogram[i];
indices++;
} else
indices[0] = 0;
// extract edges
#ifdef ENABLE_SMART_LOG
const Size &size (border.getSize ());
#endif
forEachEdgePt (rect, tileItem,
[
#ifdef ENABLE_SMART_LOG
&size,
#endif
&ef, &edges, &indices] (Point const &a, Point const &b) {
WeightT weight = ef.getWeight (a, b);
Edge<WeightT> &edge = edges[indices[(size_t) weight]++];
edge.points[0] = a;
edge.points[1] = b;
edge.weight = weight;
SMART_LOG_EXPR (cerr << printEdge (edge, size) << endl);
});
SMART_LOG (endl << printEdges (edges, size, sum));
return sum;
}
#endif // _OTB_TRISKELE_ARRAY_TREE_GRAPHWALKER_TPP