Values of White
This piece shows how virtual ants try to 'clean' their chaotic world and turn it into purer colours (in terms of RGB).
Size 10.7 kB - File type text/python-sourceFile contents
"""
Values of White
Embodied Vision 2007
a course by Joost Rekveld
Coded by
Joris Slob and Sonja van Kerkhoff
This piece shows how virtual ants try to
'clean' their chaotic world and turn it
into purer colours (in terms of RGB).
NOTE: The webcam library assumes that no other proram is using the webcam.
If another process is using the webcam, you will get a "Webcam failure" in
you output screen. Close the program that is using the webcam and start over.
If you start this program from IDLE and later stop the program, the webcam will
still appear to be locked. Close all pythonw.exe processes and start over.
NOTE: VideoCapture is a Windows only library.
"""
# --- IMPORTS ---
#
# Tkinter - For window management
# random - For the starting position, movement and colour desire of ants
# PIL - For the manipulation of images
# VideoCapture - To get images from a webcam device
from Tkinter import *
from random import randrange
from PIL import Image, ImageTk
from VideoCapture import Device
# --- GLOBAL VARIABLES ---
TIME_DELAY = 1 # Time delay to allow window events to happen (keep minimal)
# Don't put this to 0, it will not redraw the window
POPULATION = 3000 # The amount of ants in the world
THRESHOLD = 150 # Determines the selectiveness of the ants toward the colour
# value
LOSE_SCENT = 255 # Affects the length of the trail. Visually, if you lower this
# number the ants will paint outside of the edges of the input
# colour
DECAY = 1 # This detemines the fade rate of the output pixels
def subtract_or_zero(num, amount):
""" Utility function for lowering a value with the ammount value, but also
makes sure that it doesn't go below 0.
"""
return max(num - amount, 0)
def image_subtract(num):
""" Utility function for lowering the values of all the pixels of an image
by DECAY.
"""
return subtract_or_zero(num, DECAY)
class Ant():
""" This is the ant class. It describes the functionality of a single ant.
Once the ants are initialised they only move one step each time the
move() function is called.
Ants interact only with the input image. They react to the colour of
their 'desire' if it is above a certain THRESHOLD. They paint the pure
colour on the scentimage/outputimage
"""
def __init__(self, image):
""" Initialisation of a single ant. This function is called when a new
ant object is made. Every ant should be given the input image, so
they can determine the limits (image size) of where they can start.
"""
self.size = image.size # Determine the size of the image that the ant
# will live in. The size property is determined
# by the image extracted from the webcam.
self.image = image # Ants store their own copy of the input image to
# extract information out of it.
self.position = [randrange(0, self.size[0]), # Randomly pick a starting
randrange(0, self.size[1])] # position for the ant.
num = randrange(0,3) # Ramdomly allocates a RGB value
if num==0:
self.colour = (THRESHOLD,0,0) # Desire for red
elif num==1:
self.colour = (0,THRESHOLD,0) # Desire for green
else:
self.colour = (0,0,THRESHOLD) # Desire for blue
self.scent = 0 # Ants leave a scent trail after they find their colour.
# This determines the strength of the scent they are
# excreting at the moment.
def move(self, scentimage):
""" This function makes the ant do one move, and has all the logic in
it to react to the input image and to draw on the output image. The
ant will need the output image (= scentimage) to write on.
"""
deltax = randrange(-1,2) # Determines a random direction to move to.
deltay = randrange(-1,2) # This can be in the nine squares in the ants
# vicinity
# Now we have to make sure the ants don't walk off the screen, so we
# use the % operator (modulo) to make sure that they stay within the
# size limits.
newx = (self.position[0] + deltax) % self.size[0]
newy = (self.position[1] + deltay) % self.size[1]
newpos = [newx, newy] # These are the new x, y positions the ant will
# move to
if self.scent > 0: # If the ants have some scent left to excrete...
# first safely decrease it
self.scent = subtract_or_zero(self.scent, LOSE_SCENT)
# The ant will now get the colour from the input image
colour = self.image.getpixel((newpos[0],newpos[1]))
if (colour[0] > self.colour[0] and # Checks if RGB is higher than
colour[1] > self.colour[1] and # self.colour which is their colour
colour[2] > self.colour[2]): # of desire
self.scent = 255 # The ant will excrete the maximum intensity of
# colour
if self.scent > 0: # If the ant is excreting colour
# First we look at the current output pixel
scentpix = scentimage.getpixel((newpos[0],newpos[1]))
scentpix = [scentpix[0],scentpix[1],scentpix[2]] # *(SEE BELOW)
for i in range(3): # Go through the RGB values, ...
if self.colour[i]>0: # and if the ant wants to leave scent ...
scentpix[i] += self.scent # then add it.
# Next, make sure that none of the values go over 255
scentpix = (min(scentpix[0],255),
min(scentpix[1],255),
min(scentpix[2],255))
# Put the result in the output image
scentimage.putpixel((newpos[0],newpos[1]),scentpix)
self.position = newpos # Here the ant gets the new position
return scentimage # Return the scentimage / output
def set_image(self, image):
""" The ant needs updates of the webcam image.
"""
self.image = image
class MyWebcamApp:
""" This class has all the functionality in it for the application to work.
It has the information about the webcam, the ants and the output window
"""
def __init__(self):
""" Initialises the program. First a new window is created. Next the
webcam functionality is set up and tested. Ants will be created and
given random locations and a colour desire. Next the window will be
made ready for output.
"""
self.root = Tk() # Tk does all the work for setting up a window
succeed = False # Variable to check if we have the webcam set up yet
while(not succeed): # As long as we have no webcam set up
try:
self.webcam = Device() # VideoCapture.Device() tries to
# establish a connection with the webcam
self.img = self.webcam.getImage() # Get a frame from the webcam
# We have to convert the frame to a format that Tk can show
# using the ImageTk library
self.imagedata = ImageTk.PhotoImage(self.img)
succeed = True # If all this works, we have succeeded
except:
print "Webcam failure" # Otherwise, show something is wrong
# Ant initialisation
self.myAnts = [] # We begin with a placeholder for the ants
for i in range(POPULATION): # We then fill the placeholder
self.myAnts.append(Ant(self.img)) # With ants which are given the
# current webcam image
""" This is a good place to change code if you want to.
* The first line (which is now commented out) will start
the output as black.
* The second line will start the output image with
the initial input image
"""
# self.scent = Image.new('RGB', self.img.size, (0,0,0))
self.scent = self.img.copy()
# We convert the scent/output image to a format that Tk can show
self.imagedata = ImageTk.PhotoImage(self.scent)
# Here we put the image into a label object, which is just a
# placeholder in your window
self.label = Label(self.root, image=self.imagedata)
# The pack() function tells the window that we have every element ready,
# so it can actually draw the window and fill it.
self.label.pack()
# We need to make sure the program will do allow the ants to do a move
# with each cycle. This call starts the whole cycle.
self.update()
self.root.mainloop() # Allow the window to react to events (such as the
# user pressing the 'close' button)
def redraw(self):
""" Redraw the picture currently displayed
This is done by reconfiguring the label to show the new imagedata
"""
self.label.config(image=self.imagedata)
def update(self):
""" This function handles the real activity of each cycle. At the
end it calls itself to make sure this keeps running.
This function will - get a new webcam image,
- give this new image to the ants
- allow the ants to do their move
- do a redraw of the output of all the ants
"""
# Make sure that the whole scent/output image decays slowly
self.scent = Image.eval(self.scent, image_subtract)
self.img = self.webcam.getImage() # Do a webcam update
for ant in self.myAnts: # This runs through all the ants
ant.set_image(self.img) # Give the image to the ant
self.scent = ant.move(self.scent) # After the ant move update the
# scent / output
# Convert to the Tk format
self.imagedata = ImageTk.PhotoImage(self.scent)
self.redraw()
self.root.after(TIME_DELAY, self.update) # This makes sure the
# program keeps updating
MyApp = MyWebcamApp() # Start the whole thing
""" * About making lists mutable:
getpixel returns the colours as lists ()
In Python lists cannot be altered, so some of the code transforms
lists to sequences [], which can be altered in Python.
"""
Click here to get the file