drive a webcam with python

I bought a USB webcam off of eBay quite some time ago, and I decided to connect it to my telescope with a little bit of hardware hackery. I'll have to see about posting a writeup on how I did that at a later time. Anyway, when I installed my camera software, I quickly found how horrible the program was. It gave a tiny preview of what the camera saw, and had no way of capturing images or video without waaaay too many clicks of the mouse. That's when I decided to write my own in Python.

The main libraries that I ended up using were VideoCapture, PIL, and pygame. As you'll see, it's not really difficult at all to make a useful webcam application.

Here's the code:

PYTHON:
  1. from VideoCapture import Device
  2. import ImageDraw, sys, pygame, time
  3. from pygame.locals import *
  4. from PIL import ImageEnhance
  5.  
  6. res = (640,480)
  7. pygame.init()
  8. cam = Device()
  9. cam.setResolution(res[0],res[1])
  10. screen = pygame.display.set_mode((640,480))
  11. pygame.display.set_caption('Webcam')
  12. pygame.font.init()
  13. font = pygame.font.SysFont("Courier",11)
  14.  
  15. def disp(phrase,loc):
  16.     s = font.render(phrase, True, (200,200,200))
  17.     sh = font.render(phrase, True, (50,50,50))
  18.     screen.blit(sh, (loc[0]+1,loc[1]+1))
  19.     screen.blit(s, loc)
  20.  
  21. brightness = 1.0
  22. contrast = 1.0
  23. shots = 0
  24.  
  25. while 1:
  26.     camshot = ImageEnhance.Brightness(cam.getImage()).enhance(brightness)
  27.     camshot = ImageEnhance.Contrast(camshot).enhance(contrast)
  28.     for event in pygame.event.get():
  29.         if event.type == pygame.QUIT: sys.exit()
  30.     keyinput = pygame.key.get_pressed()
  31.     if keyinput[K_1]: brightness -= .1
  32.     if keyinput[K_2]: brightness += .1
  33.     if keyinput[K_3]: contrast -= .1
  34.     if keyinput[K_4]: contrast += .1
  35.     if keyinput[K_q]: cam.displayCapturePinProperties()
  36.     if keyinput[K_w]: cam.displayCaptureFilterProperties()
  37.     if keyinput[K_s]:
  38.         filename = str(time.time()) + ".jpg"
  39.         cam.saveSnapshot(filename, quality=80, timestamp=0)
  40.         shots += 1
  41.     camshot = pygame.image.frombuffer(camshot.tostring(), res, "RGB")
  42.     screen.blit(camshot, (0,0))
  43.     disp("S:" + str(shots), (10,4))
  44.     disp("B:" + str(brightness), (10,16))
  45.     disp("C:" + str(contrast), (10,28))
  46.     pygame.display.flip()

I decided to use pygame in order to build this because it can actually handle the fps that I need for video. I built something similar quite a while ago with wxPython, but it just wasn't fast enough at image swapping to make it work well.

A couple of noteworthy points:

  • The function on line 15 is simply there to help automate displaying information on the screen. In my case, I display the number of screenshots I've saved to disk, and the current brightness and contrast levels. The function displays the text sent to it by writing it in dark gray, and then re-writing it in light gray over the top with a pixel offset. I found this helps a TON to make the text visible in different scenarios.
  • Line 26 is where I actually apply the contrast and brightness changes. Lines 30-33 set up the number keys 1-4 to adjust contrast/brightness on the fly. This is terribly useful, in my experience.
  • Lines 34 and 35 are setting up 'q' and 'w' to show the settings dialogs for the webcam... this is where you can set resolutions, exposure levels, etc.
  • On line 36, and those under the if statement, I save the current image and name it using the current time... this insures no overlapping image names.

If you're trying to write a webcam app of your own, I hope this gets you pointed in the right direction. Let me know if you find this info useful!

13 Responses to “drive a webcam with python”

  1. sdf Says:

    amazing tut man. thanks a lot this helped me incredibly

  2. Mac [unlesbar] Says:

    Haven’t tried it yet but it looks mucho like what I want. Any ideas about making the beast portable to a Mac or Linux machine?

  3. pr Says:

    I’m glad it helps! As far as adapting it to a linux box… I’m running Linux now, I just haven’t taken a lot of time to port it over. I’ll see what I can do. :)

  4. Jo Vermeulen Says:

    A Linux version would be great! Any news on that?

    I think you need some way to interact with Video4Linux2 then …

  5. Anonymous Says:

  6. Diego Says:

    Hi
    It looks very nice
    I am trying to do the same in Ubuntu, but videocapture is for win32, do you know any Extension for Accessing Video Devices for python in linux?

    thanks

  7. John Says:

    This is really an amazing implementation. I’m using a cheap webcam and this does a fantastic job.

    I have written some improvements to this script though. I added controls to rotate the image, and use some of PIL’s imagefilters to have some fun with your mugshot.

    My goal is to build a Python app that duplicates (and may even work better) than Apple’s Photobooth. If anyone wants to see my improvements, just email me at webmaster@asporina.com

  8. R Says:

    Worked for me, great, but I had to make a couple of changes

    1. “from PIL import ImageDraw” instead of “import ImageDraw”, perhaps that’s due to a change in PIL.

    2. Added an infinite loop until the image was read, because “getImage()” does not guarantee to produce an image, and freezes the program. I used the following instead of calling getImage from inside Brightness()

    camshot = cam.getImage()
    while camshot==None:
    camshot = cam.getImage()

    Thanks a lot for this.

  9. Beau Gunderson Says:

    http://www.jperla.com/blog/2007/09/26/capturing-frames-from-a-webcam-on-linux/

    Here’s how to capture webcam images on Linux. :)

  10. BoJaN Says:

    Very nice, but I’m getting an error from the PIL Image.py script saying there is not enough image data. I can’t find my webcam right now so I’m using Fake Cam to use an avi file as a camera instead and AmCap is able to view it just fine. It’s 3am and people are sleeping so I don’t really want to go looking for my webcam ATM.

  11. robert small Says:

    thanks alot for posting this.
    I am learning python at the moment and this has taught me a few new tricks
    Rob

  12. Rand Batchelder Says:

    I have gone this far too.

    But I need to set the webcam to a higer resolution like 1600×1200 or higher and the setResolution function does not work in videoCapture.

    Any advice ?

    Rand

  13. pr Says:

    Rand, if setResolution doesn’t support it, my guess is that your driver doesn’t either. Does your webcam actually advertise that resolution?

    If it’s not supported, I think upscaling using PIL would be the only option.

Leave a Reply