Personal tools
You are here: Home Mediatechnology Courses Embodied Vision Values of White
Document Actions

Values of White

by Joris Slob last modified 2007-05-26 21:11

This piece shows how virtual ants try to 'clean' their chaotic world and turn it into purer colours (in terms of RGB).

Click here to get the file

Size 10.7 kB - File type text/python-source

File 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.
"""
« September 2010 »
Su Mo Tu We Th Fr Sa
1234
567891011
12131415161718
19202122232425
2627282930
 

Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: