821 lines
31 KiB
C++
821 lines
31 KiB
C++
#ifndef _OTB_TRISKELE_ARRAY_TREE_BUILDER_TPP
|
|
#define _OTB_TRISKELE_ARRAY_TREE_BUILDER_TPP
|
|
|
|
using namespace boost::chrono;
|
|
|
|
// ========================================
|
|
template<typename WeightT, typename PixelT>
|
|
inline
|
|
ArrayTreeBuilder<WeightT, PixelT>::ArrayTreeBuilder (const Raster<PixelT> &raster, const GraphWalker &graphWalker,
|
|
const TreeType &treeType, const size_t &countingSortCeil) :
|
|
coreCount (boost::thread::hardware_concurrency ()),
|
|
raster (raster),
|
|
graphWalker (graphWalker),
|
|
treeType (treeType),
|
|
countingSortCeil (countingSortCeil),
|
|
compWeights (nullptr),
|
|
childCount (nullptr),
|
|
newCompId (nullptr)
|
|
{
|
|
DEF_LOG ("ArrayTreeBuilder::ArrayTreeBuilder", "");
|
|
}
|
|
|
|
template<typename WeightT, typename PixelT>
|
|
inline
|
|
ArrayTreeBuilder<WeightT, PixelT>::~ArrayTreeBuilder () {
|
|
}
|
|
|
|
// ========================================
|
|
template<typename WeightT, typename PixelT>
|
|
inline void
|
|
ArrayTreeBuilder<WeightT, PixelT>::buildTree (Tree &tree, WeightAttributes<WeightT> &weightAttributes) {
|
|
DEF_LOG ("ArrayTreeBuilder::buildTree", "size:" << graphWalker.vertexMaxCount ());
|
|
setTreeSize (tree, graphWalker.getSize ());
|
|
weightAttributes.updateTranscient ();
|
|
if (!leafCount)
|
|
return;
|
|
leaders.book (leafCount);
|
|
childCount = childrenStart+2;
|
|
newCompId = leaders.getLeaders ();
|
|
compWeights = weightAttributes.getValues ();
|
|
SMART_LOG_EXPR (dealThreadFill_n (leafCount-1, coreCount, compWeights, 0));
|
|
|
|
auto start = high_resolution_clock::now ();
|
|
switch (treeType) {
|
|
case MIN:
|
|
buildTree (tree, MaxWeight<PixelT, WeightT> (raster.getPixels (), raster.getSize ()));
|
|
break;
|
|
case MAX:
|
|
buildTree (tree, MinWeight<PixelT, WeightT> (raster.getPixels (), raster.getSize ()));
|
|
break;
|
|
case TOS:
|
|
buildTree (tree, MedianWeight<PixelT, WeightT> (raster.getPixels (), graphWalker));
|
|
break;
|
|
case ALPHA:
|
|
buildTree (tree, DiffWeight<PixelT, WeightT> (raster.getPixels (), raster.getSize ()));
|
|
break;
|
|
default:
|
|
cerr << "*** unknown tree type: " << treeType << endl;
|
|
}
|
|
|
|
auto startChildren = high_resolution_clock::now ();
|
|
|
|
buildChildren ();
|
|
childCount = nullptr;
|
|
|
|
auto end = high_resolution_clock::now ();
|
|
|
|
globalTreeStats.addTime (buildTreeStats, duration_cast<duration<double> > (startChildren-start).count ());
|
|
globalTreeStats.addTime (buildChildrenStats, duration_cast<duration<double> > (end-start).count ());
|
|
globalTreeStats.addDim (treeType, leafCount, nodeCount-leafCount);
|
|
|
|
leaders.free ();
|
|
newCompId = nullptr;
|
|
weightAttributes.setWeightBounds (tree);
|
|
|
|
SMART_LOG (tree.printTree ());
|
|
}
|
|
|
|
// ========================================
|
|
template<typename WeightT, typename PixelT>
|
|
inline void
|
|
ArrayTreeBuilder<WeightT, PixelT>::setAttributProfiles (AttributeProfiles<PixelT> &attributeProfiles) {
|
|
DEF_LOG ("ArrayTreeBuilder::setAttributProfiles", "");
|
|
attributeProfiles.updateTranscient ();
|
|
switch (treeType) {
|
|
case MIN:
|
|
setAttributProfiles (attributeProfiles, MaxWeight<PixelT, WeightT> (raster.getPixels (), raster.getSize ()));
|
|
break;
|
|
case MAX:
|
|
setAttributProfiles (attributeProfiles, MinWeight<PixelT, WeightT> (raster.getPixels (), raster.getSize ()));
|
|
break;
|
|
case TOS:
|
|
setAttributProfiles (attributeProfiles, MedianWeight<PixelT, WeightT> (raster.getPixels (), graphWalker));
|
|
break;
|
|
case ALPHA:
|
|
setAttributProfiles (attributeProfiles, DiffWeight<PixelT, WeightT> (raster.getPixels (), raster.getSize ()));
|
|
break;
|
|
default:
|
|
cerr << "*** unknown tree type: " << treeType << endl;
|
|
}
|
|
}
|
|
|
|
// ========================================
|
|
template<typename WeightT, typename PixelT>
|
|
template<typename WeightFunct>
|
|
inline void
|
|
ArrayTreeBuilder<WeightT, PixelT>::buildTree (Tree &tree, const WeightFunct &weightFunct) {
|
|
DEF_LOG ("ArrayTreeBuilder::buildTree", "");
|
|
coreCount = tree.getCoreCount ();
|
|
|
|
// buildParents
|
|
auto start = high_resolution_clock::now ();
|
|
vector<Edge<WeightT> > allEdges (graphWalker.edgeMaxCount ());
|
|
vector<Rect> tiles;
|
|
vector<Rect> boundaries;
|
|
vector<bool> verticalBoundaries;
|
|
const Size &size (graphWalker.getSize ());
|
|
graphWalker.setTiles (coreCount, Rect (NullPoint, size), tiles, boundaries, verticalBoundaries);
|
|
unsigned int tileCount = tiles.size ();
|
|
unsigned int boundCount = boundaries.size ();
|
|
|
|
vector<DimImg> vertexMaxBounds;
|
|
vector<DimImg> edgesMaxBounds;
|
|
graphWalker.setMaxBounds (tiles, vertexMaxBounds, edgesMaxBounds);
|
|
|
|
vector<Edge<WeightT> *> tileEdges (tileCount);
|
|
vector<DimImg> compBases (tileCount);
|
|
vector<DimImg> compTops (tileCount);
|
|
Edge<WeightT> *edgeBase = &allEdges[0];
|
|
for (unsigned int i = 0; i < tileCount; ++i) {
|
|
tileEdges [i] = &allEdges[edgesMaxBounds[i]];
|
|
compBases [i] = compTops [i] = vertexMaxBounds [i];
|
|
}
|
|
auto startParent = high_resolution_clock::now ();
|
|
dealThreadRange (tileCount, coreCount, [this, &tileEdges, &weightFunct, &tiles, &compTops] (DimImg threadId) {
|
|
buildParents (tileEdges [threadId], weightFunct, tiles [threadId], compTops [threadId]);
|
|
});
|
|
|
|
SMART_LOG ("leaders:" << endl
|
|
<< printMap (leaders.getLeaders (), size, 0) << endl << endl
|
|
<< "compWeights:" << endl
|
|
<< printMap (compWeights, size, 0) << endl << endl
|
|
<< tree.printTree (2*leafCount-1));
|
|
// merge sub-tree
|
|
auto startMerge = high_resolution_clock::now ();
|
|
DimImg *topC = NULL;
|
|
DimImg compBase = vertexMaxBounds[tileCount];
|
|
if (boundCount) {
|
|
vector<Edge<WeightT> *> edgeBounds (boundCount);
|
|
vector<DimImg> edgeCounts (boundCount);
|
|
Edge<WeightT> *allBoundEdges = edgeBase;
|
|
for (unsigned int i = 0; i < boundCount; ++i) {
|
|
edgeBounds [i] = edgeBase;
|
|
DimImg borderDim = verticalBoundaries [i] ? boundaries[i].height : boundaries[i].width;
|
|
edgeBase += graphWalker.edgeBoundaryMaxCount (borderDim);
|
|
}
|
|
|
|
dealThreadRange (boundCount, coreCount, [this, &edgeCounts, &boundaries, &verticalBoundaries, &edgeBounds, &weightFunct] (DimImg id) {
|
|
edgeCounts [id] = graphWalker.getSortedEdges (boundaries [id], verticalBoundaries [id] ?
|
|
Vertical : Horizontal, edgeBounds [id], weightFunct);
|
|
});
|
|
LOG ("edgeBounds: " << edgeBase-allBoundEdges);
|
|
|
|
unsigned int rangeIdx = 0;
|
|
DimImg maxC = 0;
|
|
callOnSortedSets<DimImg, WeightT> (edgeCounts,
|
|
[&edgeBounds] (const DimImg &vectId, const DimImg &itemId) {
|
|
return edgeBounds [vectId][itemId].weight;
|
|
},
|
|
weightFunct.isWeightInf,
|
|
[this, &edgeBounds, &topC, &maxC, &rangeIdx, &tileCount, &compBases, &compBase, &compTops, &size, &weightFunct] (const DimImg &vectId, const DimImg &itemId) {
|
|
Edge<WeightT> *edge = &edgeBounds [vectId][itemId];
|
|
if (topC == NULL || *topC >= maxC)
|
|
for ( ; rangeIdx < tileCount; ++rangeIdx) {
|
|
maxC = rangeIdx == tileCount-1 ? leafCount : compBases[rangeIdx+1];
|
|
if (compTops[rangeIdx] < maxC) {
|
|
compBase = compTops[rangeIdx];
|
|
compBases.push_back (compBase);
|
|
compTops.push_back (compBase);
|
|
topC = &compTops[compTops.size ()-1];
|
|
break;
|
|
}
|
|
}
|
|
connectLeaf (point2idx (size, edge->points[0]), point2idx (size, edge->points[1]), edge->weight, *topC, weightFunct);
|
|
});
|
|
}
|
|
|
|
// SMART_LOG ("compWeights:" << endl
|
|
// << printMap (compWeights, size, 0) << endl << endl
|
|
// << tree.printTree (2*leafCount-1));
|
|
auto startForest = high_resolution_clock::now ();
|
|
if (graphWalker.border.exists ()) {
|
|
// merge comp forest
|
|
DimImg rootId = 0;
|
|
for (unsigned int tileId = 0; tileId < tileCount; tileId++)
|
|
if (compTops [tileId] != compBases [tileId]) {
|
|
rootId = findRoot (compTops [tileId] - 1);
|
|
break;
|
|
}
|
|
|
|
LOG ("merge forest: " << printComp (rootId));
|
|
for (unsigned int tileId = 0; tileId < tileCount; ++tileId)
|
|
for (DimImg compId = compBases [tileId]; compId < compTops [tileId]; ++compId)
|
|
if (compParents [compId] == DimImg_MAX) {
|
|
connectComp (compId, rootId, weightFunct);
|
|
rootId = findRoot (rootId);
|
|
LOG ("merge top: compId:" << printComp (compId) << " nr:" << printComp (rootId));
|
|
}
|
|
|
|
// merge pixels forest
|
|
vector<DimImg> lonelyPixelsCount (tileCount, 0);
|
|
vector<WeightT> topsWeight (tileCount, compWeights [rootId]);
|
|
dealThreadRange (tileCount, coreCount, [this, &tiles, &rootId, &weightFunct, &lonelyPixelsCount, &topsWeight] (const DimImg &tileId) {
|
|
WeightT &topWeight (topsWeight [tileId]);
|
|
DimImg &lonelyPixelCount (lonelyPixelsCount [tileId]);
|
|
graphWalker.forEachVertexIdx (tiles [tileId], [this, &rootId, &lonelyPixelCount, &topWeight, &weightFunct] (const DimImg &leafId) {
|
|
if (leafParents [leafId] == DimImg_MAX) {
|
|
WeightT pixelWeight (weightFunct.getWeight (leafId));
|
|
leafParents [leafId] = rootId;
|
|
lonelyPixelCount++;
|
|
if (weightFunct.isWeightInf (topWeight, pixelWeight))
|
|
topWeight = pixelWeight;
|
|
}
|
|
});
|
|
});
|
|
for (unsigned int tileId = 0; tileId < tileCount; ++tileId) {
|
|
childCount [rootId] += lonelyPixelsCount [tileId];
|
|
if (weightFunct.isWeightInf (compWeights [rootId], topsWeight [tileId]))
|
|
compWeights [rootId] = topsWeight [tileId];
|
|
// XXX on ne reprend pas la fraterie inférieur car plus d'appel à findMultiChildrenTop
|
|
LOG ("merge pixels: tileId:" << tileId << " lonely:" << lonelyPixelsCount [tileId] << " root:" << printComp (rootId));
|
|
}
|
|
}
|
|
|
|
SMART_LOG ("compWeights:" << endl
|
|
<< printMap (compWeights, size, 0) << endl << endl
|
|
<< tree.printTree (2*leafCount-1));
|
|
// compress
|
|
auto startIndex = high_resolution_clock::now ();
|
|
DimImg maxUsed = max (compTops[tileCount-1], topC != NULL ? *topC : 0);
|
|
dealThreadFill_n (maxUsed, coreCount, newCompId, DimImg_MAX);
|
|
|
|
SMART_LOG ("reuse leaders:" << endl
|
|
<< printMap (newCompId, size, 0) << endl << endl);
|
|
DimImg maxTop = updateNewId (compBases, compTops, weightFunct);
|
|
|
|
SMART_LOG ("updateNewId:" << endl
|
|
<< printMap (newCompId, size, 0) << endl << endl);
|
|
|
|
auto startCompress = high_resolution_clock::now ();
|
|
compress (maxUsed);
|
|
SMART_LOG ("compress:" << endl
|
|
<< printMap (newCompId, size, 0) << endl << endl);
|
|
leaders.free ();
|
|
|
|
while (maxTop > 1 && childCount[maxTop-1] == 1) {
|
|
--maxTop;
|
|
compParents [maxTop-1] = DimImg_MAX;
|
|
SMART_LOG ("reduce lonely root:" << printComp (maxTop) << endl);
|
|
}
|
|
setNodeCount (tree, leafCount+maxTop);
|
|
LOG ("nodeCount:" << tree.getNodeCount());
|
|
// DimEdge rootId = maxTop-1;
|
|
// compParents[rootId] = rootId;
|
|
|
|
SMART_LOG ("compWeights:" << endl
|
|
<< printMap (compWeights, size, 0) << endl << endl);
|
|
auto end = high_resolution_clock::now ();
|
|
globalTreeStats.addTime (buildSetupStats, duration_cast<duration<double> > (startParent-start).count ());
|
|
globalTreeStats.addTime (buildParentsStats, duration_cast<duration<double> > (startMerge-startParent).count ());
|
|
globalTreeStats.addTime (buildMergeStats, duration_cast<duration<double> > (startForest-startMerge).count ());
|
|
globalTreeStats.addTime (buildForestStats, duration_cast<duration<double> > (startIndex-startForest).count ());
|
|
globalTreeStats.addTime (buildIndexStats, duration_cast<duration<double> > (startCompress-startIndex).count ());
|
|
globalTreeStats.addTime (buildCompressStats, duration_cast<duration<double> > (end-startCompress).count ());
|
|
}
|
|
|
|
// ========================================
|
|
template<typename WeightT, typename PixelT>
|
|
template<typename WeightFunct>
|
|
inline void
|
|
ArrayTreeBuilder<WeightT, PixelT>::setAttributProfiles (AttributeProfiles<PixelT> &attributeProfiles, const WeightFunct &weightFunct) {
|
|
PixelT *leafAP = attributeProfiles.getValues ();
|
|
dealThreadBound (leafCount, coreCount, [&weightFunct, &leafAP] (const DimImg &minVal, const DimImg &maxVal) {
|
|
weightFunct.copyPixelsBound (leafAP, minVal, maxVal);
|
|
});
|
|
PixelT *compAP = leafAP+leafCount;
|
|
dealThreadBound (getCompCount (), coreCount, [this, &weightFunct, &compAP] (const DimImg &minVal, const DimImg &maxVal) {
|
|
weightFunct.weight2valueBound (compAP, compWeights, minVal, maxVal);
|
|
});
|
|
}
|
|
|
|
// ========================================
|
|
template<typename WeightT, typename PixelT>
|
|
template<typename WeightFunct>
|
|
inline void
|
|
ArrayTreeBuilder<WeightT, PixelT>::buildParents (Edge<WeightT> *edges, const WeightFunct &weightFunct,
|
|
const Rect &tile, DimImg &topParent) {
|
|
SMART_DEF_LOG ("ArrayTreeBuilder::buildParents", " tile:" << tile << " topParent:" << topParent << " counting:" << countingSortCeil);
|
|
DimEdge edgeCount = (sizeof (WeightT) <= countingSortCeil) ?
|
|
graphWalker.getCountingSortedEdges<WeightT, WeightFunct> (tile, Surface, edges, weightFunct) :
|
|
graphWalker.getSortedEdges (tile, Surface, edges, weightFunct);
|
|
|
|
const Size &size = graphWalker.getSize ();
|
|
for (DimEdge edgeIdx = 0; edgeIdx < edgeCount; ++edgeIdx) {
|
|
Edge<WeightT> &curEdge = edges[edgeIdx];
|
|
DimImg pa = point2idx (size, curEdge.points[0]);
|
|
DimImg pb = point2idx (size, curEdge.points[1]);
|
|
DimImg la = leaders.find (pa);
|
|
DimImg lb = leaders.find (pb);
|
|
DimImg ra = findRoot (leafParents [la]); // for alphaTree
|
|
DimImg rb = findRoot (leafParents [lb]); // for alphaTree
|
|
|
|
BOOST_ASSERT (pa < leafCount);
|
|
BOOST_ASSERT (pb < leafCount);
|
|
BOOST_ASSERT (la < leafCount);
|
|
BOOST_ASSERT (lb < leafCount);
|
|
BOOST_ASSERT (ra < leafCount || ra == DimImg_MAX);
|
|
BOOST_ASSERT (rb < leafCount || rb == DimImg_MAX);
|
|
BOOST_ASSERT (ra == DimImg_MAX || compParents [ra] == DimImg_MAX);
|
|
BOOST_ASSERT (rb == DimImg_MAX || compParents [rb] == DimImg_MAX);
|
|
SMART_LOG (" e:" << printEdge (curEdge, size));
|
|
SMART_LOG ("pa:" << pa << " pb:" << pb << " la:" << la << " lb:" << lb);
|
|
SMART_LOG ("ra:" << printComp (ra) << " rb:" << printComp (rb));
|
|
|
|
if (la == lb) {
|
|
leaders.link (pa, la);
|
|
leaders.link (pb, la);
|
|
SMART_LOG ("la=lb");
|
|
continue;
|
|
}
|
|
if (ra == DimImg_MAX) {
|
|
swap (la, lb);
|
|
swap (ra, rb);
|
|
}
|
|
DimImg leader = DimImg_MAX;
|
|
if (ra == DimImg_MAX) {
|
|
// ra = rb = DimImg_MAX
|
|
createParent (topParent, curEdge.weight, leafParents [la], leafParents [lb]);
|
|
if (weightFunct.isWeightInf (weightFunct.getWeight(la), weightFunct.getWeight(lb)))
|
|
swap (la, lb);
|
|
leader = la;
|
|
} else if (rb == DimImg_MAX) {
|
|
if (curEdge.weight == compWeights[ra]) {
|
|
// rb.weight <= curEdge.weight = ra.weight
|
|
addChild (ra, leafParents [lb]);
|
|
leader = la;
|
|
} else {
|
|
// ra.weight < curEdge.weight = rb.weight
|
|
createParent (topParent, curEdge.weight, compParents [ra], leafParents [lb]);
|
|
leader = lb;
|
|
}
|
|
} else if (ra == rb) {
|
|
SMART_LOG ("ra=rb **** XXXX ****");
|
|
BOOST_ASSERT (false);
|
|
leader = la;
|
|
} else if (compWeights[ra] == compWeights [rb]) {
|
|
// ra.weight = rb.weight // XXX ?= curEdge.weight
|
|
if (childCount [ra] < childCount [rb]) {
|
|
swap (la, lb);
|
|
swap (ra, rb);
|
|
}
|
|
addChildren (ra, rb);
|
|
leader = la;
|
|
} else {
|
|
if (weightFunct.isWeightInf (compWeights[ra], compWeights[rb])) {
|
|
swap (la, lb);
|
|
swap (ra, rb);
|
|
}
|
|
leader = la;
|
|
if (compWeights[ra] == curEdge.weight)
|
|
// rb.weight <= ra.weight = curEdge.weight
|
|
addChild (ra, compParents [rb]);
|
|
else
|
|
// ra.weight & rb.weight < curEdge.weight
|
|
createParent (topParent, curEdge.weight, compParents [ra], compParents [rb]);
|
|
}
|
|
BOOST_ASSERT (leader != DimImg_MAX);
|
|
leaders.link (pa, leader);
|
|
leaders.link (pb, leader);
|
|
|
|
SMART_LOG (" leader:" << leader << " ra:" << printComp (ra) << " rb:" << printComp (rb) << " nr:" << printComp (findRoot (leafParents [la])));
|
|
}
|
|
|
|
SMART_LOG ("topParent:" << topParent);
|
|
}
|
|
|
|
// ========================================
|
|
template<typename WeightT, typename PixelT>
|
|
inline void
|
|
ArrayTreeBuilder<WeightT, PixelT>::unlinkParent (const DimImg &par) {
|
|
SMART_DEF_LOG ("ArrayTreeBuilder::unlinkParent", "par: " << printComp (par));
|
|
if (par == DimImg_MAX)
|
|
return;
|
|
BOOST_ASSERT (childCount [par]);
|
|
--childCount [par];
|
|
}
|
|
|
|
// ----------------------------------------
|
|
template<typename WeightT, typename PixelT>
|
|
template<typename WeightFunct>
|
|
inline void
|
|
ArrayTreeBuilder<WeightT, PixelT>::connectLeaf (DimImg a, DimImg b, const WeightT &weight, DimImg &parCount, const WeightFunct &weightFunct) {
|
|
SMART_DEF_LOG ("ArrayTreeBuilder::connectLeaf", "a:" << a << " b:" << b << " weight:" << weight);
|
|
BOOST_ASSERT (a < leafCount);
|
|
BOOST_ASSERT (b < leafCount);
|
|
BOOST_ASSERT (leafParents[a] < leafCount || leafParents[a] == DimImg_MAX);
|
|
BOOST_ASSERT (leafParents[b] < leafCount || leafParents[b] == DimImg_MAX);
|
|
DimImg parA = findTopComp (leafParents[a], weight, weightFunct);
|
|
DimImg parB = findTopComp (leafParents[b], weight, weightFunct);
|
|
SMART_LOG ("parA: " << printComp (parA) << " parB: " << printComp (parB));
|
|
// upW0 : no parent(s)
|
|
// Border case if parX == DimImg_MAX
|
|
if (parA == parB) {
|
|
if (parA == DimImg_MAX) {
|
|
SMART_LOG ("upW0: no parents");
|
|
createParent (parCount, weight, leafParents [a], leafParents [b]);
|
|
SMART_LOG ("createParent: " << printComp (leafParents[a]));
|
|
}
|
|
SMART_LOG ("same parents for: " << a << ", " << b);
|
|
return;
|
|
}
|
|
if (parB == DimImg_MAX) {
|
|
// XXX 20180776 bug fixed parA => parB
|
|
swap (a, b);
|
|
swap (parA, parB);
|
|
SMART_LOG ("swap: " << printComp (parA) << " " << printComp (parB));
|
|
}
|
|
// XXX parB =? DimImg_MAX
|
|
if ((parA == DimImg_MAX || weightFunct.isWeightInf (weight, compWeights[parA])) &&
|
|
weightFunct.isWeightInf (weight, compWeights[parB])) {
|
|
// upW1 & upW2 : upper
|
|
SMART_LOG ("upW1 | upW2: upper");
|
|
unlinkParent (parA);
|
|
unlinkParent (parB);
|
|
SMART_LOG ("parA: " << printComp (parA) << " parB: " << printComp (parB));
|
|
DimImg newComp = createParent (parCount, weight, leafParents [a], leafParents [b]);
|
|
SMART_LOG ("createParent: " << printComp (newComp));
|
|
connect3Comp (newComp, parA, parB, weightFunct);
|
|
return;
|
|
}
|
|
if (parA != DimImg_MAX && weightFunct.isWeightInf (compWeights[parA], compWeights[parB])) {
|
|
swap (a, b);
|
|
swap (parA, parB);
|
|
SMART_LOG ("swap: " << printComp (parA) << " " << printComp (parB));
|
|
}
|
|
if (weightFunct.isWeightInf (compWeights[parB], weight) &&
|
|
(parA == DimImg_MAX ||
|
|
weightFunct.isWeightInf (compWeights[parA], weight) ||
|
|
weightFunct.isWeightInf (weight, compWeights[parA]))) {
|
|
// loW0 | loW1 | loW2 : lower
|
|
SMART_LOG ("loW0 | loW1 | loW2");
|
|
if (weightFunct.isWeightInf (compWeights[parA], weight)) {
|
|
swap (a, b);
|
|
swap (parA, parB);
|
|
SMART_LOG ("swap: " << printComp (parA) << " " << printComp (parB));
|
|
}
|
|
DimImg grandParB = findTopComp (compParents[parB], weightFunct);
|
|
unlinkParent (grandParB);
|
|
SMART_LOG ("grandParB: " << printComp (grandParB));
|
|
if (parA == DimImg_MAX || weightFunct.isWeightInf (weight, compWeights[parA])) {
|
|
// loW1 | loW2
|
|
SMART_LOG ("loW1 | loW2: lower");
|
|
unlinkParent (parA);
|
|
SMART_LOG ("parA: " << printComp (parA));
|
|
DimImg newComp = createParent (parCount, weight, leafParents [a], compParents [parB]);
|
|
SMART_LOG ("createParent: " << printComp (newComp));
|
|
connect3Comp (newComp, parA, grandParB, weightFunct);
|
|
return;
|
|
}
|
|
// loW0
|
|
SMART_LOG ("loW0: lower");
|
|
DimImg grandParA = findTopComp (compParents[parA], weightFunct);
|
|
unlinkParent (grandParA);
|
|
SMART_LOG ("grandParA: " << printComp (grandParA));
|
|
DimImg newComp = createParent (parCount, weight, compParents [parA], compParents [parB]);
|
|
SMART_LOG ("createParent: " << printComp (newComp));
|
|
connect3Comp (newComp, grandParA, grandParB, weightFunct);
|
|
return;
|
|
}
|
|
// eqW0 | eqW1 | eqW2 : no creation
|
|
if (parA == DimImg_MAX || weightFunct.isWeightInf (weight, compWeights[parA])) {
|
|
// eqW1 | eqW2
|
|
SMART_LOG ("eqW1 | eqW2: incr leaf");
|
|
unlinkParent (parA);
|
|
++childCount[parB];
|
|
leafParents[a] = parB;
|
|
SMART_LOG ("link a: " << a << " parB: " << printComp (parB));
|
|
}
|
|
// eqW0 | eqW1 | eqW2
|
|
SMART_LOG ("eqW0 | eqW1 | eqW2: connect");
|
|
connectComp (parA, parB, weightFunct);
|
|
}
|
|
|
|
// ----------------------------------------
|
|
template<typename WeightT, typename PixelT>
|
|
template<typename WeightFunct>
|
|
inline void
|
|
ArrayTreeBuilder<WeightT, PixelT>::connect3Comp (DimImg newComp, DimImg topA, DimImg topB, const WeightFunct &weightFunct) {
|
|
SMART_DEF_LOG ("ArrayTreeBuilder::connect3Comp", "newComp:" << newComp << " topA:" << topA << " topB:" << topB);
|
|
BOOST_ASSERT (newComp != DimImg_MAX);
|
|
|
|
if (topB == DimImg_MAX)
|
|
swap (topA, topB);
|
|
if (topB == DimImg_MAX)
|
|
return;
|
|
BOOST_ASSERT (topB != DimImg_MAX);
|
|
if (topA != DimImg_MAX && weightFunct.isWeightInf (compWeights[topA], compWeights[topB]))
|
|
swap (topA, topB);
|
|
BOOST_ASSERT (findTopComp (topB, weightFunct) == topB);
|
|
BOOST_ASSERT (weightFunct.isWeightInf (compWeights[newComp], compWeights[topB]));
|
|
addChild (topB, compParents[newComp]);
|
|
SMART_LOG ("topB: " << printComp (topB));
|
|
connectComp (topA, topB, weightFunct);
|
|
}
|
|
|
|
// ----------------------------------------
|
|
template<typename WeightT, typename PixelT>
|
|
template<typename WeightFunct>
|
|
inline void
|
|
ArrayTreeBuilder<WeightT, PixelT>::connectComp (DimImg topA, DimImg topB, const WeightFunct &weightFunct) {
|
|
SMART_DEF_LOG ("ArrayTreeBuilder::connectComp", "topA:" << topA << " topB:" << topB);
|
|
|
|
for (;;) {
|
|
if (topA == DimImg_MAX || topB == DimImg_MAX)
|
|
return;
|
|
BOOST_ASSERT (findTopComp (topA, weightFunct) == topA);
|
|
BOOST_ASSERT (findTopComp (topB, weightFunct) == topB);
|
|
if (weightFunct.isWeightInf (compWeights[topA], compWeights[topB]))
|
|
swap (topA, topB);
|
|
topB = findTopComp (topB, compWeights[topA], weightFunct);
|
|
if (topA == topB)
|
|
return;
|
|
if (compWeights[topA] == compWeights[topB] &&
|
|
childCount[topA] < childCount[topB])
|
|
swap (topA, topB);
|
|
DimImg grandParB = findTopComp (compParents[topB], weightFunct);
|
|
if (compWeights[topA] == compWeights[topB]) {
|
|
childCount[topA] += childCount[topB];
|
|
childCount[topB] = 0;
|
|
} else
|
|
++childCount[topA];
|
|
compParents[topB] = topA;
|
|
SMART_LOG ("topA: " << printComp (topA) << " topB: " << printComp (topB));
|
|
if (grandParB == DimImg_MAX)
|
|
return;
|
|
BOOST_ASSERT (childCount [grandParB]);
|
|
--childCount[grandParB];
|
|
SMART_LOG ("grandParB: " << printComp (grandParB));
|
|
topB = topA;
|
|
topA = findTopComp (grandParB, compWeights[topA], weightFunct);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------
|
|
template<typename WeightT, typename PixelT>
|
|
template<typename WeightFunct>
|
|
inline DimImg
|
|
ArrayTreeBuilder<WeightT, PixelT>::updateNewId (const vector<DimImg> &compBases, const vector<DimImg> &compTops,
|
|
const WeightFunct &weightFunct) {
|
|
// DEF_LOG ("ArrayTreeBuilder::updateNewId", "");
|
|
DimImg compCount = compBases[0];
|
|
vector<DimImg> sizes (compBases.size ());
|
|
for (DimImg i = 0; i < sizes.size (); ++i)
|
|
sizes [i] = compTops [i] - compBases [i];
|
|
// XXX non parallèle
|
|
callOnSortedSets<DimImg, WeightT> (sizes,
|
|
[this, &compBases] (const DimImg &vectId, const DimImg &itemId) {
|
|
return compWeights[compBases[vectId]+itemId]; },
|
|
weightFunct.isWeightInf,
|
|
[this, &compBases, &compCount] (const DimImg &vectId, const DimImg &itemId) {
|
|
updateNewId (compBases[vectId]+itemId, compCount); });
|
|
return compCount;
|
|
}
|
|
|
|
// ----------------------------------------
|
|
template<typename WeightT, typename PixelT>
|
|
inline void
|
|
ArrayTreeBuilder<WeightT, PixelT>::updateNewId (const DimImg curComp, DimImg &compCount) {
|
|
if (newCompId[curComp] != DimImg_MAX)
|
|
// top already set
|
|
return;
|
|
const DimImg &top = findMultiChildrenTop (curComp);
|
|
BOOST_ASSERT (top != DimImg_MAX);
|
|
BOOST_ASSERT (childCount[top]);
|
|
if (childCount[top] < 2 && compParents[top] != DimImg_MAX) {
|
|
// mark lonely nodes
|
|
// XXX todo: mark curComp => top
|
|
newCompId[curComp] = 0;
|
|
return;
|
|
}
|
|
if (curComp != top) {
|
|
BOOST_ASSERT (curComp != DimImg_MAX);
|
|
DimImg newTopIdx = newCompId[top];
|
|
if (newTopIdx == DimImg_MAX)
|
|
newTopIdx = newCompId[top] = compCount++;
|
|
const DimNodeId &newTopChildCount = childCount[top];
|
|
const DimImg &newTopCompParent = compParents[top];
|
|
//const WeightT &newTopWeight = compWeights[top];
|
|
for (DimImg sibling = curComp; sibling != top; ) {
|
|
DimImg nextSibling = compParents[sibling];
|
|
newCompId[sibling] = newTopIdx;
|
|
childCount[sibling] = newTopChildCount;
|
|
compParents[sibling] = newTopCompParent;
|
|
// compWeights[sibling] = newTopWeight;
|
|
sibling = nextSibling;
|
|
}
|
|
return;
|
|
}
|
|
newCompId[curComp] = compCount++;
|
|
}
|
|
|
|
// ----------------------------------------
|
|
template<typename WeightT, typename PixelT>
|
|
inline void
|
|
ArrayTreeBuilder<WeightT, PixelT>::compress (const DimImg &compTop) {
|
|
|
|
SMART_DEF_LOG ("ArrayTreeBuilder::compress", " compTop:" << compTop);
|
|
dealThreadRange (compTop, coreCount, [this] (const DimImg &curComp) {
|
|
if (newCompId[curComp] || childCount[curComp] > 1)
|
|
return;
|
|
// reduce lonely nodes (newCompId == 0)
|
|
const DimImg &top = findNotLonelyTop (curComp);
|
|
BOOST_ASSERT (top == DimImg_MAX || compParents[top] == DimImg_MAX || childCount[top] > 1);
|
|
BOOST_ASSERT (curComp != top);
|
|
childCount[curComp] = childCount[top];
|
|
compParents[curComp] = compParents[top]; // XXX pb if //
|
|
newCompId[curComp] = newCompId[top];
|
|
compWeights[curComp] = compWeights[top];
|
|
});
|
|
|
|
dealThreadRange (compTop, coreCount, [this] (const DimImg &curComp) {
|
|
DimImg old = compParents[curComp];
|
|
if (old != DimImg_MAX)
|
|
compParents[curComp] = newCompId[old];
|
|
});
|
|
|
|
dealThreadRange (leafCount, coreCount, [this] (const DimImg &leaf) {
|
|
DimImg old = leafParents[leaf];
|
|
if (old != DimImg_MAX)
|
|
leafParents[leaf] = newCompId[old];
|
|
});
|
|
|
|
// XXX non parallèle
|
|
for (DimImg curComp = 0; curComp < compTop; ) {
|
|
DimImg newIdxComp = newCompId[curComp];
|
|
if (newIdxComp == curComp || newIdxComp == DimImg_MAX || newCompId[newIdxComp] == newIdxComp) {
|
|
++curComp;
|
|
continue;
|
|
}
|
|
|
|
SMART_LOG ("comp curComp:" << curComp << " newIdxComp:" << newIdxComp);
|
|
|
|
swap (compParents[curComp], compParents[newIdxComp]);
|
|
swap (compWeights[curComp], compWeights[newIdxComp]);
|
|
swap (childCount[curComp], childCount[newIdxComp]);
|
|
swap (newCompId[curComp], newCompId[newIdxComp]);
|
|
}
|
|
// XXX YYY curComp ? compTop ?
|
|
}
|
|
|
|
// ========================================
|
|
template<typename WeightT, typename PixelT>
|
|
inline DimImg
|
|
ArrayTreeBuilder<WeightT, PixelT>::createParent (DimImg &topParent, const WeightT &weight, DimImg &parentChildA, DimImg &parentChildB) {
|
|
childCount [topParent] = 2;
|
|
compWeights [topParent] = weight;
|
|
return parentChildA = parentChildB = topParent++;
|
|
}
|
|
|
|
// ----------------------------------------
|
|
template<typename WeightT, typename PixelT>
|
|
inline void
|
|
ArrayTreeBuilder<WeightT, PixelT>::addChild (const DimImg &parent, DimImg &child) {
|
|
++childCount [parent];
|
|
child = parent;
|
|
}
|
|
|
|
// ----------------------------------------
|
|
template<typename WeightT, typename PixelT>
|
|
inline void
|
|
ArrayTreeBuilder<WeightT, PixelT>::addChildren (const DimImg &parent, const DimImg &sibling) {
|
|
childCount [parent] += childCount [sibling];
|
|
childCount [sibling] = 0;
|
|
compParents [sibling] = parent;
|
|
}
|
|
|
|
// ----------------------------------------
|
|
template<typename WeightT, typename PixelT>
|
|
inline DimImg
|
|
ArrayTreeBuilder<WeightT, PixelT>::findRoot (DimImg comp) {
|
|
if (comp == DimImg_MAX)
|
|
return comp;
|
|
for (;;) {
|
|
DimImg p = compParents [comp];
|
|
if (p == DimImg_MAX)
|
|
return comp;
|
|
comp = p;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------
|
|
template<typename WeightT, typename PixelT>
|
|
template<typename WeightFunct>
|
|
inline DimImg
|
|
ArrayTreeBuilder<WeightT, PixelT>::findTopComp (const DimImg &comp, const WeightFunct &weightFunct) {
|
|
if (comp == DimImg_MAX)
|
|
return DimImg_MAX;
|
|
DimImg result = findTopComp (comp, compWeights[comp], weightFunct);
|
|
BOOST_ASSERT (result < leafCount);
|
|
// XXX pas pour TOS ! BOOST_ASSERT (compWeights[result] == compWeights[comp]);
|
|
return result;
|
|
}
|
|
|
|
// ----------------------------------------
|
|
template<typename WeightT, typename PixelT>
|
|
template<typename WeightFunct>
|
|
inline DimImg
|
|
ArrayTreeBuilder<WeightT, PixelT>::findTopComp (DimImg comp, const WeightT &weight, const WeightFunct &weightFunct) {
|
|
if (comp == DimImg_MAX)
|
|
return DimImg_MAX;
|
|
if (weightFunct.isWeightInf (weight, compWeights [comp]))
|
|
return findTopComp (comp, compWeights [comp], weightFunct);
|
|
DimImg last = comp;
|
|
for (;;) {
|
|
if (comp == DimImg_MAX)
|
|
return last;
|
|
if (weightFunct.isWeightInf (weight, compWeights [comp]))
|
|
return last;
|
|
last = comp;
|
|
comp = compParents[comp];
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------
|
|
template<typename WeightT, typename PixelT>
|
|
inline DimImg
|
|
ArrayTreeBuilder<WeightT, PixelT>::findNotLonelyTop (DimImg comp) {
|
|
BOOST_ASSERT (comp != DimImg_MAX);
|
|
for (;;) {
|
|
if (childCount[comp] > 1)
|
|
return comp;
|
|
const DimImg &parent = compParents[comp];
|
|
if (parent == DimImg_MAX)
|
|
return comp;
|
|
comp = parent;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------
|
|
template<typename WeightT, typename PixelT>
|
|
inline DimImg
|
|
ArrayTreeBuilder<WeightT, PixelT>::findMultiChildrenTop (DimImg comp) {
|
|
BOOST_ASSERT (comp != DimImg_MAX);
|
|
for (;;) {
|
|
if (newCompId [comp] != DimImg_MAX)
|
|
return comp;
|
|
const DimImg &parent = compParents[comp];
|
|
if (parent == DimImg_MAX)
|
|
return comp;
|
|
if (compWeights[comp] != compWeights[parent]) {
|
|
BOOST_ASSERT (childCount[comp] > 0);
|
|
return comp;
|
|
}
|
|
BOOST_ASSERT (!childCount[comp]);
|
|
comp = parent;
|
|
}
|
|
}
|
|
|
|
// ========================================
|
|
template<typename WeightT, typename PixelT>
|
|
inline void
|
|
ArrayTreeBuilder<WeightT, PixelT>::buildChildren () {
|
|
|
|
SMART_DEF_LOG ("ArrayTreeBuilder::buildChildren", "");
|
|
|
|
BOOST_ASSERT (childrenStart[0] == 0);
|
|
BOOST_ASSERT (childrenStart[1] == 0);
|
|
|
|
DimImg compCount = getCompCount ();
|
|
partial_sum (childCount, childCount+compCount, childCount);
|
|
|
|
// set
|
|
DimNodeId *childGetOrder = childrenStart+1;
|
|
for (DimNodeId i = 0; i < nodeCount-1; ++i) {
|
|
if (leafParents[i] == DimImg_MAX)
|
|
continue;
|
|
BOOST_ASSERT (leafParents[i] < compCount);
|
|
children[childGetOrder[leafParents[i]]++] = i;
|
|
}
|
|
BOOST_ASSERT (childrenStart[0] == 0);
|
|
}
|
|
|
|
// ========================================
|
|
template<typename WeightT, typename PixelT>
|
|
ArrayTreeBuilder<WeightT, PixelT>::CPrintComp::CPrintComp (const ArrayTreeBuilder &atb, const DimImg &compId)
|
|
: atb (atb), compId (compId) {
|
|
}
|
|
template<typename WeightT, typename PixelT>
|
|
inline ostream &
|
|
ArrayTreeBuilder<WeightT, PixelT>::CPrintComp::print (ostream &out) const {
|
|
if (compId == DimImg_MAX)
|
|
return out << "M(-/-)";
|
|
return out << compId << "(" << atb.childCount[compId] << "/" << atb.compWeights [compId] << ")";
|
|
}
|
|
|
|
// template<typename WeightT, typename PixelT>
|
|
// inline ArrayTreeBuilder<WeightT, PixelT>::CPrintComp
|
|
// ArrayTreeBuilder<WeightT, PixelT>::printComp (const DimImg &compId) const {
|
|
// return ArrayTreeBuilder<WeightT, PixelT>::CPrintComp (*this, compId);
|
|
// }
|
|
|
|
// template<typename WeightT, typename PixelT>
|
|
// inline ostream&
|
|
// operator << (ostream& out, const ArrayTreeBuilder<WeightT, PixelT>::CPrintComp &lc) {
|
|
// return lc.print (out);
|
|
// }
|
|
|
|
// ========================================
|
|
|
|
#endif // _OTB_TRISKELE_ARRAY_TREE_BUILDER_TPP
|