diff --git a/AscCam.py b/AscCam.py index 09a74f3..8c51e5c 100755 --- a/AscCam.py +++ b/AscCam.py @@ -1,497 +1,497 @@ #!/usr/bin/python3 # Few required libraries import tkinter as tk import os import time import numpy as np import matplotlib from picamera import PiCamera from fractions import Fraction matplotlib.use('TkAgg') from matplotlib.figure import Figure from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg # Main Tkinter class class GUI(tk.Frame): # Initialization of the class def __init__(self, master=None): super().__init__(master) self.master = master # Instantiate the camera self.camera = PiCamera(sensor_mode=3, resolution=PiCamera.MAX_RESOLUTION, framerate_range=(0.05, 10)) self.data = np.empty((round(self.camera.resolution[1]/32)*32, round(self.camera.resolution[0]/32)*32, 3), dtype=np.uint8) # Camera warm-up time time.sleep(3) # Create the GUI self.create_widgets() # Update the camera with the default values self.setCamera() # filepath for output: self.basePath = '/home/pi/Desktop/Imaging/{}'.format(time.strftime('%Y-%m-%d')) if not os.path.exists(self.basePath): os.mkdir(self.basePath) os.chown(self.basePath, 1000, 1000) # Parameter for the timelapse self.isTLOn = False self.tlInterval = 600000 self.dt = 0 self.prevTime = None self.timelapsePath = self.basePath self.job = None # Parameter for the WB self.isHistOn = False self.jobHist = None # Create the main GUI def create_widgets(self): # Create separate frames to group similar buttons frame1 = tk.Frame(master=self.master, bd=2, relief="ridge") frame1.grid(row=0, column=0, columnspan=1, rowspan=1, sticky="N") frame2 = tk.Frame(master=self.master, bd=2) frame2.grid(row=0, column=1, columnspan=1, rowspan=1, sticky="NW") frame3 = tk.Frame(master=self.master, bd=2, relief="ridge") frame3.grid(row=0, column=2, columnspan=1, rowspan=1, sticky="NW") # In Frame1 the general handling buttons # Place the first item (a label) in the first frame self.camLabel = tk.Label(master=frame1, text="CAMERA") self.camLabel.pack() # Then the preview buttons self.camOnButt = tk.Button(master=frame1, text="ON", fg="green", command=self.camOn) self.camOnButt.pack() self.camOffButt = tk.Button(master=frame1, text="OFF", fg="red", command=self.camOff) self.camOffButt.pack() # the acquisition section self.camResLabel = tk.Label(master=frame1, text=" Acquisition ") self.camResLabel.pack() self.camSnapButt = tk.Button(master=frame1, text="Snapshot", command=self.camSnap) self.camSnapButt.pack() self.camRecButt = tk.Button(master=frame1, text="Video", command=self.camRec) self.camRecButt.pack() # Time lapse with interval self.camTLButt = tk.Button(master=frame1, text="Time Lapse", command=self.camTL) self.camTLButt.pack() self.intervalVar = tk.IntVar(value=10) self.camInterval = tk.Scale(master=frame1, label="interval (min)", variable=self.intervalVar, from_=1, to=1000, resolution=1, orient="horizontal") self.camInterval.set(10) self.camInterval.pack() # The Exit section self.camResLabel = tk.Label(master=frame1, text=" Exit ") self.camResLabel.pack(fill="x") self.quit= tk.Button(master=frame1, text="QUIT", fg="blue", command=self.master.destroy) self.quit.pack() # In Frame 2, the camera's options # Digital zoom self.zoomVar = tk.IntVar(value=1) self.camZoom = tk.Scale(master=frame2, label="Digi Zoom", variable=self.zoomVar, from_=1, to=10, resolution=1, orient="horizontal", command=self.setZoom) self.camZoom.set(1) self.camZoom.pack() # X and Y position of the zoomed area self.xVar = tk.IntVar(value=50) self.camX = tk.Scale(master=frame2, label="X position", variable=self.xVar, from_=0, to=100, resolution=10, orient="horizontal", command=self.setZoom) self.camX.set(50) self.camX.pack() self.yVar = tk.IntVar(value=50) self.camY = tk.Scale(master=frame2, label="Y position", variable=self.yVar, from_=0, to=100, resolution=10, orient="horizontal", command=self.setZoom) self.camY.set(50) self.camY.pack() # Image rotation self.rotVar = tk.IntVar(value=270) self.camRot = tk.Scale(master=frame2, label="Rotation", variable=self.rotVar, from_=0, to=270, resolution=90, orient="horizontal", command=self.setRot) self.camRot.set(270) self.camRot.pack() # Implemented but removed from the GUI # for space issues # # Brightness #self.brightVar = tk.IntVar(value=50) #self.camBright = tk.Scale(master=frame2, label="Brightness", # variable=self.brightVar, from_=0, # to=100, resolution=5, orient="horizontal", # command=self.setBright) #self.camBright.set(50) #self.camBright.pack() # Contrast #self.contrVar = tk.IntVar(value=0) #self.camContrast = tk.Scale(master=frame2, label="Contrast", # variable=self.contrVar, from_=-100, # to=100, resolution=10, orient="horizontal", # command=self.setContrast) #self.camContrast.set(0) #self.camContrast.pack() # Exposure mode and duration self.expLabel = tk.Label(master=frame2, text=" Exposure modes ") self.expLabel.pack(fill="x") exp_options = list(PiCamera.EXPOSURE_MODES.keys()) self.expVar = tk.StringVar() self.expVar.set("off") self.expMenu = tk.OptionMenu(frame2, self.expVar, *exp_options, command=self.setExpMode) self.expMenu.pack(fill="x") self.shutterVar = tk.IntVar(value=250) self.camExp = tk.Scale(master=frame2, label="exposure (ms)", variable=self.shutterVar, from_=1, to=2000, resolution=10, orient="horizontal", command=self.setExp) self.camExp.set(250) self.camExp.pack() # In frame 3 the white-balance # First the modes self.wbLabel = tk.Label(master=frame3, text=" White-balance modes ") self.wbLabel.pack(fill="x") wb_options = list(PiCamera.AWB_MODES.keys()) self.wbVar = tk.StringVar() self.wbVar.set("off") self.wbMenu = tk.OptionMenu(frame3, self.wbVar, *wb_options, command=self.setAWBMode) self.wbMenu.pack(fill="x") # Setup the camer AWB awb_red = float(self.camera.awb_gains[0]) awb_green = float(self.camera.awb_gains[1]) # And then the gains self.redVar = tk.DoubleVar(value=awb_red) self.wbRed = tk.Scale(master=frame3, label="red gain", variable=self.redVar, from_=0.0, to=8.0, resolution=0.1, orient="horizontal", command=self.setGain) self.wbRed.set(awb_red) self.wbRed.pack() self.greenVar = tk.DoubleVar(value=awb_green) self.wbGreen = tk.Scale(master=frame3, label="green gain", variable=self.greenVar, from_=0.0, to=8.0, resolution=0.1, orient="horizontal", command=self.setGain) self.wbGreen.set(awb_green) self.wbGreen.pack() # Then the histogram button self.camHistButt = tk.Button(master=frame3, text="Histogram", command=self.camHist) self.camHistButt.pack() self.fig = Figure(figsize=(1.5,1.5), dpi=100, frameon=False) self.axes = self.fig.add_axes([0, 0, 1, 1]) self.axes.axis('off') self.canevas = FigureCanvasTkAgg(self.fig, master=frame3) self.canevas.get_tk_widget().pack() - self.canevas.show() + self.canevas.draw() # This function sets the parameters of the camer # to the values of the GUI def setCamera(self): #self.camera.iso = 100 self.setZoom(0) self.setRot(int(self.camRot.get())) self.setAWBMode(self.wbVar.get()) self.setExpMode(self.expVar.get()) return # This function turns on the preview def camOn(self): # Turn off the other modes self.camSnapButt.configure(state=tk.DISABLED) self.camRecButt.configure(state=tk.DISABLED) self.camTLButt.configure(state=tk.DISABLED) # The actual preview self.camera.start_preview(fullscreen=False, window=(0, 0, 360, 480)) # We need to make sure that all is good self.setCamera() return # Turns off the preview def camOff(self): self.camera.stop_preview() self.camSnapButt.configure(state=tk.NORMAL) self.camRecButt.configure(state=tk.NORMAL) self.camTLButt.configure(state=tk.NORMAL) return # Take a single picture def camSnap(self): photoPath = self.basePath + '/snaps/' #check to see if the snap output folder is present: if not os.path.exists(photoPath): #if not, create it: os.makedirs(photoPath) os.chown(photoPath, 1000, 1000) # Camera warm-up time time.sleep(1) self.camera.capture(photoPath + 'snap_' + time.strftime("%Y-%m-%d-%H-%M-%S") + '.png') return # Starts or ends a time-lapse job def camTL(self): # Turning off if self.isTLOn: # Deletes the "after" job if self.job is not None: root.after_cancel(self.job) self.job = None self.prevTime = None self.dt = 0 # Reverts the buttons self.camTLButt.configure(text="Time Lapse") self.camInterval.configure(state=tk.NORMAL) self.camRecButt.configure(state=tk.NORMAL) # Starts the TL else: self.timelapsePath = (self.basePath + '/timelapse_' + time.strftime("%Y-%m-%d-%H-%M-%S")) #check to see if the snap output folder is present: if not os.path.exists(self.timelapsePath): #if not, create it: os.makedirs(self.timelapsePath) os.chown(self.timelapsePath, 1000, 1000) # Sets the job self.camRecButt.configure(state=tk.DISABLED) self.camInterval.configure(state=tk.DISABLED) self.tlInterval = int(self.camInterval.get())*60000; self.dt = 0 self.camTLButt.configure(text="STOP TL") # Switch the current status of the TL self.isTLOn = not self.isTLOn # Actually start the TL if self.isTLOn: self.acquireTL() return # This function recursively acquires frames # for the TL def acquireTL(self): # Maybe it was stopped in between # If not, we can get a new picture if self.isTLOn: self.camera.capture(self.timelapsePath + '/timelapse_' + time.strftime("%d-%H-%M-%S") + '.png') # We try to compensate between the interval # that we want and the one we got now = time.time() if self.prevTime is not None: self.dt = self.dt + self.tlInterval - round((now - self.prevTime)*1000) self.prevTime = now # Schedule the next picture self.job = root.after(self.tlInterval + self.dt, self.acquireTL) return # For videos, but not implemented yet def camRec(self): return # Starts or stops the display of the WB histogram def camHist(self): # Stops the display and cancels the job if self.isHistOn: if self.jobHist is not None: root.after_cancel(self.jobHist) self.jobHist = None self.camHistButt.configure(text="Histogram") self.camOnButt.configure(state=tk.NORMAL) self.camSnapButt.configure(state=tk.NORMAL) self.camRecButt.configure(state=tk.NORMAL) self.camTLButt.configure(state=tk.NORMAL) self.isHistOn = False # Starts the display and initiate the job elif not self.isTLOn and not self.camera.previewing: self.camOnButt.configure(state=tk.DISABLED) self.camSnapButt.configure(state=tk.DISABLED) self.camRecButt.configure(state=tk.DISABLED) self.camTLButt.configure(state=tk.DISABLED) self.camHistButt.configure(text="STOP") self.isHistOn = True self.camDrawHist() return # Actually draw the histogram recursively def camDrawHist(self): # Analyze a new picture and draw its histogram if self.isHistOn: self.camera.capture(self.data, 'rgb') color = ('r', 'g', 'b') self.axes.clear() for channel in range(3): hist,bins = np.histogram(self.data[:,:,channel], 256, [0, 256]) self.axes.plot(hist, color=color[channel]) self.canevas.draw() # Schedule the next drawing self.jobHist = root.after(200, self.camDrawHist) return # Sets the zoom of the camera def setZoom(self, value): zoom = self.camZoom.get() xfrac = float(self.camX.get())/100 yfrac = 1-float(self.camY.get())/100 zoomSide = 1 / float(zoom) edgeX = (1 - zoomSide)*xfrac edgeY = (1 - zoomSide)*yfrac self.camera.zoom = (edgeX, edgeY, zoomSide, zoomSide) return # Sets the rotation of the preview # This affects only the preview not to degrade # the pictures taken def setRot(self, rot): if self.camera.preview is not None: self.camera.preview.rotation = int(rot) return # Sets the current mode of AWB # Will set the gains if needed def setAWBMode(self, awb): if self.camera.awb_mode == "off" and awb != "off": self.wbRed.configure(state=tk.DISABLED) self.wbGreen.configure(state=tk.DISABLED) self.camHistButt.configure(state=tk.DISABLED) if self.isHistOn: root.after_cancel(self.jobHist) self.jobHist = None self.isHistOn = False self.camera.awb_mode = awb if awb == "off": self.wbRed.configure(state=tk.NORMAL) self.wbGreen.configure(state=tk.NORMAL) self.camHistButt.configure(state=tk.NORMAL) self.setGain(0) return # Sets the WB gains def setGain(self, gain): red = self.wbRed.get() green = self.wbGreen.get() self.camera.awb_gains = (Fraction(red), Fraction(green)) return # Sets the brightness def setBright(self, bright): self.camera.brightness = int(bright) return # Sets the contrast def setContrast(self, contr): self.camera.contrast = int(contr) return # Sets the type of exposure mode used. # Will set the shutter speed if needed def setExpMode(self, exp): if self.camera.exposure_mode == "off" and exp != "off": self.setExp(0) self.camExp.configure(state=tk.DISABLED) self.camera.exposure_mode = exp if exp == "off": self.camExp.configure(state=tk.NORMAL) self.setExp(self.camExp.get()) return # Sets the shutter speed (exposure time) def setExp(self, exp): exp = int(exp)*1000 self.camera.shutter_speed = exp return # Create the tkinter GUI root = tk.Tk() -root.title("AscCam 0.01") +root.title("AscCam 0.02") root.resizable(width=False, height=False) -root.geometry("+15+450") +root.geometry("+15+410") app = GUI(master=root) app.mainloop()