python getting Segmentation fault: 11 on OS 10.13 - python-3.x

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?

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)

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

Related

Move Robot in a 10 X 10 grid

I am working on this code challenge:
Given a 2D bot/robot which can only move in four directions, move forward which is UP(U), move backward which is DOWN(D), LEFT(L), RIGHT(R) in a 10x10 grid. The robot can't go beyond the 10x10 area.
Given a string consisting of instructions to move.
Output the coordinates of a robot after executing the instructions. Initial position of robot is at origin(0, 0).
Example:
Input : move = “UDDLRL”
Output : (-1, -1)
Explanation:
Move U : (0, 0)–(0, 1)
Move D : (0, 1)–(0, 0)
Move D : (0, 0)–(0, -1)
Move L : (0, -1)–(-1, -1)
Move R : (-1, -1)–(0, -1)
Move L : (0, -1)–(-1, -1)
Therefore final position after the complete
movement is: (-1, -1)
I got the code working without using the 10x10 grid information. How could I incorporate the 10x10 grid information into my solution in an OOP fashion? My solution doesn't follow the OOP principles.
# function to find final position of
# robot after the complete movement
def finalPosition(move):
l = len(move)
countUp, countDown = 0, 0
countLeft, countRight = 0, 0
# traverse the instruction string 'move'
for i in range(l):
# for each movement increment its respective counter
if (move[i] == 'U'):
countUp += 1
elif(move[i] == 'D'):
countDown += 1
elif(move[i] == 'L'):
countLeft += 1
elif(move[i] == 'R'):
countRight += 1
# required final position of robot
print("Final Position: (", (countRight - countLeft),
", ", (countUp - countDown), ")")
# Driver code
if __name__ == '__main__':
move = "UDDLLRUUUDUURUDDUULLDRRRR"
finalPosition(move)
This fixes it:
class Robot:
class Mover:
def __init__(self, x, y):
self.x, self.y = x, y
def new_pos(self, x, y):
new_x = x + self.x
new_y = y + self.y
if (new_x > 9 or new_y > 9):
raise ValueError("Box dimensions are greater than 10 X 10")
return new_x, new_y
WALKS = dict(U=Mover(0, 1), D=Mover(0, -1),
L=Mover(-1, 0), R=Mover(1, 0))
def move(self, moves):
x = y = 0
for id in moves:
x, y = self.WALKS[id].new_pos(x, y)
return (x,y)
if __name__ == '__main__':
moves2 = "UDDLLRUUUDUURUDDUULLDRRRR"
robot = Robot()
print(robot.move(moves2))
Output :
(2,3)
The way you use your counters makes it less trivial to detect that you would hit the border of the 10x10 grid. Without changing too much, you could replace the countUp and countDown variables by one countVertical variable, and add -1 to it when going up and 1 when going down. Then ignore a move if it would make that counter negative or greater than 9. And obviously you would do the same for horizontal movements.
[Edit: After the edit to your question, it turns out that you want the Y-coordinate to be opposite to what I assumed above. So I have changed the sign of the Y-coordinate updates (+1, -1).]
That's really it.
Now to make this more OOP, you could define a Robot class, which would maintain its x and y coordinate. Anyhow it would be good to remove the print call out of your function, so the function only deals with the movements, not with the reporting (separation of concern).
Here is how it could work:
class Robot:
def __init__(self, x=0, y=0):
self.position(x, y)
def position(self, x, y):
self.x = min(9, max(0, x))
self.y = min(9, max(0, y))
def move(self, moves):
for move in moves:
if move == 'U':
self.position(self.x, self.y + 1)
elif move == 'D':
self.position(self.x, self.y - 1)
elif move == 'L':
self.position(self.x - 1, self.y)
elif move == 'R':
self.position(self.x + 1, self.y)
else:
raise ValueError(f"Invalid direction '{move}'")
if __name__ == '__main__':
moves = "UDDLLRUUUDUURUDDUULLDRRRR"
robot = Robot(0, 0)
robot.move(moves)
print(f"Final position: {robot.x}, {robot.y}")

How to change the color of 4 pixels in an image, multiple times using opencv?

