pygame random points function - for-loop

im trying to create a function that fill the screen with dots(that will be the points in the game)
the problem is the points created by a for loop and when i run the program the points just move around and wont stay in place.
the code:
def random_points():
point_x = random.randint(0, 900)
point_y = random.randint(0, 500)
rand_color = (random.random(), random.random(), (random.random()))
R = random.randint(1, 4)
for _ in range(1, 5):
pygame.draw.circle(WIN, rand_color, (point_x, point_y), R)

You need to create a list of points before the application loop:
point_list = []
for _ in range(1, 5):
point_x = random.randint(0, 900)
point_y = random.randint(0, 500)
rand_color = (random.random(), random.random(), (random.random()))
R = random.randint(1, 4)
point = (rand_color, (point_x, point_y), R)
point_list.append(point)
Draw the points from the list in the application loop:
run = True
while run:
for event = pygame.event.get():
if event.type == pygame.QUIT:
run = False
WIN.fill(0)
for color, center, rad in point_list:
pygame.draw.circle(WIN, color, center, rad)
pygame.disaply.flip()

Related

Pygame sprite hitboxes don't follow as screen scrolls/zooms

First, the CameraGroup class is attributed to the wonderful youtube channel Clear Code.
Second, the hitboxes will not zoom (mousewheel) or scroll (WASD keys) with the planet icons. Try clicking the planets before zooming or scrolling and you will see the hitbox in action.
Third, as the screen is zoomed out the planets get smaller and the camera window shrinks towards the middle of the screen. Ideally, the camera window should stay the full size of the parent window to allow displaying more planets in the zoomed out state.
Finally, I am eager to learn, so please be brutal. Just drop the two planet icons in the folder with the .py file.
import os
import pygame
from pygame import *
from sys import exit
class CameraGroup(pygame.sprite.Group):
def __init__(self):
super().__init__()
self.display_surf_foreground = pygame.display.get_surface()
# camera offset
self.offset = pygame.math.Vector2()
self.half_w = self.display_surf_foreground.get_size()[0] // 2
self.half_h = self.display_surf_foreground.get_size()[1] // 2
self.scroll_offset = (0, 0)
# box setup
self.camera_borders = {'left': 200, 'right': 200, 'top': 100, 'bottom': 100}
l = self.camera_borders['left']
t = self.camera_borders['top']
w = self.display_surf_foreground.get_size()[0] - (self.camera_borders['left'] + self.camera_borders['right'])
h = self.display_surf_foreground.get_size()[1] - (self.camera_borders['top'] + self.camera_borders['bottom'])
self.camera_rect = pygame.Rect(l, t, w, h)
# camera speed
self.keyboard_speed = 10
# zoom
self.zoom_scale = 1
self.foreground_surf_size = (400, 400)
self.foreground_surf = pygame.Surface(self.foreground_surf_size, pygame.SRCALPHA)
self.foreground_rect = self.foreground_surf.get_rect(center=(self.half_w, self.half_h))
self.foreground_surf_size_vector = pygame.math.Vector2(self.foreground_surf_size)
self.foreground_offset = pygame.math.Vector2()
self.foreground_offset.x = self.foreground_surf_size[0] // 2 - self.half_w
self.foreground_offset.y = self.foreground_surf_size[1] // 2 - self.half_h
# planets and labels
self.planet_surf = pygame.Surface
self.planet_rect = pygame.Rect
def keyboard_control(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_a]:
self.camera_rect.x -= self.keyboard_speed
if keys[pygame.K_d]:
self.camera_rect.x += self.keyboard_speed
if keys[pygame.K_w]:
self.camera_rect.y -= self.keyboard_speed
if keys[pygame.K_s]:
self.camera_rect.y += self.keyboard_speed
self.offset.x = self.camera_rect.left - self.camera_borders['left']
self.offset.y = self.camera_rect.top - self.camera_borders['top']
def zoom_keyboard_control(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_q]:
self.zoom_scale += 0.1
if self.zoom_scale > 2:
self.zoom_scale = 2
if keys[pygame.K_e]:
self.zoom_scale -= 0.1
if self.zoom_scale < .5:
self.zoom_scale = .5
def custom_draw(self, planets):
self.keyboard_control()
self.zoom_keyboard_control()
self.foreground_surf.fill((0, 0, 0, 255))
# active elements
for planet in planets:
self.planet_surf = pygame.image.load(planet.icon).convert_alpha()
offset_coord = planet.coord - self.offset + self.foreground_offset
self.planet_rect = self.planet_surf.get_rect(center=offset_coord)
self.foreground_surf.blit(self.planet_surf, self.planet_rect)
scaled_surf = pygame.transform.scale(self.foreground_surf, self.foreground_surf_size_vector * self.zoom_scale)
scaled_rect = scaled_surf.get_rect(center=(self.half_w, self.half_h))
self.display_surf_foreground.blit(scaled_surf, scaled_rect)
class Game:
def __init__(self):
self.game_over = False
self.game_year = 0
self.game_state = 'splash'
#staticmethod
def activate_planet(screen, planets):
active_planet_coord = None
for planet in planets:
if planet.rect.collidepoint(pygame.mouse.get_pos()):
active_planet_coord = planet.rect.center
return active_planet_coord
return active_planet_coord
#staticmethod
def heartbeat(screen, active_planet_coord):
# global heartbeat_mod
global heartbeat
ticks = pygame.time.get_ticks()
heartbeat_thump = round(ticks / 1000) % 2
if heartbeat_thump == 0:
heartbeat_mod = .1
else:
heartbeat_mod = -.1
heartbeat += heartbeat_mod
if heartbeat < 1:
heartbeat = 1
elif heartbeat > 6:
heartbeat = 6
heartbeat_color = (0, 255, 0)
pygame.draw.circle(screen, heartbeat_color, active_planet_coord, 25 + round(heartbeat), round(heartbeat) + 2)
class Planet(pygame.sprite.Sprite):
def __init__(self, icon, group):
super().__init__(group)
self.icon = icon
self.coord = (0, 0)
self.group = group
self.image = pygame.image.load(self.icon).convert_alpha()
self.rect = self.image.get_rect(center=self.coord)
self.planet_icons = []
self.planet_names = []
#staticmethod
def update_coords(planets, star_coords):
i = 0
for planet in planets:
planet.coord = tuple(star_coords[i])
planet.rect = planet.image.get_rect(center=planet.coord)
i += 1
if i == len(star_coords):
del planets[len(star_coords):]
return planets
def main():
global heartbeat
global heartbeat_mod
pygame.init()
width, height = 400, 400
screen = pygame.display.set_mode((width, height))
pygame.display.init()
pygame.display.update()
active_planet_coord = (-100, -100)
heartbeat = 0
heartbeat_mod = .1
clock = pygame.time.Clock()
game = Game()
camera_group = CameraGroup()
planet_array = os.listdir('./')
planet_array.pop(0) # remove 'camera scroll example.py' file
planet_icons = planet_array
planets = []
for new_planet in range(2):
icon = planet_icons.pop()
planet = Planet(icon, camera_group)
planets.append(planet)
star_coords = [[100, 100], [200, 200]]
planets = planet.update_coords(planets, star_coords)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
pygame.quit()
exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
active_planet_coord = game.activate_planet(screen, camera_group)
if active_planet_coord is None:
active_planet_coord = (-100, -100)
pygame.display.update()
elif event.type == pygame.MOUSEWHEEL:
camera_group.zoom_scale += event.y * 0.1
if camera_group.zoom_scale > 2:
camera_group.zoom_scale = 2
elif camera_group.zoom_scale < .5:
camera_group.zoom_scale = .5
camera_group.update()
camera_group.custom_draw(planets)
game.heartbeat(screen, active_planet_coord)
pygame.display.update()
clock.tick(60)
if __name__ == '__main__':
main()
An alternative way to solve this problem is to "inverse zoom" the mouse position when you use it for click detection:
zoom:
p_zoom = (p - zoom_center) * zoom_scale + zoom_center
inverse zoom:
p = (p_zoom - zoom_center) / zoom_scale + zoom_center
Apply this to your code:
class Game:
# [...]
#staticmethod
def activate_planet(screen, planets):
zoom_scale = planets.zoom_scale
zoom_center = pygame.math.Vector2(screen.get_rect().center)
pos = pygame.math.Vector2(pygame.mouse.get_pos())
pos = (pos - zoom_center) / zoom_scale + zoom_center
active_planet_coord = None
for planet in planets:
if planet.rect.collidepoint(pos):
planet_center = (planet.rect.center - zoom_center) * zoom_scale + zoom_center
active_planet_coord = round(planet_center.x), round(planet_center.y)
return active_planet_coord
return active_planet_coord

