def start_aqcuisition(self): global_pos = np.array( ((-5000, -5000), (-5000, 5000), (5000, -5000), (5000, 5000))) global_pos_name = ['A', 'B', 'C', 'D'] delta = 200 local_pos = np.transpose( np.reshape( np.meshgrid(np.array((-delta, 0, delta)), np.array((-delta, 0, delta))), (2, -1))) local_pos_name = [str(i) for i in range(9)] self.cam = CamActuator() self.cam.initializeCamera() # Offset variables are used to generate replicates for good statistics offset_y = offset_x = delta cnt = 0 for i in range(global_pos.shape[0]): for j in range(local_pos.shape[0]): x = global_pos[i, 0] + local_pos[j, 0] + offset_x y = global_pos[i, 1] + local_pos[j, 1] + offset_y stage_movement_thread = StagemovementAbsoluteThread(x, y) stage_movement_thread.start() time.sleep(2) stage_movement_thread.quit() stage_movement_thread.wait() image = self.cam.SnapImage(0.04) filename = global_pos_name[i] + local_pos_name[j] self.save_image(filename, image) cnt += 1 print( str(cnt) + '/' + str(len(local_pos_name) * len(global_pos_name))) self.cam.Exit()
def run(self): #Make sure registration can only start when camera is connected try: self.cam = CamActuator() self.cam.initializeCamera() except: print(sys.exc_info()) self.backend.ui_widget.normalOutputWritten( 'Unable to connect Hamamatsu camera') return self.cam.setROI(0, 0, 2048, 2048) if self.device_1 == 'galvos': reference_coordinates = self.gather_reference_coordinates_galvos() self.dict_transformations['camera-galvos'] = findTransform(reference_coordinates[0], \ reference_coordinates[1]) elif self.device_1 == 'dmd': reference_coordinates = self.gather_reference_coordinates_dmd() for laser in self.laser_list: self.dict_transformations['camera-dmd-'+laser] = findTransform(reference_coordinates[0], \ reference_coordinates[1]) elif self.device_1 == 'stage': reference_coordinates = self.gather_reference_coordinates_stage() self.dict_transformations['camera-stage'] = findTransform(reference_coordinates[0], \ reference_coordinates[1]) self.cam.Exit() ## Save transformation to file with open('CoordinatesManager/Registration/transformation.txt', 'w') as json_file: dict_transformations_list_format = {} for key, value in self.dict_transformations.items(): dict_transformations_list_format[key] = value.tolist() json.dump(dict_transformations_list_format, json_file) self.sig_finished_registration.emit(self.dict_transformations)
class DMDRegistator: def __init__(self, parent): self.DMD = DMDActuator.DMDActuator() self.cam = CamActuator() self.cam.initializeCamera() def registration(self, laser='640', points=6): x_coords = np.linspace(0, 1024, 5)[1:-1] y_coords = np.linspace(0, 768, 4)[1:-1] dmd_coordinates = np.vstack((x_coords, y_coords)) camera_coordinates = np.zeros(dmd_coordinates.shape) cnt = 0 for i in range(points): for j in range(y_coords.shape[0]): mask = create_registration_image(i, j) self.DMD.send_data_to_DMD(mask) self.DMD.start_projection() image = self.cam.SnapImage(0.4) camera_coordinates[cnt, :] = touchingCoordinateFinder( image, method='curvefit') cnt += 1 self.DMD.stop_projection() self.DMD.free_memory() self.DMD.disconnect_DMD() transformation = findTransformationCurvefit(camera_coordinates, dmd_coordinates, kx=3, ky=2) return transformation def create_registration_image(x, y, sigma=75): array = np.zeros((1024, 768)) array[skd.draw.rectangle((x - sigma, y - sigma), (x, y))] = 255 array[skd.draw.rectangle((x + sigma, y + sigma), (x, y))] = 255 return array
class RegistrationThread(QThread): sig_finished_registration = pyqtSignal(dict) def __init__(self, parent, laser=None): QThread.__init__(self) self.flag_finished = [0, 0, 0] self.backend = parent self.dmd = self.backend.DMD if not isinstance(laser, list): self.laser_list = [laser] else: self.laser_list = laser self.dict_transformators = {} self.dict_transformations = {} self.dtype_ref_co = np.dtype([('camera', int, (3, 2)), ('dmd', int, (3, 2)), ('galvos', int, (3, 2)), ('stage', int, (3, 2))]) self.reference_coordinates = {} def set_device_to_register(self, device_1, device_2='camera'): self.device_1 = device_1 self.device_2 = device_2 def run(self): #Make sure registration can only start when camera is connected try: self.cam = CamActuator() self.cam.initializeCamera() except: print(sys.exc_info()) self.backend.ui_widget.normalOutputWritten( 'Unable to connect Hamamatsu camera') return self.cam.setROI(0, 0, 2048, 2048) if self.device_1 == 'galvos': reference_coordinates = self.gather_reference_coordinates_galvos() self.dict_transformations['camera-galvos'] = findTransform(reference_coordinates[0], \ reference_coordinates[1]) elif self.device_1 == 'dmd': reference_coordinates = self.gather_reference_coordinates_dmd() for laser in self.laser_list: self.dict_transformations['camera-dmd-'+laser] = findTransform(reference_coordinates[0], \ reference_coordinates[1]) elif self.device_1 == 'stage': reference_coordinates = self.gather_reference_coordinates_stage() self.dict_transformations['camera-stage'] = findTransform(reference_coordinates[0], \ reference_coordinates[1]) self.cam.Exit() ## Save transformation to file with open('CoordinatesManager/Registration/transformation.txt', 'w') as json_file: dict_transformations_list_format = {} for key, value in self.dict_transformations.items(): dict_transformations_list_format[key] = value.tolist() json.dump(dict_transformations_list_format, json_file) self.sig_finished_registration.emit(self.dict_transformations) def gather_reference_coordinates_stage(self): image = np.zeros((2048, 2048, 3)) stage_coordinates = np.array([[-2800, 100], [-2500, 400], [-1900, -200]]) self.backend.loadMask(mask=np.ones((768, 1024))) self.backend.startProjection() for idx, pos in enumerate(stage_coordinates): stage_movement_thread = StagemovementAbsoluteThread(pos[0], pos[1]) stage_movement_thread.start() time.sleep(0.5) stage_movement_thread.quit() stage_movement_thread.wait() image[:, :, idx] = self.cam.SnapImage(0.04) camera_coordinates = find_subimage_location(image, save=True) self.backend.stopProjection() self.backend.freeMemory() return np.array([camera_coordinates, stage_coordinates]) def gather_reference_coordinates_galvos(self): galvothread = DAQmission() readinchan = [] camera_coordinates = np.zeros((3, 2)) galvo_coordinates = np.array([[0, 3], [3, -3], [-3, -3]]) for i in range(3): pos_x = galvo_coordinates[i, 0] pos_y = galvo_coordinates[i, 1] galvothread.sendSingleAnalog('galvosx', pos_x) galvothread.sendSingleAnalog('galvosy', pos_y) image = self.cam.SnapImage(0.04) camera_coordinates[i, :] = gaussian_fitting(image) del galvothread return np.array([camera_coordinates, galvo_coordinates]) def gather_reference_coordinates_dmd(self): galvo_coordinates = np.zeros((3, 2)) for laser in self.laser_list: self.flag_finished = [0, 0, 0] self.backend.ui_widget.sig_control_laser.emit(laser, 5) self.registration_single_laser(laser) self.backend.ui_widget.sig_control_laser.emit(laser, 0) return np.array( [self.camera_coordinates, self.dmd_coordinates, galvo_coordinates]) def registration_single_laser(self, laser): date_time = datetime.datetime.now().timetuple() image_id = '' for i in range(5): image_id += str(date_time[i]) + '_' image_id += str(date_time[5]) + '_l' + laser self.camera_coordinates = np.zeros((3, 2)) self.touchingCoordinateFinder = [] for i in range(3): self.touchingCoordinateFinder.append( touchingCoordinateFinder_Thread(i, method='curvefit')) self.touchingCoordinateFinder[ i].sig_finished_coordinatefinder.connect( self.touchingCoordinateFinder_finished) for i in range(3): self.loadFileName = './CoordinatesManager/Registration_Images/TouchingSquares/registration_mask_' + str( i) + '.png' # Transpose because mask in file is rotated by 90 degrees. mask = np.transpose(plt.imread(self.loadFileName)) self.backend.loadMask(mask) self.backend.startProjection() time.sleep(0.5) self.image = self.cam.SnapImage(0.0015) time.sleep(0.5) self.backend.stopProjection() self.backend.freeMemory() # Start touchingCoordinateFinder thread self.touchingCoordinateFinder[i].put_image(self.image) self.touchingCoordinateFinder[i].start() self.dmd_coordinates = self.read_dmd_coordinates_from_file() # Block till all touchingCoordinateFinder_Thread threads are finished while np.prod(self.flag_finished) == 0: time.sleep(0.1) def read_dmd_coordinates_from_file(self): file = open( './CoordinatesManager/Registration_Images/TouchingSquares/positions.txt', 'r') self.dmd_coordinates = [] for ln in file.readlines(): self.dmd_coordinates.append(ln.strip().split(',')) file.close() return np.asarray(self.dmd_coordinates).astype(int) def touchingCoordinateFinder_finished(self, sig): self.camera_coordinates[sig, :] = np.flip( self.touchingCoordinateFinder[sig].coordinates) self.flag_finished[sig] = 1
def __init__(self, parent): self.DMD = DMDActuator.DMDActuator() self.cam = CamActuator() self.cam.initializeCamera()
class CameraThread(QThread): snapsignal = pyqtSignal(np.ndarray) livesignal = pyqtSignal(np.ndarray) def __init__(self, camerahandle=None): self.exposuretime = 0.02 # seconds self.GUIframerate = 25 # frames per second self.sleeptime = np.max([1/self.GUIframerate, self.exposuretime]) self.frame = np.random.rand(2048, 2048) self.mutex = QMutex() # Camera attributes if camerahandle == None: self.camera = CamActuator() self.camera.initializeCamera() else: self.camera = camerahandle self.camera.hcam.setPropertyValue("exposure_time", self.exposuretime) # QThread attributes super().__init__() self.isrunning = False self.moveToThread(self) self.started.connect(self.live) def stop(self): self.isrunning = False self.quit() self.wait() def snap(self): time.sleep(self.sleeptime) snap = np.random.rand(2048, 2048) self.mutex.lock() snap = copy(self.frame) self.mutex.unlock() self.snapsignal.emit(snap) return snap @pyqtSlot() def live(self): print('camera thread started') self.camera.isLiving = True self.camera.hcam.acquisition_mode = "run_till_abort" # Wait a second for camera acquisition to start self.camera.hcam.startAcquisition() QThread.msleep(1000) # Emit and get frames from the camera at a rate of 1/sleeptime self.isrunning = True while self.isrunning: QThread.msleep(int(self.sleeptime *1000)) try: [frames, dims] = self.camera.hcam.getFrames() self.mutex.lock() self.frame = np.resize(frames[-1].np_array, (dims[1], dims[0])) self.livesignal.emit(self.frame) self.mutex.unlock() except: pass self.camera.hcam.stopAcquisition() self.camera.isLiving = False self.camera.Exit() print('camera thread stopped')
def run(self): """ # ========================================================================================================================================================== # Initialization # ========================================================================================================================================================== """ #%% """ # ============================================================================= # connect the Objective motor # ============================================================================= """ print('----------------------Starting to connect the Objective motor-------------------------') self.pi_device_instance = PIMotor() print('Objective motor connected.') self.errornum = 0 self.ObjCurrentPos = self.pi_device_instance.pidevice.qPOS(self.pi_device_instance.pidevice.axes) """ # ============================================================================= # connect the Hmamatsu camera # ============================================================================= """ self._use_camera = False for key in self.RoundQueueDict: if "RoundPackage_" in key: for waveform_and_cam_key in self.RoundQueueDict[key][1]: if "CameraPackage_" in waveform_and_cam_key: if len(self.RoundQueueDict[key][1][waveform_and_cam_key]) != 0: self._use_camera = True if self._use_camera == True: print('Connecting camera...') self.HamamatsuCam = CamActuator() self.HamamatsuCam.initializeCamera() else: print('No camera involved.') """ # ============================================================================= # connect the Insight X3 # ============================================================================= """ if len(self.RoundQueueDict['InsightEvents']) != 0: self.Laserinstance = InsightX3('COM11') try: querygap = 1.1 # self.Laserinstance.SetWatchdogTimer(0) # Disable the laser watchdog! # Status_watchdog_thread = threading.Thread(target = self.Status_watchdog, args=[querygap], daemon=True) # Status_watchdog_thread.start() time.sleep(1) #-------------Initialize laser-------------- self.watchdog_flag = False time.sleep(0.5) warmupstatus = 0 while int(warmupstatus) != 100: try: warmupstatus = self.Laserinstance.QueryWarmupTime() time.sleep(0.6) except: time.sleep(0.6) # if int(warmupstatus) == 100: # self.warmupstatus = True # print('Laser fully warmed up.') # if 'Laser state:Ready' in self.Status_list: # self.Laserinstance.Turn_On_PumpLaser() # self.laserRun = True # elif 'Laser state:RUN' in self.Status_list: # self.laserRun = True self.watchdog_flag = True time.sleep(0.5) except: print('Laser not connected.') # If turn on the laser shutter in the beginning if 'Shutter_Open' in self.GeneralSettingDict['StartUpEvents']: time.sleep(0.5) while True: try: self.Laserinstance.Open_TunableBeamShutter() break except: time.sleep(1) time.sleep(0.5) #%% """ # ========================================================================================================================================================== # Execution # ========================================================================================================================================================== """ GridSequence = 0 TotalGridNumber = self.meshgridnumber**2 ScanningMaxCoord = int(np.amax(self.RoundCoordsDict['CoordsPackage_1'])) # Get the largest coordinate for EachGrid in range(TotalGridNumber): """ # ============================================================================= # For each small repeat unit in the scanning meshgrid # ============================================================================= """ ScanningGridOffset_Row = int(GridSequence % self.meshgridnumber) * (ScanningMaxCoord + self.GeneralSettingDict['Scanning step']) # Offset coordinate row value for each well. ScanningGridOffset_Col = int(GridSequence/self.meshgridnumber) * (ScanningMaxCoord + self.GeneralSettingDict['Scanning step']) # Offset coordinate colunm value for each well. GridSequence += 1 time.sleep(0.5) for EachRound in range(int(len(self.RoundQueueDict)/2-1)): # EachRound is the round sequence number starting from 0, while the actual number used in dictionary is 1. print ('----------------------------------------------------------------------------') print('Below is Grid {}, Round {}.'.format(EachGrid, EachRound+1)) # EachRound+1 is the corresponding round number when setting the dictionary starting from round 1. """ # ============================================================================= # Unpack the settings for each round # ============================================================================= """ # Initialize variables CoordOrder = 0 # Counter for n th coordinates, for appending cell properties array. CellPropertiesDict = {} ND_filter1_Pos = None ND_filter2_Pos = None EM_filter_Pos = None cp_end_index = -1 self.IndexLookUpCellPropertiesDict = {} #look up dictionary for each cell properties #-------------Unpack the focus stack information. ZStackinfor = self.GeneralSettingDict['FocusStackInfoDict']['RoundPackage_{}'.format(EachRound+1)] self.ZStackNum = int(ZStackinfor[ZStackinfor.index('Focus')+5]) self.ZStackStep = float(ZStackinfor[ZStackinfor.index('Being')+5:len(ZStackinfor)]) #-------------Unpack infor for stage move. CoordsNum = int(len(self.RoundCoordsDict['CoordsPackage_{}'.format(EachRound+1)])/2) #Each pos has 2 coords #-------------Unpack infor for filter event. In the list, the first one is for ND filter and the second one is for emission filter. FilterEventIndexList = [i for i,x in enumerate(self.RoundQueueDict['FilterEvents']) if 'Round_{}'.format(EachRound+1) in x] if len(FilterEventIndexList) > 0: NDposText = self.RoundQueueDict['FilterEvents'][FilterEventIndexList[0]] NDnumber = NDposText[NDposText.index('ToPos_')+6:len(NDposText)] EMposText = self.RoundQueueDict['FilterEvents'][FilterEventIndexList[1]] EMprotein = EMposText[EMposText.index('ToPos_')+6:len(EMposText)] # "COM9" for filter 1 port, which has ND values from 0 to 3. # "COM7" for filter 2 port, which has ND values from 0 to 0.5. if NDnumber == '0': ND_filter1_Pos = 0 ND_filter2_Pos = 0 elif NDnumber == '1': ND_filter1_Pos = 1 ND_filter2_Pos = 0 elif NDnumber == '2': ND_filter1_Pos = 2 ND_filter2_Pos = 0 elif NDnumber == '2.3': ND_filter1_Pos = 2 ND_filter2_Pos = 2 elif NDnumber == '2.5': ND_filter1_Pos = 2 ND_filter2_Pos = 3 elif NDnumber == '0.5': ND_filter1_Pos = 0 ND_filter2_Pos = 3 elif NDnumber == '0.3': ND_filter1_Pos = 0 ND_filter2_Pos = 2 if EMprotein == 'Arch': EM_filter_Pos = 0 elif EMprotein == 'eGFP' or EMprotein == 'Citrine': EM_filter_Pos = 1 #-------------Unpack infor for Insight X3. In the list, the first one is for shutter event and the second one is for wavelength event. InsightX3EventIndexList = [i for i,x in enumerate(self.RoundQueueDict['InsightEvents']) if 'Round_{}'.format(EachRound+1) in x] """ # ============================================================================= # Execute Insight event at the beginning of each round # ============================================================================= """ if len(InsightX3EventIndexList) == 1: print(InsightX3EventIndexList) InsightText = self.RoundQueueDict['InsightEvents'][InsightX3EventIndexList[0]] if 'Shutter_Open' in InsightText: self.watchdog_flag = False time.sleep(0.5) while True: try: self.Laserinstance.Open_TunableBeamShutter() break except: time.sleep(1) time.sleep(0.5) print('Laser shutter open.') self.watchdog_flag = True time.sleep(0.5) elif 'Shutter_Close' in InsightText: self.watchdog_flag = False time.sleep(0.5) while True: try: self.Laserinstance.Close_TunableBeamShutter() break except: time.sleep(1) time.sleep(0.5) print('Laser shutter closed.') self.watchdog_flag = True time.sleep(0.5) elif 'WavelengthTo' in InsightText: self.watchdog_flag = False time.sleep(0.5) TargetWavelen = int(InsightText[InsightText.index('To_')+3:len(InsightText)]) print(TargetWavelen) while True: try: self.Laserinstance.SetWavelength(TargetWavelen) break except: time.sleep(1) time.sleep(5) self.watchdog_flag = True time.sleep(0.5) elif len(InsightX3EventIndexList) == 2: InsightText_wl = self.RoundQueueDict['InsightEvents'][InsightX3EventIndexList[1]] InsightText_st = self.RoundQueueDict['InsightEvents'][InsightX3EventIndexList[0]] if 'WavelengthTo' in InsightText_wl and 'Shutter_Open' in InsightText_st: self.watchdog_flag = False time.sleep(0.5) TargetWavelen = int(InsightText_wl[InsightText_wl.index('To_')+3:len(InsightText_wl)]) while True: try: self.Laserinstance.SetWavelength(TargetWavelen) break except: time.sleep(1) time.sleep(5) while True: try: self.Laserinstance.Open_TunableBeamShutter() break except: time.sleep(1) print('Laser shutter open.') self.watchdog_flag = True time.sleep(0.5) elif 'WavelengthTo' in InsightText_wl and 'Shutter_Close' in InsightText_st: self.watchdog_flag = False time.sleep(0.5) TargetWavelen = int(InsightText_wl[InsightText_wl.index('To_')+3:len(InsightText_wl)]) while True: try: self.Laserinstance.SetWavelength(TargetWavelen) break except: time.sleep(1) time.sleep(5) while True: try: self.Laserinstance.Close_TunableBeamShutter() break except: time.sleep(1) time.sleep(1) print('Laser shutter closed.') self.watchdog_flag = True time.sleep(0.5) time.sleep(2) """ # ============================================================================= # Execute filter event at the beginning of each round # ============================================================================= """ if ND_filter1_Pos != None and ND_filter2_Pos != None: #Move filter 1 self.filter1 = ELL9Filter("COM9") self.filter1.moveToPosition(ND_filter1_Pos) time.sleep(1) #Move filter 2 self.filter2 = ELL9Filter("COM7") self.filter2.moveToPosition(ND_filter2_Pos) time.sleep(1) if EM_filter_Pos != None: self.filter3 = ELL9Filter("COM15") self.filter3.moveToPosition(EM_filter_Pos) time.sleep(1) self.currentCoordsSeq = 0 #%% for EachCoord in range(CoordsNum): #-----------------------------------------------At each stage coordinate:-------------------------------------------- self.error_massage = None self.currentCoordsSeq += 1 """ # ============================================================================= # Stage movement # ============================================================================= """ RowIndex = int(self.RoundCoordsDict['CoordsPackage_{}'.format(EachRound+1)][EachCoord*2:EachCoord*2+2][0]) + ScanningGridOffset_Row ColumnIndex = int(self.RoundCoordsDict['CoordsPackage_{}'.format(EachRound+1)][EachCoord*2:EachCoord*2+2][1]) + ScanningGridOffset_Col try: self.ludlStage.moveAbs(RowIndex,ColumnIndex) # Row/Column indexs of np.array are opposite of stage row-col indexs. except: self.error_massage = 'Fail_MoveStage' self.errornum += 1 print('Stage move failed! Error number: {}'.format(int(self.errornum))) print ('Round {}. Current index: {}.'.format(EachRound+1, [RowIndex,ColumnIndex])) time.sleep(1) """ # ============================================================================= # Get the z stack objective positions ready # ============================================================================= """ #-------------------------------------------If focus correction applies---------------------------------------- if len(self.GeneralSettingDict['FocusCorrectionMatrixDict']) > 0: FocusPosArray = self.GeneralSettingDict['FocusCorrectionMatrixDict']['RoundPackage_{}_Grid_{}'.format(EachRound+1, EachGrid)] # print(FocusPosArray) FocusPosArray = FocusPosArray.flatten('F') FocusPos_fromCorrection = FocusPosArray[EachCoord] print('Target focus pos: '.format(FocusPos_fromCorrection)) # Without focus correction if len(self.GeneralSettingDict['FocusCorrectionMatrixDict']) == 0: ZStacklinspaceStart = self.ObjCurrentPos['1'] - (math.floor(self.ZStackNum/2)-1)*self.ZStackStep ZStacklinspaceEnd = self.ObjCurrentPos['1'] + (self.ZStackNum - math.floor(self.ZStackNum/2))*self.ZStackStep # With focus correction elif len(self.GeneralSettingDict['FocusCorrectionMatrixDict']) > 0: ZStacklinspaceStart = FocusPos_fromCorrection - (math.floor(self.ZStackNum/2)-1)*self.ZStackStep ZStacklinspaceEnd = FocusPos_fromCorrection + (self.ZStackNum - math.floor(self.ZStackNum/2))*self.ZStackStep ZStackPosList = np.linspace(ZStacklinspaceStart, ZStacklinspaceEnd, num = self.ZStackNum) print(ZStackPosList) """ # ============================================================================= # Execute waveform packages # ============================================================================= """ self.WaveforpackageNum = int(len(self.RoundQueueDict['RoundPackage_{}'.format(EachRound+1)][0])) #Execute each individual waveform package print('*******************************************Round {}. Current index: {}.**************************************************'.format(EachRound+1, [RowIndex,ColumnIndex])) #------------------Move to Z stack focus------------------- for EachZStackPos in range(self.ZStackNum): print('--------------------------------------------Stack {}--------------------------------------------------'.format(EachZStackPos+1)) if self.ZStackNum > 1: self.ZStackOrder = int(EachZStackPos +1) # Here the first one is 1, not starting from 0. FocusPos = ZStackPosList[EachZStackPos] print('Target focus pos: {}'.format(FocusPos)) pos = PIMotor.move(self.pi_device_instance.pidevice, FocusPos) self.ObjCurrentPosInStack = self.pi_device_instance.pidevice.qPOS(self.pi_device_instance.pidevice.axes) print("Current position: {:.4f}".format(self.ObjCurrentPosInStack['1'])) time.sleep(0.3) else: self.ZStackOrder = 1 #------------For waveforms in each coordinate---------- for EachWaveform in range(self.WaveforpackageNum): # Extract information WaveformPackageToBeExecute = self.RoundQueueDict['RoundPackage_{}'.format(EachRound+1)][0]['WaveformPackage_{}'.format(EachWaveform+1)] CameraPackageToBeExecute = self.RoundQueueDict['RoundPackage_{}'.format(EachRound+1)][1]["CameraPackage_{}".format(EachWaveform+1)] WaveformPackageGalvoInfor = self.RoundQueueDict['GalvoInforPackage_{}'.format(EachRound+1)]['GalvoInfor_{}'.format(EachWaveform+1)] self.readinchan = WaveformPackageToBeExecute[3] self.RoundWaveformIndex = [EachRound+1, EachWaveform+1] # first is current round number, second is current waveform package number. self.CurrentPosIndex = [RowIndex, ColumnIndex] #----------------Camera operations----------------- _camera_isUsed = False if CameraPackageToBeExecute != {}: # if camera operations are configured _camera_isUsed = True CamSettigList = CameraPackageToBeExecute["Settings"] self.HamamatsuCam.StartStreaming(BufferNumber = CameraPackageToBeExecute["Buffer_number"], trigger_source = CamSettigList[CamSettigList.index("trigger_source")+1], exposure_time = CamSettigList[CamSettigList.index("exposure_time")+1], trigger_active = CamSettigList[CamSettigList.index("trigger_active")+1]) # Make sure that the camera is prepared before waveform execution. # while self.HamamatsuCam.isStreaming == False: # print('Waiting for camera...') # time.sleep(0.5) time.sleep(1) print('Now start waveforms') #----------------Waveforms operations-------------- if WaveformPackageGalvoInfor != 'NoGalvo': # Unpack the information of galvo scanning. self.readinchan = WaveformPackageGalvoInfor[0] self.repeatnum = WaveformPackageGalvoInfor[1] self.PMT_data_index_array = WaveformPackageGalvoInfor[2] self.averagenum = WaveformPackageGalvoInfor[3] self.lenSample_1 = WaveformPackageGalvoInfor[4] self.ScanArrayXnum = WaveformPackageGalvoInfor[5] if self.clock_source == 'Dev1 as clock source': self.adcollector = execute_analog_readin_optional_digital_thread() self.adcollector.set_waves(WaveformPackageToBeExecute[0], WaveformPackageToBeExecute[1], WaveformPackageToBeExecute[2], WaveformPackageToBeExecute[3]) #[0] = sampling rate, [1] = analogcontainer_array, [2] = digitalcontainer_array, [3] = readinchan self.adcollector.collected_data.connect(self.ProcessData) self.adcollector.run() time.sleep(0.2) #self.ai_dev_scaling_coeff = self.adcollector.get_ai_dev_scaling_coeff() elif self.clock_source == 'Cam as clock source' : self.adcollector = execute_analog_and_readin_digital_optional_camtrig_thread() self.adcollector.set_waves(WaveformPackageToBeExecute[0], WaveformPackageToBeExecute[1], WaveformPackageToBeExecute[2], WaveformPackageToBeExecute[3]) self.adcollector.collected_data.connect(self.ProcessData) self.adcollector.run() #------------------Camera saving------------------- if _camera_isUsed == True: self.HamamatsuCam.isSaving = True tif_name = os.path.join(self.scansavedirectory, 'Round'+str(self.RoundWaveformIndex[0])+'_Coords'+str(self.currentCoordsSeq)+'_R'+str(self.CurrentPosIndex[0])+'C'+str(self.CurrentPosIndex[1])+'_Cam_'+'Zpos'+str(self.ZStackOrder)+'.tif') self.HamamatsuCam.StopStreaming(saving_dir = tif_name) # Make sure that the saving process is finished. while self.HamamatsuCam.isSaving == True: print('Camera saving...') time.sleep(0.5) time.sleep(1) time.sleep(0.6) # Wait for receiving data to be done. time.sleep(0.3) print('*************************************************************************************************************************') #%% """ # ========================================================================================================================================================== # Finalizing # ========================================================================================================================================================== """ # Switch off laser if len(self.RoundQueueDict['InsightEvents']) != 0: self.watchdog_flag = False time.sleep(0.5) while True: try: self.Laserinstance.Close_TunableBeamShutter() break except: time.sleep(1) time.sleep(0.5) self.Laserinstance.SaveVariables() while True: try: self.Laserinstance.Turn_Off_PumpLaser() break except: time.sleep(1) # Disconnect camera if self._use_camera == True: self.HamamatsuCam.Exit() # Disconnect focus motor try: PIMotor.CloseMotorConnection(self.pi_device_instance.pidevice) print('Objective motor disconnected.') except: pass
class ScanningExecutionThread(QThread): ScanningResult = pyqtSignal(np.ndarray, np.ndarray, object, object) #The signal for the measurement, we can connect to this signal def __init__(self, RoundQueueDict, RoundCoordsDict, GeneralSettingDict, *args, **kwargs): super().__init__(*args, **kwargs) self.RoundQueueDict = RoundQueueDict self.RoundCoordsDict = RoundCoordsDict self.GeneralSettingDict = GeneralSettingDict self.Status_list = None self.ludlStage = LudlStage("COM12") self.watchdog_flag = True # self.PMTimageDict = {} # for i in range(int(len(self.RoundQueueDict)/2-1)): # initial the nested PMTimageDict dictionary. -2 because default keys for insight and filter. # self.PMTimageDict['RoundPackage_{}'.format(i+1)] = {} self.clock_source = 'Dev1 as clock source' # Should be set by GUI. self.scansavedirectory = self.GeneralSettingDict['savedirectory'] self.meshgridnumber = int(self.GeneralSettingDict['Meshgrid']) def Try_until_Success(func): """ This is the decorator to try to execute the function until succeed. """ def wrapper(*args, **kwargs): success = None failnumber = 0 while success is None: if failnumber <8: try: returnValue = func(*args, **kwargs) success = True except: failnumber += 1 print('Laser action failed, failnumber: {}'.format(failnumber)) time.sleep(0.2) else: print('Fail for 8 times, give up - -') success = False return returnValue return wrapper def run(self): """ # ========================================================================================================================================================== # Initialization # ========================================================================================================================================================== """ #%% """ # ============================================================================= # connect the Objective motor # ============================================================================= """ print('----------------------Starting to connect the Objective motor-------------------------') self.pi_device_instance = PIMotor() print('Objective motor connected.') self.errornum = 0 self.ObjCurrentPos = self.pi_device_instance.pidevice.qPOS(self.pi_device_instance.pidevice.axes) """ # ============================================================================= # connect the Hmamatsu camera # ============================================================================= """ self._use_camera = False for key in self.RoundQueueDict: if "RoundPackage_" in key: for waveform_and_cam_key in self.RoundQueueDict[key][1]: if "CameraPackage_" in waveform_and_cam_key: if len(self.RoundQueueDict[key][1][waveform_and_cam_key]) != 0: self._use_camera = True if self._use_camera == True: print('Connecting camera...') self.HamamatsuCam = CamActuator() self.HamamatsuCam.initializeCamera() else: print('No camera involved.') """ # ============================================================================= # connect the Insight X3 # ============================================================================= """ if len(self.RoundQueueDict['InsightEvents']) != 0: self.Laserinstance = InsightX3('COM11') try: querygap = 1.1 # self.Laserinstance.SetWatchdogTimer(0) # Disable the laser watchdog! # Status_watchdog_thread = threading.Thread(target = self.Status_watchdog, args=[querygap], daemon=True) # Status_watchdog_thread.start() time.sleep(1) #-------------Initialize laser-------------- self.watchdog_flag = False time.sleep(0.5) warmupstatus = 0 while int(warmupstatus) != 100: try: warmupstatus = self.Laserinstance.QueryWarmupTime() time.sleep(0.6) except: time.sleep(0.6) # if int(warmupstatus) == 100: # self.warmupstatus = True # print('Laser fully warmed up.') # if 'Laser state:Ready' in self.Status_list: # self.Laserinstance.Turn_On_PumpLaser() # self.laserRun = True # elif 'Laser state:RUN' in self.Status_list: # self.laserRun = True self.watchdog_flag = True time.sleep(0.5) except: print('Laser not connected.') # If turn on the laser shutter in the beginning if 'Shutter_Open' in self.GeneralSettingDict['StartUpEvents']: time.sleep(0.5) while True: try: self.Laserinstance.Open_TunableBeamShutter() break except: time.sleep(1) time.sleep(0.5) #%% """ # ========================================================================================================================================================== # Execution # ========================================================================================================================================================== """ GridSequence = 0 TotalGridNumber = self.meshgridnumber**2 ScanningMaxCoord = int(np.amax(self.RoundCoordsDict['CoordsPackage_1'])) # Get the largest coordinate for EachGrid in range(TotalGridNumber): """ # ============================================================================= # For each small repeat unit in the scanning meshgrid # ============================================================================= """ ScanningGridOffset_Row = int(GridSequence % self.meshgridnumber) * (ScanningMaxCoord + self.GeneralSettingDict['Scanning step']) # Offset coordinate row value for each well. ScanningGridOffset_Col = int(GridSequence/self.meshgridnumber) * (ScanningMaxCoord + self.GeneralSettingDict['Scanning step']) # Offset coordinate colunm value for each well. GridSequence += 1 time.sleep(0.5) for EachRound in range(int(len(self.RoundQueueDict)/2-1)): # EachRound is the round sequence number starting from 0, while the actual number used in dictionary is 1. print ('----------------------------------------------------------------------------') print('Below is Grid {}, Round {}.'.format(EachGrid, EachRound+1)) # EachRound+1 is the corresponding round number when setting the dictionary starting from round 1. """ # ============================================================================= # Unpack the settings for each round # ============================================================================= """ # Initialize variables CoordOrder = 0 # Counter for n th coordinates, for appending cell properties array. CellPropertiesDict = {} ND_filter1_Pos = None ND_filter2_Pos = None EM_filter_Pos = None cp_end_index = -1 self.IndexLookUpCellPropertiesDict = {} #look up dictionary for each cell properties #-------------Unpack the focus stack information. ZStackinfor = self.GeneralSettingDict['FocusStackInfoDict']['RoundPackage_{}'.format(EachRound+1)] self.ZStackNum = int(ZStackinfor[ZStackinfor.index('Focus')+5]) self.ZStackStep = float(ZStackinfor[ZStackinfor.index('Being')+5:len(ZStackinfor)]) #-------------Unpack infor for stage move. CoordsNum = int(len(self.RoundCoordsDict['CoordsPackage_{}'.format(EachRound+1)])/2) #Each pos has 2 coords #-------------Unpack infor for filter event. In the list, the first one is for ND filter and the second one is for emission filter. FilterEventIndexList = [i for i,x in enumerate(self.RoundQueueDict['FilterEvents']) if 'Round_{}'.format(EachRound+1) in x] if len(FilterEventIndexList) > 0: NDposText = self.RoundQueueDict['FilterEvents'][FilterEventIndexList[0]] NDnumber = NDposText[NDposText.index('ToPos_')+6:len(NDposText)] EMposText = self.RoundQueueDict['FilterEvents'][FilterEventIndexList[1]] EMprotein = EMposText[EMposText.index('ToPos_')+6:len(EMposText)] # "COM9" for filter 1 port, which has ND values from 0 to 3. # "COM7" for filter 2 port, which has ND values from 0 to 0.5. if NDnumber == '0': ND_filter1_Pos = 0 ND_filter2_Pos = 0 elif NDnumber == '1': ND_filter1_Pos = 1 ND_filter2_Pos = 0 elif NDnumber == '2': ND_filter1_Pos = 2 ND_filter2_Pos = 0 elif NDnumber == '2.3': ND_filter1_Pos = 2 ND_filter2_Pos = 2 elif NDnumber == '2.5': ND_filter1_Pos = 2 ND_filter2_Pos = 3 elif NDnumber == '0.5': ND_filter1_Pos = 0 ND_filter2_Pos = 3 elif NDnumber == '0.3': ND_filter1_Pos = 0 ND_filter2_Pos = 2 if EMprotein == 'Arch': EM_filter_Pos = 0 elif EMprotein == 'eGFP' or EMprotein == 'Citrine': EM_filter_Pos = 1 #-------------Unpack infor for Insight X3. In the list, the first one is for shutter event and the second one is for wavelength event. InsightX3EventIndexList = [i for i,x in enumerate(self.RoundQueueDict['InsightEvents']) if 'Round_{}'.format(EachRound+1) in x] """ # ============================================================================= # Execute Insight event at the beginning of each round # ============================================================================= """ if len(InsightX3EventIndexList) == 1: print(InsightX3EventIndexList) InsightText = self.RoundQueueDict['InsightEvents'][InsightX3EventIndexList[0]] if 'Shutter_Open' in InsightText: self.watchdog_flag = False time.sleep(0.5) while True: try: self.Laserinstance.Open_TunableBeamShutter() break except: time.sleep(1) time.sleep(0.5) print('Laser shutter open.') self.watchdog_flag = True time.sleep(0.5) elif 'Shutter_Close' in InsightText: self.watchdog_flag = False time.sleep(0.5) while True: try: self.Laserinstance.Close_TunableBeamShutter() break except: time.sleep(1) time.sleep(0.5) print('Laser shutter closed.') self.watchdog_flag = True time.sleep(0.5) elif 'WavelengthTo' in InsightText: self.watchdog_flag = False time.sleep(0.5) TargetWavelen = int(InsightText[InsightText.index('To_')+3:len(InsightText)]) print(TargetWavelen) while True: try: self.Laserinstance.SetWavelength(TargetWavelen) break except: time.sleep(1) time.sleep(5) self.watchdog_flag = True time.sleep(0.5) elif len(InsightX3EventIndexList) == 2: InsightText_wl = self.RoundQueueDict['InsightEvents'][InsightX3EventIndexList[1]] InsightText_st = self.RoundQueueDict['InsightEvents'][InsightX3EventIndexList[0]] if 'WavelengthTo' in InsightText_wl and 'Shutter_Open' in InsightText_st: self.watchdog_flag = False time.sleep(0.5) TargetWavelen = int(InsightText_wl[InsightText_wl.index('To_')+3:len(InsightText_wl)]) while True: try: self.Laserinstance.SetWavelength(TargetWavelen) break except: time.sleep(1) time.sleep(5) while True: try: self.Laserinstance.Open_TunableBeamShutter() break except: time.sleep(1) print('Laser shutter open.') self.watchdog_flag = True time.sleep(0.5) elif 'WavelengthTo' in InsightText_wl and 'Shutter_Close' in InsightText_st: self.watchdog_flag = False time.sleep(0.5) TargetWavelen = int(InsightText_wl[InsightText_wl.index('To_')+3:len(InsightText_wl)]) while True: try: self.Laserinstance.SetWavelength(TargetWavelen) break except: time.sleep(1) time.sleep(5) while True: try: self.Laserinstance.Close_TunableBeamShutter() break except: time.sleep(1) time.sleep(1) print('Laser shutter closed.') self.watchdog_flag = True time.sleep(0.5) time.sleep(2) """ # ============================================================================= # Execute filter event at the beginning of each round # ============================================================================= """ if ND_filter1_Pos != None and ND_filter2_Pos != None: #Move filter 1 self.filter1 = ELL9Filter("COM9") self.filter1.moveToPosition(ND_filter1_Pos) time.sleep(1) #Move filter 2 self.filter2 = ELL9Filter("COM7") self.filter2.moveToPosition(ND_filter2_Pos) time.sleep(1) if EM_filter_Pos != None: self.filter3 = ELL9Filter("COM15") self.filter3.moveToPosition(EM_filter_Pos) time.sleep(1) self.currentCoordsSeq = 0 #%% for EachCoord in range(CoordsNum): #-----------------------------------------------At each stage coordinate:-------------------------------------------- self.error_massage = None self.currentCoordsSeq += 1 """ # ============================================================================= # Stage movement # ============================================================================= """ RowIndex = int(self.RoundCoordsDict['CoordsPackage_{}'.format(EachRound+1)][EachCoord*2:EachCoord*2+2][0]) + ScanningGridOffset_Row ColumnIndex = int(self.RoundCoordsDict['CoordsPackage_{}'.format(EachRound+1)][EachCoord*2:EachCoord*2+2][1]) + ScanningGridOffset_Col try: self.ludlStage.moveAbs(RowIndex,ColumnIndex) # Row/Column indexs of np.array are opposite of stage row-col indexs. except: self.error_massage = 'Fail_MoveStage' self.errornum += 1 print('Stage move failed! Error number: {}'.format(int(self.errornum))) print ('Round {}. Current index: {}.'.format(EachRound+1, [RowIndex,ColumnIndex])) time.sleep(1) """ # ============================================================================= # Get the z stack objective positions ready # ============================================================================= """ #-------------------------------------------If focus correction applies---------------------------------------- if len(self.GeneralSettingDict['FocusCorrectionMatrixDict']) > 0: FocusPosArray = self.GeneralSettingDict['FocusCorrectionMatrixDict']['RoundPackage_{}_Grid_{}'.format(EachRound+1, EachGrid)] # print(FocusPosArray) FocusPosArray = FocusPosArray.flatten('F') FocusPos_fromCorrection = FocusPosArray[EachCoord] print('Target focus pos: '.format(FocusPos_fromCorrection)) # Without focus correction if len(self.GeneralSettingDict['FocusCorrectionMatrixDict']) == 0: ZStacklinspaceStart = self.ObjCurrentPos['1'] - (math.floor(self.ZStackNum/2)-1)*self.ZStackStep ZStacklinspaceEnd = self.ObjCurrentPos['1'] + (self.ZStackNum - math.floor(self.ZStackNum/2))*self.ZStackStep # With focus correction elif len(self.GeneralSettingDict['FocusCorrectionMatrixDict']) > 0: ZStacklinspaceStart = FocusPos_fromCorrection - (math.floor(self.ZStackNum/2)-1)*self.ZStackStep ZStacklinspaceEnd = FocusPos_fromCorrection + (self.ZStackNum - math.floor(self.ZStackNum/2))*self.ZStackStep ZStackPosList = np.linspace(ZStacklinspaceStart, ZStacklinspaceEnd, num = self.ZStackNum) print(ZStackPosList) """ # ============================================================================= # Execute waveform packages # ============================================================================= """ self.WaveforpackageNum = int(len(self.RoundQueueDict['RoundPackage_{}'.format(EachRound+1)][0])) #Execute each individual waveform package print('*******************************************Round {}. Current index: {}.**************************************************'.format(EachRound+1, [RowIndex,ColumnIndex])) #------------------Move to Z stack focus------------------- for EachZStackPos in range(self.ZStackNum): print('--------------------------------------------Stack {}--------------------------------------------------'.format(EachZStackPos+1)) if self.ZStackNum > 1: self.ZStackOrder = int(EachZStackPos +1) # Here the first one is 1, not starting from 0. FocusPos = ZStackPosList[EachZStackPos] print('Target focus pos: {}'.format(FocusPos)) pos = PIMotor.move(self.pi_device_instance.pidevice, FocusPos) self.ObjCurrentPosInStack = self.pi_device_instance.pidevice.qPOS(self.pi_device_instance.pidevice.axes) print("Current position: {:.4f}".format(self.ObjCurrentPosInStack['1'])) time.sleep(0.3) else: self.ZStackOrder = 1 #------------For waveforms in each coordinate---------- for EachWaveform in range(self.WaveforpackageNum): # Extract information WaveformPackageToBeExecute = self.RoundQueueDict['RoundPackage_{}'.format(EachRound+1)][0]['WaveformPackage_{}'.format(EachWaveform+1)] CameraPackageToBeExecute = self.RoundQueueDict['RoundPackage_{}'.format(EachRound+1)][1]["CameraPackage_{}".format(EachWaveform+1)] WaveformPackageGalvoInfor = self.RoundQueueDict['GalvoInforPackage_{}'.format(EachRound+1)]['GalvoInfor_{}'.format(EachWaveform+1)] self.readinchan = WaveformPackageToBeExecute[3] self.RoundWaveformIndex = [EachRound+1, EachWaveform+1] # first is current round number, second is current waveform package number. self.CurrentPosIndex = [RowIndex, ColumnIndex] #----------------Camera operations----------------- _camera_isUsed = False if CameraPackageToBeExecute != {}: # if camera operations are configured _camera_isUsed = True CamSettigList = CameraPackageToBeExecute["Settings"] self.HamamatsuCam.StartStreaming(BufferNumber = CameraPackageToBeExecute["Buffer_number"], trigger_source = CamSettigList[CamSettigList.index("trigger_source")+1], exposure_time = CamSettigList[CamSettigList.index("exposure_time")+1], trigger_active = CamSettigList[CamSettigList.index("trigger_active")+1]) # Make sure that the camera is prepared before waveform execution. # while self.HamamatsuCam.isStreaming == False: # print('Waiting for camera...') # time.sleep(0.5) time.sleep(1) print('Now start waveforms') #----------------Waveforms operations-------------- if WaveformPackageGalvoInfor != 'NoGalvo': # Unpack the information of galvo scanning. self.readinchan = WaveformPackageGalvoInfor[0] self.repeatnum = WaveformPackageGalvoInfor[1] self.PMT_data_index_array = WaveformPackageGalvoInfor[2] self.averagenum = WaveformPackageGalvoInfor[3] self.lenSample_1 = WaveformPackageGalvoInfor[4] self.ScanArrayXnum = WaveformPackageGalvoInfor[5] if self.clock_source == 'Dev1 as clock source': self.adcollector = execute_analog_readin_optional_digital_thread() self.adcollector.set_waves(WaveformPackageToBeExecute[0], WaveformPackageToBeExecute[1], WaveformPackageToBeExecute[2], WaveformPackageToBeExecute[3]) #[0] = sampling rate, [1] = analogcontainer_array, [2] = digitalcontainer_array, [3] = readinchan self.adcollector.collected_data.connect(self.ProcessData) self.adcollector.run() time.sleep(0.2) #self.ai_dev_scaling_coeff = self.adcollector.get_ai_dev_scaling_coeff() elif self.clock_source == 'Cam as clock source' : self.adcollector = execute_analog_and_readin_digital_optional_camtrig_thread() self.adcollector.set_waves(WaveformPackageToBeExecute[0], WaveformPackageToBeExecute[1], WaveformPackageToBeExecute[2], WaveformPackageToBeExecute[3]) self.adcollector.collected_data.connect(self.ProcessData) self.adcollector.run() #------------------Camera saving------------------- if _camera_isUsed == True: self.HamamatsuCam.isSaving = True tif_name = os.path.join(self.scansavedirectory, 'Round'+str(self.RoundWaveformIndex[0])+'_Coords'+str(self.currentCoordsSeq)+'_R'+str(self.CurrentPosIndex[0])+'C'+str(self.CurrentPosIndex[1])+'_Cam_'+'Zpos'+str(self.ZStackOrder)+'.tif') self.HamamatsuCam.StopStreaming(saving_dir = tif_name) # Make sure that the saving process is finished. while self.HamamatsuCam.isSaving == True: print('Camera saving...') time.sleep(0.5) time.sleep(1) time.sleep(0.6) # Wait for receiving data to be done. time.sleep(0.3) print('*************************************************************************************************************************') #%% """ # ========================================================================================================================================================== # Finalizing # ========================================================================================================================================================== """ # Switch off laser if len(self.RoundQueueDict['InsightEvents']) != 0: self.watchdog_flag = False time.sleep(0.5) while True: try: self.Laserinstance.Close_TunableBeamShutter() break except: time.sleep(1) time.sleep(0.5) self.Laserinstance.SaveVariables() while True: try: self.Laserinstance.Turn_Off_PumpLaser() break except: time.sleep(1) # Disconnect camera if self._use_camera == True: self.HamamatsuCam.Exit() # Disconnect focus motor try: PIMotor.CloseMotorConnection(self.pi_device_instance.pidevice) print('Objective motor disconnected.') except: pass #%% #--------------------------------------------------------------Reconstruct and save images from 1D recorded array.-------------------------------------------------------------------------------- def ProcessData(self, data_waveformreceived): print('ZStackOrder is:'+str(self.ZStackOrder)+'numis_'+str(self.ZStackNum)) self.adcollector.save_as_binary(self.scansavedirectory) self.channel_number = len(data_waveformreceived) if self.channel_number == 1: if 'Vp' in self.readinchan: pass elif 'Ip' in self.readinchan: pass elif 'PMT' in self.readinchan: # repeatnum, PMT_data_index_array, averagenum, ScanArrayXnum self.data_collected_0 = data_waveformreceived[0]*-1 self.data_collected_0 = self.data_collected_0[0:len(self.data_collected_0)-1] print(len(self.data_collected_0)) for imageSequence in range(self.repeatnum): try: self.PMT_image_reconstructed_array = self.data_collected_0[np.where(self.PMT_data_index_array == imageSequence+1)] # if imageSequence == int(self.repeatnum)-1: # self.PMT_image_reconstructed_array = self.PMT_image_reconstructed_array[0:len(self.PMT_image_reconstructed_array)-1] # Extra one sample at the end. # print(self.PMT_image_reconstructed_array.shape) Dataholder_average = np.mean(self.PMT_image_reconstructed_array.reshape(self.averagenum, -1), axis=0) # print(Dataholder_average.shape) Value_yPixels = int(self.lenSample_1/self.ScanArrayXnum) self.PMT_image_reconstructed = np.reshape(Dataholder_average, (Value_yPixels, self.ScanArrayXnum)) self.PMT_image_reconstructed = self.PMT_image_reconstructed[:, 50:550] # Crop size based on: M:\tnw\ist\do\projects\Neurophotonics\Brinkslab\Data\Xin\2019-12-30 2p beads area test 4um # self.PMT_image_reconstructed = self.PMT_image_reconstructed[:, 70:326] # for 256*256 images #---------------------------------------------For multiple images in one z pos, Stack the arrays into a 3d array-------------------------------------------------------------------------- if imageSequence == 0: self.PMT_image_reconstructed_stack = self.PMT_image_reconstructed[np.newaxis, :, :] # Turns into 3d array else: self.PMT_image_reconstructed_stack = np.concatenate((self.PMT_image_reconstructed_stack, self.PMT_image_reconstructed[np.newaxis, :, :]), axis=0) print(self.PMT_image_reconstructed_stack.shape) #---------------------------------------------Calculate the z max projection----------------------------------------------------------------------- if self.repeatnum == 1: # Consider one repeat image situlation if self.ZStackNum > 1: if self.ZStackOrder == 1: self.PMT_image_maxprojection_stack = self.PMT_image_reconstructed[np.newaxis, :, :] else: self.PMT_image_maxprojection_stack = np.concatenate((self.PMT_image_maxprojection_stack, self.PMT_image_reconstructed[np.newaxis, :, :]), axis=0) else: self.PMT_image_maxprojection_stack = self.PMT_image_reconstructed[np.newaxis, :, :] # Save the max projection image if self.ZStackOrder == self.ZStackNum: self.PMT_image_maxprojection = np.max(self.PMT_image_maxprojection_stack, axis=0) LocalimgZprojection = Image.fromarray(self.PMT_image_maxprojection) #generate an image object LocalimgZprojection.save(os.path.join(self.scansavedirectory, 'Round'+str(self.RoundWaveformIndex[0])+'_Coords'+str(self.currentCoordsSeq)+'_R'+str(self.CurrentPosIndex[0])+'C'+str(self.CurrentPosIndex[1])+'_PMT_'+str(imageSequence)+'Zmax'+'.tif')) #save as tif # Localimg = Image.fromarray(self.PMT_image_reconstructed) #generate an image object Localimg.save(os.path.join(self.scansavedirectory, 'Round'+str(self.RoundWaveformIndex[0])+'_Coords'+str(self.currentCoordsSeq)+'_R'+str(self.CurrentPosIndex[0])+'C'+str(self.CurrentPosIndex[1])+'_PMT_'+str(imageSequence)+'Zpos'+str(self.ZStackOrder)+'.tif')) #save as tif plt.figure() plt.imshow(self.PMT_image_reconstructed, cmap = plt.cm.gray) # For reconstructed image we pull out the first layer, getting 2d img. plt.show() except: print('No.{} image failed to generate.'.format(imageSequence)) elif self.channel_number == 2: if 'PMT' not in self.readinchan: pass elif 'PMT' in self.readinchan: self.data_collected_0 = data_waveformreceived[0]*-1 self.data_collected_0 = self.data_collected_0[0:len(self.data_collected_0)-1] print(len(self.data_collected_0)) for imageSequence in range(self.repeatnum): try: self.PMT_image_reconstructed_array = self.data_collected_0[np.where(self.PMT_data_index_array == imageSequence+1)] if imageSequence == int(self.repeatnum)-1: self.PMT_image_reconstructed_array = self.PMT_image_reconstructed_array[0:len(self.PMT_image_reconstructed_array)-1] # Extra one sample at the end. Dataholder_average = np.mean(self.PMT_image_reconstructed_array.reshape(self.averagenum, -1), axis=0) Value_yPixels = int(self.lenSample_1/self.ScanArrayXnum) self.PMT_image_reconstructed = np.reshape(Dataholder_average, (Value_yPixels, self.ScanArrayXnum)) self.PMT_image_reconstructed = self.PMT_image_reconstructed[:, 50:550] # Stack the arrays into a 3d array if imageSequence == 0: self.PMT_image_reconstructed_stack = self.PMT_image_reconstructed[np.newaxis, :, :] else: self.PMT_image_reconstructed_stack = np.concatenate((self.PMT_image_reconstructed_stack, self.PMT_image_reconstructed[np.newaxis, :, :]), axis=0) #---------------------------------------------Calculate the z max projection----------------------------------------------------------------------- if self.repeatnum == 1: # Consider one repeat image situlation if self.ZStackNum > 1: if self.ZStackOrder == 1: self.PMT_image_maxprojection_stack = self.PMT_image_reconstructed[np.newaxis, :, :] else: self.PMT_image_maxprojection_stack = np.concatenate((self.PMT_image_maxprojection_stack, self.PMT_image_reconstructed[np.newaxis, :, :]), axis=0) else: self.PMT_image_maxprojection_stack = self.PMT_image_reconstructed[np.newaxis, :, :] # Save the max projection image if self.ZStackOrder == self.ZStackNum: self.PMT_image_maxprojection = np.max(self.PMT_image_maxprojection_stack, axis=0) LocalimgZprojection = Image.fromarray(self.PMT_image_maxprojection) #generate an image object LocalimgZprojection.save(os.path.join(self.scansavedirectory, 'Round'+str(self.RoundWaveformIndex[0])+'_Coords'+str(self.currentCoordsSeq)+'_R'+str(self.CurrentPosIndex[0])+'C'+str(self.CurrentPosIndex[1])+'_PMT_'+str(imageSequence)+'Zmax'+'.tif')) #save as tif Localimg = Image.fromarray(self.PMT_image_reconstructed) #generate an image object Localimg.save(os.path.join(self.scansavedirectory, 'Round'+str(self.RoundWaveformIndex[0])+'_Coords'+str(self.currentCoordsSeq)+'_R'+str(self.CurrentPosIndex[0])+'C'+str(self.CurrentPosIndex[1])+'_PMT_'+str(imageSequence)+'Zpos'+str(self.ZStackOrder)+'.tif')) #save as tif plt.figure() plt.imshow(self.PMT_image_reconstructed, cmap = plt.cm.gray) plt.show() except: print('No.{} image failed to generate.'.format(imageSequence)) print('ProcessData executed.') #----------------------------------------------------------------WatchDog for laser---------------------------------------------------------------------------------- def Status_watchdog(self, querygap): while True: if self.watchdog_flag == True: self.Status_list = self.Laserinstance.QueryStatus() time.sleep(querygap) else: print('Watchdog stopped') time.sleep(querygap)
class StageWidget(QWidget): def __init__(self, parent=None, *args, **kwargs): super().__init__(*args, **kwargs) self.main_application = parent self.set_image_saving_location( os.getcwd() + '/CoordinatesManager/Registration_Images/StageRegistration/') self.init_gui() self.ludlStage = LudlStage("COM12") def init_gui(self): layout = QGridLayout() # self.setFixedSize(320,100) self.box = roundQGroupBox() self.box.setTitle("Stage") box_layout = QGridLayout() self.box.setLayout(box_layout) self.setLayout(layout) self.collect_data_button = QPushButton('Collect data') self.collect_data_button.clicked.connect(self.start_aqcuisition) box_layout.addWidget(self.collect_data_button) layout.addWidget(self.box) def set_image_saving_location(self, filepath): self.image_file_path = filepath def start_aqcuisition(self): global_pos = np.array( ((-5000, -5000), (-5000, 5000), (5000, -5000), (5000, 5000))) global_pos_name = ['A', 'B', 'C', 'D'] delta = 200 local_pos = np.transpose( np.reshape( np.meshgrid(np.array((-delta, 0, delta)), np.array((-delta, 0, delta))), (2, -1))) local_pos_name = [str(i) for i in range(9)] self.cam = CamActuator() self.cam.initializeCamera() # Offset variables are used to generate replicates for good statistics offset_y = offset_x = delta cnt = 0 for i in range(global_pos.shape[0]): for j in range(local_pos.shape[0]): x = global_pos[i, 0] + local_pos[j, 0] + offset_x y = global_pos[i, 1] + local_pos[j, 1] + offset_y self.ludlStage.moveAbs(x=x, y=y) # stage_movement_thread = StagemovementAbsoluteThread(x, y) # stage_movement_thread.start() # time.sleep(2) # stage_movement_thread.quit() # stage_movement_thread.wait() image = self.cam.SnapImage(0.04) filename = global_pos_name[i] + local_pos_name[j] self.save_image(filename, image) cnt += 1 print( str(cnt) + '/' + str(len(local_pos_name) * len(global_pos_name))) self.cam.Exit() def save_image(self, filename, image): plt.imsave(self.image_file_path + filename + '.png', image)
class MainGUI(QWidget): # signal_DMDmask is cictionary with laser specification as key and binary mask as content. signal_DMDmask = pyqtSignal(dict) signal_DMDcontour = pyqtSignal(list) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) os.chdir('./') # Set directory to current folder. self.setFont(QFont("Arial")) # self.setMinimumSize(900, 1020) self.setWindowTitle("Cell Selection") self.layout = QGridLayout(self) self.roi_list_freehandl_added = [] self.selected_ML_Index = [] self.selected_cells_infor_dict = {} self.mask_color_multiplier = [1, 1, 0] # ============================================================================= # Container for image display # ============================================================================= graphContainer = StylishQT.roundQGroupBox() graphContainerLayout = QGridLayout() self.Imgviewtabs = QTabWidget() MLmaskviewBox = QWidget() MLmaskviewBoxLayout = QGridLayout() self.Matdisplay_Figure = Figure() self.Matdisplay_Canvas = FigureCanvas(self.Matdisplay_Figure) self.Matdisplay_Canvas.setFixedWidth(500) self.Matdisplay_Canvas.setFixedHeight(500) self.Matdisplay_Canvas.mpl_connect('button_press_event', self._onclick) self.Matdisplay_toolbar = NavigationToolbar(self.Matdisplay_Canvas, self) MLmaskviewBoxLayout.addWidget(self.Matdisplay_toolbar, 0, 0) MLmaskviewBoxLayout.addWidget(self.Matdisplay_Canvas, 1, 0) MLmaskviewBox.setLayout(MLmaskviewBoxLayout) self.Imgviewtabs.addTab(MLmaskviewBox, "MaskRCNN") # ============================================================================= # Mask editing tab # ============================================================================= MLmaskEditBox = QWidget() MLmaskEditBoxLayout = QGridLayout() self.Mask_edit_view = DrawingWidget(self) self.Mask_edit_view.enable_drawing(False) # Disable drawing first # self.Mask_edit_view = pg.ImageView() # self.Mask_edit_view.getView().setLimits(xMin = 0, xMax = 2048, yMin = 0, yMax = 2048, minXRange = 2048, minYRange = 2048, maxXRange = 2048, maxYRange = 2048) self.Mask_edit_viewItem = self.Mask_edit_view.getImageItem() # self.ROIitem = pg.PolyLineROI([[0,0], [80,0], [80,80], [0,80]], closed=True) self.Mask_edit_view_getView = self.Mask_edit_view.getView() # self.Mask_edit_view_getView.addItem(self.ROIitem) self.Mask_edit_view.ui.roiBtn.hide() self.Mask_edit_view.ui.menuBtn.hide() self.Mask_edit_view.ui.normGroup.hide() self.Mask_edit_view.ui.roiPlot.hide() MLmaskEditBoxLayout.addWidget(self.Mask_edit_view, 0, 0) MLmaskEditBox.setLayout(MLmaskEditBoxLayout) self.Imgviewtabs.addTab(MLmaskEditBox, "Mask edit") graphContainerLayout.addWidget(self.Imgviewtabs, 0, 0) graphContainer.setLayout(graphContainerLayout) # ============================================================================= # Operation container # ============================================================================= operationContainer = StylishQT.roundQGroupBox() operationContainerLayout = QGridLayout() self.init_ML_button = QPushButton('Initialize ML', self) operationContainerLayout.addWidget(self.init_ML_button, 0, 0) self.init_ML_button.clicked.connect(self.init_ML) #---------------------Load image from file----------------------------- self.textbox_loadimg = QLineEdit(self) operationContainerLayout.addWidget(self.textbox_loadimg, 1, 0) self.button_import_img_browse = QPushButton('Browse', self) operationContainerLayout.addWidget(self.button_import_img_browse, 1, 1) self.button_import_img_browse.clicked.connect(self.get_img_file_tif) self.run_ML_button = QPushButton('Analysis', self) operationContainerLayout.addWidget(self.run_ML_button, 2, 0) self.run_ML_button.clicked.connect(self.run_ML_onImg_and_display) self.generate_MLmask_button = QPushButton('Mask', self) operationContainerLayout.addWidget(self.generate_MLmask_button, 2, 1) self.generate_MLmask_button.clicked.connect(self.generate_MLmask) self.update_MLmask_button = QPushButton('Update mask', self) operationContainerLayout.addWidget(self.update_MLmask_button, 3, 0) self.update_MLmask_button.clicked.connect(self.update_mask) self.enable_modify_MLmask_button = QPushButton('Enable free-hand', self) self.enable_modify_MLmask_button.setCheckable(True) operationContainerLayout.addWidget(self.enable_modify_MLmask_button, 4, 0) self.enable_modify_MLmask_button.clicked.connect(self.enable_free_hand) # self.modify_MLmask_button = QPushButton('Add patch', self) # operationContainerLayout.addWidget(self.modify_MLmask_button, 4, 1) # self.modify_MLmask_button.clicked.connect(self.addedROIitem_to_Mask) self.clear_roi_button = QPushButton('Clear ROIs', self) operationContainerLayout.addWidget(self.clear_roi_button, 5, 0) self.clear_roi_button.clicked.connect(self.clear_edit_roi) # self.maskLaserComboBox = QComboBox() # self.maskLaserComboBox.addItems(['640', '532', '488']) # operationContainerLayout.addWidget(self.maskLaserComboBox, 6, 0) # # self.generate_transformed_mask_button = QPushButton('Transform mask', self) # operationContainerLayout.addWidget(self.generate_transformed_mask_button, 6, 1) # self.generate_transformed_mask_button.clicked.connect(self.generate_transformed_mask) self.emit_transformed_mask_button = QPushButton('Emit mask', self) operationContainerLayout.addWidget(self.emit_transformed_mask_button, 7, 1) self.emit_transformed_mask_button.clicked.connect( self.emit_mask_contour) operationContainer.setLayout(operationContainerLayout) # ============================================================================= # Mask para container # ============================================================================= MaskparaContainer = StylishQT.roundQGroupBox() MaskparaContainerContainerLayout = QGridLayout() #---------------------------------------------------------------------- self.fillContourButton = QCheckBox() self.invertMaskButton = QCheckBox() self.thicknessSpinBox = QSpinBox() self.thicknessSpinBox.setRange(1, 25) MaskparaContainerContainerLayout.addWidget(QLabel('Fill contour:'), 0, 0) MaskparaContainerContainerLayout.addWidget(self.fillContourButton, 0, 1) MaskparaContainerContainerLayout.addWidget(QLabel('Invert mask:'), 1, 0) MaskparaContainerContainerLayout.addWidget(self.invertMaskButton, 1, 1) MaskparaContainerContainerLayout.addWidget(QLabel('Thickness:'), 2, 0) MaskparaContainerContainerLayout.addWidget(self.thicknessSpinBox, 2, 1) MaskparaContainer.setLayout(MaskparaContainerContainerLayout) # ============================================================================= # Device operation container # ============================================================================= deviceOperationContainer = StylishQT.roundQGroupBox() deviceOperationContainerLayout = QGridLayout() #---------------------------------------------------------------------- self.CamExposureBox = QDoubleSpinBox(self) self.CamExposureBox.setDecimals(6) self.CamExposureBox.setMinimum(0) self.CamExposureBox.setMaximum(100) self.CamExposureBox.setValue(0.001501) self.CamExposureBox.setSingleStep(0.001) deviceOperationContainerLayout.addWidget(self.CamExposureBox, 0, 1) deviceOperationContainerLayout.addWidget(QLabel("Exposure time:"), 0, 0) cam_snap_button = QPushButton('Cam snap', self) deviceOperationContainerLayout.addWidget(cam_snap_button, 0, 2) cam_snap_button.clicked.connect(self.cam_snap) cam_snap_button = QPushButton('Cam snap', self) deviceOperationContainerLayout.addWidget(cam_snap_button, 0, 2) cam_snap_button.clicked.connect(self.cam_snap) deviceOperationContainer.setLayout(deviceOperationContainerLayout) self.layout.addWidget(graphContainer, 0, 0, 3, 1) self.layout.addWidget(operationContainer, 0, 1) self.layout.addWidget(MaskparaContainer, 1, 1) self.layout.addWidget(deviceOperationContainer, 2, 1) self.setLayout(self.layout) #%% # ============================================================================= # MaskRCNN detection part # ============================================================================= # @run_in_thread def init_ML(self): # Initialize the detector instance and load the model. self.ProcessML = ProcessImageML() def get_img_file_tif(self): self.img_tif_filePath, _ = QtWidgets.QFileDialog.getOpenFileName( self, 'Single File', 'M:/tnw/ist/do/projects/Neurophotonics/Brinkslab/Data', "(*.tif)") self.textbox_loadimg.setText(self.img_tif_filePath) if self.img_tif_filePath != None: self.Rawimage = imread(self.img_tif_filePath) self.MLtargetedImg_raw = self.Rawimage.copy() self.MLtargetedImg = self.convert_for_MaskRCNN( self.MLtargetedImg_raw) self.show_raw_image(self.MLtargetedImg) self.addedROIitemMask = np.zeros( (self.MLtargetedImg.shape[0], self.MLtargetedImg.shape[1])) self.MLmask = np.zeros( (self.MLtargetedImg.shape[0], self.MLtargetedImg.shape[1])) def show_raw_image(self, image): # display a single image try: self.Matdisplay_Figure.clear() except: pass ax1 = self.Matdisplay_Figure.add_subplot(111) ax1.set_xticks([]) ax1.set_yticks([]) ax1.imshow(image) self.Matdisplay_Figure.tight_layout() self.Matdisplay_Canvas.draw() RGB_image = gray2rgb(image) self.Mask_edit_viewItem.setImage(RGB_image) def convert_for_MaskRCNN(self, input_img): """Convert the image size and bit-depth to make it suitable for MaskRCNN detection.""" if input_img.shape[0] > 1024 or input_img.shape[1] > 1024: resized_img = resize(input_img, [1024, 1024], preserve_range=True).astype(input_img.dtype) minval = np.min(resized_img) maxval = np.max(resized_img) return ((resized_img - minval) / (maxval - minval) * 255).astype( np.uint8) def run_ML_onImg_and_display(self): """Run MaskRCNN on input image""" self.Matdisplay_Figure.clear() ax1 = self.Matdisplay_Figure.add_subplot(111) # Depends on show_mask or not, the returned figure will be input raw image with mask or not. self.MLresults, self.Matdisplay_Figure_axis, self.unmasked_fig = self.ProcessML.DetectionOnImage( self.MLtargetedImg, axis=ax1, show_mask=False, show_bbox=False) self.Mask = self.MLresults['masks'] self.Label = self.MLresults['class_ids'] self.Score = self.MLresults['scores'] self.Bbox = self.MLresults['rois'] self.SelectedCellIndex = 0 self.NumCells = int(len(self.Label)) self.selected_ML_Index = [] self.selected_cells_infor_dict = {} self.Matdisplay_Figure_axis.imshow(self.unmasked_fig.astype(np.uint8)) self.Matdisplay_Figure.tight_layout() self.Matdisplay_Canvas.draw() #%% # ============================================================================= # Configure click event to add clicked cell mask # ============================================================================= def _onclick(self, event): """Highlights the cell selected in the figure by the user when clicked on""" if self.NumCells > 0: ShapeMask = np.shape(self.Mask) # get coorinates at selected location in image coordinates if event.xdata == None or event.ydata == None: return xcoor = min(max(int(event.xdata), 0), ShapeMask[1]) ycoor = min(max(int(event.ydata), 0), ShapeMask[0]) # search for the mask coresponding to the selected cell for EachCell in range(self.NumCells): if self.Mask[ycoor, xcoor, EachCell]: self.SelectedCellIndex = EachCell break # highlight selected cell if self.SelectedCellIndex not in self.selected_ML_Index: # Get the selected cell's contour coordinates and mask patch self.contour_verts, self.Cell_patch = self.get_cell_polygon( self.Mask[:, :, self.SelectedCellIndex]) self.Matdisplay_Figure_axis.add_patch(self.Cell_patch) self.Matdisplay_Canvas.draw() self.selected_ML_Index.append(self.SelectedCellIndex) self.selected_cells_infor_dict['cell{}_verts'.format( str(self.SelectedCellIndex))] = self.contour_verts else: # If click on the same cell self.Cell_patch.remove() self.Matdisplay_Canvas.draw() self.selected_ML_Index.remove(self.SelectedCellIndex) self.selected_cells_infor_dict.pop('cell{}_verts'.format( str(self.SelectedCellIndex))) def get_cell_polygon(self, mask): # Mask Polygon # Pad to ensure proper polygons for masks that touch image edges. padded_mask = np.zeros((mask.shape[0] + 2, mask.shape[1] + 2), dtype=np.uint8) padded_mask[1:-1, 1:-1] = mask contours = find_contours(padded_mask, 0.5) for verts in contours: # Subtract the padding and flip (y, x) to (x, y) verts = np.fliplr(verts) - 1 contour_polygon = mpatches.Polygon( verts, facecolor=self.random_colors(1)[0]) return contours, contour_polygon def random_colors(self, N, bright=True): """ Generate random colors. To get visually distinct colors, generate them in HSV space then convert to RGB. """ brightness = 1.0 if bright else 0.7 hsv = [(i / N, 1, brightness) for i in range(N)] colors = list(map(lambda c: colorsys.hsv_to_rgb(*c), hsv)) random.shuffle(colors) return colors #%% # ============================================================================= # For mask generation # ============================================================================= def generate_MLmask(self): """ Generate binary mask with all selected cells""" self.MLmask = np.zeros( (self.MLtargetedImg.shape[0], self.MLtargetedImg.shape[1])) if len(self.selected_ML_Index) > 0: for selected_index in self.selected_ML_Index: self.MLmask = np.add(self.MLmask, self.Mask[:, :, selected_index]) self.intergrate_into_final_mask() self.add_rois_of_selected() else: self.intergrate_into_final_mask() # self.Mask_edit_viewItem.setImage(gray2rgb(self.MLtargetedImg)) def add_rois_of_selected(self): """ Using find_contours to get list of contour coordinates in the binary mask, and then generate polygon rois based on these coordinates. """ for selected_index in self.selected_ML_Index: contours = self.selected_cells_infor_dict['cell{}_verts'.format( str(selected_index))] # contours = find_contours(self.Mask[:,:,selected_index], 0.5) # Find iso-valued contours in a 2D array for a given level value. for n, contour in enumerate(contours): contour_coord_array = contours[n] #Swap columns contour_coord_array[:, 0], contour_coord_array[:, 1] = contour_coord_array[:, 1], contour_coord_array[:, 0].copy( ) #Down sample the coordinates otherwise it will be too dense. contour_coord_array_del = np.delete( contour_coord_array, np.arange(2, contour_coord_array.shape[0] - 3, 2), 0) self.selected_cells_infor_dict['cell{}_ROIitem'.format(str(selected_index))] = \ pg.PolyLineROI(positions=contour_coord_array_del, closed=True) self.Mask_edit_view.getView().addItem( self.selected_cells_infor_dict['cell{}_ROIitem'.format( str(selected_index))]) def update_mask(self): """ Regenerate the masks for MaskRCNN and free-hand added (in case they are changed), and show in imageview. !!!ISSUE: getLocalHandlePositions: moving handles changes the position read out, dragging roi as a whole doesn't. """ # Binary mask from ML detection if len(self.selected_ML_Index) > 0: # Delete items in dictionary that are not roi items roi_dict = self.selected_cells_infor_dict.copy() del_key_list = [] for key in roi_dict: print(key) if 'ROIitem' not in key: del_key_list.append(key) for key in del_key_list: del roi_dict[key] self.MLmask = ProcessImage.ROIitem2Mask( roi_dict, mask_resolution=(self.MLtargetedImg.shape[0], self.MLtargetedImg.shape[1])) # Binary mask of added rois self.addedROIitemMask = ProcessImage.ROIitem2Mask( self.roi_list_freehandl_added, mask_resolution=(self.MLtargetedImg.shape[0], self.MLtargetedImg.shape[1])) self.intergrate_into_final_mask() # if type(self.roi_list_freehandl_added) is list: # for ROIitem in self.roi_list_freehandl_added: # # ROIitem.sigHoverEvent.connect(lambda: self.show_roi_detail(ROIitem)) # # plt.figure() # plt.imshow(self.addedROIitemMask) # plt.show() # ============================================================================= # For free-hand rois # ============================================================================= def enable_free_hand(self): if self.enable_modify_MLmask_button.isChecked(): self.Mask_edit_view.enable_drawing(True) else: self.Mask_edit_view.enable_drawing(False) def add_freehand_roi(self, roi): # For drawwidget self.roi_list_freehandl_added.append(roi) def clear_edit_roi(self): """ Clean up all the free-hand rois. """ for roi in self.roi_list_freehandl_added: self.Mask_edit_view.getView().removeItem(roi) self.roi_list_freehandl_added = [] if len(self.selected_cells_infor_dict) > 0: # Remove all selected masks for roiItemkey in self.selected_cells_infor_dict: if 'ROIitem' in roiItemkey: self.Mask_edit_view.getView().removeItem( self.selected_cells_infor_dict[roiItemkey]) self.selected_cells_infor_dict = {} self.MLmask = np.zeros( (self.MLtargetedImg.shape[0], self.MLtargetedImg.shape[1])) self.intergrate_into_final_mask() def intergrate_into_final_mask(self): # Binary mask of added rois self.addedROIitemMask = ProcessImage.ROIitem2Mask( self.roi_list_freehandl_added, mask_resolution=(self.MLtargetedImg.shape[0], self.MLtargetedImg.shape[1])) #Display the RGB mask, ML mask plus free-hand added. self.Mask_edit_viewItem.setImage(gray2rgb(self.addedROIitemMask) * self.mask_color_multiplier + \ gray2rgb(self.MLmask) * self.mask_color_multiplier + gray2rgb(self.MLtargetedImg)) self.final_mask = self.MLmask + self.addedROIitemMask # In case the input image is 2048*2048, and it is resized to fit in MaskRCNN, need to convert back to original size for DMD tranformation. if self.final_mask.shape[0] != self.Rawimage.shape[ 0] or self.final_mask.shape[1] != self.Rawimage.shape[1]: self.final_mask = resize( self.final_mask, [self.Rawimage.shape[0], self.Rawimage.shape[1]], preserve_range=True).astype(self.final_mask.dtype) # self.final_mask = np.where(self.final_mask <= 1, self.final_mask, int(1)) plt.figure() plt.imshow(self.final_mask) plt.show() # ============================================================================= # For DMD transformation and mask generation # ============================================================================= def generate_transformed_mask(self): self.read_transformations_from_file() # self.transform_to_DMD_mask(laser = self.maskLaserComboBox.currentText(), dict_transformations = self.dict_transformations) target_laser = self.maskLaserComboBox.currentText() self.final_DMD_mask = self.finalmask_to_DMD_mask( laser=target_laser, dict_transformations=self.dict_transformations) plt.figure() plt.imshow(self.final_DMD_mask) plt.show() def emit_mask_contour(self): """Use find_contours to get a list of (n,2)-ndarrays consisting of n (row, column) coordinates along the contour, and then feed the list of signal:[list_of_rois, flag_fill_contour, contour_thickness, flag_invert_mode] to the receive_mask_coordinates function in DMDWidget. """ contours = find_contours(self.final_mask, 0.5) sig = [ contours, self.fillContourButton.isChecked(), self.thicknessSpinBox.value(), self.invertMaskButton.isChecked() ] self.signal_DMDcontour.emit(sig) def emit_mask(self): target_laser = self.maskLaserComboBox.currentText() final_DMD_mask_dict = {} final_DMD_mask_dict['camera-dmd-' + target_laser] = self.final_DMD_mask self.signal_DMDmask.emit(final_DMD_mask_dict) def read_transformations_from_file(self): try: with open( r'M:\tnw\ist\do\projects\Neurophotonics\Brinkslab\People\Xin Meng\Code\Python_test\DMDManager\Registration\transformation.txt', 'r') as json_file: self.dict_transformations = json.load(json_file) except: print( 'No transformation could be loaded from previous registration run.' ) return # def transform_to_DMD_mask(self, laser, dict_transformations, flag_fill_contour = True, contour_thickness = 1, flag_invert_mode = False, mask_resolution = (1024, 768)): # """ # Get roi vertices from all roi items and perform the transformation, and then create the mask for DMD. # """ # # #list of roi vertices each being (n,2) numpy array for added rois # if len(self.roi_list_freehandl_added) > 0: # self.addedROIitem_vertices = ProcessImage.ROIitem2Vertices(self.roi_list_freehandl_added) # #addedROIitem_vertices needs to be seperated to be inidividual (n,2) np.array # self.ROIitems_mask_transformed = ProcessImage.vertices_to_DMD_mask(self.addedROIitem_vertices, laser, dict_transformations, flag_fill_contour = True, contour_thickness = 1,\ # flag_invert_mode = False, mask_resolution = (1024, 768)) # # #Dictionary with (n,2) numpy array for clicked cells # if len(self.selected_cells_infor_dict) > 0: # #Convert dictionary to np.array # for roiItemkey in self.selected_cells_infor_dict: # #Each one is 'contours' from find_contour # if '_verts' in roiItemkey: # self.selected_cells_infor_dict[roiItemkey] # # self.MLitems_mask_transformed = ProcessImage.vertices_to_DMD_mask(self.selected_cells_infor_dict, laser, dict_transformations, flag_fill_contour = True, contour_thickness = 1,\ # flag_invert_mode = False, mask_resolution = (1024, 768)) # # if len(self.roi_list_freehandl_added) > 0: # self.final_DMD_mask = self.ROIitems_mask_transformed + self.MLitems_mask_transformed # self.final_DMD_mask[self.final_DMD_mask>1] = 1 # else: # self.final_DMD_mask = self.MLitems_mask_transformed # # return self.final_DMD_mask def finalmask_to_DMD_mask(self, laser, dict_transformations, flag_fill_contour=True, contour_thickness=1, flag_invert_mode=False, mask_resolution=(1024, 768)): """ Same goal as transform_to_DMD_mask, with input being the final binary mask and using find_contour to get all vertices and perform transformation, and then coordinates to mask. """ self.final_DMD_mask = ProcessImage.binarymask_to_DMD_mask(self.final_mask, laser, dict_transformations, flag_fill_contour = True, \ contour_thickness = 1, flag_invert_mode = False, mask_resolution = (1024, 768)) return self.final_DMD_mask def closeEvent(self, event): QtWidgets.QApplication.quit() event.accept() # def apply_mask(self, image, mask, color, alpha=0.5): # """Apply the given mask to the image. # """ # for c in range(3): # image[:, :, c] = np.where(mask == 1, # image[:, :, c] * # (1 - alpha) + alpha * color[c] * 255, # image[:, :, c]) # return image #%% # @run_in_thread def cam_snap(self): """Get a image from camera""" self.cam = CamActuator() self.cam.initializeCamera() exposure_time = self.CamExposureBox.value() self.Rawimage = self.cam.SnapImage(exposure_time) self.cam.Exit() print('Snap finished') self.MLtargetedImg_raw = self.Rawimage.copy() self.MLtargetedImg = self.convert_for_MaskRCNN(self.MLtargetedImg_raw) self.show_raw_image(self.MLtargetedImg) self.addedROIitemMask = np.zeros( (self.MLtargetedImg.shape[0], self.MLtargetedImg.shape[1])) self.MLmask = np.zeros( (self.MLtargetedImg.shape[0], self.MLtargetedImg.shape[1]))
def run(self): """~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Connect devices. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~""" """ # ============================================================================= # connect the Objective motor # ============================================================================= """ print('----------------------Starting to connect the Objective motor-------------------------') self.pi_device_instance = PIMotor() print('Objective motor connected.') self.errornum = 0 self.init_focus_position = self.pi_device_instance.pidevice.qPOS(self.pi_device_instance.pidevice.axes)['1'] print("init_focus_position : {}".format(self.init_focus_position)) """ # ============================================================================= # connect the Hmamatsu camera # ============================================================================= """ self._use_camera = False # Check if camera is used. for key in self.RoundQueueDict: if "RoundPackage_" in key: for waveform_and_cam_key in self.RoundQueueDict[key][1]: if "CameraPackage_" in waveform_and_cam_key: if len(self.RoundQueueDict[key][1][waveform_and_cam_key]) != 0: self._use_camera = True if self._use_camera: print('Connecting camera...') self.HamamatsuCam = CamActuator() self.HamamatsuCam.initializeCamera() else: print('No camera involved.') """ # ============================================================================= # connect the Insight X3 # ============================================================================= """ if len(self.RoundQueueDict['InsightEvents']) != 0: self.Laserinstance = InsightX3('COM11') try: # querygap = 1.1 # self.Laserinstance.SetWatchdogTimer(0) # Disable the laser watchdog! # Status_watchdog_thread = threading.Thread(target = self.Status_watchdog, args=[querygap], daemon=True) # Status_watchdog_thread.start() # time.sleep(1) #-------------Initialize laser-------------- self.watchdog_flag = False time.sleep(0.5) warmupstatus = 0 while int(warmupstatus) != 100: warmupstatus = self.Laserinstance.QueryWarmupTime() time.sleep(0.6) self.watchdog_flag = True time.sleep(0.5) except: print('Laser not connected.') # If turn on the laser shutter in the beginning if 'Shutter_Open' in self.GeneralSettingDict['StartUpEvents']: time.sleep(0.5) self.Laserinstance.Open_TunableBeamShutter() time.sleep(0.5) """ # ============================================================================= # Initialize ML # ============================================================================= """ self._use_ML = False # Check if machine learning segmentation is used. for key in self.RoundQueueDict: if "RoundPackage_" in key: for photocycle_key in self.RoundQueueDict[key][2]: if "PhotocyclePackage_" in photocycle_key: if len(self.RoundQueueDict[key][2][photocycle_key]) != 0: self._use_ML = True if self._use_ML: from ImageAnalysis.ImageProcessing_MaskRCNN import ProcessImageML self.Predictor = ProcessImageML() print("ML loaded.") #%% """~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Execution # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~""" GridSequence = 0 TotalGridNumber = self.meshgridnumber**2 for EachGrid in range(TotalGridNumber): """ #------------------------------------------------------------------------------ #:::::::::::::::::::::::::::::::: AT EACH GRID :::::::::::::::::::::::::::::::: #------------------------------------------------------------------------------ """ self.Grid_index = EachGrid """ # ============================================================================= # For each small repeat unit in the scanning meshgrid # ============================================================================= """ time.sleep(0.5) for EachRound in range(int(len(self.RoundQueueDict)/2-1)): # EachRound is the round sequence number starting from 0, while the actual number used in dictionary is 1. """ #------------------------------------------------------------------------------- #:::::::::::::::::::::::::::::::: AT EACH ROUND :::::::::::::::::::::::::::::::: #------------------------------------------------------------------------------- """ print ('----------------------------------------------------------------------------') print('Below is Grid {}, Round {}.'.format(EachGrid, EachRound+1)) # EachRound+1 is the corresponding round number when setting the dictionary starting from round 1. """ # ============================================================================= # Execute Insight event at the beginning of each round # ============================================================================= """ self.laser_init(EachRound) """ # ============================================================================= # Execute filter event at the beginning of each round # ============================================================================= """ self.filters_init(EachRound) """ # ============================================================================= # Generate focus position list at the beginning of each round # ============================================================================= """ if EachRound == 0: ZStackinfor = self.GeneralSettingDict['FocusStackInfoDict']['RoundPackage_{}'.format(EachRound+1)] ZStackNum = int(ZStackinfor[ZStackinfor.index('Focus')+5]) ZStackStep = float(ZStackinfor[ZStackinfor.index('Being')+5:len(ZStackinfor)]) # Generate position list. ZStacklinspaceStart = self.init_focus_position - (math.floor(ZStackNum/2)) * ZStackStep ZStacklinspaceEnd = self.init_focus_position + (ZStackNum - math.floor(ZStackNum/2)-1) * ZStackStep self.ZStackPosList = np.linspace(ZStacklinspaceStart, ZStacklinspaceEnd, num = ZStackNum) self.currentCoordsSeq = 0 #%% #-------------Unpack infor for stage move. CoordsNum = len(self.RoundCoordsDict['CoordsPackage_{}'.format(EachRound+1)]) for EachCoord in range(CoordsNum): """ #------------------------------------------------------------------------------------ #:::::::::::::::::::::::::::::::: AT EACH COORDINATE :::::::::::::::::::::::::::::::: #------------------------------------------------------------------------------------ """ self.error_massage = None self.currentCoordsSeq += 1 """ # ============================================================================= # Stage movement # ============================================================================= """ self.coord_array = self.RoundCoordsDict['CoordsPackage_{}'.format(EachRound+1)][EachCoord] # Offset coordinate row value for each well. ScanningGridOffset_Row = int(EachGrid % self.meshgridnumber) * (self.GeneralSettingDict['StageGridOffset']) # Offset coordinate colunm value for each well. ScanningGridOffset_Col = int(EachGrid/self.meshgridnumber) * (self.GeneralSettingDict['StageGridOffset']) RowIndex = self.coord_array['row'] + ScanningGridOffset_Row ColumnIndex = self.coord_array['col'] + ScanningGridOffset_Col try: # for _ in range(2): # Repeat twice # self.ludlStage.moveAbs(RowIndex,ColumnIndex) # Row/Column indexs of np.array are opposite of stage row-col indexs. # time.sleep(1) self.ludlStage.moveAbs(RowIndex,ColumnIndex) # Row/Column indexs of np.array are opposite of stage row-col indexs. time.sleep(1.2) except: self.error_massage = 'Fail_MoveStage' self.errornum += 1 print('Stage move failed! Error number: {}'.format(int(self.errornum))) time.sleep(0.2) """ # ============================================================================= # Focus position # Unpack the focus stack information, conduct auto-focusing if set. # ============================================================================= """ # Here also generate the ZStackPosList. self.ZStackNum = self.unpack_focus_stack(EachGrid, EachRound, EachCoord) self.stack_focus_degree_list = [] print('*******************************************Round {}. Current index: {}.**************************************************'.format\ (EachRound+1, [RowIndex,ColumnIndex])) #------------------Move to Z stack focus------------------- for EachZStackPos in range(self.ZStackNum): """ #------------------------------------------------------------------------------------ #:::::::::::::::::::::::::::::::: AT EACH ZSTACK :::::::::::::::::::::::::::::::::::: #------------------------------------------------------------------------------------ """ print('--------------------------------------------Stack {}--------------------------------------------------'.format(EachZStackPos+1)) if self.ZStackNum > 1: self.ZStackOrder = int(EachZStackPos +1) # Here the first one is 1, not starting from 0. self.FocusPos = self.ZStackPosList[EachZStackPos]# + self.wavelength_offset # Add the focus degree of previous image to the list. # For stack of 3 only. if EachZStackPos > 0: try: self.stack_focus_degree_list.append(self.FocusDegree_img_reconstructed) except: # FocusDegree_img_reconstructed is not generated with camera imaging. pass print('stack_focus_degree_list is {}'.format(self.stack_focus_degree_list)) #-----Suppose now it's the 3rd stack position----- if len(self.stack_focus_degree_list) == 2: if self.stack_focus_degree_list[-1] < self.stack_focus_degree_list[-2]: self.FocusPos = self.ZStackPosList[0] - (self.ZStackPosList[1] - self.ZStackPosList[0])/2 print('Focus degree decreasing, run the other direction.') #------------------------------------------------- print('Target focus pos: {}'.format(self.FocusPos)) self.pi_device_instance.move(self.FocusPos) # self.auto_focus_positionInStack = self.pi_device_instance.pidevice.qPOS(self.pi_device_instance.pidevice.axes) # print("Current position: {:.4f}".format(self.auto_focus_positionInStack['1'])) time.sleep(0.3) else: self.ZStackOrder = 1 self.FocusPos = self.init_focus_position """ # ============================================================================= # Execute waveform packages # ============================================================================= """ self.Waveform_sequence_Num = int(len(self.RoundQueueDict['RoundPackage_{}'.format(EachRound+1)][0])) #------------For waveforms in each coordinate---------- for EachWaveform in range(self.Waveform_sequence_Num): """ # ============================================================================= # For photo-cycle # ============================================================================= """ # Get the photo cycle information PhotocyclePackageToBeExecute = self.RoundQueueDict['RoundPackage_{}'.format(EachRound+1)][2] \ ["PhotocyclePackage_{}".format(EachWaveform+1)] # See if in this waveform sequence photo cycle is involved. # PhotocyclePackageToBeExecute is {} if not configured. if len(PhotocyclePackageToBeExecute) > 0: # Load the previous acquired camera image self.cam_tif_name = r"M:\tnw\ist\do\projects\Neurophotonics\Brinkslab\Data\Octoscope\2020-8-13 Screening Archon1 library V5 and 6\V6\Round2_Coords181_R19800C0_PMT_0Zmax.tif" previous_cam_img = imread(self.cam_tif_name) img_width = previous_cam_img.shape[1] img_height = previous_cam_img.shape[0] # Get the segmentation of full image. fig, ax = plt.subplots() MLresults = self.Predictor.DetectionOnImage(previous_cam_img, axis = ax) ROI_number = len(MLresults["scores"]) print('roi number: {}'.format(ROI_number)) for each_ROI in range(ROI_number): # if MLresults['class_ids'][each_ROI] == 3: ROIlist = MLresults['rois'][each_ROI] print(ROIlist) # np array's column([1]) is the width of image, and is the row in stage coordinates. ROI_center_width = int(ROIlist[1] + (ROIlist[3] - ROIlist[1])/2) print('ROI_center_width '.format(ROIlist)) ROI_center_height = int(ROIlist[0] + (ROIlist[2] + ROIlist[0])/2) print('ROI_center_height '.format(ROIlist)) cam_stage_transform_factor = 1.135 stage_move_col = (int((img_width)/2) - ROI_center_width) * cam_stage_transform_factor print(stage_move_col) stage_move_row = (int((img_height)/2) - ROI_center_height) * cam_stage_transform_factor print(stage_move_row) # Move cell of interest to the center of field of view self.ludlStage.moveRel(xRel = stage_move_row, yRel= stage_move_col) time.sleep(1) # Move the cell back self.ludlStage.moveRel(xRel = -1*stage_move_row, yRel= -1*stage_move_col) time.sleep(1) #-------------------------------------------------- """ # ============================================================================= # Execute pre-set operations at EACH COORDINATE. # ============================================================================= """ self.inidividual_coordinate_operation(EachRound, EachWaveform, RowIndex, ColumnIndex) time.sleep(0.6) # Wait for receiving data to be done. time.sleep(0.5) print('*************************************************************************************************************************') #%% """~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Disconnect devices. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~""" # Switch off laser if len(self.RoundQueueDict['InsightEvents']) != 0: self.watchdog_flag = False time.sleep(0.5) self.Laserinstance.Close_TunableBeamShutter() time.sleep(0.5) self.Laserinstance.SaveVariables() self.Laserinstance.Turn_Off_PumpLaser() # Disconnect camera if self._use_camera == True: self.HamamatsuCam.Exit() # Disconnect focus motor try: self.pi_device_instance.CloseMotorConnection() print('Objective motor disconnected.') except: pass
class ScanningExecutionThread(QThread): ScanningResult = pyqtSignal(np.ndarray, np.ndarray, object, object) #The signal for the measurement, we can connect to this signal #%% def __init__(self, RoundQueueDict, RoundCoordsDict, GeneralSettingDict, *args, **kwargs): super().__init__(*args, **kwargs) self.RoundQueueDict = RoundQueueDict self.RoundCoordsDict = RoundCoordsDict self.GeneralSettingDict = GeneralSettingDict self.Status_list = None self.ludlStage = LudlStage("COM12") self.watchdog_flag = True self.clock_source = 'DAQ' # Should be set by GUI. self.scansavedirectory = self.GeneralSettingDict['savedirectory'] self.meshgridnumber = int(self.GeneralSettingDict['Meshgrid']) self.wavelength_offset = 0 # An offset of 0.002 mm is observed between 900 and 1280 nm. #%% def run(self): """~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Connect devices. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~""" """ # ============================================================================= # connect the Objective motor # ============================================================================= """ print('----------------------Starting to connect the Objective motor-------------------------') self.pi_device_instance = PIMotor() print('Objective motor connected.') self.errornum = 0 self.init_focus_position = self.pi_device_instance.pidevice.qPOS(self.pi_device_instance.pidevice.axes)['1'] print("init_focus_position : {}".format(self.init_focus_position)) """ # ============================================================================= # connect the Hmamatsu camera # ============================================================================= """ self._use_camera = False # Check if camera is used. for key in self.RoundQueueDict: if "RoundPackage_" in key: for waveform_and_cam_key in self.RoundQueueDict[key][1]: if "CameraPackage_" in waveform_and_cam_key: if len(self.RoundQueueDict[key][1][waveform_and_cam_key]) != 0: self._use_camera = True if self._use_camera: print('Connecting camera...') self.HamamatsuCam = CamActuator() self.HamamatsuCam.initializeCamera() else: print('No camera involved.') """ # ============================================================================= # connect the Insight X3 # ============================================================================= """ if len(self.RoundQueueDict['InsightEvents']) != 0: self.Laserinstance = InsightX3('COM11') try: # querygap = 1.1 # self.Laserinstance.SetWatchdogTimer(0) # Disable the laser watchdog! # Status_watchdog_thread = threading.Thread(target = self.Status_watchdog, args=[querygap], daemon=True) # Status_watchdog_thread.start() # time.sleep(1) #-------------Initialize laser-------------- self.watchdog_flag = False time.sleep(0.5) warmupstatus = 0 while int(warmupstatus) != 100: warmupstatus = self.Laserinstance.QueryWarmupTime() time.sleep(0.6) self.watchdog_flag = True time.sleep(0.5) except: print('Laser not connected.') # If turn on the laser shutter in the beginning if 'Shutter_Open' in self.GeneralSettingDict['StartUpEvents']: time.sleep(0.5) self.Laserinstance.Open_TunableBeamShutter() time.sleep(0.5) """ # ============================================================================= # Initialize ML # ============================================================================= """ self._use_ML = False # Check if machine learning segmentation is used. for key in self.RoundQueueDict: if "RoundPackage_" in key: for photocycle_key in self.RoundQueueDict[key][2]: if "PhotocyclePackage_" in photocycle_key: if len(self.RoundQueueDict[key][2][photocycle_key]) != 0: self._use_ML = True if self._use_ML: from ImageAnalysis.ImageProcessing_MaskRCNN import ProcessImageML self.Predictor = ProcessImageML() print("ML loaded.") #%% """~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Execution # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~""" GridSequence = 0 TotalGridNumber = self.meshgridnumber**2 for EachGrid in range(TotalGridNumber): """ #------------------------------------------------------------------------------ #:::::::::::::::::::::::::::::::: AT EACH GRID :::::::::::::::::::::::::::::::: #------------------------------------------------------------------------------ """ self.Grid_index = EachGrid """ # ============================================================================= # For each small repeat unit in the scanning meshgrid # ============================================================================= """ time.sleep(0.5) for EachRound in range(int(len(self.RoundQueueDict)/2-1)): # EachRound is the round sequence number starting from 0, while the actual number used in dictionary is 1. """ #------------------------------------------------------------------------------- #:::::::::::::::::::::::::::::::: AT EACH ROUND :::::::::::::::::::::::::::::::: #------------------------------------------------------------------------------- """ print ('----------------------------------------------------------------------------') print('Below is Grid {}, Round {}.'.format(EachGrid, EachRound+1)) # EachRound+1 is the corresponding round number when setting the dictionary starting from round 1. """ # ============================================================================= # Execute Insight event at the beginning of each round # ============================================================================= """ self.laser_init(EachRound) """ # ============================================================================= # Execute filter event at the beginning of each round # ============================================================================= """ self.filters_init(EachRound) """ # ============================================================================= # Generate focus position list at the beginning of each round # ============================================================================= """ if EachRound == 0: ZStackinfor = self.GeneralSettingDict['FocusStackInfoDict']['RoundPackage_{}'.format(EachRound+1)] ZStackNum = int(ZStackinfor[ZStackinfor.index('Focus')+5]) ZStackStep = float(ZStackinfor[ZStackinfor.index('Being')+5:len(ZStackinfor)]) # Generate position list. ZStacklinspaceStart = self.init_focus_position - (math.floor(ZStackNum/2)) * ZStackStep ZStacklinspaceEnd = self.init_focus_position + (ZStackNum - math.floor(ZStackNum/2)-1) * ZStackStep self.ZStackPosList = np.linspace(ZStacklinspaceStart, ZStacklinspaceEnd, num = ZStackNum) self.currentCoordsSeq = 0 #%% #-------------Unpack infor for stage move. CoordsNum = len(self.RoundCoordsDict['CoordsPackage_{}'.format(EachRound+1)]) for EachCoord in range(CoordsNum): """ #------------------------------------------------------------------------------------ #:::::::::::::::::::::::::::::::: AT EACH COORDINATE :::::::::::::::::::::::::::::::: #------------------------------------------------------------------------------------ """ self.error_massage = None self.currentCoordsSeq += 1 """ # ============================================================================= # Stage movement # ============================================================================= """ self.coord_array = self.RoundCoordsDict['CoordsPackage_{}'.format(EachRound+1)][EachCoord] # Offset coordinate row value for each well. ScanningGridOffset_Row = int(EachGrid % self.meshgridnumber) * (self.GeneralSettingDict['StageGridOffset']) # Offset coordinate colunm value for each well. ScanningGridOffset_Col = int(EachGrid/self.meshgridnumber) * (self.GeneralSettingDict['StageGridOffset']) RowIndex = self.coord_array['row'] + ScanningGridOffset_Row ColumnIndex = self.coord_array['col'] + ScanningGridOffset_Col try: # for _ in range(2): # Repeat twice # self.ludlStage.moveAbs(RowIndex,ColumnIndex) # Row/Column indexs of np.array are opposite of stage row-col indexs. # time.sleep(1) self.ludlStage.moveAbs(RowIndex,ColumnIndex) # Row/Column indexs of np.array are opposite of stage row-col indexs. time.sleep(1.2) except: self.error_massage = 'Fail_MoveStage' self.errornum += 1 print('Stage move failed! Error number: {}'.format(int(self.errornum))) time.sleep(0.2) """ # ============================================================================= # Focus position # Unpack the focus stack information, conduct auto-focusing if set. # ============================================================================= """ # Here also generate the ZStackPosList. self.ZStackNum = self.unpack_focus_stack(EachGrid, EachRound, EachCoord) self.stack_focus_degree_list = [] print('*******************************************Round {}. Current index: {}.**************************************************'.format\ (EachRound+1, [RowIndex,ColumnIndex])) #------------------Move to Z stack focus------------------- for EachZStackPos in range(self.ZStackNum): """ #------------------------------------------------------------------------------------ #:::::::::::::::::::::::::::::::: AT EACH ZSTACK :::::::::::::::::::::::::::::::::::: #------------------------------------------------------------------------------------ """ print('--------------------------------------------Stack {}--------------------------------------------------'.format(EachZStackPos+1)) if self.ZStackNum > 1: self.ZStackOrder = int(EachZStackPos +1) # Here the first one is 1, not starting from 0. self.FocusPos = self.ZStackPosList[EachZStackPos]# + self.wavelength_offset # Add the focus degree of previous image to the list. # For stack of 3 only. if EachZStackPos > 0: try: self.stack_focus_degree_list.append(self.FocusDegree_img_reconstructed) except: # FocusDegree_img_reconstructed is not generated with camera imaging. pass print('stack_focus_degree_list is {}'.format(self.stack_focus_degree_list)) #-----Suppose now it's the 3rd stack position----- if len(self.stack_focus_degree_list) == 2: if self.stack_focus_degree_list[-1] < self.stack_focus_degree_list[-2]: self.FocusPos = self.ZStackPosList[0] - (self.ZStackPosList[1] - self.ZStackPosList[0])/2 print('Focus degree decreasing, run the other direction.') #------------------------------------------------- print('Target focus pos: {}'.format(self.FocusPos)) self.pi_device_instance.move(self.FocusPos) # self.auto_focus_positionInStack = self.pi_device_instance.pidevice.qPOS(self.pi_device_instance.pidevice.axes) # print("Current position: {:.4f}".format(self.auto_focus_positionInStack['1'])) time.sleep(0.3) else: self.ZStackOrder = 1 self.FocusPos = self.init_focus_position """ # ============================================================================= # Execute waveform packages # ============================================================================= """ self.Waveform_sequence_Num = int(len(self.RoundQueueDict['RoundPackage_{}'.format(EachRound+1)][0])) #------------For waveforms in each coordinate---------- for EachWaveform in range(self.Waveform_sequence_Num): """ # ============================================================================= # For photo-cycle # ============================================================================= """ # Get the photo cycle information PhotocyclePackageToBeExecute = self.RoundQueueDict['RoundPackage_{}'.format(EachRound+1)][2] \ ["PhotocyclePackage_{}".format(EachWaveform+1)] # See if in this waveform sequence photo cycle is involved. # PhotocyclePackageToBeExecute is {} if not configured. if len(PhotocyclePackageToBeExecute) > 0: # Load the previous acquired camera image self.cam_tif_name = r"M:\tnw\ist\do\projects\Neurophotonics\Brinkslab\Data\Octoscope\2020-8-13 Screening Archon1 library V5 and 6\V6\Round2_Coords181_R19800C0_PMT_0Zmax.tif" previous_cam_img = imread(self.cam_tif_name) img_width = previous_cam_img.shape[1] img_height = previous_cam_img.shape[0] # Get the segmentation of full image. fig, ax = plt.subplots() MLresults = self.Predictor.DetectionOnImage(previous_cam_img, axis = ax) ROI_number = len(MLresults["scores"]) print('roi number: {}'.format(ROI_number)) for each_ROI in range(ROI_number): # if MLresults['class_ids'][each_ROI] == 3: ROIlist = MLresults['rois'][each_ROI] print(ROIlist) # np array's column([1]) is the width of image, and is the row in stage coordinates. ROI_center_width = int(ROIlist[1] + (ROIlist[3] - ROIlist[1])/2) print('ROI_center_width '.format(ROIlist)) ROI_center_height = int(ROIlist[0] + (ROIlist[2] + ROIlist[0])/2) print('ROI_center_height '.format(ROIlist)) cam_stage_transform_factor = 1.135 stage_move_col = (int((img_width)/2) - ROI_center_width) * cam_stage_transform_factor print(stage_move_col) stage_move_row = (int((img_height)/2) - ROI_center_height) * cam_stage_transform_factor print(stage_move_row) # Move cell of interest to the center of field of view self.ludlStage.moveRel(xRel = stage_move_row, yRel= stage_move_col) time.sleep(1) # Move the cell back self.ludlStage.moveRel(xRel = -1*stage_move_row, yRel= -1*stage_move_col) time.sleep(1) #-------------------------------------------------- """ # ============================================================================= # Execute pre-set operations at EACH COORDINATE. # ============================================================================= """ self.inidividual_coordinate_operation(EachRound, EachWaveform, RowIndex, ColumnIndex) time.sleep(0.6) # Wait for receiving data to be done. time.sleep(0.5) print('*************************************************************************************************************************') #%% """~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Disconnect devices. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~""" # Switch off laser if len(self.RoundQueueDict['InsightEvents']) != 0: self.watchdog_flag = False time.sleep(0.5) self.Laserinstance.Close_TunableBeamShutter() time.sleep(0.5) self.Laserinstance.SaveVariables() self.Laserinstance.Turn_Off_PumpLaser() # Disconnect camera if self._use_camera == True: self.HamamatsuCam.Exit() # Disconnect focus motor try: self.pi_device_instance.CloseMotorConnection() print('Objective motor disconnected.') except: pass #%% def laser_init(self, EachRound): """ Execute Insight event at the beginning of each round Parameters ---------- EachRound : int Round index. Returns ------- None. """ #-Unpack infor for Insight X3. In the list, the first one is for shutter event and the second one is for wavelength event. InsightX3EventIndexList = [i for i,x in enumerate(self.RoundQueueDict['InsightEvents']) if 'Round_{}'.format(EachRound+1) in x] if len(InsightX3EventIndexList) == 1: print(InsightX3EventIndexList) InsightText = self.RoundQueueDict['InsightEvents'][InsightX3EventIndexList[0]] if 'Shutter_Open' in InsightText: self.watchdog_flag = False time.sleep(0.5) self.Laserinstance.Open_TunableBeamShutter() time.sleep(0.5) print('Laser shutter open.') self.watchdog_flag = True time.sleep(0.5) elif 'Shutter_Close' in InsightText: self.watchdog_flag = False time.sleep(0.5) self.Laserinstance.Close_TunableBeamShutter() time.sleep(0.5) print('Laser shutter closed.') self.watchdog_flag = True time.sleep(0.5) elif 'WavelengthTo' in InsightText: self.watchdog_flag = False time.sleep(0.5) TargetWavelen = int(InsightText[InsightText.index('To_')+3:len(InsightText)]) if TargetWavelen == 1280: self.wavelength_offset = -0.002 # give an offset if wavelength goes to 1280. elif TargetWavelen == 900: self.wavelength_offset = 0 self.Laserinstance.SetWavelength(TargetWavelen) time.sleep(5) self.watchdog_flag = True time.sleep(0.5) elif len(InsightX3EventIndexList) == 2: InsightText_wl = self.RoundQueueDict['InsightEvents'][InsightX3EventIndexList[1]] InsightText_st = self.RoundQueueDict['InsightEvents'][InsightX3EventIndexList[0]] if 'WavelengthTo' in InsightText_wl and 'Shutter_Open' in InsightText_st: self.watchdog_flag = False time.sleep(0.5) TargetWavelen = int(InsightText_wl[InsightText_wl.index('To_')+3:len(InsightText_wl)]) self.Laserinstance.SetWavelength(TargetWavelen) if TargetWavelen == 1280: self.wavelength_offset = -0.002 # give an offset if wavelength goes to 1280. elif TargetWavelen == 900: self.wavelength_offset = 0 time.sleep(5) self.Laserinstance.Open_TunableBeamShutter() print('Laser shutter open.') self.watchdog_flag = True time.sleep(0.5) elif 'WavelengthTo' in InsightText_wl and 'Shutter_Close' in InsightText_st: self.watchdog_flag = False time.sleep(0.5) TargetWavelen = int(InsightText_wl[InsightText_wl.index('To_')+3:len(InsightText_wl)]) self.Laserinstance.SetWavelength(TargetWavelen) if TargetWavelen == 1280: self.wavelength_offset = -0.002 # give an offset if wavelength goes to 1280. elif TargetWavelen == 900: self.wavelength_offset = 0 time.sleep(5) self.Laserinstance.Close_TunableBeamShutter() time.sleep(1) print('Laser shutter closed.') self.watchdog_flag = True time.sleep(0.5) time.sleep(2) def filters_init(self, EachRound): """ Execute filter event at the beginning of each round. Parameters ---------- EachRound : int Round index. Returns ------- None. """ #-Unpack infor for filter event. In the list, the first one is for ND filter and the second one is for emission filter. FilterEventIndexList = [i for i,x in enumerate(self.RoundQueueDict['FilterEvents']) if 'Round_{}'.format(EachRound+1) in x] if len(FilterEventIndexList) > 0: NDposText = self.RoundQueueDict['FilterEvents'][FilterEventIndexList[0]] NDnumber = NDposText[NDposText.index('ToPos_')+6:len(NDposText)] EMposText = self.RoundQueueDict['FilterEvents'][FilterEventIndexList[1]] EMprotein = EMposText[EMposText.index('ToPos_')+6:len(EMposText)] # "COM9" for filter 1 port, which has ND values from 0 to 3. # "COM7" for filter 2 port, which has ND values from 0 to 0.5. if NDnumber == '0': ND_filter1_Pos = 0 ND_filter2_Pos = 0 elif NDnumber == '1': ND_filter1_Pos = 1 ND_filter2_Pos = 0 elif NDnumber == '2': ND_filter1_Pos = 2 ND_filter2_Pos = 0 elif NDnumber == '2.3': ND_filter1_Pos = 2 ND_filter2_Pos = 2 elif NDnumber == '2.5': ND_filter1_Pos = 2 ND_filter2_Pos = 3 elif NDnumber == '0.5': ND_filter1_Pos = 0 ND_filter2_Pos = 3 elif NDnumber == '0.3': ND_filter1_Pos = 0 ND_filter2_Pos = 2 if EMprotein == 'Arch': EM_filter_Pos = 0 elif EMprotein == 'eGFP' or EMprotein == 'Citrine': EM_filter_Pos = 1 # Execution if ND_filter1_Pos != None and ND_filter2_Pos != None: #Move filter 1 self.filter1 = ELL9Filter("COM9") self.filter1.moveToPosition(ND_filter1_Pos) time.sleep(1) #Move filter 2 self.filter2 = ELL9Filter("COM7") self.filter2.moveToPosition(ND_filter2_Pos) time.sleep(1) if EM_filter_Pos != None: self.filter3 = ELL9Filter("COM15") self.filter3.moveToPosition(EM_filter_Pos) time.sleep(1) def unpack_focus_stack(self, EachGrid, EachRound, EachCoord): """ Unpack the focus stack information. Determine focus position either from pre-set numbers of by auto-focusing. Parameters ---------- EachGrid : int Current grid index. EachRound : int Current round index. EachCoord : int Current coordinate index. Returns ------- ZStackNum : int Number of focus positions in stack. ZStackPosList : list List of focus stack positions for objective to go to. """ ZStackinfor = self.GeneralSettingDict['FocusStackInfoDict']['RoundPackage_{}'.format(EachRound+1)] ZStackNum = int(ZStackinfor[ZStackinfor.index('Focus')+5]) ZStackStep = float(ZStackinfor[ZStackinfor.index('Being')+5:len(ZStackinfor)]) # If manual focus correction applies, unpact the target focus infor. if len(self.GeneralSettingDict['FocusCorrectionMatrixDict']) > 0: FocusPosArray = self.GeneralSettingDict['FocusCorrectionMatrixDict']['RoundPackage_{}_Grid_{}'.format(EachRound+1, EachGrid)] FocusPosArray = FocusPosArray.flatten('F') FocusPos_fromCorrection = FocusPosArray[EachCoord] ZStacklinspaceStart = FocusPos_fromCorrection - (math.floor(ZStackNum/2))* ZStackStep ZStacklinspaceEnd = FocusPos_fromCorrection + (ZStackNum - math.floor(ZStackNum/2)-1) * ZStackStep # With auto-focus correction else: # If go for auto-focus at this coordinate auto_focus_flag = self.coord_array['auto_focus_flag'] # auto_focus_flag = False print('focus_position {}'.format(self.coord_array['focus_position'])) #-----------------------Auto focus--------------------------------- if auto_focus_flag == "yes": if self.coord_array['focus_position'] == -1.: instance_FocusFinder = FocusFinder(motor_handle = self.pi_device_instance) print("--------------Start auto-focusing-----------------") # instance_FocusFinder.total_step_number = 7 # instance_FocusFinder.init_step_size = 0.013 # self.auto_focus_position = instance_FocusFinder.gaussian_fit() self.auto_focus_position = instance_FocusFinder.bisection() relative_move_coords = [[1550,0],[0,1550],[1550,1550]] trial_num = 0 while self.auto_focus_position == False: # If there's no cell in FOV if trial_num <= 2: print('No cells found. move to next pos.') # Move to next position in real scanning coordinates. self.ludlStage.moveRel(relative_move_coords[trial_num][0],relative_move_coords[trial_num][1]) time.sleep(1) print('Now stage pos is {}'.format(self.ludlStage.getPos())) self.auto_focus_position = instance_FocusFinder.bisection() # Move back self.ludlStage.moveRel(-1*relative_move_coords[trial_num][0],-1*relative_move_coords[trial_num][1]) trial_num += 1 else: print('No cells in neighbouring area.') self.auto_focus_position = self.ZStackPosList[int(len(self.ZStackPosList)/2)] break print("--------------End of auto-focusing----------------") time.sleep(1) # Record the position, try to write it in the NEXT round dict. try: self.RoundCoordsDict['CoordsPackage_{}'.format(EachRound + 2)][EachCoord]['focus_position'] = self.auto_focus_position except:# If it's already the last round, skip. pass # Generate position list. ZStacklinspaceStart = self.auto_focus_position - (math.floor(ZStackNum/2)) * ZStackStep ZStacklinspaceEnd = self.auto_focus_position + (ZStackNum - math.floor(ZStackNum/2)-1) * ZStackStep else: # If there's already position from last round, move to it. self.previous_auto_focus_position = self.RoundCoordsDict['CoordsPackage_{}'.format(EachRound+1)][EachCoord]['focus_position'] try: # Record the position, try to write it in the NEXT round dict. self.RoundCoordsDict['CoordsPackage_{}'.format(EachRound + 2)][EachCoord]['focus_position'] = self.previous_auto_focus_position except: pass # Generate position list. ZStacklinspaceStart = self.previous_auto_focus_position - (math.floor(ZStackNum/2)) * ZStackStep ZStacklinspaceEnd = self.previous_auto_focus_position + (ZStackNum - math.floor(ZStackNum/2)-1) * ZStackStep # self.previous_auto_focus_position = self.auto_focus_position # print("=====================Move to last recorded position=================") # self.pi_device_instance.move(self.previous_auto_focus_position) # time.sleep(0.2) # instance_FocusFinder = FocusFinder(motor_handle = self.pi_device_instance) # print("--------------Start auto-focusing-----------------") # self.auto_focus_position = instance_FocusFinder.bisection() # try: # if self.auto_focus_position[0] == False: # If there's no cell in FOV # # Skip? mid_position = [False, self.current_pos] # self.auto_focus_position = self.auto_focus_position[1] # except: # pass # print("--------------End of auto-focusing----------------") # time.sleep(1) # # Record the position, try to write it in the NEXT round dict. # try: # self.RoundCoordsDict['CoordsPackage_{}'.format(EachRound + 2)][EachCoord]['focus_position'] = self.auto_focus_position # except:# If it's already the last round, skip. # pass # Generate the position list, for none-auto-focus coordinates they will use the same list variable. self.ZStackPosList = np.linspace(ZStacklinspaceStart, ZStacklinspaceEnd, num = ZStackNum) print('ZStackPos is : {}'.format(self.ZStackPosList)) #------------------------------------------------------------------ # If not auto focus, use the same list variable self.ZStackPosList. else: pass return ZStackNum def inidividual_coordinate_operation(self, EachRound, EachWaveform, RowIndex, ColumnIndex): """ Execute pre-set operations at each coordinate. Parameters ---------- EachRound : int Current round index. EachWaveform : int Current waveform package index. RowIndex : int Current sample stage row index. ColumnIndex : int Current sample stage row index. Returns ------- None. """ # Extract information WaveformPackageToBeExecute = self.RoundQueueDict['RoundPackage_{}'.format(EachRound+1)][0]['WaveformPackage_{}'.format(EachWaveform+1)] CameraPackageToBeExecute = self.RoundQueueDict['RoundPackage_{}'.format(EachRound+1)][1]["CameraPackage_{}".format(EachWaveform+1)] WaveformPackageGalvoInfor = self.RoundQueueDict['GalvoInforPackage_{}'.format(EachRound+1)]['GalvoInfor_{}'.format(EachWaveform+1)] self.readinchan = WaveformPackageToBeExecute[3] self.RoundWaveformIndex = [EachRound+1, EachWaveform+1] # first is current round number, second is current waveform package number. self.CurrentPosIndex = [RowIndex, ColumnIndex] #----------------Camera operations----------------- _camera_isUsed = False if CameraPackageToBeExecute != {}: # if camera operations are configured _camera_isUsed = True CamSettigList = CameraPackageToBeExecute["Settings"] self.HamamatsuCam.StartStreaming(BufferNumber = CameraPackageToBeExecute["Buffer_number"], trigger_source = CamSettigList[CamSettigList.index("trigger_source")+1], exposure_time = CamSettigList[CamSettigList.index("exposure_time")+1], trigger_active = CamSettigList[CamSettigList.index("trigger_active")+1], subarray_hsize = CamSettigList[CamSettigList.index("subarray_hsize")+1], subarray_vsize = CamSettigList[CamSettigList.index("subarray_vsize")+1], subarray_hpos = CamSettigList[CamSettigList.index("subarray_hpos")+1], subarray_vpos = CamSettigList[CamSettigList.index("subarray_vpos")+1]) # HamamatsuCam starts another thread to pull out frames from buffer. # Make sure that the camera is prepared before waveform execution. # while self.HamamatsuCam.isStreaming == False: # print('Waiting for camera...') # time.sleep(0.5) time.sleep(1) print('Now start waveforms') #----------------Waveforms operations-------------- if WaveformPackageGalvoInfor != 'NoGalvo': # Unpack the information of galvo scanning. self.readinchan = WaveformPackageGalvoInfor[0] self.repeatnum = WaveformPackageGalvoInfor[1] self.PMT_data_index_array = WaveformPackageGalvoInfor[2] self.averagenum = WaveformPackageGalvoInfor[3] self.lenSample_1 = WaveformPackageGalvoInfor[4] self.ScanArrayXnum = WaveformPackageGalvoInfor[5] self.adcollector = DAQmission() # self.adcollector.collected_data.connect(self.ProcessData) self.adcollector.runWaveforms(clock_source = self.clock_source, sampling_rate = WaveformPackageToBeExecute[0], analog_signals = WaveformPackageToBeExecute[1], digital_signals = WaveformPackageToBeExecute[2], readin_channels = WaveformPackageToBeExecute[3]) self.adcollector.save_as_binary(self.scansavedirectory) self.recorded_raw_data = self.adcollector.get_raw_data() self.Process_raw_data() #------------------Camera saving------------------- if _camera_isUsed == True: self.HamamatsuCam.isSaving = True img_text = "_Cam_"+str(self.RoundWaveformIndex[1])+"_Zpos" + str(self.ZStackOrder) self.cam_tif_name = self.generate_tif_name(extra_text = img_text) self.HamamatsuCam.StopStreaming(saving_dir = self.cam_tif_name) # Make sure that the saving process is finished. while self.HamamatsuCam.isSaving == True: print('Camera saving...') time.sleep(0.5) time.sleep(1) time.sleep(0.5) def Process_raw_data(self): self.channel_number = len(self.recorded_raw_data) self.data_collected_0 = self.recorded_raw_data[0][0:len(self.recorded_raw_data[0])-1]*-1 print(len(self.data_collected_0)) if self.channel_number == 1: if 'Vp' in self.readinchan: pass elif 'Ip' in self.readinchan: pass elif 'PMT' in self.readinchan: # repeatnum, PMT_data_index_array, averagenum, ScanArrayXnum # Reconstruct the image from np array and save it. self.PMT_image_processing() elif self.channel_number == 2: if 'PMT' not in self.readinchan: pass elif 'PMT' in self.readinchan: self.PMT_image_processing() print('ProcessData executed.') # def ProcessData(self, data_waveformreceived): # print('ZStackOrder is:'+str(self.ZStackOrder)+'numis_'+str(self.ZStackNum)) # self.adcollector.save_as_binary(self.scansavedirectory) # self.channel_number = len(data_waveformreceived) # self.data_collected_0 = data_waveformreceived[0]*-1 # self.data_collected_0 = self.data_collected_0[0:len(self.data_collected_0)-1] # print(len(self.data_collected_0)) # if self.channel_number == 1: # if 'Vp' in self.readinchan: # pass # elif 'Ip' in self.readinchan: # pass # elif 'PMT' in self.readinchan: # repeatnum, PMT_data_index_array, averagenum, ScanArrayXnum # # Reconstruct the image from np array and save it. # self.PMT_image_processing() # elif self.channel_number == 2: # if 'PMT' not in self.readinchan: # pass # elif 'PMT' in self.readinchan: # self.PMT_image_processing() # print('ProcessData executed.') def PMT_image_processing(self): """ Reconstruct the image from np array and save it. Returns ------- None. """ for imageSequence in range(self.repeatnum): try: self.PMT_image_reconstructed_array = self.data_collected_0[np.where(self.PMT_data_index_array == imageSequence+1)] Dataholder_average = np.mean(self.PMT_image_reconstructed_array.reshape(self.averagenum, -1), axis=0) Value_yPixels = int(self.lenSample_1/self.ScanArrayXnum) self.PMT_image_reconstructed = np.reshape(Dataholder_average, (Value_yPixels, self.ScanArrayXnum)) self.PMT_image_reconstructed = self.PMT_image_reconstructed[:, 50:550] # Crop size based on: M:\tnw\ist\do\projects\Neurophotonics\Brinkslab\Data\Xin\2019-12-30 2p beads area test 4um # self.PMT_image_reconstructed = self.PMT_image_reconstructed[:, 70:326] # for 256*256 images # Evaluate the focus degree of re-constructed image. self.FocusDegree_img_reconstructed = ProcessImage.local_entropy(self.PMT_image_reconstructed.astype('float32')) print('FocusDegree_img_reconstructed is {}'.format(self.FocusDegree_img_reconstructed)) # Save the individual file. with skimtiff.TiffWriter(os.path.join(self.scansavedirectory, 'Round'+str(self.RoundWaveformIndex[0]) + '_Grid' + str(self.Grid_index) +'_Coords'+str(self.currentCoordsSeq)+'_R'+str(self.CurrentPosIndex[0])+'C'+str(self.CurrentPosIndex[1])+'_PMT_'+str(imageSequence)+'Zpos'+str(self.ZStackOrder)+'.tif'), imagej = True) as tif: tif.save(self.PMT_image_reconstructed.astype('float32'), compress=0, metadata = {"FocusPos: " : str(self.FocusPos)}) plt.figure() plt.imshow(self.PMT_image_reconstructed, cmap = plt.cm.gray) # For reconstructed image we pull out the first layer, getting 2d img. plt.show() #---------------------------------------------For multiple images in one z pos, Stack the arrays into a 3d array-------------------------------------------------------------------------- # if imageSequence == 0: # self.PMT_image_reconstructed_stack = self.PMT_image_reconstructed[np.newaxis, :, :] # Turns into 3d array # else: # self.PMT_image_reconstructed_stack = np.concatenate((self.PMT_image_reconstructed_stack, self.PMT_image_reconstructed[np.newaxis, :, :]), axis=0) # print(self.PMT_image_reconstructed_stack.shape) #---------------------------------------------Calculate the z max projection----------------------------------------------------------------------- if self.repeatnum == 1: # Consider one repeat image situlation if self.ZStackNum > 1: if self.ZStackOrder == 1: self.PMT_image_maxprojection_stack = self.PMT_image_reconstructed[np.newaxis, :, :] else: self.PMT_image_maxprojection_stack = np.concatenate((self.PMT_image_maxprojection_stack, self.PMT_image_reconstructed[np.newaxis, :, :]), axis=0) else: self.PMT_image_maxprojection_stack = self.PMT_image_reconstructed[np.newaxis, :, :] # Save the max projection image if self.ZStackOrder == self.ZStackNum: self.PMT_image_maxprojection = np.max(self.PMT_image_maxprojection_stack, axis=0) # Save the zmax file. with skimtiff.TiffWriter(os.path.join(self.scansavedirectory, 'Round'+str(self.RoundWaveformIndex[0])+ '_Grid' + str(self.Grid_index) + '_Coords'+str(self.currentCoordsSeq)+'_R'+str(self.CurrentPosIndex[0])+'C'+str(self.CurrentPosIndex[1])+'_PMT_'+str(imageSequence)+'Zmax'+'.tif'), imagej = True) as tif: tif.save(self.PMT_image_maxprojection.astype('float32'), compress=0, metadata = {"FocusPos: " : str(self.FocusPos)}) except: print('No.{} image failed to generate.'.format(imageSequence)) def generate_tif_name(self, extra_text = "_"): tif_name = os.path.join(self.scansavedirectory, 'Round'+str(self.RoundWaveformIndex[0])+'_Coords'+str(self.currentCoordsSeq)+ \ '_R'+str(self.CurrentPosIndex[0])+'C'+str(self.CurrentPosIndex[1])+ extra_text +'.tif') return tif_name #----------------------------------------------------------------WatchDog for laser---------------------------------------------------------------------------------- def Status_watchdog(self, querygap): while True: if self.watchdog_flag == True: self.Status_list = self.Laserinstance.QueryStatus() time.sleep(querygap) else: print('Watchdog stopped') time.sleep(querygap)
class CoordinatesWidgetUI(QWidget): sig_cast_mask_coordinates_to_dmd = pyqtSignal(list) sig_cast_mask_coordinates_to_galvo = pyqtSignal(list) sig_start_registration = pyqtSignal() sig_finished_registration = pyqtSignal() sig_cast_camera_image = pyqtSignal(np.ndarray) def __init__(self, parent=None, *args, **kwargs): super().__init__(*args, **kwargs) self.main_application = parent self.init_gui() def closeEvent(self, event): try: self.DMD except: pass else: self.DMD.disconnect_DMD() QtWidgets.QApplication.quit() event.accept() def init_gui(self): self.setWindowTitle("Coordinate control") self.layout = QGridLayout() self.setMinimumSize(1250, 1000) self.setLayout(self.layout) self.image_mask_stack = QTabWidget() self.selection_view = DrawingWidget(self) self.selection_view.enable_drawing(True) self.selection_view.getView().setLimits(xMin=0, xMax=2048, yMin=0, yMax=2048, minXRange=2048, minYRange=2048, maxXRange=2048, maxYRange=2048) self.selection_view.ui.roiBtn.hide() self.selection_view.ui.menuBtn.hide() self.selection_view.ui.normGroup.hide() self.selection_view.ui.roiPlot.hide() # self.selection_view.setImage(plt.imread('CoordinatesManager/Registration_Images/StageRegistration/Distance200_Offset0/A1.png')) self.mask_view = SquareImageView() self.mask_view.getView().setLimits(xMin=0, xMax=2048, yMin=0, yMax=2048, minXRange=2048, minYRange=2048, maxXRange=2048, maxYRange=2048) self.mask_view.ui.roiBtn.hide() self.mask_view.ui.menuBtn.hide() self.mask_view.ui.normGroup.hide() self.mask_view.ui.roiPlot.hide() self.mask_view.ui.histogram.hide() self.image_mask_stack.addTab(self.selection_view, 'Select') self.image_mask_stack.addTab(self.mask_view, 'Mask') self.layout.addWidget(self.image_mask_stack, 0, 0, 5, 1) # ---------------------- Mask generation Container -------------- self.maskGeneratorContainer = roundQGroupBox() self.maskGeneratorContainer.setFixedSize(320, 220) self.maskGeneratorContainer.setTitle("Mask generator") self.maskGeneratorContainerLayout = QGridLayout() self.maskGeneratorLayout = QGridLayout() self.maskGeneratorContainer.setLayout( self.maskGeneratorContainerLayout) self.loadMaskFromFileButton = QPushButton('Open mask') self.loadMaskFromFileButton.clicked.connect(self.load_mask_from_file) self.addRoiButton = QPushButton("Add ROI") self.createMaskButton = QPushButton("Create mask") self.removeSelectionButton = QPushButton("Remove ROIs") self.addRoiButton.clicked.connect(self.add_polygon_roi) self.createMaskButton.clicked.connect(self.create_mask) self.removeSelectionButton.clicked.connect(self.remove_selection) self.maskGeneratorContainerLayout.addWidget(self.addRoiButton, 1, 0) self.maskGeneratorContainerLayout.addWidget(self.createMaskButton, 2, 0) self.maskGeneratorContainerLayout.addWidget(self.removeSelectionButton, 1, 1) self.selectionOptionsContainer = roundQGroupBox() self.selectionOptionsContainer.setTitle('Options') self.selectionOptionsLayout = QGridLayout() self.fillContourButton = QCheckBox() self.invertMaskButton = QCheckBox() self.thicknessSpinBox = QSpinBox() self.thicknessSpinBox.setRange(1, 25) self.selectionOptionsLayout.addWidget(QLabel('Fill contour:'), 0, 0) self.selectionOptionsLayout.addWidget(self.fillContourButton, 0, 1) self.selectionOptionsLayout.addWidget(QLabel('Invert mask:'), 1, 0) self.selectionOptionsLayout.addWidget(self.invertMaskButton, 1, 1) self.selectionOptionsLayout.addWidget(QLabel('Thickness:'), 2, 0) self.selectionOptionsLayout.addWidget(self.thicknessSpinBox, 2, 1) self.selectionOptionsContainer.setLayout(self.selectionOptionsLayout) self.snapFovButton = QPushButton('Image FOV') self.snapFovButton.clicked.connect(self.snap_fov) self.maskGeneratorContainerLayout.addWidget(self.snapFovButton, 0, 0, 1, 1) self.maskGeneratorContainerLayout.addWidget( self.loadMaskFromFileButton, 0, 1, 1, 1) self.maskGeneratorContainerLayout.addWidget( self.selectionOptionsContainer, 2, 1, 2, 1) self.layout.addWidget(self.maskGeneratorContainer, 0, 1) self.DMDWidget = DMDWidget.DMDWidget() self.layout.addWidget(self.DMDWidget, 1, 1) self.DMDWidget.sig_request_mask_coordinates.connect( lambda: self.cast_mask_coordinates('dmd')) self.sig_cast_mask_coordinates_to_dmd.connect( self.DMDWidget.receive_mask_coordinates) self.DMDWidget.sig_start_registration.connect( lambda: self.sig_start_registration.emit()) self.DMDWidget.sig_finished_registration.connect( lambda: self.sig_finished_registration.emit()) self.GalvoWidget = GalvoWidget.GalvoWidget() self.layout.addWidget(self.GalvoWidget, 2, 1) self.GalvoWidget.sig_request_mask_coordinates.connect( lambda: self.cast_mask_coordinates('galvo')) self.sig_cast_mask_coordinates_to_galvo.connect( self.GalvoWidget.receive_mask_coordinates) self.GalvoWidget.sig_start_registration.connect( lambda: self.sig_start_registration.emit()) self.GalvoWidget.sig_finished_registration.connect( lambda: self.sig_finished_registration.emit()) self.ManualRegistrationWidget = ManualRegistration.ManualRegistrationWidget( self) self.ManualRegistrationWidget.sig_request_camera_image.connect( self.cast_camera_image) self.sig_cast_camera_image.connect( self.ManualRegistrationWidget.receive_camera_image) self.layout.addWidget(self.ManualRegistrationWidget, 3, 1) self.StageRegistrationWidget = StageRegistrationWidget.StageWidget( self) self.layout.addWidget(self.StageRegistrationWidget, 4, 1) def cast_transformation_to_DMD(self, transformation, laser): self.DMDWidget.transform[laser] = transformation self.DMDWidget.save_transformation() def cast_transformation_to_galvos(self, sig): transformation = sig self.GalvoWidget.transform = transformation self.GalvoWidget.save_transformation() def cast_camera_image(self): image = self.selection_view.image if type(image) == np.ndarray: self.sig_cast_camera_image.emit(image) def snap_fov(self): self.DMDWidget.interupt_projection() self.DMDWidget.project_full_white() self.cam = CamActuator() self.cam.initializeCamera() image = self.cam.SnapImage(0.04) self.cam.Exit() self.selection_view.setImage(image) def cast_mask_coordinates(self, receiver): list_of_rois = self.get_list_of_rois() sig = [ list_of_rois, self.fillContourButton.isChecked(), self.thicknessSpinBox.value(), self.invertMaskButton.isChecked() ] if receiver == 'dmd': self.sig_cast_mask_coordinates_to_dmd.emit(sig) else: self.sig_cast_mask_coordinates_to_galvo.emit(sig) def get_list_of_rois(self): view = self.selection_view list_of_rois = [] for roi in view.roilist: roi_handle_positions = roi.getLocalHandlePositions() roi_origin = roi.pos() for idx, pos in enumerate(roi_handle_positions): roi_handle_positions[idx] = pos[1] num_vertices = len(roi_handle_positions) vertices = np.zeros([num_vertices, 2]) for idx, vertex in enumerate(roi_handle_positions): vertices[idx, :] = np.array( [vertex.x() + roi_origin.x(), vertex.y() + roi_origin.y()]) list_of_rois.append(vertices) return list_of_rois def create_mask(self): flag_fill_contour = self.fillContourButton.isChecked() flag_invert_mode = self.invertMaskButton.isChecked() contour_thickness = self.thicknessSpinBox.value() list_of_rois = self.get_list_of_rois() self.mask = ProcessImage.CreateBinaryMaskFromRoiCoordinates(list_of_rois, \ fill_contour = flag_fill_contour, \ contour_thickness = contour_thickness, \ invert_mask = flag_invert_mode) self.mask_view.setImage(self.mask) def remove_selection(self): self.selection_view.clear_rois() def set_camera_image(self, sig): self.selection_view.setImage(sig) def add_polygon_roi(self): view = self.selection_view x = (view.getView().viewRect().x()) * 0.3 y = (view.getView().viewRect().y()) * 0.3 a = (view.getView().viewRect().width() + x) * 0.3 b = (view.getView().viewRect().height() + y) * 0.3 c = (view.getView().viewRect().width() + x) * 0.7 d = (view.getView().viewRect().height() + y) * 0.7 polygon_roi = pg.PolyLineROI([[a, b], [c, b], [c, d], [a, d]], pen=view.pen, closed=True, movable=True, removable=True) view.getView().addItem(polygon_roi) view.append_to_roilist(polygon_roi) def load_mask_from_file(self): """ Open a file manager to browse through files, load image file """ self.loadFileName, _ = QtWidgets.QFileDialog.getOpenFileName( self, 'Select file', './CoordinateManager/Images/', "(*.png, *.tiff, *.jpg)") try: image = plt.imread(self.loadFileName) self.mask = image self.mask_view.setImage(self.mask) except: print('fail to load file.')
def __init__(self, source_of_image = "PMT", init_search_range = 0.010, total_step_number = 5, imaging_conditions = {'edge_volt':5}, \ motor_handle = None, camera_handle = None, twophoton_handle = None, *args, **kwargs): """ Parameters ---------- source_of_image : string, optional The input source of image. The default is PMT. init_search_range : int, optional The step size when first doing coarse searching. The default is 0.010. total_step_number : int, optional Number of steps in total to find optimal focus. The default is 5. imaging_conditions : list Parameters for imaging. For PMT, it specifies the scanning voltage. For camera, it specifies the AOTF voltage and exposure time. motor_handle : TYPE, optional Handle to control PI motor. The default is None. twophoton_handle : TYPE, optional Handle to control Insight X3. The default is None. Returns ------- None. """ super().__init__(*args, **kwargs) # The step size when first doing coarse searching. self.init_search_range = init_search_range # Number of steps in total to find optimal focus. self.total_step_number = total_step_number # Parameters for imaging. self.imaging_conditions = imaging_conditions if motor_handle == None: # Connect the objective if the handle is not provided. self.pi_device_instance = PIMotor() else: self.pi_device_instance = motor_handle # Current position of the focus. self.current_pos = self.pi_device_instance.GetCurrentPos() # Number of steps already tried. self.steps_taken = 0 # The focus degree of previous position. self.previous_degree_of_focus = 0 # Number of going backwards. self.turning_point = 0 # The input source of image. self.source_of_image = source_of_image if source_of_image == "PMT": self.galvo = RasterScan(Daq_sample_rate = 500000, edge_volt = self.imaging_conditions['edge_volt']) elif source_of_image == "Camera": if camera_handle == None: # If no camera instance fed in, initialize camera. self.HamamatsuCam_ins = CamActuator() self.HamamatsuCam_ins.initializeCamera() else: self.HamamatsuCam_ins = camera_handle
class FocusFinder(): def __init__(self, source_of_image = "PMT", init_search_range = 0.010, total_step_number = 5, imaging_conditions = {'edge_volt':5}, \ motor_handle = None, camera_handle = None, twophoton_handle = None, *args, **kwargs): """ Parameters ---------- source_of_image : string, optional The input source of image. The default is PMT. init_search_range : int, optional The step size when first doing coarse searching. The default is 0.010. total_step_number : int, optional Number of steps in total to find optimal focus. The default is 5. imaging_conditions : list Parameters for imaging. For PMT, it specifies the scanning voltage. For camera, it specifies the AOTF voltage and exposure time. motor_handle : TYPE, optional Handle to control PI motor. The default is None. twophoton_handle : TYPE, optional Handle to control Insight X3. The default is None. Returns ------- None. """ super().__init__(*args, **kwargs) # The step size when first doing coarse searching. self.init_search_range = init_search_range # Number of steps in total to find optimal focus. self.total_step_number = total_step_number # Parameters for imaging. self.imaging_conditions = imaging_conditions if motor_handle == None: # Connect the objective if the handle is not provided. self.pi_device_instance = PIMotor() else: self.pi_device_instance = motor_handle # Current position of the focus. self.current_pos = self.pi_device_instance.GetCurrentPos() # Number of steps already tried. self.steps_taken = 0 # The focus degree of previous position. self.previous_degree_of_focus = 0 # Number of going backwards. self.turning_point = 0 # The input source of image. self.source_of_image = source_of_image if source_of_image == "PMT": self.galvo = RasterScan(Daq_sample_rate = 500000, edge_volt = self.imaging_conditions['edge_volt']) elif source_of_image == "Camera": if camera_handle == None: # If no camera instance fed in, initialize camera. self.HamamatsuCam_ins = CamActuator() self.HamamatsuCam_ins.initializeCamera() else: self.HamamatsuCam_ins = camera_handle def gaussian_fit(self, move_to_focus = True): # The upper edge. upper_position = self.current_pos + self.init_search_range # The lower edge. lower_position = self.current_pos - self.init_search_range # Generate the sampling positions. sample_positions = np.linspace(lower_position, upper_position, self.total_step_number) degree_of_focus_list = [] for each_pos in sample_positions: # Go through each position and write down the focus degree. degree_of_focus = self.evaluate_focus(round(each_pos, 6)) degree_of_focus_list.append(degree_of_focus) print(degree_of_focus_list) try: interpolated_fitted_curve = ProcessImage.gaussian_fit(degree_of_focus_list) # Generate the inpterpolated new focus position axis. x_axis_new = np.linspace(lower_position, upper_position, len(interpolated_fitted_curve)) # Generate a dictionary and find the position where has the highest focus degree. max_focus_pos = dict(zip(interpolated_fitted_curve, x_axis_new))[np.amax(interpolated_fitted_curve)] if True: # Plot the fitting. plt.plot(sample_positions, np.asarray(degree_of_focus_list),'b+:',label='data') plt.plot(x_axis_new, interpolated_fitted_curve,'ro:',label='fit') plt.legend() plt.title('Fig. Fit for focus degree') plt.xlabel('Position') plt.ylabel('Focus degree') plt.show() max_focus_pos = round(max_focus_pos, 6) print(max_focus_pos) self.pi_device_instance.move(max_focus_pos) # max_focus_pos_focus_degree = self.evaluate_focus(round(max_focus_pos, 6)) except: print("Fitting failed. Find max in the list.") max_focus_pos = sample_positions[degree_of_focus_list.index(max(degree_of_focus_list))] print(max_focus_pos) if move_to_focus == True: self.pi_device_instance.move(max_focus_pos) return max_focus_pos def bisection(self): """ Bisection way of finding focus. Returns ------- mid_position : float DESCRIPTION. """ # The upper edge in which we run bisection. upper_position = self.current_pos + self.init_search_range # The lower edge in which we run bisection. lower_position = self.current_pos - self.init_search_range for step_index in range(1, self.total_step_number + 1): # In each step of bisection finding. # In the first round, get degree of focus at three positions. if step_index == 1: # Get degree of focus in the mid. mid_position = (upper_position + lower_position)/2 degree_of_focus_mid = self.evaluate_focus(mid_position) print("mid focus degree: {}".format(round(degree_of_focus_mid, 5))) # Break the loop if focus degree is below threshold which means # that there's no cell in image. if not ProcessImage.if_theres_cell(self.galvo_image.astype('float32')): print('no cell') mid_position = False break # Move to top and evaluate. degree_of_focus_up = self.evaluate_focus(obj_position = upper_position) print("top focus degree: {}".format(round(degree_of_focus_up, 5))) # Move to bottom and evaluate. degree_of_focus_low = self.evaluate_focus(obj_position = lower_position) print("bot focus degree: {}".format(round(degree_of_focus_low, 5))) # Sorting dicitonary of degrees in ascending. biesection_range_dic = {"top":[upper_position, degree_of_focus_up], "bot":[lower_position, degree_of_focus_low]} # In the next rounds, only need to go to center and update boundaries. elif step_index > 1: # The upper edge in which we run bisection. upper_position = biesection_range_dic["top"][0] # The lower edge in which we run bisection. lower_position = biesection_range_dic["bot"][0] # Get degree of focus in the mid. mid_position = (upper_position + lower_position)/2 degree_of_focus_mid = self.evaluate_focus(mid_position) print("Current focus degree: {}".format(round(degree_of_focus_mid, 5))) # If sits in upper half, make the middle values new bottom. if biesection_range_dic["top"][1] > biesection_range_dic["bot"][1]: biesection_range_dic["bot"] = [mid_position, degree_of_focus_mid] else: biesection_range_dic["top"] = [mid_position, degree_of_focus_mid] print("The upper pos: {}; The lower: {}".format(biesection_range_dic["top"][0], biesection_range_dic["bot"][0])) return mid_position def evaluate_focus(self, obj_position = None): """ Evaluate the focus degree of certain objective position. Parameters ---------- obj_position : float, optional The target objective position. The default is None. Returns ------- degree_of_focus : float Degree of focus. """ if obj_position != None: self.pi_device_instance.move(obj_position) # Get the image. if self.source_of_image == "PMT": self.galvo_image = self.galvo.run() plt.figure() plt.imshow(self.galvo_image) plt.show() if False: with skimtiff.TiffWriter(os.path.join(r'M:\tnw\ist\do\projects\Neurophotonics\Brinkslab\Data\Xin\2020-11-17 gaussian fit auto-focus cells\trial_11', str(obj_position).replace(".", "_")+ '.tif')) as tif: tif.save(self.galvo_image.astype('float32'), compress=0) degree_of_focus = ProcessImage.local_entropy(self.galvo_image.astype('float32')) elif self.source_of_image == "Camera": # First configure the AOTF. self.AOTF_runner = DAQmission() # Find the AOTF channel key for key in self.imaging_conditions: if 'AO' in key: # like '488AO' AOTF_channel_key = key # Set the AOTF first. self.AOTF_runner.sendSingleDigital('blankingall', True) self.AOTF_runner.sendSingleAnalog(AOTF_channel_key, self.imaging_conditions[AOTF_channel_key]) # Snap an image from camera self.camera_image = self.HamamatsuCam_ins.SnapImage(self.imaging_conditions['exposure_time']) time.sleep(0.5) # Set back AOTF self.AOTF_runner.sendSingleDigital('blankingall', False) self.AOTF_runner.sendSingleAnalog(AOTF_channel_key, 0) plt.figure() plt.imshow(self.camera_image) plt.show() if False: with skimtiff.TiffWriter(os.path.join(r'M:\tnw\ist\do\projects\Neurophotonics\Brinkslab\Data\Xin\2021-03-06 Camera AF\beads', str(obj_position).replace(".", "_")+ '.tif')) as tif: tif.save(self.camera_image.astype('float32'), compress=0) degree_of_focus = ProcessImage.variance_of_laplacian(self.camera_image.astype('float32')) time.sleep(0.2) return degree_of_focus
class DMDRegistator: def __init__(self, DMD, *args, **kwargs): self.DMD = DMD self.cam = CamActuator() self.cam.initializeCamera() def registration(self, laser='640', grid_points_x=2, grid_points_y=3, registration_pattern='circles'): x_coords = np.linspace(0, 768, grid_points_x + 2)[1:-1] y_coords = np.linspace(0, 1024, grid_points_y + 2)[1:-1] x_mesh, y_mesh = np.meshgrid(x_coords, y_coords) x_coords = np.ravel(x_mesh) y_coords = np.ravel(y_mesh) dmd_coordinates = np.stack((x_coords, y_coords), axis=1) camera_coordinates = np.zeros(dmd_coordinates.shape) for i in range(dmd_coordinates.shape[0]): x = int(dmd_coordinates[i, 0]) y = int(dmd_coordinates[i, 1]) if registration_pattern == 'squares': mask = DMDRegistator.create_registration_image_touching_squares( x, y) else: mask = DMDRegistator.create_registration_image_circle(x, y) self.DMD.send_data_to_DMD(mask) self.DMD.start_projection() image = self.cam.SnapImage(0.01) plt.imsave( os.getcwd() + '/CoordinatesManager/Registration_Images/TouchingSquares/image_' + str(i) + '.png', image) camera_coordinates[ i, :] = readRegistrationImages.touchingCoordinateFinder( image, method='curvefit') self.DMD.stop_projection() print('DMD coordinates:') print(dmd_coordinates) print('Found camera coordinates:') print(camera_coordinates) self.DMD.free_memory() self.cam.Exit() transformation = CoordinateTransformations.polynomial2DFit( camera_coordinates, dmd_coordinates, order=1) print('Transformation found for x:') print(transformation[:, :, 0]) print('Transformation found for y:') print(transformation[:, :, 1]) return transformation def create_registration_image_touching_squares(x, y, sigma=75): array = np.zeros((768, 1024)) array[skimage.draw.rectangle((x - sigma, y - sigma), (x, y))] = 255 array[skimage.draw.rectangle((x + sigma, y + sigma), (x, y))] = 255 return array def create_registration_image_circle(x, y, sigma=75): array = np.zeros((768, 1024)) array[skimage.draw.circle(x, y, sigma)] = 255 return array
def __init__(self, DMD, *args, **kwargs): self.DMD = DMD self.cam = CamActuator() self.cam.initializeCamera()
class GalvoRegistrator: def __init__(self, *args, **kwargs): self.cam = CamActuator() self.cam.initializeCamera() def registration(self, grid_points_x=3, grid_points_y=3): """ By default, generate 9 galvo voltage coordinates from (-5,-5) to (5,5), take the camera images of these points, return a function matrix that transforms camera_coordinates into galvo_coordinates using polynomial transform. Parameters ---------- grid_points_x : TYPE, optional DESCRIPTION. The default is 3. grid_points_y : TYPE, optional DESCRIPTION. The default is 3. Returns ------- transformation : TYPE DESCRIPTION. """ galvothread = DAQmission() readinchan = [] x_coords = np.linspace(-10, 10, grid_points_x + 2)[1:-1] y_coords = np.linspace(-10, 10, grid_points_y + 2)[1:-1] xy_mesh = np.reshape(np.meshgrid(x_coords, y_coords), (2, -1), order='F').transpose() galvo_coordinates = xy_mesh camera_coordinates = np.zeros((galvo_coordinates.shape)) for i in range(galvo_coordinates.shape[0]): galvothread.sendSingleAnalog('galvosx', galvo_coordinates[i, 0]) galvothread.sendSingleAnalog('galvosy', galvo_coordinates[i, 1]) time.sleep(1) image = self.cam.SnapImage(0.06) plt.imsave( os.getcwd() + '/CoordinatesManager/Registration_Images/2P/image_' + str(i) + '.png', image) camera_coordinates[i, :] = readRegistrationImages.gaussian_fitting( image) print('Galvo Coordinate') print(galvo_coordinates) print('Camera coordinates') print(camera_coordinates) del galvothread self.cam.Exit() transformation_cam2galvo = CoordinateTransformations.polynomial2DFit( camera_coordinates, galvo_coordinates, order=1) transformation_galvo2cam = CoordinateTransformations.polynomial2DFit( galvo_coordinates, camera_coordinates, order=1) print('Transformation found for x:') print(transformation_cam2galvo[:, :, 0]) print('Transformation found for y:') print(transformation_cam2galvo[:, :, 1]) print('galvo2cam found for x:') print(transformation_galvo2cam[:, :, 0]) print('galvo2cam found for y:') print(transformation_galvo2cam[:, :, 1]) return transformation_cam2galvo