2

So I have a python program in which I'm using the picamera library to shoot pictures and record video. I'm using my program for scientific purposes and my goal is keep each picture as close to the previous picture as possible, both visually and in file size (post & pre-processing). I'm aware that I most likely should be creating YUV images or getting the Bayer data, but JPEGs allow me to visually inspect the images easily and I want to see if they will be good enough.

So what I am doing is similar to both this recipe and this question. In that I'm trying to keep all picamera parameters held constant: resolution, no denoise, LED off, shutter speed, iso and AWB. The issue is that I create a new PiCamera() instance everytime I call my take_picture() function. So what I believe it happening is in the time from when I create the camera instance to when I turn off exposure_mode the digital_gain and analog_gain could settle on different values based on light conditions. This could skew the results of my tests.

So what I believe I'll do is make my camera module a class and create the PiCamera() instance in init so that it is persistent through program scope and all parameters are held constant. The question I have is that I usually exit my program by pressing CTRL+C, A.K.A. raising a KeyboardInterrupt. If I do this will the camera instance never call close() and be left in a weird state?

  • You want to implement a signal handler (Ctrl-C is SIGINT) so you that when you interrupt/stop the process it has a chance to do some clean-up. docs.python.org/2/library/signal.html – goldilocks Mar 12 '15 at 16:45
  • This is one potential solution and I will probably end up implementing this. I just feel like registering a SIGINT handler makes my code a little more "hacky", but I could be completely off base here. Also it's probably better than just never calling picamera.close().. – C. Zach Martin Mar 12 '15 at 20:08
  • It's a standard practice for this -- really an only practice, since SIGINT comes from the operating system and if you don't catch it, the process just dies. There could (in theory) be higher level event driven input handling libraries that will wrap this (although I doubt it), but even if so, you'd be adding a bunch of library to get functionality that's already simple. Signals are awkward in that they require you use globals to do much (something a wrapper could conceal), and they're asynchronous to program flow (but what else could they be?). – goldilocks Mar 13 '15 at 11:10
  • Gotcha, yeah I guess I could always exit my program using the graceful method I coded in, but that'll never happen! – C. Zach Martin Mar 13 '15 at 14:03
2

If you're trying to shoot absolutely consistent pictures the one thing you can't do is re-initialize the camera between each shot. The reason is that the camera firmware provides no means of setting the camera's gains; all it provides is the ability to fix them at their current values (or let them float according to the results of the AGC process).

So, I'd recommend doing as the recipe suggests and set up the camera, then capture several images without re-initializing it. The recipe demonstrates one method of doing that with the capture_sequence method, but you could simply use capture instead, and even do that within your take_picture function. For example:

import time
import picamera

def take_picture(cam, filename):
    cam.capture(filename)

with picamera.PiCamera() as camera:
    camera.resolution = (1280, 720)
    camera.framerate = 30
    # Wait for analog gain to settle on a higher value than 1
    while camera.analog_gain <= 1:
        time.sleep(0.1)
    # Now fix the values
    camera.shutter_speed = camera.exposure_speed
    camera.exposure_mode = 'off'
    g = camera.awb_gains
    camera.awb_mode = 'off'
    camera.awb_gains = g
    # Finally, take several photos with the fixed settings
    take_picture(camera, '1.jpg')
    take_picture(camera, '2.jpg')
    take_picture(camera, '3.jpg')
    take_picture(camera, '4.jpg')

No need to be messing around with signal handlers here! In the code above there's no need to explicitly call close on the camera as it'll be called implicitly when the with block exits (even in response to KeyboardInterrupt). Generally speaking, there's very rarely a need to call close. It's mentioned in the docs because I wasn't sure whether it was required or not, so I figured I should err on the side of caution, but subsequent practice has shown the firmware is generally very good at cleaning up on shutdown. There are some exceptions to this (usually involving complex situations with multiple recordings) so I won't be removing the recommendation from the docs, but don't worry too much!

  • 1
    Unfortunately my program is more complex than this script and image capture is just a small part of it. So what I did is redesign my camera module to do this. This required me to add my camera functions into a MyCamera class and create the PiCamera instance in my init method so that camera initialization is persistent throughout program scope. I didn't really see significant improvements in image consistency, so I reverted the changes as it wasn't particularly good style & kinda hacked together. – C. Zach Martin Mar 19 '15 at 21:01
  • It sounds more complex than it needs to be; I've yet to encounter a situation where someone needed to subclass PiCamera! – Dave Jones Mar 19 '15 at 22:53
  • You're more than likely right. My original goal was to encapsulate all camera related functionality into a single module, but what I could do instead is create the PiCamera instance in my "main" module and then functions further down the call stack would have view/access to it. As it stand now it's "good enough" with the gains re-initializing every image, but thanks for the additional solution. I'd upvote your solution, but I have no rep :( – C. Zach Martin Mar 25 '15 at 15:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.