New to the Pi and Python (in fact a long time since I did any programming!) so set myself a small project to write a GUI to control the Pi Camera i.e. an interface to make various settings and then press a button to take the photo(s). It's only for still shots at the moment (i.e. no video functions). A lot was done by trial and error, loads of googling and reading posts on this forum. I've copied the py code below and would welcome constructive feedback on how I could have done this better or more efficiently. Happy for suggestions on improvements or additions to the program.
You need to install the picamera library - details at http://picamera.readthedocs.org/en/rele ... tall3.html.
Now to think of the next project!
Rob
Code: Select all
from tkinter import *
import time
import tkinter.messagebox as mb
from picamera import *
class PiCameraControl:
def __init__ (self, master):
frame = Frame (master)
frame.pack()
# Radio Buttons for still or continuous and number of continuous shots entry if allowed
mode_Label = Label (frame, text = 'Select mode', width = 13, anchor = W)
mode_Label.grid(row = 0, column = 0)
mode_frame = Frame (frame)
self.mode_select = StringVar()
self.no_of_shots = IntVar()
self.interval_var = IntVar()
self.b1 = Radiobutton (mode_frame, text = 'Single', variable = self.mode_select, value = 'S', command = self.single_sel)
self.b1.pack(side=LEFT)
self.b2 = Radiobutton (mode_frame, text = 'Continuous ', variable = self.mode_select, value = 'C', command = self.change_enter_state)
self.b2.pack(side=LEFT)
mode_frame.grid(row=0, column=1, sticky = W)
self.shots_Label = Label(frame, text='No. of shots', width = 18, anchor = W)
self.shots_Label.grid(row = 0, column = 2)
self.shots_Label.config(foreground = 'grey')
self.Enter_Shots = Entry(frame, textvariable=self.no_of_shots, state=DISABLED, width = 5)
self.Enter_Shots.grid(row=0, column=3, sticky = W)
self.interval_Label = Label(frame, text = 'Interval (secs)', width = 14, anchor = W)
self.interval_Label.grid(row = 0, column = 4, padx = 10)
self.interval_Scale = Scale(frame, from_=1, to=60, orient = HORIZONTAL, variable = self.interval_var, length = 200)
self.interval_Scale.grid(row = 0, column = 5)
#User sets filename - if continuous mode this will be used with {counter}
self.FileName = StringVar()
name_Label = Label(frame, text = 'Choose Filename', width = 14, anchor = W).grid (row = 1, column = 0)
self.Enter_Filename = Entry(frame, textvariable=self.FileName, width = 15)
self.Enter_Filename.grid(row = 1 , column = 1, sticky = W)
#File format selection
self.FileFormat = StringVar ()
format_Label = Label(frame, text = 'File Format', width = 18, anchor = W).grid(row = 1, column = 2)
self.fileext = Spinbox(frame, values = ('jpeg', 'png', 'gif', 'bmp', 'yuv', 'rgb', 'rgba', 'raw'), wrap=True, textvariable = self.FileFormat, \
width = 10, command = self.file_ext).grid(row = 1, column = 3, sticky = W)
# For jpeg format, option to select encoder quality
self.jpeg_quality_var = IntVar()
self.quality_Label = Label(frame, text = 'JPEG Quality', width = 14, anchor = W)
self.quality_Label.grid(row = 1, column = 4)
self.jpeg_quality_Scale = Scale(frame, from_=1, to=100, orient=HORIZONTAL, variable = self.jpeg_quality_var, length = 200)
self.jpeg_quality_Scale.grid(row = 1, column = 5)
# ISO selection
self.ISO_Mode = IntVar()
iso_Label = Label (frame, text = 'ISO (0=Auto)', width = 14, anchor = W).grid(row = 2, column = 0)
self.iso_select = Spinbox(frame, values = (0, 100, 200, 320, 400, 500, 640, 800), wrap=True, textvariable = self.ISO_Mode, width = 5, command = self.ISO_select)
self.iso_select.grid(row = 2, column = 1, sticky = W)
#Exposure Mode selection
self.Exposure_Mode = StringVar()
self.exposure_Label = Label (frame, text = 'Exposure Mode', width = 18, anchor = W)
self.exposure_Label.grid(row = 2, column = 2)
self.exposure_mode_Spinbox = Spinbox(frame, values = ('auto', 'off', 'night', 'nightpreview', 'backlight', 'spotlight', 'sports', 'snow', 'beach', 'verylong', \
'fixedfps', 'antishake', 'fireworks'), wrap = True, textvariable = self.Exposure_Mode, width = 10)
self.exposure_mode_Spinbox.grid(row = 2, column = 3, sticky = W)
#Set White Balance Mode
self.AWB_Mode = StringVar()
self.awb_Label = Label(frame, text = 'AWB Mode', width = 14, anchor = W)
self.awb_Label.grid(row = 3, column = 0)
self.awb_Spinbox = Spinbox(frame, values = ('auto', 'off', 'sunlight', 'cloudy', 'shade', 'tungsten', 'fluorescent', 'incandescent', 'flash', 'horizon'), wrap = True, \
textvariable = self.AWB_Mode, width = 14)
self.awb_Spinbox.grid(row = 3, column = 1, sticky = W, pady = 10)
#Set metering mode
self.meter_Mode = StringVar()
self.meter_mode_Label = Label(frame, text = 'Metering Mode', width = 18, anchor = W)
self.meter_mode_Label.grid(row = 3, column = 2)
self.meter_mode_Spinbox = Spinbox(frame, values = ('average', 'spot', 'backlit', 'matrix'), wrap = True, textvariable = self.meter_Mode, width = 10)
self.meter_mode_Spinbox.grid(row = 3, column = 3, sticky = W)
#Set Image Effects
self.image_Effect = StringVar()
self.image_effect_Label = Label(frame, text = 'Image Effect', width =14, anchor = W)
self.image_effect_Label.grid(row = 4, column = 0, pady = 10)
self.image_effect_Spinbox = Spinbox(frame, values = ('none', 'negative', 'solarize', 'posterise', 'whiteboard', ' blackboard', 'sketch', 'denoise', 'emboss', 'oilpaint', 'hatch', \
'gpen', 'pastel', 'watercolor', 'film', 'blur', 'saturation', 'colorswap', 'washedout', 'colorpoint', 'colorbalance', 'cartoon'), \
wrap = True, textvariable = self.image_Effect, width = 14)
self.image_effect_Spinbox.grid(row = 4, column = 1, sticky = W)
#Set Brightness - range 0-100, default 50
self.Brightness_Level = IntVar()
self.brigthness_Label = Label(frame, text = 'Brightness', width = 14, anchor = W)
self.brigthness_Label.grid(row = 3, column = 4)
self.brightness_Scale = Scale(frame, from_ =0, to = 100, orient = HORIZONTAL, variable = self.Brightness_Level, length = 200)
self.brightness_Scale.grid(row = 3, column = 5, sticky = W)
#Set Contrast - range -100 to 100, default 0
self.Contrast_Level = IntVar()
self.contrast_Label = Label(frame, text = 'Contrast', width = 14, anchor = W)
self.contrast_Label.grid(row = 5, column = 0)
self.contrast_Scale = Scale(frame, from_ = -100, to =100, orient = HORIZONTAL, variable = self.Contrast_Level, length = 430)
self.contrast_Scale.grid(row = 5, column = 1, columnspan = 3, sticky = W)
#Set Exposure Compensation - range -25 to 25 default 0
self.Exposure_Comp = IntVar()
self.exposure_comp_Label = Label(frame, text = 'Exposure Comp', width = 14, anchor = W)
self.exposure_comp_Label.grid(row = 2, column = 4)
self.exposure_comp_Scale = Scale(frame, from_=-25, to= 25, orient = HORIZONTAL, variable = self.Exposure_Comp, length = 200)
self.exposure_comp_Scale.grid(row = 2, column = 5, sticky = W)
#Set Saturation - range -100 to 100, default 0
self.Saturation_Level = IntVar()
self.saturation_Label = Label(frame, text = 'Saturation', width = 14, anchor = W)
self.saturation_Label.grid(row = 6, column = 0)
self.saturation_Scale = Scale(frame, from_ = -100, to =100, orient = HORIZONTAL, variable = self.Saturation_Level, length = 430)
self.saturation_Scale.grid(row = 6, column = 1, columnspan = 3, sticky = W)
#Set Sharpness - range -100 to 100, default 0
self.Sharpness_Level = IntVar()
self.sharpness_Label = Label(frame, text = 'Sharpness', width = 14, anchor = W)
self.sharpness_Label.grid(row = 7, column = 0)
self.sharpness_Scale = Scale(frame, from_ = -100, to =100, orient = HORIZONTAL, variable = self.Sharpness_Level, length = 430)
self.sharpness_Scale.grid(row = 7, column = 1, columnspan = 3, sticky = W)
#Set Shutter Speed - in milliseconds, default 0, Auto based on exposure
self.Shutter_Speed = StringVar()
self.shutter_speed_Label = Label(frame, text = 'Shutter Speed (ms)', width = 18, anchor = W)
self.shutter_speed_Label.grid(row = 4, column = 2)
self.shutter_speed_Entry = Entry(frame, textvariable = self.Shutter_Speed, width = 11)
self.shutter_speed_Entry.grid(row = 4, column = 3, sticky = W)
#Take picture button
Button (frame, text = 'Take Photo(s)', command = self.take, width = 22).grid(row = 9, column = 5, sticky = E)
#Reset defaults button
Button(frame, text = 'Reset Defaults', command = self.set_defaults, width = 22).grid(row = 8, column = 5, sticky = E, pady = 10)
#Set default values
self.set_defaults()
def single_sel(self):
self.shots_Label.config(foreground = 'grey')
self.Enter_Shots.config(state=DISABLED)
self.no_of_shots.set(1)
self.interval_var.set(1)
self.interval_Label.config(foreground = 'grey')
self.interval_Scale.config(state=DISABLED)
def change_enter_state(self):
self.shots_Label.config(foreground = 'black')
self.Enter_Shots.config(state=NORMAL)
self.interval_Label.config(foreground = 'black')
self.interval_Scale.config(state=NORMAL)
def file_ext(self):
if self.FileFormat.get()!='jpeg':
self.quality_Label.config(foreground = 'grey')
self.jpeg_quality_Scale.config(state=DISABLED)
else:
self.quality_Label.config(foreground = 'black')
self.jpeg_quality_Scale.config(state=NORMAL)
def ISO_select(self):
if self.ISO_Mode.get() != 0:
self.exposure_Label.config(foreground = 'grey')
self.Exposure_Mode.set('auto')
self.exposure_mode_Spinbox.config(state = DISABLED)
mb.showinfo('Information', 'Exposure options disabled when ISO is not set to 0 Auto')
else:
self.exposure_Label.config(foreground = 'black')
self.exposure_mode_Spinbox.config(state = NORMAL)
def take(self):
self.camera = PiCamera()
self.camera.ISO = self.ISO_Mode.get()
self.camera.awb_mode = self.AWB_Mode.get()
self.camera.exposure_mode = self.Exposure_Mode.get()
self.camera.exposure_compensation = self.Exposure_Comp.get()
self.camera.meter_mode = self.meter_Mode.get()
self.camera.image_effect = self.image_Effect.get()
self.camera.brightness = self.Brightness_Level.get()
self.camera.contrast = self.Contrast_Level.get()
self.camera.saturation = self.Saturation_Level.get()
self.camera.sharpness = self.Sharpness_Level.get()
if self.Shutter_Speed.get() == 'auto':
self.camera.shutter_speed = 0
else:
try:
self.camera.shutter_speed = int(self.Shutter_Speed.get())
except ValueError:
mb.showwarning('Warning', "You've entered an invalid quantity, please retry")
self.Shutter_Speed.set('auto')
if self.FileName.get()=="":
self.FileName.set('Image')
try:
if self.no_of_shots.get()==0:
self.no_of_shots.set(1)
if self.no_of_shots.get() == 1:
if self.FileFormat.get()=='jpeg':
self.camera.capture(self.FileName.get(), 'jpeg', quality = self.jpeg_quality_var.get())
else:
self.camera.capture(self.FileName.get(), self.FileFormat.get())
else:
if self.FileFormat.get()=='jpeg':
for i, filename in enumerate(self.camera.capture_continuous(self.FileName.get() + '{counter}.jpg', quality = self.jpeg_quality_var.get())):
time.sleep(self.interval_var.get())
if i == self.no_of_shots.get() - 1:
break
else:
for i, filename in enumerate(self.camera.capture_continuous(self.FileName.get() + '{counter}', self.FileFormat.get())):
time.sleep(self.interval_var.get())
if i == self.no_of_shots.get() - 1:
break
except ValueError:
mb.showwarning('Warning', "You've entered an invalid quantity, please retry")
self.no_of_shots.set(1)
finally:
self.camera.close()
def set_defaults(self):
self.b1.select()
self.single_sel()
self.FileName.set('')
self.FileFormat.set('jpeg')
self.file_ext()
self.jpeg_quality_Scale.set(85)
self.ISO_Mode.set(0)
self.ISO_select()
self.Exposure_Mode.set('auto')
self.Exposure_Comp.set(0)
self.AWB_Mode.set('auto')
self.meter_Mode.set('average')
self.image_Effect.set('none')
self.Brightness_Level.set(50)
self.Contrast_Level.set(0)
self.Saturation_Level.set(0)
self.Sharpness_Level.set(0)
self.Shutter_Speed.set('auto')
root = Tk()
root.resizable(0,0)
root.wm_title('Pi Camera Controller')
control = PiCameraControl (root)
root.mainloop()