""" Folder watcher used for smart imaging It first pop up a user input to choose the method to use for smart imaging anf if we are in a test mode (in this case we have to define an image folder and the job files will be saved in a subfolder) Then it calls Config method from the corresponding script for smart imaging that pops up another user input window to configure this selected method. Once this configuration is closed, the main script calls the Run method from the subscript with every image it founs while watching the folder The Run method perform the smart imaging detection and return the objective coordinates for the high magnification acquisition. NB : the compution of the corrdiantes is done in the subscript since it has access to the image and template dimension. It could be done in the main script below but this would mean returning a lot of variables fron the subscript The main script use this corrdiantes to geenrate the JobFile before going to the next image. This is repeated until the max number of images set in the configuration window is reached (or until the macro is killed, otherwise the folder watching keeps going on) This version is made for IM04 only sonce the metadata for objective... are extracted from the filename """ #@PrefService prefs import os, time from os.path import join,isdir,isfile from ij import IJ from fiji.util.gui import GenericDialogPlus from java.lang.System import getProperty from ast import literal_eval ##################################################################################### # Create function that will write the job files def WriteJob(ImageName,X,Y): global JobFolder,doSwitch ''' Function that will be call with each image after detection of the region of interest X,Y : Objective coordinates in mm with 3 decimal digits for high objective imaging ''' # Write job file for higher magnification for each processed image IJ.log('Writing job file') print 'Writing job file' # Extract Metadata before writing job file - IM4 name convention here ! Well = ImageName[1:5] # A1 for instance WellNum = int(ImageName[106:111]) # 1 to 96, convert to int to remove leading 0 PixelSize_Low = ImageName[34:39] ObjIdx_Low = PixToObj[PixelSize_Low] # Get objective index from pixel size read from image name Obj_Low = ObjToMag[ObjIdx_Low] # Magnification '2X','4X','10X' or '20X' #Power = int(ImageName[43:47]) #Integration = int(ImageName[51:55]) Path_TmpFileName = os.path.join(JobFolder, ImageName+".tmp") # first created as a tmp file to prevent machine from reading itthen rename as .job JobFile = open(Path_TmpFileName,'w') JobFile.write("SetWellNo({})\n".format(WellNum)) JobFile.write("SetMeta('Well Coordinate','{}')\n".format(Well)) JobFile.write("SetMeta('Well Pos in Well','1')\n") JobFile.write("GotoXY({:.3f},{:.3f},'Abs')\n".format(X,Y)) # x,y as float 3-decimal, force the trailing 0 if 0 as last decimal JobFile.write("SetMeta('Objective','{}')\n".format(HighObj_Mag)) # '2X','4X','10X' or '20X' JobFile.write("SetMeta('Objective Pixel Size','{}')\n".format(PixelSize_High)) JobFile.write("SetObjective({})\n".format(ObjIdx_High)) ''' JobFile.write("SetLight(6,10,10,0.000)\n") JobFile.write("AcquireAutofocus(7,100.000,2,'True','True')\n") JobFile.write("SetLight(6,50,10,0.000,'Flash')\n") JobFile.write("AcquireAutofocus(6,20.000,2,'True','True')\n") JobFile.write("SetLight(6,50,10,0.000)\n") JobFile.write("Acquire(1,0.000,1,'D:\IMAGING-DATA\IMAGES\SCRIPTS','True','SIdata')\n") # Images will be saved in a subfolder SIdata ''' JobFile.write(Script+'\n') # Switching off the light JobFile.write("SetLight(0,0,0,0)\n") if doSwitch: # Going back to previous obj. JobFile.write("SetMeta('Objective','{}')\n".format(Obj_Low)) JobFile.write("SetMeta('Objective Pixel Size','{}')\n".format(PixelSize_Low)) JobFile.write("SetObjective({})\n".format(ObjIdx_Low)) else: # The switch should be done for the very last well ? pass JobFile.close() # Rename from tmp to job Path_JobFileName = Path_TmpFileName[:-4]+'.job' # Check that the job file is not already existing if isfile(Path_JobFileName): IJ.log('Overwriting existing JobFile') print 'Overwriting existing JobFile' os.remove(Path_JobFileName) # Finally rename from .tmp to .job os.rename(Path_TmpFileName,Path_JobFileName) ######################################################################################## # START # Try to recover previous input from persistence Method0 = prefs.get("SImethod","Template matching") CountMax0 = prefs.getInt("nWell",96) # this one fails Test0 = prefs.getInt("Test",True) # for Boolean use getInt (see forum for bug) Path_ImageFolder0 = prefs.get("ImagePathSI","ImageFolder") HighObj_Mag0 = prefs.get("HighMag","10x") doJob0 = prefs.getInt("WriteJob",False) doSwitch0 = prefs.getInt("SwitchObj",True) template = """SetLight(6,10,10,0.000) AcquireAutofocus(7,100.000,2,'True','True') SetLight(6,50,10,0.000,'Flash') AcquireAutofocus(6,20.000,2,'True','True') SetLight(6,50,10,0.000) Acquire(1,0.000,1,'D:\IMAGING-DATA\IMAGES\SCRIPTS','True','SIdata') """ Script0 = prefs.get(None,"SIscript",template) # Input GUI Win = GenericDialogPlus("Smart Imaging") Win.addChoice("Smart imaging method",["Template matching","Keypoint matching","Center of mass"],Method0) Win.addNumericField("Number of well to process",CountMax0,0) Win.addCheckbox("Test mode (if not on the microscope)",Test0) Win.addDirectoryField("Directory to watch (in test mode)",Path_ImageFolder0) Win.addChoice("Objective for smart imaging",["2x","4x","10x","20x"],HighObj_Mag0) Win.addCheckbox("Write job files", doJob0) # JobFile are written anyway if we are not in Test mode Win.addCheckbox("Switch to previous objective after each smart imaging job", doSwitch0) # Add a text field with the smart imaging script Win.addMessage("Copy/Paste a smart imaging script in the field below or use a template : ") Win.addTextAreas(Script0,None,5,100) # Add help button Disclaimer = '''

