def liveview_acquire(datapath, config_filename, writeToDisk=False): '''Aquire images from the SilCam Args: datapath (str) : Path to the image storage config_filename=None (str) : Camera config file writeToDisk=True (Bool) : True will enable writing of raw data to disc False will disable writing of raw data to disc gui=None (Class object) : Queue used to pass information between process thread and GUI initialised in ProcThread within guicals.py ''' #Load the configuration, create settings object settings = PySilcamSettings(config_filename) #Print configuration to screen print('---- CONFIGURATION ----\n') settings.config.write(sys.stdout) print('-----------------------\n') if (writeToDisk): # Copy config file configFile2Copy = datetime.datetime.now().strftime( 'D%Y%m%dT%H%M%S.%f') + os.path.basename(config_filename) copyfile(config_filename, os.path.join(datapath, configFile2Copy)) configure_logger(settings.General) # update path_length updatePathLength(settings, logger) acq = Acquire(USE_PYMBA=True) # ini class t1 = time.time() aqgen = acq.get_generator(datapath, camera_config_file=config_filename, writeToDisk=writeToDisk) for i, (timestamp, imraw) in enumerate(aqgen): t2 = time.time() aq_freq = np.round(1.0 / (t2 - t1), 1) requested_freq = settings.Camera.acquisitionframerateabs rest_time = (1 / requested_freq) - (1 / aq_freq) rest_time = np.max([rest_time, 0.]) actual_aq_freq = 1 / (1 / aq_freq + rest_time) logger.info('Image {0} acquired at frequency {1:.1f} Hz'.format( i, actual_aq_freq)) t1 = time.time() yield timestamp, imraw
def silcam_process(config_filename, datapath, multiProcess=True, realtime=False, discWrite=False, nbImages=None, gui=None, overwriteSTATS=True): '''Run processing of SilCam images Args: config_filename (str) : The filename (including path) of the config.ini file datapath (str) : Path to the data directory multiProcess=True (bool) : If True, multiprocessing is used realtime=False (bool) : If True, a faster but less accurate methods is used for segmentation and rts stats become active discWrite=False (bool) : True will enable writing of raw data to disc False will disable writing of raw data to disc nbImages=None (int) : Number of images to skip gui=None (Class object) : Queue used to pass information between process thread and GUI initialised in ProcThread within guicals.py ''' print(config_filename) print('') # ---- SETUP ---- # Load the configuration, create settings object settings = PySilcamSettings(config_filename) # Print configuration to screen print('---- CONFIGURATION ----\n') settings.config.write(sys.stdout) print('-----------------------\n') # Configure logging configure_logger(settings.General) logger = logging.getLogger(__name__ + '.silcam_process') logger.info('Processing path: ' + datapath) if realtime: if discWrite: # copy config file into data path configFile2Copy = datetime.datetime.now().strftime( 'D%Y%m%dT%H%M%S.%f') + os.path.basename(config_filename) copyfile(config_filename, os.path.join(datapath, configFile2Copy)) # update path_length updatePathLength(settings, logger) # make datafilename autogenerated for easier batch processing if (not os.path.isdir(settings.General.datafile)): logger.info('Folder ' + settings.General.datafile + ' was not found and is created') os.mkdir(settings.General.datafile) procfoldername = os.path.split(datapath)[-1] datafilename = os.path.join(settings.General.datafile, procfoldername) logger.info('output stats to: ' + datafilename) adminSTATS(logger, settings, overwriteSTATS, datafilename, datapath) # Initialize the image acquisition generator if 'REALTIME_DISC' in os.environ.keys(): print('acq = Acquire(USE_PYMBA=False)') aq = Acquire(USE_PYMBA=False) else: aq = Acquire(USE_PYMBA=realtime) aqgen = aq.get_generator(datapath, writeToDisk=discWrite, camera_config_file=config_filename) # Get number of images to use for background correction from config print('* Initializing background image handler') bggen = backgrounder( settings.Background.num_images, aqgen, bad_lighting_limit=settings.Process.bad_lighting_limit, real_time_stats=settings.Process.real_time_stats) # Create export directory if needed if settings.ExportParticles.export_images: if (not os.path.isdir(settings.ExportParticles.outputpath)): logger.info('Export folder ' + settings.ExportParticles.outputpath + ' was not found and is created') os.mkdir(settings.ExportParticles.outputpath) # ---- END SETUP ---- # ---- RUN PROCESSING ---- # If only one core is available, no multiprocessing will be done multiProcess = multiProcess and (multiprocessing.cpu_count() > 1) print('* Commencing image acquisition and processing') # initialise realtime stats class regardless of whether it is used later rts = scog.rt_stats(settings) if (multiProcess): proc_list = [] mem = psutil.virtual_memory() memAvailableMb = mem.available >> 20 distributor_q_size = np.min([ int(memAvailableMb / 2 * 1 / 15), np.copy(multiprocessing.cpu_count() * 4) ]) logger.debug('setting up processing queues') inputQueue, outputQueue = defineQueues(realtime, distributor_q_size) logger.debug('setting up processing distributor') distributor(inputQueue, outputQueue, config_filename, proc_list, gui) # iterate on the bggen generator to obtain images logger.debug('Starting acquisition loop') t2 = time.time() for i, (timestamp, imc, imraw) in enumerate(bggen): t1 = np.copy(t2) t2 = time.time() print(t2 - t1, 'Acquisition loop time') logger.debug('Corrected image ' + str(timestamp) + ' acquired from backgrounder') # handle errors if the loop function fails for any reason if (nbImages != None): if (nbImages <= i): break logger.debug('Adding image to processing queue: ' + str(timestamp)) addToQueue( realtime, inputQueue, i, timestamp, imc ) # the tuple (i, timestamp, imc) is added to the inputQueue logger.debug('Processing queue updated') # write the images that are available for the moment into the csv file logger.debug('Running collector') collector(inputQueue, outputQueue, datafilename, proc_list, False, settings, rts=rts) logger.debug('Data collected') if not gui == None: logger.debug('Putting data on GUI Queue') while (gui.qsize() > 0): try: gui.get_nowait() time.sleep(0.001) except: continue # try: rtdict = dict() rtdict = { 'dias': rts.dias, 'vd_oil': rts.vd_oil, 'vd_gas': rts.vd_gas, 'oil_d50': rts.oil_d50, 'gas_d50': rts.gas_d50, 'saturation': rts.saturation } gui.put_nowait((timestamp, imc, imraw, rtdict)) logger.debug('GUI queue updated') if 'REALTIME_DISC' in os.environ.keys(): scog.realtime_summary(datafilename + '-STATS.csv', config_filename) logger.debug('Acquisition loop completed') if (not realtime): logger.debug('Halting processes') for p in proc_list: inputQueue.put(None) # some images might still be waiting to be written to the csv file logger.debug('Running collector on left over data') collector(inputQueue, outputQueue, datafilename, proc_list, True, settings, rts=rts) logger.debug('All data collected') for p in proc_list: p.join() logger.info('%s.exitcode = %s' % (p.name, p.exitcode)) else: # no multiprocessing # load the model for particle classification and keep it for later nnmodel = [] nnmodel, class_labels = sccl.load_model( model_path=settings.NNClassify.model_path) # iterate on the bggen generator to obtain images for i, (timestamp, imc, imraw) in enumerate(bggen): # handle errors if the loop function fails for any reason if (nbImages != None): if (nbImages <= i): break image = (i, timestamp, imc) # one single image is processed at a time stats_all = processImage(nnmodel, class_labels, image, settings, logger, gui) if (not stats_all is None): # if frame processed # write the image into the csv file writeCSV(datafilename, stats_all) if 'REALTIME_DISC' in os.environ.keys(): scog.realtime_summary(datafilename + '-STATS.csv', config_filename) if not gui == None: collect_rts(settings, rts, stats_all) logger.debug('Putting data on GUI Queue') while (gui.qsize() > 0): try: gui.get_nowait() time.sleep(0.001) except: continue # try: rtdict = dict() rtdict = { 'dias': rts.dias, 'vd_oil': rts.vd_oil, 'vd_gas': rts.vd_gas, 'oil_d50': rts.oil_d50, 'gas_d50': rts.gas_d50, 'saturation': rts.saturation } gui.put_nowait((timestamp, imc, imraw, rtdict)) logger.debug('GUI queue updated') print('PROCESSING COMPLETE.')
def silcam_acquire(datapath, config_filename, writeToDisk=True, gui=None): '''Aquire images from the SilCam Args: datapath (str) : Path to the image storage config_filename=None (str) : Camera config file writeToDisk=True (Bool) : True will enable writing of raw data to disc False will disable writing of raw data to disc gui=None (Class object) : Queue used to pass information between process thread and GUI initialised in ProcThread within guicals.py ''' # Load the configuration, create settings object settings = PySilcamSettings(config_filename) # Print configuration to screen print('---- CONFIGURATION ----\n') settings.config.write(sys.stdout) print('-----------------------\n') if (writeToDisk): # Copy config file configFile2Copy = datetime.datetime.now().strftime( 'D%Y%m%dT%H%M%S.%f') + os.path.basename(config_filename) copyfile(config_filename, os.path.join(datapath, configFile2Copy)) configure_logger(settings.General) logger = logging.getLogger(__name__ + '.silcam_acquire') # update path_length updatePathLength(settings, logger) acq = Acquire(USE_PYMBA=True) # ini class t1 = time.time() aqgen = acq.get_generator(datapath, camera_config_file=config_filename, writeToDisk=writeToDisk) for i, (timestamp, imraw) in enumerate(aqgen): t2 = time.time() aq_freq = np.round(1.0 / (t2 - t1), 1) requested_freq = settings.Camera.acquisitionframerateabs rest_time = (1 / requested_freq) - (1 / aq_freq) rest_time = np.max([rest_time, 0.]) time.sleep(rest_time) actual_aq_freq = 1 / (1 / aq_freq + rest_time) print('Image {0} acquired at frequency {1:.1f} Hz'.format( i, actual_aq_freq)) t1 = time.time() if not gui == None: while (gui.qsize() > 0): try: gui.get_nowait() time.sleep(0.001) except: continue # try: rtdict = dict() rtdict = { 'dias': 0, 'vd_oil': 0, 'vd_gas': 0, 'oil_d50': 0, 'gas_d50': 0, 'saturation': 0 } gui.put_nowait((timestamp, imraw, imraw, rtdict))