I'm trying to write a program that will convert a 480x480 image into 240x240 quality, by taking the average color of 4 pixels and replacing all 4 with that average color. Then I repeat this for all 2x2 squares in the image. My program so far keeps replacing the entire image with the average color from the top left corner 4 squares, which is bgr [150, 138, 126]. Can someone help me see what I'm doing wrong?
def get_square(x1, x2, y1, y2):
square = image[x1:x2, y1:y2]
return square
def bgr_vals(img):
b_vals, g_vals, r_vals = [], [], []
x, y = 0, 0
for i in range(4):
b, g, r = image[x][y]
b_vals.append(b)
g_vals.append(g)
r_vals.append(r)
if y != 1:
y += 1
elif x == 0 and y == 1:
x += 1
elif x == 1 and y == 1:
y -= 1
return b_vals, g_vals, r_vals
def avg_color(bgr_vals):
b_avg = np.average(bgr_vals[0])
g_avg = np.average(bgr_vals[1])
r_avg = np.average(bgr_vals[2])
return [b_avg, g_avg, r_avg]
image = cv2.imread('src.jpg')
y1, y2 = 0, 2
for i in range(240):
x1, x2 = 0, 2
for i in range(240):
patch = get_square(x1, x2, y1, y2)
bgr_colors = bgr_vals(patch)
color = avg_color(bgr_colors)
image[x1:x2, y1:y2] = color
x1 += 2
x2 += 2
y1 += 2
y2 += 2
Thanks!
In your function bgr_vals you take argument img (which is the current patch), but within the method you inadvertently access image (the whole image) in this line:
b, g, r = image[x][y]
Your script works fine when you fix this typo.
Here are some tips for the future:
Images in OpenCV (and most libraries) are stored in row-first order, this means that you should write image[y][x] or img[y][x]. In your case it doesn't matter but in future work it might.
In general try to test your programs with non-square images, it is a common pitfall to only test with square-sized images
When you have cascaded loops, don't use the same variable name in the loop (you used i both times). Again, in your case it doesn't matter but as soon as you would use the value of i the confusion would start
Instead of increasing x, y within the loop you can use the loop variable directly, by getting a range with a step:
for y in range(0, 480, 2):
for x in range(0, 480, 2):
…
Use array shape instead of hard-coding dimensions:
for y in range(0, image.shape[0], 2):
for x in range(0, image.shape[1], 2):
…

Why in this recursive function in Python does the execution continue even after the base condition is met?

