11

I defined in python some shapes with corresponding corner points, like this:

square = [[251, 184],
          [22, 192],
          [41, 350],
          [244, 346]]

triangle = [[250, 181],
            [133, 43],
            [21, 188]]

pentagon = [[131,  37],
            [11, 192],
            [37, 354],
            [247, 350],
            [256, 182]]

Then, I make use of NetworkX package to create a Graph:

G = nx.DiGraph()

Then, I create a node in the graph for each shape:

G.add_node('square', points = square, center = (139, 265))
G.add_node('triangle', points = triangle, center = (139, 135))
G.add_node('pentagon', points = pentagon, center = (138, 223))

Now is the problem, I have to create some edges connecting two nodes if a condition is satisfied. The condition to satisfy is if the center of a shape is inside or outside another shape, then create an edge like this:

G.add_edge('triangle', 'pentagon', relation = 'inside')
G.add_edge('triangle', 'square', relation = 'outside')

To do so, I have to loop through the nodes, extract the center of a shape, extract the points of the other shapes (NOT themselves, it's useless) and make the pointPolygonTest.

I've been trying quite much, but didn't came out with any solution. The closest (not really effective) solution I got is this:

nodes_p=dict([((u),d['points']) for u,d in G.nodes(data=True)])
nodes_c=dict([((u),d['center']) for u,d in G.nodes(data=True)])
for z,c in nodes_c.items():
    print z + ' with center', c
    for z,p in nodes_p.items():
        p_array = np.asarray(p)
        if cv2.pointPolygonTest(p_array,c,False)>=0:
            print 'inside ' + z
            #create edge
        else:
            print 'outside ' + z
            #create edge

This, gives me the following output, that is not optimal because there are some relation that should have been avoided (like triangle inside triangle) or some wrong relations (like pentagon inside square)

triangle with center (139, 135)
inside triangle
outside square
inside pentagon
square with center (139, 265)
outside triangle
inside square
inside pentagon
pentagon with center (138, 223)
outside triangle
inside square
inside pentagon

How can I solve this problem? Any suggestion is apreciated. Reminder: the main problem is how to loop through the nodes and extract the info. The packages I import for the whole script are:

import numpy as np
import networkx as nx
import cv2
Francesco Sgaramella
  • 1,009
  • 5
  • 21
  • 39

1 Answers1

8

Here is an image of your polygons Polygon image

First, there is no need to cast the nodes as dictionaries, we can iterate on them directly. This code is based off of this example

for u,outer_d in G.nodes(data=True):
   center = outer_d['center']
   print u, "with center", center
   for v, inner_d in G.nodes(data=True):
        #Don't compare self to self
        if u != v:
            # Create a source image
            src = np.zeros((400,400),np.uint8)          
            # draw an polygon on image src
            points = np.array(inner_d['points'],np.int0)
            cv2.polylines(src,[points],True,255,3)
            contours,_ = cv2.findContours(src,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
            if cv2.pointPolygonTest(contours[0],center,True) <= 0:
                print 'outside',v
            else:
                print 'inside',v

The output is

pentagon with center (138, 223)
inside square
outside triangle
square with center (139, 265)
inside pentagon
outside triangle
triangle with center (139, 135)
inside pentagon
outside square

Since the goal is to determine if one polygon is completely inside the other, we should check all of the vertices of one polygon are inside another. Here is a tentative (unfortunately untested) solution.

def checkPoint(point, poly,r=400):
    ''' determine if point is on the interior of poly'''
    # Create a source image
    src = np.zeros((r,r),np.uint8)       
    # draw an polygon on image src
    verts = np.array(poly,np.int0)
    cv2.polylines(src,[verts],True,255,3)
    contours,_ = cv2.findContours(src,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
    return cv2.pointPolygonTest(contours[0],tuple(point),True) > 0:


for u,outer_d in G.nodes(data=True):
    points = outer_d['points']
    center = outer_d['center']
    print u, "with center", center
    for v, inner_d in G.nodes(data=True):
        poly = inner_d['points']
        if u != v:
            if all([checkPoint(point,poly) for point in points]):
                print 'inside',v
            else:
                print 'outside',v

The output for this example is as follows and now should be correct.

pentagon with center (138, 223)
outside square
outside triangle
square with center (139, 265)
inside pentagon
outside triangle
triangle with center (139, 135)
inside pentagon
outside square

Note that I have made the assumption that the polygons will be convex. If this is not true, then you could check all the points on the contour instead of just the corner points. You could also build in a convexity check using cv2, see this blog for details.

yardsale8
  • 940
  • 9
  • 15
  • Sorry, mixed up the inequality. Is it correct now? – yardsale8 Feb 07 '14 at 13:04
  • The output is wrong. It should be: pentagon outside triangle, outside square, square inside pentagon, outside triangle, triangle inside pentagon, outside square – Francesco Sgaramella Feb 07 '14 at 13:05
  • "inside" means the center is inside, correct? If so, it should be pentagon outside triangle, **inside** square, square inside pentagon, outside triangle, triangle inside pentagon, outside square – yardsale8 Feb 07 '14 at 14:31
  • What you are saying is actually true. However, is not consistent with the image I am experimenting with. In the image there a pentagon containing a square and a triangle. The square is below the triangle. So that's why the output is not 100% perfect. I don't know how to solve it. Because of course the pointPolygonTest for pentagon against square returns inside, but should be actually outside. – Francesco Sgaramella Feb 07 '14 at 14:44
  • The image you put is completely true. So you can see that the centroid of the pentagon is placed inside the square, but actually the pentagon contains the square, meaning that the pentagon is outside the square. How to overcome this? – Francesco Sgaramella Feb 07 '14 at 14:50
  • Ok, one solution would be to check to see if each _point_ of one polygon is inside the other. I will add a tentative solution, but I can't test it now since I don't have cv2 on my work computer. – yardsale8 Feb 07 '14 at 15:07
  • It is not working your solution. But I understood what you trying, and I'll try myself. I will let you know how it goes. Anyway, really really really thank you for your help! – Francesco Sgaramella Feb 07 '14 at 16:26
  • I have identified and fixed the problems with the second solution. Note the `tuple` in the last line of the function and the `[` and `]` in the call to `all`. I hope this helps. – yardsale8 Feb 07 '14 at 21:15