Syllabus 20091117
On this day Megan was in the HotSeat, we visited Python's IF-THEN statement, and talked a little about how to smooth out those noisy live data sources.
IF-THEN Minimalist VJ
Code that responds to z, x, c and the i key!
In the code you see the following inside the "Event handling" code:
red = event.type == pygame.KEYDOWN
This assigns to the variable ("red" in this case), a True or False value reflecting "is the type of the current event a "KEYDOWN" -- so that means when it's key is pressed (KEYDOWN) red with get set to True, and when it's released (KEYUP), it will get set to False.
The full code:
import pygame, sys
pygame.init()
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
(red, green, blue) = (False, False, False)
square = False
while True:
# 1. PROCESS EVENTS
for event in pygame.event.get():
if event.type==pygame.QUIT or \
(event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
sys.exit()
elif event.type == pygame.KEYDOWN and event.key == pygame.K_f:
# http://www.pygame.org/docs/ref/display.html#pygame.display.toggle_fullscreen
pygame.display.toggle_fullscreen()
elif event.type == pygame.KEYDOWN or event.type == pygame.KEYUP:
if event.key == pygame.K_z:
red = event.type == pygame.KEYDOWN
if event.key == pygame.K_x:
green = event.type == pygame.KEYDOWN
if event.key == pygame.K_c:
blue = event.type == pygame.KEYDOWN
if event.key == pygame.K_i:
square = event.type == pygame.KEYDOWN
# 2. DRAW THE SCREEN!
if red:
a = 255
else:
a = 0
if green:
b = 255
else:
b = 0
if blue:
c = 255
else:
c = 0
screen.fill((a, b, c))
if square:
pygame.draw.rect(screen, (0, 0, 0), (100, 100, 640-200, 480-200))
pygame.display.update()
clock.tick(30)
Smoothing Live Data
To start consider this very simple version, the rectangle (which gets drawn at position rx & ry), just jumps straight to the mouse (it looks at the difference in position between it and the mouse, and adds the full amount). This is just a slightly indirect way of directly setting the position, as in:
rx = mx
By saying:
rx = rx + (mx - rx)
or more compactly using the plus-equals operator:
rx += (mx-rx)
import pygame, sys
pygame.init()
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
(rx, ry) = (0, 0)
while True:
# PROCESS EVENTS
for event in pygame.event.get():
if event.type==pygame.QUIT or \
(event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
sys.exit()
elif event.type == pygame.KEYDOWN and event.key == pygame.K_f:
# http://www.pygame.org/docs/ref/display.html#pygame.display.toggle_fullscreen
pygame.display.toggle_fullscreen()
mx, my = pygame.mouse.get_pos()
# direct mapping
rx += (mx - rx)
ry += (my - ry)
screen.fill((0, 0, 0))
pygame.draw.rect(screen, (0, 0, 255), (rx, ry, 60, 60))
pygame.display.update()
clock.tick(30)
Now, to introduce a "chase" behavior, it's simple a question of only going part of the way. So instead of adding the full difference, we add a fraction of it -- in this case a quarter (0.25):
import pygame, sys
pygame.init()
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
(rx, ry) = (0, 0)
while True:
# PROCESS EVENTS
for event in pygame.event.get():
if event.type==pygame.QUIT or \
(event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
sys.exit()
elif event.type == pygame.KEYDOWN and event.key == pygame.K_f:
# http://www.pygame.org/docs/ref/display.html#pygame.display.toggle_fullscreen
pygame.display.toggle_fullscreen()
mx, my = pygame.mouse.get_pos()
# dampened feedback
rx += 0.25 * (mx - rx)
ry += 0.25 * (my - ry)
screen.fill((0, 0, 0))
pygame.draw.rect(screen, (0, 0, 255), (rx, ry, 60, 60))
pygame.display.update()
clock.tick(30)
Finally, we can add a bit of "momentum" by mixing in the previous dx/dy value: A subtle point in this code, by defining dx (and then adding it in the next step), this allows the right-hand side of the assignment to make use of dx's current (that is, the value it had in the last frame, and before we change it).
dx = (0.9 * dx) + (0.25 * (mx - rx))
rx += dx
The following does the same thing but is maybe easier to read:
old_dx = dx
dx = (mx - rx)
rx += (0.9 * old_dx) + (0.25 * dx)
By playing with the number ("slider") applied to old_dx (0.9 in this case), you can change how "heavy" the object is (by making it use more or less of it's old movement value).
import pygame, sys
pygame.init()
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
(rx, ry) = (0, 0)
(dx, dy) = (0, 0)
while True:
# PROCESS EVENTS
for event in pygame.event.get():
if event.type==pygame.QUIT or \
(event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
sys.exit()
elif event.type == pygame.KEYDOWN and event.key == pygame.K_f:
# http://www.pygame.org/docs/ref/display.html#pygame.display.toggle_fullscreen
pygame.display.toggle_fullscreen()
mx, my = pygame.mouse.get_pos()
# WITH "HISTORY"
dx = (0.9 * dx) + (0.25 * (mx - rx))
rx += dx
dy = (0.9 * dy) + (0.25 * (my - ry))
ry += dy
screen.fill((0, 0, 0))
pygame.draw.rect(screen, (0, 0, 255), (rx, ry, 60, 60))
pygame.display.update()
clock.tick(30)
daemon off
quiet on
# You may very well need to change this (check with 'dmesg'
# after plugging in your webcam).
videodevice /dev/video1
# Image size in pixels (valid range is camera dependent).
width 352
height 288
# width 640
# height 480
framerate 5
quality 85
auto_brightness off
# General threshold level and noise threshold
# level (for distinguishing between noise and motion).
threshold 4500
noise_level 64
# Initial brightness, contrast, hue (NTSC), and saturation.
# 0 = disabled (valid range 0-255).
brightness 0
contrast 0
saturation 0
hue 0
# Encode movies in real-time (install ffmpeg before enabling).
ffmpeg_cap_new off
# Codec to be used by ffmpeg for the video compression.
# Supported formats: mpeg4, msmpeg4.
ffmpeg_video_codec msmpeg4
# Target base directory for pictures and films (you may need
# to change this (or change its permissions) depending on
# which system user runs motion).
# target_dir /var/lib/motion/snapshots
target_dir images
output_motion off
output_normal on
#locate on
# on_motion_detected echo motion %K %L %i %J %D
# on_picture_save echo image %K %L %i %J %D
on_picture_save echo image %K %L %i %J %D %f
# FROM THE MOTION DOCS:
# %i Width of the rectangle containing the motion pixels (the rectangle that is shown on the image when locate is on).
# %J Height of the rectangle containing the motion pixels (the rectangle that is shown on the image when locate is on).
# %K X coordinate in pixels of the center point of motion. Origin is upper left corner.
# %L Y coordinate in pixels of the center point of motion. Origin is upper left corner and number is positive moving downwards (I may change this soon).
# %D Number of pixels detected as Motion. If labelling is enabled the number is the number of pixels in the largest labelled motion area.