how to display results as titles on multiple plots in one image output (python matplotlib)?

What i have done: I am plotting mean values of a distribution of 'v' values on an x-y grid. I choose only those cells in the grid that have mean>2 and I plot them and make them appear as a single image on my console (jupyter notebook).
What I want to do: I want the mean value of each plot to appear as the title of that particular plot in image. Any ideas on how to do that? Thanks!
The full code is:
import matplotlib.pyplot as plt
import numpy as np
x=np.array([11,12,12,13,21,14])
y=np.array([28,5,15,16,12,4])
v=np.array([10,5,2,10,6,7])
x = x // 4
y = y // 4
k=10
cells = [[[] for y in range(k)] for x in range(k)] #creating cells or pixels on x-y plane
#letting v values to fall into the grid cells
for ycell in range(k):
for xcell in range(k):
cells[ycell][xcell] = v[(y == ycell) & (x == xcell)]
for ycell in range(k):
for xcell in range(k):
this = cells[ycell][xcell]
#getting mean from velocity values in each cell
mean_v = [[[] for y in range(k)] for x in range(k)]
to_plot = []
for ycell in range(k):
for xcell in range(k):
cells[ycell][xcell] = v[(y== ycell) & (x== xcell)]
mean_v[ycell][xcell] = np.mean(cells[ycell][xcell])
#h3_pixel=h3[ycell][xcell]
if mean_v[ycell][xcell]>2:
to_plot.append(cells[ycell][xcell])
plt.rcParams["figure.figsize"] = (20, 10)
SIZE = 5
f, ax = plt.subplots(SIZE,SIZE)
for idx, data in enumerate(to_plot):
x = idx % SIZE
y = idx // SIZE
ax[y, x].hist(data)
plt.show()
In your list to_plot, you can hold tuples of (cell, title) and then use set_title to set the title of each subplot.
for ycell in range(k):
for xcell in range(k):
cells[ycell][xcell] = v[(y== ycell) & (x== xcell)]
mean_v[ycell][xcell] = np.mean(cells[ycell][xcell])
if mean_v[ycell][xcell]>2:
to_plot.append((cells[ycell][xcell], mean_v[ycell][xcell]))
plt.rcParams["figure.figsize"] = (20, 10)
SIZE = 5
f, ax = plt.subplots(SIZE,SIZE)
for idx, data in enumerate(to_plot):
x = idx % SIZE
y = idx // SIZE
ax[y, x].hist(data[0])
ax[y, x].set_title(f'Mean = {data[1]}')

