Search code examples
pythonfor-looptimebreak

loop without break in Python


I try to write the fastest code that would select a point inside a contour. I need the point coordinates, not the pixels from the image. I wrote this definition OnePointInsideContour

Determine if a point is inside or outside of a shape with opencv

def OnePointInsideContour(contourArray, PointTuple, tol):
L = len(contourArray);
y0 = PointTuple[0]; # horizontal
x0 = PointTuple[1]; # vertical
ret = [];
inside = False;
counter = 0

for k in range(L):
    ycont = list(contourArray[k])[0];
    xcont = list(contourArray[k])[1];
    if ycont > y0 - tol and ycont < y0 + tol and xcont > x0: 
        p = (ycont, xcont); 
        counter += 1; 
        ret.append(p);
        break

for k in range(L):
    ycont = list(contourArray[k])[0];
    xcont = list(contourArray[k])[1];
    if ycont > y0 - tol and ycont < y0 + tol and xcont < x0: 
        p = (ycont, xcont); 
        counter += 1; 
        ret.append(p);
        break           

for k in range(L):
    ycont = list(contourArray[k])[0];
    xcont = list(contourArray[k])[1];
    if xcont > x0 - tol and xcont < x0 + tol and ycont < y0:
        p = (ycont, xcont); 
        counter += 1; 
        ret.append(p);
        break  

for k in range(L):
    ycont = list(contourArray[k])[0];
    xcont = list(contourArray[k])[1];
    if xcont > x0 - tol and xcont < x0 + tol and ycont > y0: 
        p = (ycont, xcont); 
        counter += 1; 
        ret.append(p);
        break

if counter == 4:
    inside = True

return inside, ret

but the fact that it uses 4 loops to iterate along contour each time a new point is tested, means that the execution time for 100 k points is about 1 hour! In the image below I show an example a successful confirmation that a given point (black dot) is inside the contour. This takes 0.012 seconds just for one point.

enter image description here

The problem is that there may be a few other dots on the contour near each of the North(red), South(green), East(cyan) and West(blue) points and for this reason once the first point is found the for loop is stopped with break and a new one starts, looking for the next condition.

Only if all four coloured dots are found on the contour, the test point is accepted as being inside.

Any suggestion how to make the execution faster?


Solution

  • You can surely reduce the computation time by improving the looping operations. For example, you can try something like:

    found1, found2, found3, found4 = False, False, False, False
    for k in range(L):
        ycont = list(contourArray[k])[0]
        xcont = list(contourArray[k])[1]
        
        if not found1 and (ycont > y0 - tol and ycont < y0 + tol and xcont > x0): 
            p = (ycont, xcont)
            counter += 1 
            ret.append(p)
            found1 = True
                
        if not found2 and (ycont > y0 - tol and ycont < y0 + tol and xcont < x0): 
            p = (ycont, xcont)
            counter += 1
            ret.append(p)
            found2 = True
    
        if not found3 and (xcont > x0 - tol and xcont < x0 + tol and ycont < y0):
            p = (ycont, xcont)
            counter += 1
            ret.append(p)
            found3 = True
    
        if not found4 and (xcont > x0 - tol and xcont < x0 + tol and ycont < y0):
            p = (ycont, xcont)
            counter += 1 
            ret.append(p)
            found4 = True
    

    Note that you need to avoid breaking the loop since you're trying to iterate over L one time only. You seem to have some code replication that you can get rid of, all the parts below can be written as a function.

    ...
    p = (ycont, xcont)
    counter += 1 
    ret.append(p)
    ...