C++ OpenCV sort contour hierarchy by level - sorting

I have a contour (RETR_TREE). I do understand, that I have a tree of contours denoted by the array
hierarchy[][4]
Structure is [Next, Previous, First_Child, Parent]
(http://docs.opencv.org/trunk/doc/py_tutorials/py_imgproc/py_contours/py_contours_hierarchy/py_contours_hierarchy.html)
My problem is to get the level of the current contour. I want to know the level. I have absolute no idea how to get this level from the parent, child, next or previous contour.
Can anyone provide code to get the level of the contour in the tree?
Thank you very much

When you want to get the level of contour you have to go to the parent of the parent of the parent, until you reach the root. This is true for any data structure that is tree, not only this one.
int nodeIndex = ....; // the contour whose depth you want to know
int depth=0;
// move from child to parent until you reach the outermost contour
while(hierarchy[nodeIndex][3] != -1) {
depth++;
nodeIndex = hierarchy[nodeIndex][3];
}

Related

Terrain Quadtree LOD can't detect out where T-junctions appears that generates cracks

I implemented a Quadtree that stores a single mesh of data with different LOD levels, where each four children have their own vertices and their corresponding indexes to the four corners(x0, y0, x1, y1 -> from top to bottom) that makes up their corresponding LOD level.
QuadTree.prototype.fillTree = function(currentNode, depth, currentBox, currentIndex) {
if(depth === 0 || !currentBox.checkPartition())
return;
let node = {
"vertices" : [],
"lines" : [],
"children" : [],
"box" : currentBox
};
currentNode.push(node);
currentBox.getVerticesCoord(this.cols, currentIndex).forEach((coord) => {
this.getPlaneVertices(node.vertices, coord);
});
currentBox.getLinesCoord(this.cols, currentIndex).forEach((coord) => {
this.getPlaneVertices(node.lines, coord);
});
currentBox.getPartitions().forEach((box, index) => {
this.fillTree(node["children"], depth-1, box, index);
});
};
I have also a checkFrustumBoundaries method where I calculate the minimum distance between a LOD level and the camera location [0, 0, 0] and also checks if it's visible by being within [-1, 1] range for all the coordinates by being multiplied by the projection matrix and divided by w.
Finally I have the method that selects needed LOD levels for the current state by finding the minimum distance between camera origins and their corresponding depth and all 4 children being checked if they are within the visible zone and store them into an array that will be rendered.
Note: That I want children to inherit the depth of their sibling with lowest Complexity level if he is ready to be rendered, thus I will always have a 4 four square with same LOD level.
QuadTree.prototype.readComplexity = function(projection, viewCamera, currentNode, currentIndex, currentDepth = 1) {
let childrenToBeRendered = [];
let minDepth = this.depth;
currentNode.children.forEach((child, index) => {
let frustumBoundaries = this.checkFrustumBoundaries(child.vertices, projection, viewCamera);
if(frustumBoundaries.withinFrustum) {
//Section is the 1.0/this.depth
let depth = this.depth-Math.ceil(frustumBoundaries.minDistance/this.section);
minDepth = Math.min(minDepth, depth);
childrenToBeRendered.push({
"child" : child,
"index" : index
});
}
});
childrenToBeRendered.forEach((child => {
if(minDepth <= currentDepth) {
//Even complexity, or the others quarters inherits on of their siblings with lowest complexity level
this.fetchLines(projection, viewCamera, child.child, currentDepth, child.index);
} else if(minDepth > currentDepth) {
//Needs more complexity because it's too near to camera origins
this.readComplexity(projection, viewCamera, child.child, child.index, currentDepth+1);
}
}));
};
But here I stumbled on the biggest problem, it appears T-junctions are causing cracks between different LOD levels:
I figured out that I could remove the cracks by disabling the vertices that make up the T-junction by using a stack and append to it the 2 vertices that makes a half diamond and use the following child where I use his vertex whose index is different from the previous two used. By cycling, starting from the top-left to top-right, bottom-right, bottom-left with a flag in case there is a LOD difference between the top-right and the left neighbor of him.
But before doing that, I need to know if the child's neighbors have less complexity or equal, thus if the child let's say is at top-left, I need to know if there is a LOD level at left and top that takes four times more space and by logic has less complexity.
How can I manage to do it, how can I reach for neighbors if they can be located at different quad-tree levels, if I try to use the node's box to generate the two neighbors' boxes and calculate their depth, I can't compare them with the node because during the selection process, there is the possibility that the neighbor inherited his siblings depth, thus the comparison will be wrong. But, if I chose to not use the rule of four, consequently I can't use the tactics of diamond selection I mentioned above.

Algorithm for sorting unordered list to tree structure

I am looking for an algorithm to sort an unordered list of items into a tree structure, using the minimum number of "is child" comparison operations as possible.
A little background on my specific case, but I guess I am just looking for a generic sorting algorithm of a sort I have been unable to find (it is a hard search term to refine).
I have an unordered list of contours, which are simply lists of coordinates that describe closed polygons. I want to create a tree that represents the relationship between these contours, such that the outermost is the root, with each contour at the next level as children, and so forth. So a tree structure with zero-to-many children per node.
A key requirement of the algorithm is that tests to determine whether or not a contour is the child of another are kept to a minimum, as this operation is very expensive. Contours can (and often do) share many vertices, but should not intersect. These shared vertices usually arise where map limits are reached - picture a set of concentric semi circles against the straight edge of a map. The point-in-poly test is slow if I need to run through lots of point-on-lines before I get to a definitive answer.
Here's the algorithm I have come up with so far. It's pretty naive, no doubt, but it works. There are probably some heuristics that may help - a contour is only likely to be a child of another contour with a depth within a certain range, for example - but I want to nail the basic algorithm first. The first red flag is that it is exponential.
for each candidate_contour in all_contours
for each contour in all_contours
// note already contains means "is direct or indirect child of"
if contour == candidate_contour or contour already contains(candidate_contour)
continue
else
list contours_to_check
contours_to_check.add(candidate_contour)
contour parent_contour = candidate_contour.parent
while (parent_contour != null)
contours_to_check.add(parent_contour)
parent_contour = parent_contour.parent
for each possible_move_candidate in contours_to_check (REVERSE ITERATION)
if possible_move_candidate is within contour
// moving a contour moves the contour and all of its children
move possible_move_candidate to direct child of contour
break
So that works - or at least it seems to - but it gets very slow with a non-trivial number of contours (think - several hundred, to possibly several thousand).
Is there a fundamentally better way to do this, or indeed - are there known algorithms that deal with exactly this? As mentioned before - the key in my case is to keep the "is contour within" comparisons to a minimum.
Edit to add solution based on Jim's answer below - thanks Jim!
This is the first iteration - which produce good (10x) improvements. See below for iteration 2.
This code versus my original algorithm is > 10x faster once the contour set becomes non-trivially big. See image below that is now sorted in a couple of seconds (v's 30 odd seconds prior), and rendered in order. I think there is room to further improve with some added heuristics - for example, now that the original list is sorted according to area, then each new candidate has to be a leaf node somewhere in the tree. The difficulty is determining which branches to traverse to test the existing leaves - if there are many branches/leaves, then it is probably still quicker to cut the search space down by examining the branches at the top.. something more to think about!
public static iso_area sort_iso_areas(List<iso_area> areas, iso_area root)
{
if (areas.Count == 0)
return null;
areas.Sort(new iso_comparer_descending());
foreach (iso_area area in areas)
{
if (root.children.Count == 0)
root.children.Add(area);
else
{
bool found_child = false;
foreach (iso_area child in root.children)
{
// check if this iso_area is within the child
// if it is, follow the children down to find the insertion position
if (child.try_add_child(area))
{
found_child = true;
break;
}
}
if (!found_child)
root.children.Add(area);
}
}
return root;
}
// try and add the provided child to this area
// if it fits, try adding to a subsequent child
// keep trying until failure - then add to the previous child in which it fitted
bool try_add_child(iso_area area)
{
if (within(area))
{
// do a recursive search through all children
foreach (iso_area child in children)
{
if (child.try_add_child(area))
return true;
}
area.move_to(this);
return true;
}
else
return false;
}
Iteration two - comparing against existing leaves only
Following on from my earlier thought that new contours could only fit into existing leaves, it struck me that in fact this would be much quicker as the poly in poly test would fail at the first bounds check for all leaves other than the target leaf. The first solution involved traversing a branch to find the target where, by definition, each and every poly along the way would pass the bounds check, and involve a full poly-in-poly test until no further leaves were found.
Following Jim's comment and re-examination of the code - the second solution did not work, unfortunately. I'm wondering if there may still be some merit to looking at lower elements in the tree before the branches, as the poly-in-poly test should fail quickly, and you know that if you find a leaf that accepts the candidate, there are no more polys that need to be examined..
Iteration two revisited
Although it is not the case that contours can only fit into leaves, it is the case that they almost always do - and also that they will usually fit into a recent predecessor in the ordered list of contours. This final updated code is the fastest yet, and ditches the tree traversal completely. It simply walks backwards through the recent larger polygons and tries each - polys from other branches will likely fail the poly-in-poly test at the bounds check, and the first poly found that surrounds the candidate poly has to be the immediate parent, due to the prior sorting of the list. This code brings the sorting down into the millisecond range again and is about 5x faster than the tree traversal (significant speed improvements were also made to the poly-in-poly test which accounts for the rest of the speed-up). The root is now taken from the sorted list of areas. Note that I now supply a root in the list that I know encompasses all the contours (bounding box of all).
Thanks for the help - and Jim in particular - for helping me think about this problem. The key really was the original sorting of the contours into a list in which it was guaranteed that no contour could be a child of a later contour in the list.
public static iso_area sort_iso_areas(List<iso_area> areas)
{
if (areas.Count == 0)
return null;
areas.Sort(new iso_comparer_descending());
for (int i = 0; i < areas.Count; ++i)
{
for (int j = i - 1; j >= 0; --j)
{
if (areas[j].try_add_child(areas[i]))
break;
}
}
return areas[0];
}
My original attempt: 133 s
Iteration 1 (traverse branch to find leaf): 9s
Iteration 2 (walk backwards through contours in ascending size order): 25ms (with other pt-in-poly improvements also).
I did something similar a while back by first sorting by area.
If polygon B is contained within polygon A, then the bounding box for polygon A has to be larger than the bounding box for polygon B. More to the point, if you specify the bounding box as ((x1, y1), (x2, y2)), then:
A.x1 < B.x1
A.y1 < B.y1
A.x2 > B.x2
A.y2 > B.y2
(Those relationships might be <= and >= if polygons can share edges or vertices.)
So the first thing you should do is compute the bounding boxes and sort the polygons by bounding box area, descending (so the largest is first).
Create a structure that is essentially a polygon and a list of its children:
PolygonNode
{
Polygon poly
PolygonNode[] Children
}
So you start out with your polygons sorted by bounding box area, descending, and an initially empty list of PolygonNode structures:
Polygon[] sortedPolygons
PolygonNode[] theTree
Now, starting from the first member of sortedPolygons, which is the polygon with the largest area, check to see if it's a child of any of the top-level members of theTree. If it's not, add the polygon to the theTree. The bounding boxes help here because you don't have to do the full polygon-in-polygon test if the bounding box test fails.
If it is a child of a node, then check to see if it's a child of one of that node's children, and follow the child chain down until you find the insertion spot.
Repeat that for every polygon in sortedPolygons.
Worst case, that algorithm is O(n^2), which will happen if there are no parent/child relationships. But assuming that there are many nested parent/child relationships, the search space gets cut down very quickly.
You can probably speed it up somewhat by ordering the theTree list and the child nodes lists by position. You could then use a binary search to more quickly locate the potential parent for a polygon. Doing so complicates things a little bit, but it might be worthwhile if you have a lot of top-level polygons. I wouldn't add that optimization on the first cut, though. It's quite possible that the version I outlined using sequential search will be plenty fast enough.
Edit
Understanding the nature of the data helps. I didn't realize when I wrote my original response that your typical case is that given the sorted list of polygons, the normal case is that p[i] is a child of p[i-1], which is a child of p[i-2], etc. Your comments indicate that it's not always the case, but it is very often.
Given that, perhaps you should make a simple modification to your implementation so that you save the last polygon and check it first rather than starting in with the tree. So your loop looks something like this:
iso_area last_area = null; // <============
foreach (iso_area area in areas)
{
if (root.children.Count == 0)
root.children.Add(area);
else if (!last_area.try_add_child(area)) // <=======
{
bool found_child = false;
foreach (iso_area child in root.children)
{
// check if this iso_area is within the child
// if it is, follow the children down to find the insertion position
if (child.try_add_child(area))
{
found_child = true;
break;
}
}
if (!found_child)
root.children.Add(area);
}
last_area = area; // <============
}
return root;
If the data is as you said, then this optimization should help quite a bit because it eliminates a bunch of searching through the tree.
A recursive approach works well when dealing with trees. The following algorithm ought to be O(N log(N)) in cases where your shapes are distributed fairly evenly. It becomes O(N²) worse-case if your shapes are all concentric in one long tunnel-like distribution.
boolean tryAddToNode(Node possibleParent, Node toAdd)
{
if not toAdd.isChildOf(possibleParent)
return false
for each child in possibleParent.children
if(tryAddToNode(child, toAdd))
return true
// not a child of any of my children, but
// it is a child of me.
possibleParent.children.add(toAdd)
return true
}

How to detect a hole in the triangular mesh?

Actually, I can detect border or edges of a convex triangular mesh by checking which edge of the triangle does not have any neighbor. So, if a mesh has some holes, then we can highlight that part easily because we have edge vertices.
But the issue is, if we just have the edge vertices or borders, how can we know that the mesh has some holes ? and how many holes the mesh has ?
I thought enough about this issue, but unable to get it, any idea ? What should be the condition or check for hole detection ?
After detection of a hole I want to fill it. But first thing is to detect it ?
Thanks.
Assuming that the mesh is connected and you can highlight all the boundaries. You are left with all the holes + one additional boundary which is that of mesh itself. You can just discard the boundary with the biggest length of them and get all the holes.
A triangular mesh derived from a scanner (eg. Kinect) can have small fragments (isolated patches) as well as small holes. I suggest a hole can generally be detected by counting the number of vertices that neighbor the vertices on the boundary. It is not a hole if there are fewer neighboring vertices than boundary vertices.
My answer will only work for a closed mesh, but it will handle the case of concave and convex holes.
For the sake of explanation, lets imagine a 2D mesh.
Calculate a bounding box for the mesh. In our example the bounding box needs to store min and max values for the X and Y axis, and a corresponding vertex index for each value:
struct BoundingBox
{
float minX,maxX,minY,maxY;
int vminX,vmaxX,vminY,vmaxY;
}
Iterate over every vertex in the mesh, growing the bounding box as you add each point. When a vertex is responsible for changing one of the min/max values, store or overwrite the corresponding vmin/vmax value with the vertex mesh index.
E.g.
BoundingBox bounds;
bounds.minX = verts[0].X;
bounds.maxX = verts[0].X;
bounds.minY = verts[0].Y;
bounds.maxY = verts[0].Y;
bounds.vminX = bounds.vmaxX = bounds.vminY = bounds.vmaxY = 0;
for (int i = 1; i < numVerts; i++)
{
Vertex v = verts[i];
if (v.X < bounds.minX) { bounds.minX = v.X; bounds.vminX = i; }
if (v.X > bounds.maxX) { bounds.maxX = v.X; bounds.vmaxX = i; }
if (v.Y < bounds.minY) { bounds.minY = v.Y; bounds.vminY = i; }
if (v.Y > bounds.maxY) { bounds.maxY = v.Y; bounds.vmaxY = i; }
}
Now iterate over your boundaries until you find one which contains ALL the vertices you gathered in the bounding box. This is your outer boundary. The remaining boundaries are holes within the mesh.
Indeed, a hole in triangular mesh is a closed loop of adjacent oriented boundary edges, each of which does not have a triangle from one side (e.g. from left).
So the algorithm to enumerate all holes can be as follows
Find all boundary edges (the edges without left triangle) and compose a set with them.
Take any boundary edge from the set, then search for the next edge in the set originating in the vertex where the previous edge terminates, remove it from the set as well and continue until edge loop is closed. This will give you one of the holes.
Repeat step 2. until the set is empty.
Some operations here can be optimized by using specialized data structures for mesh representation, e.g. half-edges.
The animation below demonstrates how starting from an arbitrary boundary edge (under the cursor), the whole hole can be found and highlighted:
(captured in MeshInspector application)

Adjacent cells in QuadTree

Is there any way to find adjacent cells in a quadtree subdivision? I mean all the cell adjacent to the selected one at any level?
A space filling curves fills a space completley and reduces the 2 dimension to 1 dimension. I've written a free php class at phpclasses.org (hilbert curve). It includes a z curve, 4 hilbert curves and the moore curve and a quadkey function. Here is a blog about collision detection and quadtrees: lab.polygonal.de/?p=202?
A morton a.k.a. z-curve is easy to construct. Translate the x-and y-value to binary and concatenate the values. You can find some code here:http://msdn.microsoft.com/en-us/library/bb259689.aspx. You can verify the upper boundaries by using the most significant bits.
You need to keep track of which child the node is. If the adjacent node is in the same parent, just return it. If not, you need to walk upward in the tree until you can find a common ancestor. Then follow a similar path downwards until you come back to the correct level (or reach the bottom).
Node WalkLeft(Node node)
{
if (node == null) return null;
Node leftParent;
switch (node.ChildDirection)
{
case ChildDirection.Root:
return null;
case ChildDirection.TopRight:
return node.Parent.TopLeft;
case ChildDirection.BottomRight:
return node.Parent.BottomLeft;
case ChildDirection.TopLeft:
leftParent = WalkLeft(node.Parent);
return leftParent.TopRight ?? leftParent;
case ChildDirection.BottomLeft:
leftParent = WalkLeft(node.Parent);
return leftParent.BottomLeft ?? leftParent;
}
}
Similarly for the other directions.
x ?? y picks the first non-null value.

Algorithms for converting flat list of objects with size/position to tree?

I have a list of objects like this:
[
Rectangle(20, 30, 100, 200), // x, y, width, height
Rectangle(50, 40, 50, 50),
Text(60, 50, 'Text')
]
For the sake of this example, the first Rectangle is the bottom-most object, Text is top-most. Based on the position/size, the second Rectangle should be a child of the first as it is entirely contained within the first and on top. The text object should be a child of the second Rectangle for the same reasons.
I'm looking for discussion or a general pointer toward an algorithm to efficiently do this. I'm building my own, but there is likely something clever I'm missing.
EDIT: Here is my implementation in coffeescript:
obj =
_isParent: (parent, child) ->
pb = parent.getBounds() # this returns a rectangle
return pb.contains(child.getBounds())
generateHiearchy: (object, index, objects, cache) ->
return cache[object._id] if cache[object._id]
exObject = new Node(object)
cache[object._id] = exObject
for i in [index+1...objects.length]
potentialParent = objects[i]
if #_isParent(potentialParent, object)
exParent = #generateHiearchy(potentialParent, i, objects, cache)
exParent.addChild(exObject)
break
exObject
generateTree: (objects) ->
return [] unless objects and _.size(objects)
cache = {}
objects = #sort(objects)
for i in [0...objects.length]
object = objects[i]
exobj = #generateHiearchy(object, i, objects, cache)
(val for k, val of cache when not val.parent)
Basically, I sort it so the top-most is at the array head, then walk the array. On each iteration, I recurse from the current node all the way to the top of the hierarchy, caching nodes along the way.
You might want to look at R-trees. This data structure keeps rectangles in a tree hierarchy. Basically, if a rectangle node R1 has a child node rectangle R2, it means R2 is contained within R1. Have a look at the illustration on Wikipedia, it's very self-explanatory.
To tailor this data structure to your needs, you can find a way to represent Text objects as a Rectangle (or some other multi-dimensional object compatible with R-trees).
It should be easy to find an open-source implementation. Hope this suits your needs!

Resources