Emotion detection using facial landmarks

I plan on using scikit svm for class prediction.
I have been trying this :
Get images from a webcam
Detect Facial Landmarks
Train a machine learning algorithm (we will use a linear SVM)
Predict emotions
I have a problem in this line : clf.fit(npar_train, training_labels)
also I have a problem in site-packages\sklearn\svm_base.py and in site-packages\sklearn\utils\validation.py
How can I remove this error?
thank you in advance
python script
emotions = ['neutral', 'sad', 'happy', 'anger']
data={}
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
clf = SVC(kernel='linear', probability=True, tol=1e-3)
def get_files(emotion):
files = glob.glob('img\\datasets\\%s\\*' %emotion)
random.shuffle(files)
training = files[:int(len(files)*0.8)]
prediction = files[-int(len(files)*0.2)]
return training, prediction
def get_landmarks(image):
detections = detector(image, 1)
for k, d in enumerate(detections): # For all detected face instances individually
shape = predictor(image, d) # Draw Facial Landmarks with the predictor class
xlist = []
ylist = []
for i in range(1, 68): # Store X and Y coordinates in two lists
xlist.append(float(shape.part(i).x))
ylist.append(float(shape.part(i).y))
xmean = np.mean(xlist)
ymean = np.mean(ylist)
xcentral = [(x - xmean) for x in xlist]
ycentral = [(y - ymean) for y in ylist]
landmarks_vectorised = []
for x, y, w, z in zip(xcentral, ycentral, xlist, ylist):
landmarks_vectorised.append(w)
landmarks_vectorised.append(z)
meannp = np.asarray((ymean, xmean))
coornp = np.asarray((z, w))
dist = np.linalg.norm(coornp - meannp)
landmarks_vectorised.append(dist)
landmarks_vectorised.append((math.atan2(y, x) * 360) / (2 * math.pi))
data['landmarks_vectorised'] = landmarks_vectorised
if len(detections) < 1:
data['landmarks_vestorised'] = "error"
def make_sets():
training_data = []
training_labels = []
prediction_data = []
prediction_labels = []
for emotion in emotions:
print("Working on %s emotion" %emotion)
training, prediction = get_files(emotion)
for item in training:
image = cv2.imread(item)
try:
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
except:
print()
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
clahe_image = clahe.apply(image)
get_landmarks(clahe_image)
if data['landmarks_vectorised'] == "error":
print("no face detected on this one")
else:
training_data.append(data['landmarks_vectorised']) # append image array to training data list
training_labels.append(emotions.index(emotion))
for item in prediction:
image = cv2.imread(item)
try:
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
except:
print()
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
clahe_image = clahe.apply(image)
get_landmarks(clahe_image)
if data['landmarks_vectorised'] == "error":
print("no face detected on this one")
else:
prediction_data.append(data['landmarks_vectorised'])
prediction_labels.append(emotions.index(emotion))
return training_data, training_labels, prediction_data, prediction_labels
accur_lin = []
for i in range(0,10):
print("Making sets %s" % i) # Make sets by random sampling 80/20%
training_data, training_labels, prediction_data, prediction_labels = make_sets()
npar_train = np.array(training_data)
npar_trainlabs = np.array(training_labels)
print("training SVM linear %s" % i) # train SVM
clf.fit(npar_train, training_labels)
print("getting accuracies %s" % i)
npar_pred = np.array(prediction_data)
pred_lin = clf.score(npar_pred, prediction_labels)
print("Mean value lin svm: %s" % np.mean(accur_lin))

