So I'm working on a homework assignment regarding using image objects in python. I'm using python 3.4.1 for this assignment. I feel like I have everything done, but it doesn't want to work correctly. Basically, I'm trying to get it to look like the picture that I've attached, but it only shows as 1 red line across, and 1 red line top to bottom on a white background.
Any help would be much appreciated.
The attached image:
http://imgur.com/TMho41w
import cImage as image
width = 500
height = 500
img = image.EmptyImage(width, height)
win = image.ImageWin("Exercise 3", width, height)
img.draw(win)
for row in range(height):
for col in range(width):
p = img.getPixel(col, row)
if row == 0 or col == 0:
p = image.Pixel(255, 0, 0)
else:
Sum = 0
temppixel = img.getPixel(col-1, row)
if temppixel.getRed() == 255:
Sum = Sum + 1
elif temppixel.getBlue() == 255:
Sum = Sum + 2
temppixel = img.getPixel(col-1, row-1)
if temppixel.getRed() == 255:
Sum = Sum + 1
elif temppixel.getBlue() == 255:
Sum = Sum + 2
temppixel = img.getPixel(col, row-1)
if temppixel.getRed() == 255:
Sum = Sum + 1
elif temppixel.getBlue() == 255:
Sum = Sum + 2
if Sum % 3 == 1:
p = image.Pixel(255, 0, 0)
elif Sum % 3 == 2:
p = image.Pixel(0, 0, 255)
else:
p = image.Pixel(255, 255, 255)
img.setPixel(col, row, p)
img.draw(win)
img.draw(win)
# uncomment this to save the image as a file
#img.saveTk("gradient.gif")
win.exitonclick()
Unfortunately, your code does exactly what you have written it to do. Let's name the three first if ... elif condition1, 2 and 3 :
The first pixel is set to red
Then we progress through the first line, so row = 0 which means condition 2 and 3 are using invalid coordinates (because of row-1). So there's only condition at play here, and it will always increment by 1 sum which means it'll add a new red pixel.
So you have now your first red line.
For the first column, starting from the second line : conditions 1 & 2 are using invalid coordinates. Condition 3 will always return sum = 1 which means a new red pixel. And you have your red line from top to bottom
And then from row = 1 and col = 1, all neighbors are red, which leads to a new white pixel. Unfortunately, white does contain some red, so it'll always be the sames conditions that are met, and you have your white background.
I haven't been able to find the complete algorithm for this method to build a Sierpinski carpet, so I can't really correct it. But you should be extra careful with these edges situations : what should be the three neighbors if you are on the first line or first row ?
Related
I am trying to fill the area between multiple shapes. The shapes are concave and one shape is always inside the other. The goal is to convert all pixels between the two shapes to 1 and all others to 0.
The single lines look like this :
My goal is to fill both shapes and then substract them. So that the end result only shows the area where they do not overlap.
Like this :
However as you can see the result is not very accurate and this example is one of the good images.
I think the problem is my code to fill the shapes.
Code :
def line_to_area(mask):
derivative = np.diff(mask)
states = ["firstorlast","apart","touching"]
for idx_row, row in enumerate(derivative):
toggle = False
counter = 0
state = states[1]
awareness = collections.Counter(row)[1.0]
if awareness % 2 != 0 and awareness >= 3:
state = states[2]
elif awareness % 2 != 0 and awareness ==1:
state = states[0]
for idx_pixel, pixel in enumerate(row):
if state == "firstorlast":
break
elif state == "touching" and counter == (awareness-1):
break
if pixel == 0 and toggle == False:
continue
elif pixel == 1 and toggle == False:
toggle = True
counter = counter + 1
elif pixel == 0 and toggle == True:
mask[(idx_row, idx_pixel)] = 1
elif pixel == 1 and toggle == True:
mask[(idx_row, idx_pixel)] = 1
toggle = False
return mask
The input to the function is a 2dim numpy array with the shape (208,208).
The idea is to go through every row of the array and use the slope to define the points where the pixel value needs to be changed.
However this does not work accurate since there are to many unpredictable scenarios.
The mask also exists in this format which is basically where i received the information from in this case all lines are in one array:
I have 3 columns: balls, black, white. balls is all entries in the df. black is boolean (1 for black and 0 for not), and white is also boolean (1 and 0).
I would like to create a column using:
if Black then B
if white then W
else B
I think this might answer your question:
import random
import numpy as np
import pandas as pd
# create balls
balls = []
N = 100 # user to edit
for i in range(N):
colour = ''
if np.random.random() > 0.5:
colour = 'B'
else:
colour = 'W'
balls.append(colour)
# create dataframe
df = pd.DataFrame({'balls': balls})
# add black column
df['black'] = df['balls'].apply(lambda x: 1 if x == 'B' else 0)
# add white column
df['white'] = df['balls'].apply(lambda x: 1 if x == 'W' else 0)
This results in a dataframe with 3 columns - 'balls' containing the colour, 'black' containing 1 if the ball is black otherwise 0, and 'white' which is 1 if the ball is white otherwise 0
I've trying to implement transition from an amount of space to another which is similar to acceleration and deceleration, except i failed and the only thing that i got from this was this infinite stack of mess, here is a screenshot showing this in action:
you can see a very black circle here, which are in reality something like 100 or 200 circles stacked on top of each other
and i reached this result using this piece of code:
def Place_circles(curve, circle_space, cs, draw=True, screen=None):
curve_acceleration = []
if type(curve) == tuple:
curve_acceleration = curve[1][0]
curve_intensity = curve[1][1]
curve = curve[0]
#print(curve_intensity)
#print(curve_acceleration)
Circle_list = []
idx = [0,0]
for c in reversed(range(0,len(curve))):
for p in reversed(range(0,len(curve[c]))):
user_dist = circle_space[curve_intensity[c]] + curve_acceleration[c] * p
dist = math.sqrt(math.pow(curve[c][p][0] - curve[idx[0]][idx[1]][0],2)+math.pow(curve [c][p][1] - curve[idx[0]][idx[1]][1],2))
if dist > user_dist:
idx = [c,p]
Circle_list.append(circles.circles(round(curve[c][p][0]), round(curve[c][p][1]), cs, draw, screen))
This place circles depending on the intensity (a number between 0 and 2, random) of the current curve, which equal to an amount of space (let's say between 20 and 30 here, 20 being index 0, 30 being index 2 and a number between these 2 being index 1).
This create the stack you see above and isn't what i want, i also came to the conclusion that i cannot use acceleration since the amount of time to move between 2 points depend on the amount of circles i need to click on, knowing that there are multiple circles between each points, but not being able to determine how many lead to me being unable to the the classic acceleration formula.
So I'm running out of options here and ideas on how to transition from an amount of space to another.
any idea?
PS: i scrapped the idea above and switched back to my master branch but the code for this is still available in the branch i created here https://github.com/Mrcubix/Osu-StreamGenerator/tree/acceleration .
So now I'm back with my normal code that don't possess acceleration or deceleration.
TL:DR i can't use acceleration since i don't know the amount of circles that are going to be placed between the 2 points and make the time of travel vary (i need for exemple to click circles at 180 bpm of one circle every 0.333s) so I'm looking for another way to generate gradually changing space.
First, i took my function that was generating the intensity for each curves in [0 ; 2]
Then i scrapped the acceleration formula as it's unusable.
Now i'm using a basic algorithm to determine the maximum amount of circles i can place on a curve.
Now the way my script work is the following:
i first generate a stream (multiple circles that need to be clicked at high bpm)
this way i obtain the length of each curves (or segments) of the polyline.
i generate an intensity for each curve using the following function:
def generate_intensity(Circle_list: list = None, circle_space: int = None, Args: list = None):
curve_intensity = []
if not Args or Args[0] == "NewProfile":
prompt = True
while prompt:
max_duration_intensity = input("Choose the maximum amount of curve the change in intensity will occur for: ")
if max_duration_intensity.isdigit():
max_duration_intensity = int(max_duration_intensity)
prompt = False
prompt = True
while prompt:
intensity_change_odds = input("Choose the odds of occurence for changes in intensity (1-100): ")
if intensity_change_odds.isdigit():
intensity_change_odds = int(intensity_change_odds)
if 0 < intensity_change_odds <= 100:
prompt = False
prompt = True
while prompt:
min_intensity = input("Choose the lowest amount of spacing a circle will have: ")
if min_intensity.isdigit():
min_intensity = float(min_intensity)
if min_intensity < circle_space:
prompt = False
prompt = True
while prompt:
max_intensity = input("Choose the highest amount of spacing a circle will have: ")
if max_intensity.isdigit():
max_intensity = float(max_intensity)
if max_intensity > circle_space:
prompt = False
prompt = True
if Args:
if Args[0] == "NewProfile":
return [max_duration_intensity, intensity_change_odds, min_intensity, max_intensity]
elif Args[0] == "GenMap":
max_duration_intensity = Args[1]
intensity_change_odds = Args[2]
min_intensity = Args[3]
max_intensity = Args[4]
circle_space = ([min_intensity, circle_space, max_intensity] if not Args else [Args[0][3],circle_space,Args[0][4]])
count = 0
for idx, i in enumerate(Circle_list):
if idx == len(Circle_list) - 1:
if random.randint(0,100) < intensity_change_odds:
if random.randint(0,100) > 50:
curve_intensity.append(2)
else:
curve_intensity.append(0)
else:
curve_intensity.append(1)
if random.randint(0,100) < intensity_change_odds:
if random.randint(0,100) > 50:
curve_intensity.append(2)
count += 1
else:
curve_intensity.append(0)
count += 1
else:
if curve_intensity:
if curve_intensity[-1] == 2 and not count+1 > max_duration_intensity:
curve_intensity.append(2)
count += 1
continue
elif curve_intensity[-1] == 0 and not count+1 > max_duration_intensity:
curve_intensity.append(0)
count += 1
continue
elif count+1 > 2:
curve_intensity.append(1)
count = 0
continue
else:
curve_intensity.append(1)
else:
curve_intensity.append(1)
curve_intensity.reverse()
if curve_intensity.count(curve_intensity[0]) == len(curve_intensity):
print("Intensity didn't change")
return circle_space[1]
print("\n")
return [circle_space, curve_intensity]
with this, i obtain 2 list, one with the spacing i specified, and the second one is the list of randomly generated intensity.
from there i call another function taking into argument the polyline, the previously specified spacings and the generated intensity:
def acceleration_algorithm(polyline, circle_space, curve_intensity):
new_circle_spacing = []
for idx in range(len(polyline)): #repeat 4 times
spacing = []
Length = 0
best_spacing = 0
for p_idx in range(len(polyline[idx])-1): #repeat 1000 times / p_idx in [0 ; 1000]
# Create multiple list containing spacing going from circle_space[curve_intensity[idx-1]] to circle_space[curve_intensity[idx]]
spacing.append(np.linspace(circle_space[curve_intensity[idx]],circle_space[curve_intensity[idx+1]], p_idx).tolist())
# Sum distance to find length of curve
Length += abs(math.sqrt((polyline[idx][p_idx+1][0] - polyline[idx][p_idx][0]) ** 2 + (polyline [idx][p_idx+1][1] - polyline[idx][p_idx][1]) ** 2))
for s in range(len(spacing)): # probably has 1000 list in 1 list
length_left = Length # Make sure to reset length for each iteration
for dist in spacing[s]: # substract the specified int in spacing[s]
length_left -= dist
if length_left > 0:
best_spacing = s
else: # Since length < 0, use previous working index (best_spacing), could also jsut do `s-1`
if spacing[best_spacing] == []:
new_circle_spacing.append([circle_space[1]])
continue
new_circle_spacing.append(spacing[best_spacing])
break
return new_circle_spacing
with this, i obtain a list with the space between each circles that are going to be placed,
from there, i can Call Place_circles() again, and obtain the new stream:
def Place_circles(polyline, circle_space, cs, DoDrawCircle=True, surface=None):
Circle_list = []
curve = []
next_circle_space = None
dist = 0
for c in reversed(range(0, len(polyline))):
curve = []
if type(circle_space) == list:
iter_circle_space = iter(circle_space[c])
next_circle_space = next(iter_circle_space, circle_space[c][-1])
for p in reversed(range(len(polyline[c])-1)):
dist += math.sqrt((polyline[c][p+1][0] - polyline[c][p][0]) ** 2 + (polyline [c][p+1][1] - polyline[c][p][1]) ** 2)
if dist > (circle_space if type(circle_space) == int else next_circle_space):
dist = 0
curve.append(circles.circles(round(polyline[c][p][0]), round(polyline[c][p][1]), cs, DoDrawCircle, surface))
if type(circle_space) == list:
next_circle_space = next(iter_circle_space, circle_space[c][-1])
Circle_list.append(curve)
return Circle_list
the result is a stream with varying space between circles (so accelerating or decelerating), the only issue left to be fixed is pygame not updating the screen with the new set of circle after i call Place_circles(), but that's an issue i'm either going to try to fix myself or ask in another post
the final code for this feature can be found on my repo : https://github.com/Mrcubix/Osu-StreamGenerator/tree/Acceleration_v02
I've just started with pythons Turtle graphics module, and I'm running into an issue not with Turtle itself I don't think, but my algorithm styling. I'm using the window.colormode(255) which is awesome and working great when I iterate from red to blue in my program, incrementing the blue variable and decrementing the red variable once every loop.
I'm running into a problem with my filter that should reverse the order of the color incrementor/decrementor (i want to go from blue back to red once r = 0 and b = 255):
Here's the code to draw:
counter = 1
firstlength = 1
secondlength = 1
thirdlength = 1
fourthlength = 1
fifthlength = 1
colorList = [255,0,0] # r g b
f = 0 # index for colorlist
for i in listOfTurtles:
i = turtle.Turtle()
i.pencolor(colorList[0], colorList[1], colorList[2])
i.speed(0) # no turn animations
i.left(counter)
i.forward(firstlength)
i.left(15)
i.forward(secondlength)
i.left(15)
i.forward(thirdlength)
i.left(15)
i.forward(fourthlength)
i.left(15)
i.forward(fifthlength)
counter += 1
firstlength += .1
secondlength += .11
thirdlength += .12
fourthlength += .13
fifthlength += .14
Here's the problem with iterating through the pen color (using an answer below):
blueUp = True
if blueUp == True:
colorList[0] -= 1
colorList[2] += 1
if colorList[0] <= 1:
blueUp = False
else:
colorList[0] += 1
colorList[2] -= 1
if colorList[2] <= 0:
blueUp = True
however, this filter I've set up isn't flipping the color incrementor/decrementor when it needs to; thus resulting in a "bad color sequence error: (-1, 0, 256)
So I know its incrementing my blue 1 digit too high, and my red one too low on the first pass and then erroring out, but I'm unsure how to fix it. I've played with the > values and made them higher (to catch around 5 or 250) but I'm not getting results.
I'm totally open to a completely different way to write this, as I'm sure I've thought up the worst possible way to solve this issue.
For starters, you should probably change this:
if blueUp == False:
if colorsList[2] > 0:
to this:
if blueUp == False:
if colorList[2] > 1:
I'm an idiot. My bool variable was local to my outer for statement, the one iterating through my i's. every loop it would reset the value of blueUp and force the index down again by 1. Resolved the issue by moving my bool outside my outer for loop.
So i've got an image in input an i transformed it into an array. There is two ball, and i want to remove one ball.
My idea is to run through a loop, and detect line by line if there is a red pixel. And if in this array at an i, and there is not red pixel in i+1 it erase the entire rest of the line.
for i in range(0, len(data)):
h = h + 1
#print("0"),
if (i>1) and (((data[i - 1])[1] > 40 and (data[i - 1])[2] > 40 ) and ((data[i + 1])[1] > 40 and (data[i+1])[2])):
print("_"),
elif (data[i])[1] < 40 and (data[i])[2] < 40 and (data[i])[0] > 50 :
j = j + 1
print "#" ,
else :
print("."),
#else :
# print data[i],
if h == 64 :
h = 0
test = True
print("\n")
What is wrong with my code and how can i erase a ball through my method ?
If you just want to delete anything on the left side:
data[:,:data.shape[1]/2] = 0
or right side:
data[:,data.shape[1]/2:] = 0
If your problem is that you have balls (red, green and blue) in an array (numpy) and there's no background or noise. For simplicity, if the color of red = 1, green = 2 and blue = 3 then:
data[np.where(data == 1)] = 0
will remove the red ball. For more sophisticated detection-needs you can use below...
You can use label from scipy.ndimage given that your data is an np-array by simply saying (of course if your balls get too overlapped they may not be separated):
from scipy.ndimage import label
labled_data, labels = label(data)
#If you want to remove the first ball
labled_data[np.where(labled_data == 1)] = 0
#Then your second ball will be where the labled data is 2
#Else if you just temporary want to know where the second ball is:
labled_data == 2
#Will be true for those places