The Following is a code snippet of a game called Ink Spill from the book 'Make Games with Python & Pygame' by Al Sweigart. (Full Code here: http://invpy.com/inkspill.py)
This recursive function is responsible for changing
the old color ( in this case '2', which is mainBoard[0][0]) to the new color (in this case '3', which is mainBoard[1][0])
that the player clicks on .
My question is: In this example why even when the base condition is
met and the return is executed, the execution still jumps to the next block inside the function.
I have tested this with print statements all over the function many times and with different parameters and also on Visualize Code website ...I still don't understand it!
Here, I have deleted many of my print statements and have left just two at the beginning. If you run this code you will see on your console that on the third line the condition is met (3 !=2), but the execution continues!
I really appreciate any help. Thank you very much.
And by the way unfortunately, the other question that was asked by someone else: Why does this recursive function continue even after its base case has been satisfied didn't answer my question although very similar!
boardWidth = 3
boardHeight = 3
mainBoard = [[2, 0, 0], [3, 0, 0], [4, 0, 0]]
# (blue, red, red),(yellow, red, red),(orange, red, red)
def floodFill(board, oldColor, newColor, x, y):
print(board[x][y], oldColor)
print(mainBoard)
if board[x][y] != oldColor:
return
board[x][y] = newColor # change the color of the current box
# Make the recursive call for any neighboring boxes:
if x > 0:
floodFill(board, oldColor, newColor, x - 1, y)
if x < boardWidth - 1:
floodFill(board, oldColor, newColor, x + 1, y)
if y > 0:
floodFill(board, oldColor, newColor, x, y - 1)
if y < boardHeight - 1:
floodFill(board, oldColor, newColor, x, y + 1)
floodFill(mainBoard, 2, 3, 0, 0)

Colormapping the Mandelbrot set by iterations in python

I am using np.ogrid to create the x and y grid from which I am drawing my values. I have tried a number of different ways to color the scheme according to the iterations required for |z| >= 2 but nothing seems to work. Even when iterating 10,000 times just to be sure that I have a clear picture when zooming, I cannot figure out how to color the set according to iteration ranges. Here is the code I am using, some of the structure was borrowed from a tutorial. Any suggestions?
#I found this function and searched in numpy for best usage for this type of density plot
x_val, y_val = np.ogrid[-2:2:2000j, -2:2:2000j]
#Creating the values to work with during the iterations
c = x_val + 1j*y_val
z = 0
iter_num = int(input("Please enter the number of iterations:"))
for n in range(iter_num):
z = z**2 + c
if n%10 == 0:
print("Iterations left: ",iter_num - n)
#Creates the mask to filter out values of |z| > 2
z_mask = abs(z) < 2
proper_z_mask = z_mask - 255 #switches current black/white pallette
#Creating the figure and sizing for optimal viewing on a small laptop screen
plt.figure(1, figsize=(8,8))
plt.imshow(z_mask.T, extent=[-2, 2, -2, 2])
plt.gray()
plt.show()

How to detect objects shape from images using python3?

i want to write a code in python3 that detects objects shapes from images.
I want to choose a pixel from an object in the given image and find the neighbours pixels.
If they have the same RGB value that means that they are part of the object.
When neighbour pixel changes the RGB value with an ajustable difference from original pixel the algorithm should stop searching for neighbours. I think that this will work unless the backgroud and object have the same color.
I have found a way to put the pixels with same color in an rectangle,but this will not help me. I want to save just the shape of the object and put it in a different image.
For example,
If i want to start my algorithm from the middle of an object, let's
say a black table with a white background,the algorithm will find
pixels with the same color in any direction. When the neighbour pixel
RGB values will change with more than 30 units in one direction,the
algorithm will stop going in that direction,and will start going in
another direction untill I have the shape of the table.
I found a code on another post that help me to determinate regions of pixels with a shared value using PIL
Thanks!
from collections import defaultdict
from PIL import Image, ImageDraw
def connected_components(edges):
"""
Given a graph represented by edges (i.e. pairs of nodes), generate its
connected components as sets of nodes.
Time complexity is linear with respect to the number of edges.
"""
neighbors = defaultdict(set)
for a, b in edges:
neighbors[a].add(b)
neighbors[b].add(a)
seen = set()
def component(node, neighbors=neighbors, seen=seen, see=seen.add):
unseen = set([node])
next_unseen = unseen.pop
while unseen:
node = next_unseen()
see(node)
unseen |= neighbors[node] - seen
yield node
return (set(component(node)) for node in neighbors if node not in seen)
def matching_pixels(image, test):
"""
Generate all pixel coordinates where pixel satisfies test.
"""
width, height = image.size
pixels = image.load()
for x in xrange(width):
for y in xrange(height):
if test(pixels[x, y]):
yield x, y
def make_edges(coordinates):
"""
Generate all pairs of neighboring pixel coordinates.
"""
coordinates = set(coordinates)
for x, y in coordinates:
if (x - 1, y - 1) in coordinates:
yield (x, y), (x - 1, y - 1)
if (x, y - 1) in coordinates:
yield (x, y), (x, y - 1)
if (x + 1, y - 1) in coordinates:
yield (x, y), (x + 1, y - 1)
if (x - 1, y) in coordinates:
yield (x, y), (x - 1, y)
yield (x, y), (x, y)
def boundingbox(coordinates):
"""
Return the bounding box of all coordinates.
"""
xs, ys = zip(*coordinates)
return min(xs), min(ys), max(xs), max(ys)
def disjoint_areas(image, test):
"""
Return the bounding boxes of all non-consecutive areas
who's pixels satisfy test.
"""
for each in connected_components(make_edges(matching_pixels(image, test))):
yield boundingbox(each)
def is_black_enough(pixel):
r, g, b = pixel
return r < 10 and g < 10 and b < 10
if __name__ == '__main__':
image = Image.open('some_image.jpg')
draw = ImageDraw.Draw(image)
for rect in disjoint_areas(image, is_black_enough):
draw.rectangle(rect, outline=(255, 0, 0))
image.show()
Try using opencv with Python.
With opencv you can make advanced image analysis and there are many tutorials to use it.
http://www.pyimagesearch.com/2014/04/21/building-pokedex-python-finding-game-boy-screen-step-4-6/

Resources