The smart imaging is the implementation of feedback microscopy on Acquifer's imaging machine.
The idea is to use image recognition scripts to automatically detect the ROI in the low magnification images,
and perform the corresponding high magnification acquisition. See documentation.

''' Win.addHelp(Disclaimer) Win.showDialog() if Win.wasOKed(): # Recover inputs Method = Win.getNextChoice() CountMax = Win.getNextNumber() Test = Win.getNextBoolean() Path_ImageFolder = Win.getNextString() HighObj_Mag = Win.getNextChoice() doJob = Win.getNextBoolean() doSwitch = Win.getNextBoolean() Script = Win.getNextText() # correspondance used to write the job file PixToObj = {'32500':1, '16250':2, '6500':3, '3250':4} # map pixel size from the filename to objective index ObjToPix = {v: k for k, v in PixToObj.iteritems()} # invert mapping MagToObj = {'2x':1, '4x':2, '10x':3, '20x':4} # Mapping magnification to its objective index ObjToMag = {v: k for k, v in MagToObj.iteritems()} # Mapping index to magnification ObjIdx_High = MagToObj[HighObj_Mag] # Get objective index from magnification for SI given by user PixelSize_High = ObjToPix[ObjIdx_High] # Get Pixel size from obj index # Save the inputs to memory/persistence prefs.put("SImethod",Method) prefs.put("nWell",int(CountMax)) prefs.put("Test",Test) prefs.put("ImagePathSI",Path_ImageFolder) prefs.put("HighMag",HighObj_Mag) prefs.put("WriteJob",doJob) prefs.put("SwitchObj",doSwitch) prefs.put("SIscript",Script) # Set the run method according to choice if Method == "Template matching": from Match_Template_SI_IJM import Run, Config elif Method == "Keypoint matching" : from Keypoint_SI_IJM import Run, Config elif Method == "Center of mass": from CenterOfMass import Run, Config # Pop up a user input window to configure the smart imaging method chosen Cancel = Config() if Cancel: print "Smart imaging was cancelled" pass else: # We perform the rest of the smart imaging IJ.resetEscape() # used to monitor if we quit # I - FIND IMAGE FOLDER if not Test: # We are really doing smart imaging Path_LocationFile = r"D:\IMAGING-DATA\JOBS\Image_Location.pth" #Path_LocationFile = r"C:\Users\Laurent Thomas\Desktop\Test\Image_Location.pth" # for tests JobFolder = r"D:\IMAGING-DATA\JOBS" #Try to read the LocationFile to get the image folder FoundLocation = False while not FoundLocation : if IJ.escapePressed(): # the escape can be caught by an image, the ImageJ menu bar or the log window (one of them must be selected) break # but still execute code after the while if we dont stop it properly time.sleep(1) # 1sec delay - prevent loop to run too fast and overload processes try : LocationFile = open(Path_LocationFile,'r') Path_ImageFolder = LocationFile.readline().rstrip() # read content of file and remove new line character LocationFile.close() os.remove(Path_LocationFile) # delete file once read FoundLocation = True print 'Found image location : ', Path_ImageFolder IJ.log('Found image location : ' + Path_ImageFolder) except Exception, Error : # File not existing yet FoundLocation = False print Error IJ.log(str(Error)) else: # in test mode #Path_ImageFolder = Path_ImageFolder.getCanonicalPath() # Convert from Java file to its path #Path_ImageFolder = Path_ImageFolder if doJob : JobFolder = join(Path_ImageFolder,"JOBS") if not os.path.exists(JobFolder): os.mkdir(JobFolder) # II - FOLDER WATCHING and calling the Run method from the imported script before = os.listdir(Path_ImageFolder) # initialisation must be out of the while loop since we are updating it with "current" at the end of the loop print before # INITIALISATION - We process the image present in the folder before ImageLocation.pth is created (currently this is the case, some image are saved before the file is created) count = 0 # initialise count of processed images for FileName in before : # images in test folder (if test mode) or written before the ImageLocation.pth FilePath = join(Path_ImageFolder,FileName) if IJ.escapePressed(): print "Escape" IJ.log("Escape") break elif not isdir(FilePath): # Check that it is a file and not a folder # Report progress message = '\nProcess '+FileName print message IJ.log(message) # Call Run and write job file X,Y = Run(FilePath,doJob) if doJob: if X==None and Y==None: message = "Smart imaging failed. No higher magnification imaging for this image" print message IJ.log(message) else: WriteJob(FileName,X,Y) else: # dont doJob or Test mode pass count += 1 # update count of processed image if count == CountMax : message = '\nDONE - Processed all images' print message IJ.log(message) break else: # the Filepath is a folder print "Skip folder"+FilePath continue # CONTINUATION Delay = 5 # delay in sec between successive scans for new image while count < CountMax and not IJ.escapePressed(): # strictly inferior since count starts at 0, and we update it after processing the image ie once we process the last image the counter will be CountMax and we dont want to run another round #while True: # only Keyboard interrupt version time.sleep(Delay) # before_List was updated just previously at the end of the loop so delay prior to a new listdir scan current = os.listdir(Path_ImageFolder) new = list( set(current) - set(before) ) # list containing new file and folder name in Path_ImageFolder if new != []: # New Files have appeared - PUT THE CODE TO EXECUTE HERE for FileName in new : FilePath = join(Path_ImageFolder,FileName) if not isdir(FilePath): # Check that it is a file and not a folder message = '\nProcess '+FileName print message IJ.log(message) # Call Run and write job file X,Y = Run(FilePath) if doJob: if X==None and Y==None: message = "Smart imaging failed. No higher magnification imaging for this image" print message IJ.log(message) else: WriteJob(FileName,X,Y) else: # dont doJob or Test mode ie dont write the job files pass count += 1 # update count of processed image if count == CountMax : message = '\nDONE - Processed all images' print message IJ.log(message) break else: # No new files, keep runnning the loop pass # update the 'history' of the folder watcher, and going for another round of while (except if we reached the count) before = current if IJ.escapePressed(): print "Interrupted by Escape" IJ.log("Interrupted by Escape")