ChameleonPi - Camouflage your Pi using a camera and LedBorg

Cameras and image processing can be really fun, but where do you get started?
How about getting your Raspberry Pi to blend in with it's surroundings using an LedBorg!

What we need is a simple cycle of events to do this:
  1. Take a photo using the camera
  2. Load the image data into our program
  3. Crop the image so we focus on the center of our view
  4. Average the remaining pixels into a single pixel
  5. To cope with lighting changes, brighten the pixel up so one of red, green, or blue is fully on
  6. Convert the pixel colour into an LedBorg code
  7. Set the LedBorg to the calculated code
The crop will be like this:
with the green square being the region we analyse.
Sounds complicated, but we will use Python's image library PIL to do the heavy lifting for the most part.
You can download ChameleonPi.py as text here.
Save it on your Raspberry Pi as ChameleonPi.py
Make it executable using
chmod +x ChameleonPi.py
and run it using
./ChameleonPi.py
#!/usr/bin/env python
# coding: latin-1

# Import library functions we need
import time
import os
import threading
from PIL import Image

# Setup for ChameleonPi
imageFile = '/tmp/chameleon-image.jpg'              # Image file to read in for processing
imageCommand = 'raspistill -t 0 -o ' + imageFile    # Command used to create image file
interval = 1                                        # Seconds to wait between updates

# Set the LedBorg colour by LedBorg code
def SetColour(colour):
    LedBorg=open('/dev/ledborg','w')
    LedBorg.write(colour)
    LedBorg.close()

# Convert a single 0-255 channel into an LedBorg 0-2 code
def ChannelToCode(c):
    if c < 85:
        return '0'
    elif c < 171:
        return '1'
    else:
        return '2'

# Set the LedBorg colour by 0-255 RGB values
def SetRgb(r, g, b):
    ledCode = ChannelToCode(r) + ChannelToCode(g) + ChannelToCode(b)
    SetColour(ledCode)

# Class for the user interaction thread
class WaitForUser(threading.Thread):
    # The code which will be run when the thread is started
    def run(self):
        global waiting
        # Wait for the user to press enter
        tempString = raw_input()
        # Set the running flag and finish
        print 'Please wait...'
        waiting = False

# Setup status flags
global waiting
waiting = True

try:
    # Setup a thread to wait for user input
    print 'Press ENTER to end the program'
    WaitForUser().start()
    # Run until interrupted
    while waiting:
        # Call the external command to generate a photo
        os.system(imageCommand)
        # Read in the photo
        photo = Image.open(imageFile)
        # Crop out the center section
        width, height = photo.size
        x1 = int(width * 0.4)
        x2 = int(width * 0.6)
        y1 = int(height * 0.4)
        y2 = int(height * 0.6)
        cropPhoto = photo.crop((x1, y1, x2, y2))
        # Average the cropped image down to a single colour
        tinyPhoto = cropPhoto.resize((1,1), Image.ANTIALIAS)
        r, g, b = tinyPhoto.getpixel((0,0))
        # Scale RGB such that the highest channel is fully on
        scale = 255.0 / max(r, g, b)
        r *= scale
        g *= scale
        b *= scale
        # set the LedBorg colour
        SetRgb(r, g, b)
        # Wait a while
        if waiting:
            time.sleep(interval)
    print 'All done :)'
    SetColour('000')
except KeyboardInterrupt:
    # CTRL+C exit, turn off the LedBorg
    print 'Terminated'
    SetColour('000')