Multiple function calls for parallel processing inside a loop

I wish to detect an image from my webcam and write the result whether it is moving left or right to a file. To increase the frame rate(because this project involves a lot more processing and might be run on a raspberry pi) I decided to do the file writing part through multiprocessing (which I am new to):
code:
function for multi-processing
def send_cmd(cv):
# ####EXECUTE LOGIC AND CREATE COMMAND###
# writing to file
# just a sample command// change as will
dictionary = {'left': 0, 'right': 0, 'stop': 0}
if cv[0] == 'left':
dictionary['right'] = 1
else:
dictionary['left'] = 1
cmd = '{"left":' + str(dictionary['left']) + ',"right":' + str(dictionary['left'
]) + ',"stop":' + str(dictionary['left']) + '}'
print("command written: " + cmd)
f = open('command.txt', 'w')
f.write(cmd)
f.close()
Main code:
while True:
try:
frame = cv.VideoCapture(0)
frame = imutils.resize(frame, width=400)
if W is None or H is None:
(H, W) = frame.shape[:2]
blob = cv.dnn.blobFromImage(cv.resize(frame, (300, 300)),
0.007843, (300, 300), 127.5)
net.setInput(blob)
detections = net.forward()
rects = []
for i in range(0, detections.shape[2]):
if detections[0, 0, i, 2] > args['confidence']:
box = detections[0, 0, i, 3:7] * np.array([W, H, W, H])
rects.append(box.astype('int'))
(startX, startY, endX, endY) = box.astype('int')
cv.rectangle(frame, (startX, startY), (endX, endY), (0,
0xFF, 0), 2)
objects = ct.update(rects)
for (objectID, centroid) in objects.items():
text = 'ID {}'.format(objectID)
cv.putText(
frame,
text,
(centroid[0] - 10, centroid[1] - 10),
cv.FONT_HERSHEY_SIMPLEX,
0.5,
(0, 0xFF, 0),
2,
)
cv.circle(frame, (centroid[0], centroid[1]), 4, (0, 0xFF,
0), -1)
center = (centroid[0], centroid[1])
pts.appendleft(center)
for i in np.arange(1, len(pts)):
if pts[i - 1] is None or pts[i] is None:
continue
if counter >= 10 and i == 1 and pts[-1] is not None:
dX = pts[-1][0] - pts[i][0]
dY = pts[-1][1] - pts[i][1]
global dirX
global dirY
(dirX, dirY) = ('', '')
if np.abs(dX) > 20:
dirX = ('left' if np.sign(dX) == 1 else 'right')
if np.abs(dY) > 20:
dirY = ('up' if np.sign(dY) == 1 else 'down')
#tried multiprocessing with process method but to many process calls at the same time
order = multiprocessing.Process(target = send_cmd,args = ([dirX, dirY]))
order.start()
order.join()
# send_cmd(cv=[dirX, dirY], us=ultra_sonic)
if dirX != '' and dirY != '':
direction = '{}-{}'.format(dirY, dirX)
else:
direction = (dirX if dirX != '' else dirY)
thickness = int(np.sqrt(args['buffer'] / float(i + 1))
* 2.5)
cv.putText(
frame,
direction,
(10, 30),
cv.FONT_HERSHEY_SIMPLEX,
0.65,
(0, 0, 0xFF),
3,
)
cv.putText(
frame,
'dx: {}, dy: {}'.format(dX, dY),
(10, frame.shape[0] - 10),
cv.FONT_HERSHEY_SIMPLEX,
0.35,
(0, 0, 0xFF),
1,
)
cv.imshow('Frame', frame)
key = cv.waitKey(1) & 0xFF
counter += 1
Error:
RuntimeError:
An attempt has been made to start a new process before the
current process has finished its bootstrapping phase.
This probably means that you are not using fork to start your
child processes and you have forgotten to use the proper idiom
in the main module:
if __name__ == '__main__':
freeze_support()
...
The "freeze_support()" line can be omitted if the program
is not going to be frozen to produce an executable.
Can someone guide me?

