Search code examples
pythonpython-3.xdepth-first-search

python script stops in the middle of execution without errors


i have a simple script showing dfs using python, and it stops without executing completely

the script just inputs an image, turns it into an image with just 2 colors(something like islands and water problem of dfs).

it starts with a blank image(background) and then shows an animation with islands(foreground color) becoming visible one by one.

it works upto some point and then stops completely. i have checked the condition of while loop is not met when it stops.

even the atexit message is not printed.

here's the script

import imageFilters as imf
import imutils
import cv2
import numpy as np
import random
import sys
import atexit

sys.setrecursionlimit(1000000000)

atexit.register(print, "exited ")


background = [255, 255, 255] #white
foreground = [0,0,0] #black

img_path = input("ENTER IMAGE PATH:")

img = cv2.imread(img_path)

 #imf.createLineDrawing: resizes with height = 600 and creates an image with only two colors;
img = imf.createLineDrawing(img, foreground, background)
(height, width, channel) = img.shape

blank_image = np.ndarray([height, width, channel], img.dtype)
blank_image.fill(255)

done = np.ndarray([height, width], img.dtype)
countDone = 0

def searchNeighbour(x, y):

    global done,countDone

    done[y, x] = 1
    countDone += 1
    if list(img[y, x]) == foreground:
        blank_image[y, x] = foreground
    else:
        return

    cv2.imshow("o", blank_image)
    cv2.waitKey(1)

    if x - 1 >= 0 and not(done[y, x - 1]):
        searchNeighbour(x - 1, y)
    if x + 1 <= width - 1 and not(done[y, x + 1]):
        searchNeighbour(x + 1, y)
    if y - 1 >= 0 and not(done[y - 1, x]):
        searchNeighbour(x, y - 1)
    if y + 1 <= height - 1 and not(done[y + 1, x]):
        searchNeighbour(x, y + 1)


while countDone < height*width:
    x = random.randrange(0, width - 1)
    y = random.randrange(0, height - 1)
    if not(done[y, x]):
        searchNeighbour(x, y)


Solution

  • I got the solution. This is a major drawback of python. Python is not a functional language and so it is unable to hold large recursions.

    actually the default recursion limit(10000) is not arbitrary, but is set because of small stack size. so even if you increase recursion limit, it will cause a stack overflow.

    however i got the soution using multithreading;

    i just wrapped it in a function and ran it in a different thread with increased stack limit;

    STEPS TO RUN LARGE RECURSION IN PYTHON

    1. Add below lines at starting of code
    import sys
    
    sys.setrecursionlimit(10**9)
    threading.stack_size(10**8)
    
    1. Wrap your recursive function in a parent function

    2. add below line at end of code -

    threading.Thread(target=<your_parent_function>).start()
    

    where <your_parent_function> is the name of your parent function

    my final code-

    import imageFilters as imf
    import cv2
    import numpy as np
    from random import randrange
    import threading
    import sys
    
    sys.setrecursionlimit(10**9)
    threading.stack_size(10**8)
    
    
    background = [255, 255, 255]
    foreground = [56, 50, 36]
    
    img_path = input("ENTER IMAGE PATH:")
    
    img = cv2.imread(img_path)
    img = imf.createLineDrawing(img, foreground, background)
    (height, width, channel) = img.shape
    
    blank_image = np.ndarray([height, width, channel], img.dtype)
    blank_image.fill(255)
    
    done = np.ndarray([height, width], img.dtype)
    countDone = 0
    
    
    def searchNeighbour(x, y):
    
        global done, countDone
        print(countDone)
        countDone += 1
        done[y, x] = 1
    
        if list(img[y, x]) == foreground:
            blank_image[y, x] = foreground
        else:
            print("returning")
            return 0
    
        cv2.imshow("O", blank_image)
        cv2.waitKey(1)
    
        if x - 1 >= 0 and not(done[y, x - 1]):
            searchNeighbour(x - 1, y)
        if x + 1 <= width - 1 and not(done[y, x + 1]):
            searchNeighbour(x + 1, y)
        if y - 1 >= 0 and not(done[y - 1, x]):
            searchNeighbour(x, y - 1)
        if y + 1 <= height - 1 and not(done[y + 1, x]):
            searchNeighbour(x, y + 1)
    
    
    def showAllForegrounds():
        while countDone < height*width:
            x = randrange(0, width - 1)
            y = randrange(0, height - 1)
            if not(done[y, x]):
                searchNeighbour(x, y)
    
    
    threading.Thread(target=showAllForegrounds).start()
    
    print("DONE PROGRAM %s" % countDone)