def setWB(self): debug("Determining white balance.") self.cam.awb_mode = "auto" time.sleep(2) g = self.cam.awb_gains self.cam.awb_mode = "off" self.cam.awb_gains = g
def isDaytime(self): oldres = self.cam.resolution self.cam.resolution = (320, 240) self.cam.iso = self.cfg.get('dayiso') self.cam.shutter_speed = 1000000 // self.cfg.get('dayshutter') output = np.empty((240, 320, 3), dtype=np.uint8) self.cam.capture(output, 'rgb') self.cam.resolution = oldres debug("Daytime estimation mean value: " + str(output.mean())) return output.mean() > 10
def isDaytime(self): '''algorithm for daytime estimation. if the average pixel intensity is less than 10, we assume it is night. this may be tweaked for special use cases.''' oldres = self.cam.resolution self.cam.resolution = (320, 240) self.cam.iso = self.cfg.get('dayiso') self.cam.shutter_speed = 1000000 // self.cfg.get('dayshutter') output = np.empty((240, 320, 3), dtype=np.uint8) self.cam.capture(output, 'rgb') self.cam.resolution = oldres debug("Daytime estimation mean value: " + str(output.mean())) return output.mean() > 10
def isDaytime(self): # determine if it's day or not. # we need to set a bogus shutter speed before switching to auto exposure mode # otherwise the camera can get stuck for some reason self.cam.shutter_speed = 10000 self.cam.exposure_mode = "auto" self.cam.shutter_speed = 0 self.cam.iso = 100 self.cam.meter_mode = 'matrix' # to determine day/night we use a rotating list of the last 5 exposure readings # exposure may take a very long time to settle, so we use some heuristics to determine whether it is day or night itsday = 'TBD' exps = deque([-1, 100, -1, 100, -1]) stuck = 0 while itsday == 'TBD': time.sleep(1) exps.popleft() # round the exposure to nearest 1000 exps.append(self.cam.exposure_speed // 1000) if exps[4] < exps[3] < exps[2] < exps[1] < exps[0]: if mean(exps) < 33: # decreasing exposure, value below 33000 itsday = True elif exps[4] > exps[3] > exps[2] > exps[1] > exps[0]: if mean(exps) > 33: # increasing exposure time, value above 33999 itsday = False elif exps[4] == exps[3] == exps[2] == exps[1] == exps[0]: if mean(exps) < 33: # stable exposure, value below 33000 itsday = True elif mean(exps) > 33: # stable exposure, value above 33999 itsday = False else: # we are stuck at around 1/30 for some reason stuck = stuck + 1 if stuck > 20: # we have been stuck for over 20 seconds, just call it night so we can move on itsday = False debug("[isDaytime] Daytime: " + str(itsday) + ". Exposure values: " + str(exps)) return itsday
def restart_services(): """restarts the required services after config updates. returns False if any restart command returns a non-zero exit code.""" services = ['dhcpcd', 'dnsmasq', 'hostapd'] codes = [] for s in services: p = subprocess.run(["systemctl", "restart", s], stderr=subprocess.STDOUT, stdout=subprocess.PIPE) debug("Restarted service {0} with status code {1}.".format( s, p.returncode)) codes.append(p.returncode) return (all(c == 0 for c in codes))
def takePicture(self, name): filename = "" prev_daytime = self.daytime self.daytime = self.isDaytime() if self.daytime: time.sleep(0.5) self.cam.shutter_speed = 1000000 // self.cfg.get('dayshutter') self.cam.iso = self.cfg.get('dayiso') self.cam.color_effects = None filename = os.path.join(self.dir, name + "-day.png") else: # turn on led self.hw.LEDControl(True) time.sleep(0.5) self.cam.shutter_speed = 1000000 // self.cfg.get('nightshutter') self.cam.iso = self.cfg.get('nightiso') #self.cam.color_effects = (128, 128) filename = os.path.join(self.dir, name + "-night.png") if prev_daytime != self.daytime and self.daytime and self.cam.awb_mode != "off": # if there is a daytime shift, AND it is daytime, AND white balance was not previously set, # set the white balance to a fixed value. # thus, white balance will only be fixed for the first occurence of daylight. self.setWB() debug("Capturing %s." % filename) self.cam.exposure_mode = "off" self.cam.capture(filename) self.last_captured = filename self.cam.color_effects = None self.cam.shutter_speed = 0 # we leave the cam in auto exposure mode to improve daytime assessment performance self.cam.exposure_mode = "auto" if not self.daytime: # turn off led self.hw.LEDControl(False)
def terminate(sig, frame): global shutdown if sig == signal.SIGALRM: # force shutdown debug("Shut down time-out, force-quitting.") debug("If the software locks up at this point, a reboot is needed.") debug("This is due to a bug in the underlying camera code.") cam.close() sys.exit() if not shutdown: # give the app 10 seconds to shut down, then force it shutdown = True signal.alarm(10) log("Signal " + str(sig) + " caught -- shutting down.") webui.stop() hw.motorOn(False) cam.close() hw.cleanup() sys.exit()
def runExperiment(self): if self.running: raise RuntimeError('An experiment is already running.') try: debug("Starting experiment.") self.running = True self.status = "Initiating" self.starttime = time.time() self.endtime = time.time() + 60 * 60 * 24 * self.duration self.last_captured = None self.delay = self.delay or 0.001 self.nshots = self.duration * 24 * 60 // self.delay self.cam.exposure_mode = "auto" self.cam.shutter_speed = 0 self.hw.LEDControl(False) for i in range(4): platedir = "plate" + str(i + 1) os.makedirs(os.path.join(self.dir, platedir), exist_ok=True) while time.time() < self.endtime and not self.stop_experiment: loopstart = time.time() nextloop = time.time() + 60 * self.delay if nextloop > self.endtime: nextloop = self.endtime for i in range(4): # rotate stage to starting position if i == 0: self.hw.motorOn(True) self.status = "Finding start position" debug("Finding initial position.") self.hw.findStart( calibration=self.cfg.get('calibration')) debug("Found initial position.") else: self.status = "Imaging" # rotate cube 90 degrees debug("Rotating stage.") self.hw.halfStep(100, 0.03) # wait for the cube to stabilize time.sleep(0.5) now = time.strftime("%Y%m%d-%H%M%S", time.localtime()) name = os.path.join("plate" + str(i + 1), "plate" + str(i + 1) + "-" + now) self.takePicture(name) self.nshots -= 1 self.hw.motorOn(False) self.status = "Waiting" if self.idlepos > 0: # alternate between resting positions during idle, stepping 45 degrees per image self.hw.motorOn(True) self.hw.halfStep(50 * self.idlepos, 0.03) self.hw.motorOn(False) self.idlepos += 1 if self.idlepos > 7: self.idlepos = 0 while time.time() < nextloop and not self.stop_experiment: # keep rotating while waiting, similar light conditions for each plate self.hw.motorOn(True) self.hw.halfStep(21, 0.03) self.hw.motorOn(False) time.sleep(60) finally: log("Experiment stopped.") self.cam.color_effects = None self.status = "Stopped" self.stop_experiment = False self.running = False self.cam.exposure_mode = "auto" self.cam.meter_mode = 'spot'
def runExperiment(self): if self.running: raise RuntimeError('An experiment is already running.') try: debug("Starting experiment.") self.running = True self.status = "Initiating" self.starttime = time.time() self.endtime = time.time() + 60 * 60 * 24 * self.duration self.last_captured = None self.delay = self.delay or 0.001 self.nshots = self.duration * 24 * 60 // self.delay self.cam.exposure_mode = "auto" self.cam.shutter_speed = 0 self.hw.LEDControl(False) for i in range(4): platedir = "plate" + str(i + 1) os.makedirs(os.path.join(self.dir, platedir), exist_ok=True) while time.time() < self.endtime and not self.stop_experiment: loopstart = time.time() nextloop = time.time() + 60 * self.delay if nextloop > self.endtime: nextloop = self.endtime for i in range(4): # rotate stage to starting position if i == 0: self.hw.motorOn(True) self.status = "Finding start position" debug("Finding initial position.") self.hw.findStart( calibration=self.cfg.get('calibration')) debug("Found initial position.") else: self.status = "Imaging" # rotate cube 90 degrees debug("Rotating stage.") self.hw.halfStep(100, 0.03) # wait for the cube to stabilize time.sleep(0.5) now = time.strftime("%Y%m%d-%H%M%S", time.localtime()) name = os.path.join("plate" + str(i + 1), "plate" + str(i + 1) + "-" + now) self.takePicture(name) self.nshots -= 1 self.hw.motorOn(False) # this part is "active waiting", rotating the cube slowly over the period of options.delay # this ensures consistent lighting for all plates. # account for the time spent capturing images. self.status = "Waiting" secs = 0 while time.time() < nextloop and not self.stop_experiment: time.sleep(1) secs += 1 if self.delay > 15 and secs == int(self.delay / 7.5): # don't bother if delay is very short (<= 15 min) secs = 0 self.hw.motorOn(True) self.hw.halfStep(50, 0.03) self.hw.motorOn(False) finally: log("Experiment stopped.") self.cam.color_effects = None self.status = "Stopped" self.stop_experiment = False self.running = False self.cam.exposure_mode = "auto" self.cam.meter_mode = 'spot'