the endeavor is to draw clusters of rects [bubbles] moving up the screen at varying rates of speed. i've hit a roadblock when it comes to rendering the moving rects.
the way i've gone about it thus far is to populate a list with class instances of my Bubble class. from there i've iterated through the list of instances and called their blow_bubble method, effectively drawing each bubble at a different location on the screen and initializing each with its own value for its speed of movement. these bubbles are then appended to a separate list entitled "drawn", to signify that they have indeed been drawn (though not rendered).
the next part is where it gets bumpy.
i have a while loop that accepts the length of the drawn list being greater than zero as its condition for running. as per the form in this article: http://programarcadegames.com/index.php?chapter=introduction_to_animation
the screen surface is set to fill at the beginning of the loop and at the end of it i've updated the screen surface via pygame.display.flip(). in the middle of the while loop i'm iterating through class instances in the drawn list and decrementing the attribute that represents their y value by the instance's attributed rate of movement.
somehow this doesn't work.
i've checked to make sure the y value is actually decrementing; in a print statement the output is what would be expected: the y value descends into the negative numbers. yet the rects remain drawn statically.
as always, any insights are greatly appreciated.
#colors, screen, clock, etc defined above but omitted
pygame.init()
class Bubble():
def __init__(self, screenheight, screenwidth):
self.w = self.h = 0
self.x, self.y = 0, 0
self.moverate = 0
def reset_bubble(self):
self.w = self.h = random.randrange(2, int(screenwidth*1/4))
self.x = random.randrange(0, (screenwidth-self.w))
self.y = screenheight-self.w
self.moverate = 1
def blow_bubble(self):
self.reset_bubble()
pygame.draw.rect(screen, WHITE, (self.x, self.y, self.w, self.h), 10)
bubbles = []
drawn = []
i = 0
for i in range(10): #creates list of bubble objects
bubble = Bubble(screenheight, screenwidth)
bubbles.append(bubble)
for i in range(len(bubbles)): #draws bubbles without rendering them
bubbles[i].blow_bubble()
drawn.append(bubbles[i]) #appends objects to a new list (drawn)
while len(drawn) > 0:
screen.fill((BLACK))
drawn[i].y -= drawn[i].moverate #moves the bubble up the screen
pygame.display.flip() #updates the screen
if i >= 0: #counts up til len(drawn) then counts down [then up again]
i+=1 #to make sure we move every bubble a little each iteration
if i ==len(drawn):
i-= 1
clock.tick(FPS)
pygame.quit()
Unless I'm very much mistaken about how pygame works, you've misunderstood how it works. For oygamr to work it needs a 'render loop', a loop of code in which you repeatedly move the object, draw it with something like pygame.draw.rect, and then flip the display with pygame.display.flip. You keep doing this until you're done animating.
So, you need to make a bunch of changes.
your 'blow bubble' function needs to not reset the position of the bubble, just increment its position and call pygame.draw.rect
you don't need a 'dawn' list, just the first bubble list. Inside your while loop, you need to iterate through the bubble list calling 'blow bubble' on each.
you need to move the 'pygame.display.flip' inside the while loop, but after all the bubbles have been blown.
Your index out of range error is because I is not magically reset after the for loop exits, it leaves I as whatever it was when the for loop finished.
Related
I have some data that was acquired from an individual that moved a cursor from one target that was presented on a screen to another straight-ahead target that was 10 centimeters away from the original start position. I have 15 movements from this person. The data I have is the instantaneous x-position x(t) and y-position y(t)of the cursor for each movement. Because the individual did not move the mouse at the exact same speed from one movement to another, the number of samples for each movement is not the same. Below, I am showing the x-positions, y-position, and complete x-y trajectory for all movements. A link to download the data is here as well. Hopefully this gives a sense for the nature of the data. Note that the cursor position always start at the [0,0] point, but don't always exactly end at the [0,10] point.
I am tasked with linearly interpolating the x-positions of the cursor onto a vector of y-positions every 0.05cm in order to align the cursor measurements across movements (that is, I must obtain x(y). I would like to present my code below and get some feedback about whether or not I am doing this correctly:
%% Try interpolating x as a function of y (i.e., transform x(t) to x(y))
%Goal is to linearly interpolated the x-positions of the cursor onto a
%vector of y-positions every 0.05cm to align the hand path measurements
%across movements
clear all;
close all;
home;
%load the data: xpos & ypos
load('pos_data.mat')
%create cell array that will hold interpolated data
x_interp = cell(size(xpos));
y_interp = cell(size(ypos));
%construct grid vector
ypos_grid = [0:0.05:10];
num_interp_samples = length(ypos_grid);
%loop through each movement
for k=1:num_movements
%get data for the current movement
xp = xpos{k};
yp = ypos{k};
%to deal with duplicate samples, I add a very small offset to each
%sample to make them all unique
offset = cumsum([0:length(yp)-1]*1e-16);
yp2 = yp+offset(:);
%interpolate xp wrt yp
x_interp{k} = interp1(yp2, xp, ypos_grid);
%interpolate yp so that it is the same size as x_interp
t = linspace(1,length(yp2),length(yp2));
ti = linspace(1,length(yp2),num_interp_samples);
y_interp{k} = interp1(t, yp2, ti);
end
I think this should be relatively simple, but when I plot the interpolated data, it looks a bit strange to me. See below:
Namely, the trajectories seem to have lost much of its "curvature", which has me worried. Note when plotting the interpolated trajectories, I am simply doing:
figure; hold on;
for k=1:num_movements
plot(x_interp{k}, y_interp{k}, 'color', 'k');
end
xlabel('x-position (cm)');
ylabel('y-position (cm)');
title('Examples of complete trajectories (interpolated data)');
axis equal;
Here are my specific questions:
(1) Am I interpolating correctly?
(2) If the answer to (1) is yes, then am I interpreting the interpolated result correctly? Specifically, why do the shapes of the trajectories appear as they doo (lacking curvature)?
(3) Am I perhaps missing a step where after obtaining x(y), I should re-transform the data back into x(t)?
I have been trying to code a solution for a robot to touch every point on a square or rectangular grid.
So far I have been working on a spiral solution that starts in the lower left and spirals in towards the centre and I have gotten it working and it appears to work on even(square) or uneven(rectangle) grids.
I wondered if the is a more efficient or elegant solution code-wise, than what I have below?
I'm pretty new to coding and I would love some feedback on how this code could be improved or if I'm missing a simpler mathematical solution etc.
e.g.: a 5 x 5 grid and [S] is the starting position spiralling toward position 25
[05][06][07][08][09]
[04][19][20][21][10]
[03][18][25][22][11]
[02][17][24][23][12]
[01][16][15][14][13]
[st]
at the moment my code looks like this and work ok. it does not need to be a spiral, it's just how the code currently works.
function MoveSides(depth, width)
local moving = true
-- first set of instructions are set as variables and are updated after outer grid is touched
local leftSide = depth -- for the first side turtle travels to full depth
local top = width - 1 -- turns and travels full width -1 as it is sitting on the first row
local rightSide = depth -1 -- turns and does same coming back on depth
local bottom = width -2 -- turns and travels width -2 having touched first and last space already
while moving do
for i = 1, leftSide do
turtle.forward() -- move forward one space
end
turtle.turnRight()
for i = 1, top do
turtle.forward()
end
turtle.turnRight()
for i = 1, rightSide do
turtle.forward()
end
turtle.turnRight()
for i = 1, bottom do
turtle.forward()
end
turtle.turnRight()
-- all sides loose 2 as the outers spaces have all been touched to describe next tier of grid.
leftSide = leftSide -2
top = top -2
rightSide = rightSide -2
bottom = bottom -2
if (leftSide <= 0 and top <= 0 and rightSide <= 0 and bottom <= 0) then
moving = false
end
end
end
Any help or constructive critique would be much appreciated.
If you want to touch every point in the grid there is nothing more efficient than to move from point to point, touching each point only once. That's what you're doing.
You can do it in a spiral or row- or column-wise or a mix of those. It does not matter as the number of movements is always the same.
The only difference is where your end point is.
function MoveSides(depth, width)
for i = 1, depth do
turtle.forward() -- move forward one space
end
turtle.turnRight()
if width > 1 then
return MoveSides(width - 1, depth)
end
end
function MoveSides(depth, width)
current = depth
other = width
while current > 1 do
for i = 1, current do
turtle.forward()
end
turtle.turnRight()
helper = current
current = other -1
other = helper
end
end
This solution is basically the same as Egor's recursive algorithm, but without a recurisive call.
i'm trying to code a small grid game, but i'm having trouble with coding piece movements.
I have a small 4x4 rgb pixels grid, initialized as np.zeros(4,4,3), full black. An update method to refresh objects position and free cells, a reset method, and a simple show function that uses cv2 to show the grid from a pixel matrix.
class Grid():
def __init__(self):
self.cells = np.zeros((SIZE, SIZE, 3), dtype=np.uint8)
self.free_cells = []
def update(self, c, l):
self.reset() #clear cells and free cells list
self.cells[c.x][c.y] = COIN_COL #set coin position
for i in range(len(l.coords)): #set L posiion
self.cells[l.coords[i][0]][l.coords[i][1]] = L_COL
for i in range(len(self.cells)): #calculate free cells
for j in range(len(self.cells)):
if np.amax(self.cells[i][j]) == 0:
self.free_cells.append((i, j))
def reset(self):
self.cells = np.zeros((SIZE, SIZE, 3), dtype=np.uint8)
self.free_cells = []
def show(self):
img = Image.fromarray(self.cells, "RGB")
img = img.resize((200,200))
cv2.imshow('img', np.array(img))
cv2.waitKey(0)
on the grid there are 2 pieces, an L-shaped one 3x2, and a coin 1x1.
they both have colors and coordinates
SIZE = 4
COIN_COL = (255,255,255)
L_COL = (0,0,255)
C_COORDS = np.array((0,0), dtype=np.uint8) #coin starting position
L_COORDS = np.array(((1,1),(2,1),(3,1),(3,2)), dtype=np.uint8) #L starting position
class Coin():
def __init__(self, coords):
self.x = coords[0]
self.y = coords[1]
class LShape():
def __init__(self, coords):
self.coords = coords
each piece can rotate, translate and move whenever he wants as long as it stays inside the grid, and does not overlap with other pieces.
moving the coin is straightforward: check empty cells, choose one, update coin coordinates, update grid.
Moving the L, doesn't look that simple. How can i check every possible legal move of such a piece? (there could be more than 1 coin on the grid). i started by calculating the empty cells, so that i have a layout of the free space, and i'm trying to come up with an algorithm to highlight legal moves by first removing isolated free cells (1x1), than removing isolated couples (2x1), and so on, but i got stuck halfway through.
I was also thinking about making a list of every possible position on an empty grid, and removing positions from the list if they require an occupied cell, but that doesn't seems elegant nor optimal.
Any idea on how to approach the problem?
I want to create a program that can count the number of objects in an image. All went smoothly except for the images that have:
objects that have more than 1 color.
overlapping objects.
Following is my program that can only count the number of objects in an image where the object has only 1 color and not overlapped. I use the function bwlabel.
a=imread('Tumpukan Buku2.jpg');
a_citra_keabuan = rgb2gray(a);
threshold = graythresh(a_citra_keabuan);
a_bww = im2bw(a_citra_keabuan,threshold);
a_bw=~a_bww;
[labeled,numObjects]=bwlabel(a_bw);
[m,n]=size(a_bw);
s = regionprops(labeled, 'Centroid');
B = bwboundaries(a_bw);
imshow(a_bw)
hold on
for k = 1:numel(s)
c = s(k).Centroid;
text(c(1), c(2), sprintf('%d', k), ...
'HorizontalAlignment', 'center', ...
'VerticalAlignment', 'middle');
end
for k = 1:length(B)
boundary = B{k};
plot(boundary(:,2), boundary(:,1), 'g', 'LineWidth', 0.2)
end
hold off
Here is the result for an image that has objects in 1 color:
and here is the wrong result for the image with object that has > 1 color and overlapped:
How to solve this problem?
First, you need to clearly define your input data- what types of objects do you want to detect (books, people, any types of objects?), what is the range of environmental conditions (smooth background vs. textured, lighting, perspective).
Then try out various image segmentation techniques and seeing what works for your range of input data. There is no "right" answer - it all depends on your data.
You might also try to incorporate prior information- things that you know when evaluating a scene, that a computer will not know by just evaluating pixels.
For example, maybe all objects are of some minimum size. So your algorithm can filter to only return objects having pixelArea > minArea. Maybe you only expect one objet of each color. So if the color histogram of two detected objects matches to within a given tolerance, consider them to be the same object.
I have n*n grid, where for example n=10. I have to fill it with black and white elements. Every black element has to have one, two or three black neighbors. It is not allowed to contain black elements with four or zero neighbors.
How should I build this kind of grid ?
Edit:
To be more specific, it is two-dimensional array built for example with two for loops:
n = 10
array = [][];
for ( x = 0; x < n; x++ ) {
for ( y = 0; y < n; y++ ) {
array[x][y] = rand(black/white)
}
}
This pseudo code builds somethind like:
And what I expect is:
Obviously, you're trying to generate "black path" shapes on a write grid.
So let's just do it.
Start with a white grid.
Randomly position some turtles on it.
Then, while your grid doesn't meet a proper white/black cell ratio, do the following
Move each turtle one cell in a random direction and paint it black unless doing so break the "no more than three black neighbors" rule.
Maybe this python code could be of some use. Its basic idea is to do some sort of breadth first traversal of the grid, ensuring that the blackened pixels respect the constraint that they have no more than 3 black neighbours. The graph corresponding to the blackened part of the grid is a tree, as your desired result seemed to be.
import Queue
import Image
import numpy as np
import random
#size of the problem
size = 50
#grid initialization
grid = np.zeros((size,size),dtype=np.uint8)
#start at the center
initpos = (size/2,size/2)
#create the propagation queue
qu = Queue.Queue()
#queue the starting point
qu.put((initpos,initpos))
#the starting point is queued
grid[initpos] = 1
#get the neighbouring grid cells from a position
def get_neighbours(pos):
n1 = (pos[0]+1,pos[1] )
n2 = (pos[0] ,pos[1]+1)
n3 = (pos[0]-1,pos[1] )
n4 = (pos[0] ,pos[1]-1)
return [neigh for neigh in [n1,n2,n3,n4]
if neigh[0] > -1 and \
neigh[0]<size and \
neigh[1] > -1 and \
neigh[1]<size \
]
while(not qu.empty()):
#pop a new element from the queue
#pos is its position in the grid
#parent is the position of the cell which propagated this one
(pos,parent) = qu.get()
#get the neighbouring cells
neighbours = get_neighbours(pos)
#legend for grid values
#0 -> nothing
#1 -> stacked
#2 -> black
#3 -> white
#if any neighbouring cell is black, we could join two branches
has_black = False
for neigh in neighbours:
if neigh != parent and grid[neigh] == 2:
has_black = True
break
if has_black:
#blackening this cell means joining branches, abort
grid[pos] = 3
else:
#this cell does not join branches, blacken it
grid[pos] = 2
#select all valid neighbours for propagation
propag_candidates = [n for n in neighbours if n != parent and grid[n] == 0]
#shuffle to avoid deterministic patterns
random.shuffle(propag_candidates)
#propagate the first two neighbours
for neigh in propag_candidates[:2]:
#queue the neighbour
qu.put((neigh,pos))
#mark it as queued
grid[neigh] = 1
#render image
np.putmask(grid,grid!=2,255)
np.putmask(grid,grid<255,0)
im = Image.fromarray(grid)
im.save('data.png')
Here is a result setting size = 50
and another one setting size = 1000
You can also play with the root of the tree.
With the size that you show here, you could easily go for a bit of a brute force implementation.
Write a function that checks if you meet the requirements, simply by iterating through all cells and counting neighbors.
After that, do something like this:
Start out with a white grid.
Then repeatedly:
pick a random cell
If the cell is white:
make it black
call the grid checking routine.
if the grid became invalid:
color it gray to make sure you don't try this one again
do this until you think it took long enough, or there are no more white cells.
then make all gray cells white.
If your grid is large (thousands of pixels), you should probably look for a more efficient algorithm, but for a 10x10 grid this will be calculated in a flash.