diff --git a/AscCam.py b/AscCam.py index ebb6208..3e41b76 100755 --- a/AscCam.py +++ b/AscCam.py @@ -1,353 +1,401 @@ #!/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 - # Create the GUI - self.create_widgets() - # Instantiate the camera self.camera = PiCamera(sensor_mode=3, resolution=PiCamera.MAX_RESOLUTION, framerate=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() # 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 = 60000 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=1) self.camInterval = tk.Scale(master=frame1, label="interval (min)", variable=self.intervalVar, from_=1, to=1000, resolution=1, orient="horizontal") self.camInterval.set(1) 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() # Image rotation self.rotVar = tk.IntVar(value=90) 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(90) self.camRot.pack() # 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("auto") + self.expVar.set("off") self.expMenu = tk.OptionMenu(frame2, self.expVar, *exp_options, command=self.setExpMode) self.expMenu.pack(fill="x") - self.expVar = tk.IntVar(value=50) + self.expVar = tk.IntVar(value=70) self.camExp = tk.Scale(master=frame2, label="exposure (ms)", variable=self.expVar, from_=1, - to=100, resolution=1, orient="horizontal", - command=self.setExp, state=tk.DISABLED) - self.camExp.set(50) + to=200, resolution=1, orient="horizontal", + command=self.setExp) + self.camExp.set(70) self.camExp.pack() + self.camera.exposure_mode = "off" + self.camera.shutter_speed = 70000 + # 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("auto") + 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=1.2) + 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, state=tk.DISABLED) - self.wbRed.set(1.2) + command=self.setGain) + self.wbRed.set(awb_red) self.wbRed.pack() - self.greenVar = tk.DoubleVar(value=1.2) + 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, state=tk.DISABLED) - self.wbGreen.set(1.2) + command=self.setGain) + self.wbGreen.set(awb_green) self.wbGreen.pack() # Then the preview buttons - self.camHistButt = tk.Button(master=frame3, text="Histogram", command=self.camHist) + self.camHistButt = tk.Button(master=frame3, text="Histogram", command=self.camHist, state=tk.DISABLED) self.camHistButt.pack() - self.fig = Figure(figsize=(2,2), dpi=100) - self.axes = self.fig.add_subplot(111) + self.fig = Figure(figsize=(1.5,1.5), dpi=100, frameon=False) + #self.axes = self.fig.add_subplot(111) + 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() def camOn(self): self.camera.start_preview(fullscreen=False, window=(0, 0, 640, 480)) return def camOff(self): self.camera.stop_preview() return 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 def camTL(self): if self.isTLOn: if self.job is not None: root.after_cancel(self.job) self.job = None self.prevTime = None self.dt = 0 self.camTLButt.configure(text="Time Lapse") self.camInterval.configure(state=tk.NORMAL) self.camRecButt.configure(state=tk.NORMAL) 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) 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") self.isTLOn = not self.isTLOn if self.isTLOn: self.acquireTL() return def acquireTL(self): if self.isTLOn: - # Camera warm-up time - time.sleep(1) self.camera.capture(self.timelapsePath + '/timelapse_' + time.strftime("%d-%H-%M-%S") + '.png') now = time.time() if self.prevTime is not None: self.dt = self.dt + self.tlInterval - round((now - self.prevTime)*1000) self.prevTime = now self.job = root.after(self.tlInterval + self.dt, self.acquireTL) return def camRec(self): return def camHist(self): - 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() + 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 + 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 + + def camDrawHist(self): + + 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() + + self.jobHist = root.after(200, self.camDrawHist) return def setZoom(self, zoom): zoomSide = 1 / float(zoom) edge = (1 - zoomSide)*0.5 self.camera.zoom = (edge, edge, zoomSide, zoomSide) return def setRot(self, rot): self.camera.rotation = int(rot) return 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 def setGain(self, gain): red = self.wbRed.get() - green = self.wbRed.get() + green = self.wbGreen.get() - self.camera.awb_gains = (red, green) + self.camera.awb_gains = (Fraction(red), Fraction(green)) return def setBright(self, bright): self.camera.brightness = int(bright) return def setContrast(self, contr): self.camera.contrast = int(contr) return 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 def setExp(self, exp): exp = int(exp)*1000 self.camera.shutter_speed = exp return root = tk.Tk() root.title("AscCam 0.01") root.resizable(width=False, height=False) root.geometry("+15+400") app = GUI(master=root) app.mainloop()