"Tic Tac Toe" Touch Lua random squares getting filled in?

So I recently purchased the draw library on Touch Lua! I've started trying to make a simple Tic Tac Toe game. I'm using a simple setup they used to detect clicks on the NumPad default program, so the buttons should work.
The problem is that when you tap a square, the O fills into seemingly-random squares, sometimes more than 1, up to 4+ squares may get filled.
I suspect the problem is the function Picked, which sets the title to X/O and then updates the board.
local Turn = nil
local Move = "O"
local Mode = nil
::ModePick::
print("1 player mode? (y/n)")
local plrs = io.read()
if plrs == "y" then
Mode = 1
goto TurnChoice
elseif plrs == "n" then
Mode = 2
goto Game
else
goto ModePick
end
::TurnChoice::
print("Would you like to go first? (Be O) (y/n)")
do
local pick = io.read()
if pick == "y" then
Turn = 1
elseif pick == "n" then
Turn = 2
else
goto TurnChoice
end
end
::Game::
local Buttons = {}
draw.setscreen(1)
draw.settitle("Tic Tac Toe")
draw.clear()
width, height = draw.getport()
function Picked(b)
for i,v in pairs(Buttons) do
if v == b then
b.title = Move
UpdateBoard()
end
end
--Fill in X/O details
--Detect if there's a tic/tac/toe
--Set winning screen
if Move == "O" then
--Compute Move (1 player)
--Move = "X" (2 player)
else
Move = "O"
end
end
function DrawButton(b)
draw.setfont('Helvetica', 50)
draw.setlinestyle(2, 'butt')
local x1, y1 = b.x, b.y
local x2, y2 = x1+b.width, y1+b.height
draw.rect(x1, y1, x2, y2, b.color)
local w, h = draw.stringsize(b.title)
local x = b.x + (b.width - w)/2
local y = b.y + (b.height - h)/2
draw.string(b.title, x, y, draw.black)
return b
end
function Button(x, y, x2, y2, title, color, action)
local action = action or function() end
local button = {x = x, y = y, width = x2, height = y2, color = color, title = title, action = action}
table.insert(Buttons, button)
return button
end
function LookUpButton(x, y)
for i = 1, #Buttons do
local b = Buttons[i]
if x > b.x and x < b.x+b.width and y > b.y and y < b.y+b.height then
return b
end
end
return nil
end
function TouchBegan(x, y)
local b = LookUpButton(x, y)
if b then
b.action(b)
end
end
function TouchMoved(x, y)
end
function TouchEnded(x, y)
end
draw.tracktouches(TouchBegan, TouchMoved, TouchEnded)
function CreateButton(x,y,x2,y2,txt,col,func)
return DrawButton(Button(x, y, x2, y2, txt, col, func))
end
function UpdateBoard()
draw.clear()
for i = 1,3 do
for ii = 1,3 do
CreateButton(100 * (ii - 1) + 7.5, 100 * (i - 1) + 75, 100, 100, Buttons[i + ii].title, draw.blue, Picked)
end
end
end
for i = 1,3 do
for ii = 1,3 do
CreateButton(100 * (ii - 1) + 7.5, 100 * (i - 1) + 75, 100, 100, "", draw.blue, Picked)
end
end
while true do
draw.doevents()
sleep(1)
end
Note: Sorry if the indention came out wrong, I pasted all this code in on my iPod, so I had to manually put in 4 spaces starting each line.
If anybody could help me out with this small setback I have, I'd love the help, if there's anything I'm missing I'd gladly edit it in just reply in the comments :D
EDIT: I've modified some of the code to fix how the table keeps getting new buttons, this is the code I have now, same problem, buttons are added in wrong place (and getting removed now):
function Button(x, y, x2, y2, title, color, action, prev)
local action = action or function() end
local button = {x = x, y = y, width = x2, height = y2, color = color, title = title, action = action}
if prev then
for i,v in pairs(Buttons) do
if v == prev then
table.remove(Buttons, i)
end
end
end
table.insert(Buttons, button)
return button
end
function CreateButton(x,y,x2,y2,txt,col,func, prev)
return DrawButton(Button(x, y, x2, y2, txt, col, func, prev))
end
function UpdateBoard()
draw.clear()
for i = 1,3 do
for ii = 1,3 do
CreateButton(100 * (ii - 1) + 7.5, 100 * (i - 1) + 75, 100, 100, Buttons[i + ii].title, draw.blue, Picked, Buttons[i + ii])
end
end
end
EDIT: Thanks to Etan I've fixed UpdateBoard, squares are still random:
function UpdateBoard()
draw.clear()
local n = 1
for i = 1,3 do
for ii = 1,3 do
CreateButton(100 * (ii - 1) + 7.5, 100 * (i - 1) + 75, 100, 100, Buttons[n].title, draw.blue, Picked, Buttons[n])
n = n + 1
end
end
end
It's been a while since I've got around to post the finished code, but this is what it looks like:
function UpdateBoard(ended)
local ended = ended or false
local Act = nil
if ended == true then
Act = function() end
else
Act = Picked
end
draw.clear()
local Buttons2 = {}
for i,v in pairs(Buttons) do
Buttons2[i] = v
end
Buttons = {}
local n = 1
for i = 1,3 do
for ii = 1,3 do
CreateButton(100 * (ii - 1) + 7.5, 100 * (i - 1) + 75, 100, 100, Buttons2[n].title, draw.blue, Act, Buttons2[n], i, ii)
n = n + 1
end
end
OpenButtons = {}
ClosedButtons = {}
for i,v in pairs(Buttons) do
if v.title == "" then
table.insert(OpenButtons, v)
else
table.insert(ClosedButtons, v)
end
end
end
It may seem a bit complicated for the question, but this is the code after multiple other things.
The main difference you should note here, is that it's recreating the table of buttons, so it does not recount new buttons, and it uses n to count up, instead of using i and ii.

Resources