Reputation: 495
Im getting Segmentation fault: 11
error on my mac 10.13.6
I'm running a virtualenv with Python 3.6.5 Anaconda
I'm running a pixel flood filling script
img = cv2.imread(image,1)
surface = cv2.Canny(img,100,200)
def floodfill(x, y, oldColor, newColor):
# assume surface is a 2D image and surface[x][y] is the color at x, y.
if surface[x][y] != oldColor: # the base case
return
surface[x][y] = newColor
floodfill(x + 1, y, oldColor, newColor) # right
floodfill(x - 1, y, oldColor, newColor) # left
floodfill(x, y + 1, oldColor, newColor) # down
floodfill(x, y - 1, oldColor, newColor) # up
floodfill(0, 0, 0, 100)
plt.imshow(edges, cmap='gray')
plt.show()
any suggestions?
Upvotes: 2
Views: 2288
Reputation: 495
Here is an option on how to do the same thing without recursion for anyone interested. from http://inventwithpython.com/blog/2011/08/11/recursion-explained-with-the-flood-fill-algorithm-and-zombies-and-cats/
def floodfill(x, y, oldColor, newColor):
# assume surface is a 2D image and surface[x][y] is the color at x, y.
theStack = [ (x, y) ]
while (len(theStack) > 0):
x, y = theStack.pop()
if (x == 224):
continue
if (x == -1):
continue
if (y == -1):
continue
if (y == 224):
continue
if edges[x][y] != oldColor:
continue
edges[x][y] = newColor
theStack.append( (x + 1, y) ) # right
theStack.append( (x - 1, y) ) # left
theStack.append( (x, y + 1) ) # down
theStack.append( (x, y - 1) ) # up
Upvotes: 2
Reputation: 2980
I think the problem is that your code is recursively calling itself without the previous function ending, resulting in increasing numbers of copies of your function resting on the stack until you run out of memory (which triggers the segmentation fault). Each time Python calls a new function and places it on the stack, a stack frame is created which uses up some memory, even if you aren't creating any new objects within that function call. When the function returns, the garbage collector within python frees up the memory, but if there are a lot of values in your image with value 0
, then then you can end up with a lot of copies of floodfill
running at once. This is a little old and very in-depth and technical but if you want to know more, this is a good discussion.
To see an alternative approach to tackling the problem using lists of active nodes, have a look here:
https://rosettacode.org/wiki/Bitmap/Flood_fill#Python
As an aside, you have another issue that may be deliberate, in that your code treats the image as a sphere, in the sense that when it hits a border it will jump to the other side of the image and fill there too. This is because python supports negative indices, so when x=0
and you jump to x-1
, you are looking at index -1
which is the last index in the array. To address this you could add some checks:
if x > 0: # left
floodfill(x - 1, y, oldColor, newColor) # left
if y > 0: # up
floodfill(x, y - 1, oldColor, newColor) # up
if x < surface.shape[0] - 1: # right
floodfill(x + 1, y, oldColor, newColor) # right
if y < surface.shape[1] - 1: # down
floodfill(x, y + 1, oldColor, newColor) # down
Your code works fine in general though. If you try it with a small toy example, you can see it in action (this is with the fix above):
surface_array = [[0 for i in range (0,10)] for j in range(0,10)]
surface_array[1][1] = 1
surface_array[0][1] = 1
surface_array[2][0] = 1
surface = np.array(surface_array)
print(surface)
floodfill(0, 0, 0, 100)
print(surface)
Upvotes: 2