class VolumeSliderBase(BaseProcess_noPriorWindow): """ Start Volume Slider from differnt sources |Select source (current window or saved numpy array) Returns volumeSlider GUI """ def __init__(self): if g.settings['volumeSlider'] is None or 'inputChoice' not in g.settings['volumeSlider']: s = dict() s['inputChoice'] = 'Current Window' s['keepOriginalWindow'] = False g.settings['volumeSlider'] = s BaseProcess_noPriorWindow.__init__(self) def __call__(self, inputChoice,keepOriginalWindow,keepSourceWindow=False): g.settings['volumeSlider']['inputChoice'] = inputChoice g.settings['volumeSlider']['keepOriginalWindow'] = keepOriginalWindow g.m.statusBar().showMessage("Starting Volume Slider...") if inputChoice == 'Current Window': camVolumeSlider.startVolumeSlider(keepWindow=keepOriginalWindow) elif inputChoice == 'Numpy Array': A_path = open_file_gui(directory=os.path.expanduser("~/Desktop"),filetypes='*.npy') g.m.statusBar().showMessage("Importing Array: " + A_path) A = np.load(str(A_path)) camVolumeSlider.startVolumeSlider(A=A,keepWindow=keepOriginalWindow) return def closeEvent(self, event): BaseProcess_noPriorWindow.closeEvent(self, event) def gui(self): self.gui_reset() #combobox inputChoice = ComboBox() inputChoice.addItem('Current Window') inputChoice.addItem('Numpy Array') #checkbox self.keepOriginalWindow = CheckBox() self.keepOriginalWindow.setValue(False) #populate GUI self.items.append({'name': 'inputChoice', 'string': 'Choose Input Data:', 'object': inputChoice}) self.items.append({'name': 'keepOriginalWindow','string':'Keep Original Window','object': self.keepOriginalWindow}) super().gui()
class TiffPageLoader(BaseProcess_noPriorWindow): """ Loads tiff files by page. """ def __init__(self): if g.settings['tiff_page_loader'] is None or 'setSteps' not in g.settings['tiff_page_loader']: s = dict() s['nSteps'] = 1 s['setSteps'] = True g.settings['tiff_page_loader'] = s #test saved filePath is valid super().__init__() return def __call__(self, filePath, nSteps, setSteps): g.settings['on_the_fly']['filePath'] = filePath g.settings['on_the_fly']['nSteps']=nSteps g.settings['on_the_fly']['setSteps']=setSteps g.m.statusBar().showMessage("Scanning file ...") self.mainGUI = MainGUI() self.mainGUI.show() def closeEvent(self, event): BaseProcess_noPriorWindow.closeEvent(self, event) def gui(self): s=g.settings['tiff_page_loader'] self.gui_reset() self.nSteps = pg.SpinBox(int=True, step=1) self.nSteps.setMinimum(1) self.nSteps.setValue(s['nSteps']) self.filePath = TiffSelector('*.tiff, *.tif') self.setSteps = CheckBox() self.setSteps.setValue(s['setSteps']) self.items.append({'name':'filePath','string':'Tiff file path','object': self.filePath}) self.items.append({'name': 'nSteps', 'string': 'Number of steps per volume', 'object': self.nSteps}) self.items.append({'name': 'setSteps', 'string': 'Automatically determine step size from Tiff metadata', 'object': self.setSteps}) super().gui()
class Simulate_mepp(BaseProcess_noPriorWindow): """ Simulate MEPP events in a noisy time trace Trace generated by linear summation of randomly occuring unitary events hF(t) (MEPPs) see Segal et al. Biophys J, 1985 h = time independent amplitude factor F(t) = nondimensional function of time hF(t) = h(exp(-t/dT) - exp(-t/dR)) dT = decay time constant rT = rise time constant time of MEPP addition drawn from exponential distribution (np.random.exponential()) amplitude of MEPP drawn from normal distribution (np.random.normal()) duration of MEPP drawn from normal distribution (np.random.normal()) """ def __init__(self): if g.settings[ 'mepp_simulator'] is None or 'decayTime' not in g.settings[ 'mepp_simulator']: s = dict() s['traceLength'] = 10000 s['meppAmplitude'] = 5 s['meppDuration'] = 1 s['startTime'] = 0 s['meanExp'] = 1000.0 s['baseline'] = 0.0 s['noiseSigma'] = 0.1 s['riseTime'] = 1.0 #s['riseTime_sigma'] = 0.01 s['decayTime'] = 10.0 #s['decayTime_sigma'] = 0.1 g.settings['mepp_simulator'] = s super().__init__() self.data = np.array([]) def gui(self): s = g.settings['mepp_simulator'] self.gui_reset() self.meppWindow = PlotWindow('Single MEPP (No noise)') self.traceWindow = PlotWindow('Time Trace') self.meppWindow.hide() self.traceWindow.hide() self.traceLength = SliderLabel(0) self.traceLength.setRange(0, 1000000) self.traceLength.setValue(s['traceLength']) self.startTime = SliderLabel(0) self.startTime.setRange(0, s['traceLength']) self.startTime.setValue(s['startTime']) self.meppDuration_slider = pg.SpinBox(int=True, step=1) self.meppDuration_slider.setValue(s['meppDuration']) self.meppDuration_sigma_slider = pg.SpinBox(int=True, step=1) self.meppDuration_sigma_slider.setValue(1) self.baseline_slider = pg.SpinBox(int=False, step=.01) self.baseline_slider.setValue(s['baseline']) self.noiseSigma_slider = pg.SpinBox(int=False, step=.01) self.noiseSigma_slider.setValue(s['noiseSigma']) self.meppAmplitude_slider = pg.SpinBox(int=False, step=.01) self.meppAmplitude_slider.setValue(s['meppAmplitude']) self.meppAmplitude_sigma_slider = pg.SpinBox(int=False, step=.01) self.meppAmplitude_sigma_slider.setValue(1.0) self.meppRiseTime_slider = pg.SpinBox(int=False, step=.01) self.meppRiseTime_slider.setValue(s['riseTime']) #self.meppRiseTime_sigma_slider = pg.SpinBox(int=False, step=.01) #self.meppRiseTime_sigma_slider.setValue(0.01) self.meppDecayTime_slider = pg.SpinBox(int=False, step=.01) self.meppDecayTime_slider.setValue(s['decayTime']) #self.meppDecayTime_sigma_slider = pg.SpinBox(int=False, step=.01) #self.meppDecayTime_sigma_slider.setValue(0.1) self.randommeppsAdded = False self.meanExp_slider = pg.SpinBox(int=False, step=.01) self.meanExp_slider.setValue(1000.0) self.plotHistoTimes = CheckBox() self.plotHistoTimes.setValue(False) self.exportTimes_button = QPushButton('Export times') self.exportTimes_button.pressed.connect(self.exportTimes) self.randommeppButton = QPushButton('Generate Trace') self.randommeppButton.pressed.connect(self.addRandommepps) self.plotmeppButton = QPushButton('Plot single MEPP') self.plotmeppButton.pressed.connect(self.plotSingleMEPP) self.items.append({ 'name': 'traceLength', 'string': 'Recording length', 'object': self.traceLength }) self.items.append({ 'name': 'startTime', 'string': 'Start time', 'object': self.startTime }) self.items.append({ 'name': 'meppDuration', 'string': 'MEPP duration (mean)', 'object': self.meppDuration_slider }) self.items.append({ 'name': 'meppDuration_sigma', 'string': 'MEPP duration (standard deviation)', 'object': self.meppDuration_sigma_slider }) self.items.append({ 'name': 'riseTime', 'string': 'MEPP rise time constant', 'object': self.meppRiseTime_slider }) #self.items.append({'name': 'riseTime_sigma','string':'MEPP rise time constant (standard deviation)','object':self.meppRiseTime_sigma_slider}) self.items.append({ 'name': 'decayTime', 'string': 'MEPP decay time constant', 'object': self.meppDecayTime_slider }) #self.items.append({'name': 'decayTime_sigma','string':'MEPP decay time constant (standard deviation)','object':self.meppDecayTime_sigma_slider}) self.items.append({ 'name': 'meppAmplitude', 'string': 'MEPP Amplitude (mean)', 'object': self.meppAmplitude_slider }) self.items.append({ 'name': 'meppAmplitude_sigma', 'string': 'MEPP Amplitude (standard deviation)', 'object': self.meppAmplitude_sigma_slider }) self.items.append({ 'name': 'meanExp', 'string': 'Mean of exponential distibution', 'object': self.meanExp_slider }) self.items.append({ 'name': 'baseline', 'string': 'Baseline', 'object': self.baseline_slider }) self.items.append({ 'name': 'noiseSigma', 'string': 'Noise Sigma', 'object': self.noiseSigma_slider }) self.items.append({ 'name': 'histoTimes', 'string': 'Plot histogram of mepp start times:', 'object': self.plotHistoTimes }) self.items.append({ 'name': 'random_mepp_Button', 'string': 'Click to add randomly distibuted mepps', 'object': self.randommeppButton }) self.items.append({ 'name': 'listTimes', 'string': 'Export list of mepp start times', 'object': self.exportTimes_button }) self.items.append({ 'name': 'plotMEPP', 'string': 'Plot single MEPP (without noise)', 'object': self.plotmeppButton }) super().gui() def __call__(self, keepSourceWindow=False): g.settings['mepp_simulator']['traceLength'] = self.getValue( 'traceLength') g.settings['mepp_simulator']['meppAmplitude'] = self.getValue( 'meppAmplitude') g.settings['mepp_simulator']['meppDuration'] = self.getValue( 'meppDuration') g.settings['mepp_simulator']['startTime'] = self.getValue('startTime') g.settings['mepp_simulator']['meanExp'] = self.getValue('meanExp') g.settings['mepp_simulator']['baseline'] = self.getValue('baseline') g.settings['mepp_simulator']['noiseSigma'] = self.getValue( 'noiseSigma') g.settings['mepp_simulator']['riseTime'] = self.getValue('riseTime') g.settings['mepp_simulator']['decayTime'] = self.getValue('decayTime') return def addMEPP(self, time, amplitude, duration, dT=10, rT=1): #using Segal et al. Biophys J, 1985 MINIATURE ENDPLATE POTENTIAL FREQUENCY AND AMPLITUDE DETERMINED BY AN EXTENSION OF CAMPBELL'S THEOREM #dT = decay time #rT = rise time ampList = [] for t in range(0, duration): ampList.append(amplitude * (math.exp(-t / dT) - math.exp(-t / rT))) #square event test #self.data[time:time+duration] = self.data[time:time+duration] + amplitude #add MEPP to trace self.data[time:time + duration] = self.data[time:time + duration] + np.array(ampList) def plotSingleMEPP(self): amp = self.getValue('meppAmplitude') duration = self.getValue('meppDuration') dT = self.getValue('decayTime') rT = self.getValue('riseTime') self.plotMEPP(amp, duration, dT=dT, rT=rT) def plotMEPP(self, amplitude, duration, dT=10, rT=1): ampList = [] for t in range(0, duration): ampList.append(amplitude * (math.exp(-t / dT) - math.exp(-t / rT))) #plot matplot #plt.figure(3) #plt.plot(range(0,duration),ampList) #plt.show() #plot pg self.meppWindow.update(ampList, [0, len(ampList)], [0, self.getValue('meppAmplitude')]) self.meppWindow.show() def addRandommepps(self): self.data = np.array([]) #generate noisy time trace n = int(self.getValue('traceLength')) self.data = np.random.normal(self.getValue('baseline'), self.getValue('noiseSigma'), n) #add MEPPS to trace mean = self.getValue('meanExp') meppsAdded = 0 meppsOutsideOfRange = 0 self.timesAdded = [] amp = self.getValue('meppAmplitude') duration = self.getValue('meppDuration') dT = self.getValue('decayTime') rT = self.getValue('riseTime') # add first mepp try: time = int((np.random.exponential(scale=mean, size=1) + self.getValue('startTime'))) #draw random amplitude randAmp = int( np.random.normal(amp, self.getValue('meppAmplitude_sigma'), 1)) #draw random duration randDuration = int( np.random.normal(duration, self.getValue('meppDuration_sigma'), 1)) # add MEPP self.addMEPP(time, randAmp, randDuration, dT=dT, rT=rT) #record time self.timesAdded.append(time) meppsAdded += 1 except BaseException as e: #print(e) #meppsOutsideOfRange += 1 #print('{} MEPPs added, {} MEPPs out of time range'.format(meppsAdded,meppsOutsideOfRange)) #print('1st MEPP outside of time range, aborting') pass # add mepp after each time selection untill end of stack # casting the exponential continous value as an int to select frame while time < self.getValue('traceLength') - self.getValue( 'meppDuration'): try: time = int((time + np.random.exponential(scale=mean, size=1))) #draw random amplitude randAmp = int( np.random.normal(amp, self.getValue('meppAmplitude_sigma'), 1)) #draw random duration randDuration = int( np.random.normal(duration, self.getValue('meppDuration_sigma'), 1)) # add MEPP self.addMEPP(time, randAmp, randDuration, dT=dT, rT=rT) #record time self.timesAdded.append(time) meppsAdded += 1 except BaseException as e: #print(e) meppsOutsideOfRange += 1 #print number of MEPPS added to console #print('{} MEPPs added, {} MEPPs out of time range'.format(meppsAdded,meppsOutsideOfRange)) if self.plotHistoTimes.isChecked(): plt.figure(1) plt.hist(self.timesAdded) plt.xlabel('Time MEPP added') plt.ylabel('Number of MEPPs added') plt.show() self.randommeppsAdded = True #print data to console #print(self.data) #plot data matplotlib #plt.figure(0) #plt.plot(self.data) #plt.show() #plot data pg self.traceWindow.update(self.data, [0, len(self.data)], [ self.getValue('baseline') - (3 * self.getValue('noiseSigma')), self.getValue('meppAmplitude') + (3 * self.getValue('meppAmplitude_sigma')) ]) self.traceWindow.show() return def exportTimes(self): if self.randommeppsAdded == False: g.alert('Add MEPPs first') return #set export path savePath, _ = QFileDialog.getSaveFileName(None, "Save file", "", "Text Files (*.csv)") #write file try: # opening the csv file in 'w+' mode file = open(savePath, 'w+', newline='') # writing the data into the file with file: write = csv.writer(file) write.writerows(map(lambda x: [x], self.timesAdded)) print('List of times saved to: {}'.format(savePath)) except BaseException as e: print(e) print('Export of times failed, printing times to console') print(self.timesAdded)
class OnTheFly(BaseProcess_noPriorWindow): """ Continuous light sheet analysis """ def __init__(self): if g.settings[ 'on_the_fly'] is None or 'updateRateVolViewer' not in g.settings[ 'on_the_fly']: s = dict() s['sliceNumber'] = 0 s['batchSize'] = 10 s['updateRate'] = 2 #seconds s['updateRateVolViewer'] = 120 #seconds s['nSteps'] = 1 s['displaySlice'] = 0 s['shift_factor'] = 1 s['theta'] = 45 s['triangle_scan'] = False s['interpolate'] = False s['trim_last_frame'] = False s['nChannels'] = 1 g.settings['on_the_fly'] = s BaseProcess_noPriorWindow.__init__(self) def __call__(self, recordingFolder, exportFolder, batchSize, updateRate, updateRateVolViewer, nSteps, displaySlice, shift_factor, theta, triangle_scan, interpolate, trim_last_frame, zscan, nChannels, keepSourceWindow=False): g.settings['on_the_fly']['recordingFolder'] = recordingFolder g.settings['on_the_fly']['exportFolder'] = exportFolder g.settings['on_the_fly']['batchSize'] = batchSize g.settings['on_the_fly']['updateRate'] = updateRate g.settings['on_the_fly']['updateRateVolViewer'] = updateRateVolViewer g.settings['on_the_fly']['nSteps'] = nSteps g.settings['on_the_fly']['displaySlice'] = displaySlice g.settings['on_the_fly']['shift_factor'] = shift_factor g.settings['on_the_fly']['theta'] = theta g.settings['on_the_fly']['triangle_scan'] = triangle_scan g.settings['on_the_fly']['interpolate'] = interpolate g.settings['on_the_fly']['trim_last_frame'] = trim_last_frame g.settings['on_the_fly']['zscan'] = zscan g.settings['on_the_fly']['nChannels'] = nChannels g.m.statusBar().showMessage("Starting ...") t = time() self.mainGUI = MainGUI() self.mainGUI.show() def closeEvent(self, event): BaseProcess_noPriorWindow.closeEvent(self, event) def gui(self): s = g.settings['on_the_fly'] self.gui_reset() self.batchSize = pg.SpinBox(int=True, step=1) self.batchSize.setMinimum(1) self.batchSize.setValue(s['batchSize']) self.nSteps = pg.SpinBox(int=True, step=1) self.nSteps.setMinimum(1) self.nSteps.setValue(s['nSteps']) self.shift_factor = pg.SpinBox(int=False, step=.1) self.shift_factor.setValue(s['shift_factor']) self.theta = pg.SpinBox(int=True, step=1) self.theta.setValue(s['theta']) self.triangle_scan = CheckBox() self.triangle_scan.setValue(s['triangle_scan']) self.interpolate = CheckBox() self.interpolate.setValue(s['interpolate']) self.trim_last_frame = CheckBox() self.trim_last_frame.setValue(s['trim_last_frame']) self.zscan = CheckBox() self.zscan.setValue(s['trim_last_frame']) self.recordingFolder = FolderSelector('*.txt') self.exportFolder = FolderSelector('*.txt') self.displaySlice = pg.SpinBox(int=True, step=1) self.displaySlice.setMinimum(0) self.displaySlice.setValue(s['displaySlice']) self.updateRate = pg.SpinBox(int=True, step=1) self.updateRate.setMinimum(1) self.updateRate.setValue(s['updateRate']) self.updateRateVolViewer = pg.SpinBox(int=True, step=1) self.updateRateVolViewer.setMinimum(1) self.updateRateVolViewer.setValue(s['updateRateVolViewer']) self.nChannels = pg.SpinBox(int=True, step=1) self.nChannels.setMinimum(1) self.nChannels.setMaximum(2) self.nChannels.setValue(s['nChannels']) self.items.append({ 'name': 'recordingFolder', 'string': 'Results Folder Location', 'object': self.recordingFolder }) self.items.append({ 'name': 'exportFolder', 'string': 'Export Folder Location', 'object': self.exportFolder }) self.items.append({ 'name': 'batchSize', 'string': 'Batch Size', 'object': self.batchSize }) self.items.append({ 'name': 'updateRate', 'string': 'Update Rate (seconds)', 'object': self.updateRate }) self.items.append({ 'name': 'updateRateVolViewer', 'string': 'Volume Viewer Update Rate (seconds)', 'object': self.updateRateVolViewer }) self.items.append({ 'name': 'nSteps', 'string': 'Number of Steps Per Volume', 'object': self.nSteps }) self.items.append({ 'name': 'displaySlice', 'string': 'Display Slice#', 'object': self.displaySlice }) self.items.append({ 'name': 'shift_factor', 'string': 'Shift Factor', 'object': self.shift_factor }) self.items.append({ 'name': 'theta', 'string': 'Theta', 'object': self.theta }) self.items.append({ 'name': 'triangle_scan', 'string': 'Triangle Scan', 'object': self.triangle_scan }) self.items.append({ 'name': 'interpolate', 'string': 'Interpolate', 'object': self.interpolate }) self.items.append({ 'name': 'trim_last_frame', 'string': 'Trim Last Frame', 'object': self.trim_last_frame }) self.items.append({ 'name': 'zscan', 'string': 'Z Scan', 'object': self.zscan }) self.items.append({ 'name': 'nChannels', 'string': 'Number of Channels', 'object': self.nChannels }) super().gui()
class Simulate_Puff(BaseProcess_noPriorWindow): """ Add a simulated puff to an image stack """ def __init__(self): super().__init__() self.currentWin = None self.currentROI = None self.data = None def get_init_settings_dict(self): s = dict() s['nFrames'] = 100 s['puffAmplitude'] = 5 s['x'] = 128 s['y'] = 128 s['startFrame'] = 100 s['sigma'] = 20 s['useROI'] = False s['meanExp'] = 5.0 s['nPuffs'] = 0 s['nSites'] = 10 s['meanDuration'] = 10 return s def gui(self): self.gui_reset() self.nFrames = pg.SpinBox(int=False, step=.01) #self.nFrames.setRange(0,10000) self.startFrame = SliderLabel(0) self.startFrame.setRange(0, 10000) self.puffAmplitude = pg.SpinBox(int=False, step=.01) self.puffAmplitude.setValue(1.0) self.sigma = SliderLabel(0) self.sigma.setRange(1, 1000) self.x = SliderLabel(0) self.x.setRange(1, 10000) self.y = SliderLabel(0) self.y.setRange(1, 10000) self.useROI = CheckBox() self.useFrame = CheckBox() self.active_window = WindowSelector() self.previewButton = QPushButton('Preview Puff') self.previewButton.pressed.connect(self.previewPuff) self.puffButton = QPushButton('Add Puff') self.puffButton.pressed.connect(self.addPuff) self.randomPuffsAdded = False self.nSites = 10 columnNames = ['time of puff', 'duration', 'site'] self.timesAdded = pd.DataFrame(columns=columnNames) self.siteNumber = int(0) self.nPuffs_slider = SliderLabel(0) self.nPuffs_slider.setRange(1, 1000) self.meanExp_slider = pg.SpinBox(int=False, step=.01) self.meanExp_slider.setValue(5.0) self.randomDuration = CheckBox() self.randomDuration.setValue(False) self.durationMean = 10.0 self.durationMean_box = pg.SpinBox(int=False, step=.01) self.durationMean_box.setRange(0, 10000) self.durationMean_box.setValue(self.durationMean) self.plotHistoTimes = CheckBox() self.plotHistoTimes.setValue(False) self.addPuffsSequentially = CheckBox() self.addPuffsSequentially.setValue(False) self.exportTimes_button = QPushButton('Export times') self.exportTimes_button.pressed.connect(self.exportTimes) self.randomPuffButton = QPushButton('Add Puffs to site') self.randomPuffButton.pressed.connect(self.addRandomPuffs) self.multipleRandomPuffButton = QPushButton('Add Puffs inside ROI') self.multipleRandomPuffButton.pressed.connect( self.addMultipleRandomPuffs) self.nSites_box = QSpinBox() self.nSites_box.setRange(0, 10000) self.nSites_box.setValue(self.nSites) self.items.append({ 'name': 'active_window', 'string': 'Select Window', 'object': self.active_window }) self.items.append({ 'name': 'nFrames', 'string': 'Duration (frames)', 'object': self.nFrames }) self.items.append({ 'name': 'randomDuration', 'string': 'Use exponentially distributed random duration', 'object': self.randomDuration }) self.items.append({ 'name': 'meanDuration', 'string': 'Mean duration', 'object': self.durationMean_box }) self.items.append({ 'name': 'startFrame', 'string': 'Start Frame', 'object': self.startFrame }) #self.items.append({'name': 'useCurrentFrame', 'string': 'Use Current Frame For Start', 'object': self.useFrame}) self.items.append({ 'name': 'puffAmplitude', 'string': 'Amplitude', 'object': self.puffAmplitude }) self.items.append({'name': 'x', 'string': 'x', 'object': self.x}) self.items.append({'name': 'y', 'string': 'y', 'object': self.y}) #self.items.append({'name': 'useROI', 'string': 'Use ROI for position', 'object': self.useROI}) self.items.append({ 'name': 'sigma', 'string': 'sigma', 'object': self.sigma }) self.items.append({ 'name': 'preview_Button', 'string': 'Click to preview Puff', 'object': self.previewButton }) self.items.append({ 'name': 'puff_Button', 'string': 'Click to add Puff', 'object': self.puffButton }) self.items.append({ 'name': 'blank', 'string': '---------- RANDOM PUFFS ---------------------------', 'object': None }) #self.items.append({'name': 'nPuffs', 'string': 'Number of puffs to add', 'object': self.nPuffs_slider}) self.items.append({ 'name': 'meanExp', 'string': 'Mean of exponential distibution of puff start times', 'object': self.meanExp_slider }) self.items.append({ 'name': 'puffsSequential', 'string': 'Wait until puff ends before adding next puff:', 'object': self.addPuffsSequentially }) self.items.append({ 'name': 'histoTimes', 'string': 'Plot histogram of puff start times:', 'object': self.plotHistoTimes }) self.items.append({ 'name': 'random_puff_Button', 'string': 'Click to add randomly distibuted puffs at one site', 'object': self.randomPuffButton }) self.items.append({ 'name': 'multipleRandom_puff_Button', 'string': 'Click to add randomly distibuted puffs at multiple sites', 'object': self.multipleRandomPuffButton }) self.items.append({ 'name': 'nSites', 'string': 'Number of Sites to add', 'object': self.nSites_box }) self.items.append({ 'name': 'blank', 'string': '---------- Export Puffs ---------------------------', 'object': None }) self.items.append({ 'name': 'listTimes', 'string': 'Export list of puff start times', 'object': self.exportTimes_button }) super().gui() def __call__(self): pass return def update(self): self.currentWin = self.getValue('active_window') #get image data self.data = np.array(deepcopy(self.currentWin.image)) self.dt, self.dy, self.dx = self.data.shape self.x.setRange(1, self.dx - 1) self.y.setRange(1, self.dy - 1) self.x.setValue(int((self.dx - 1) / 2)) self.y.setValue(int((self.dy - 1) / 2)) self.nFrames.setRange(0, self.dt) self.startFrame.setRange(0, self.dt - 1) self.sigma.setRange(1, int(self.dx / 7)) def addPuff(self, time=False, singleSite=True, x=None, y=None, duration=False): '''add synthetic blip to image stack''' #select window self.currentWin = self.getValue('active_window') if self.currentWin == None: g.alert('First select window') return #generate blip sigma = self.getValue('sigma') amp = self.getValue('puffAmplitude') if self.randomDuration.isChecked(): #get random duration if duration == False: duration = float( np.random.exponential(scale=self.getValue('meanDuration'), size=1)[0]) else: duration = self.getValue('nFrames') #scale puff amplitude to account for durations <1 frame if duration < 1: amp = amp * duration duration = ceil(duration) else: #round duration to nearest integer number of frames duration = ceil(duration) blip = generateBlip(sigma=sigma, amplitude=amp, duration=duration) blip_time, blip_x_size, blip_y_size = blip.shape x_size = int(blip_x_size / 2) y_size = int(blip_y_size / 2) #add blip to stack if time == False: t = self.getValue('startFrame') else: t = time if singleSite: x = self.getValue('x') y = self.getValue('y') tt = np.arange(t, t + duration, dtype=np.int) xx = np.arange(x - x_size - 1, x + x_size, dtype=np.int) yy = np.arange(y - y_size - 1, y + y_size, dtype=np.int) if time == False: try: self.data[np.ix_(tt, xx, yy)] = self.data[np.ix_(tt, xx, yy)] + blip except: g.alert( 'Error - Puff might be too large, too long or too close to edge' ) else: self.data[np.ix_(tt, xx, yy)] = self.data[np.ix_(tt, xx, yy)] + blip frame = self.currentWin.currentIndex self.currentWin.imageview.setImage(self.data) self.currentWin.image = self.data self.currentWin.setIndex(frame) print( 'Puff added at time: {}, x: {}, y: {} with duration: {}, sigma: {}, amplitude:{}' .format(t, x, y, duration, sigma, amp)) return def addRandomPuffs(self, singleSite=True, x=None, y=None): if self.getValue('active_window') == None: g.alert('First select window') return mean = self.getValue('meanExp') #nPuffs = self.getValue('nPuffs') puffsAdded = 0 puffsOutsideOfRange = 0 # add first puff try: if self.randomDuration.isChecked(): startTime = int( np.random.exponential(scale=mean, size=1) + self.getValue('startFrame')) duration = float( np.random.exponential(scale=self.getValue('meanDuration'), size=1)[0]) self.addPuff(time=startTime, singleSite=singleSite, x=x, y=y, duration=duration) else: startTime = int( np.random.exponential(scale=mean, size=1) + self.getValue('startFrame')) duration = self.getValue('nFrames') self.addPuff(time=startTime, singleSite=singleSite, x=x, y=y) if self.getValue('puffsSequential'): endTime = startTime + duration else: endTime = startTime except Exception as e: print(e) puffsOutsideOfRange += 1 print('{} puffs added, {} puffs out of range'.format( puffsAdded, puffsOutsideOfRange)) print('1st puff outside of range, aborting') return # add puff after each time selection untill end of stack # rounding the exponential continous value to an int to select frame while startTime < self.dt - self.getValue('nFrames'): try: startTime = int(endTime + np.random.exponential(scale=mean, size=1)) #if random duration if self.randomDuration.isChecked(): #print('original time: ', startTime) duration = np.random.exponential( scale=self.getValue('meanDuration'), size=1) startTime = startTime + ceil(duration) #print('time: ', startTime) #print('duration: ', duration) #add puff at time self.addPuff(time=startTime, singleSite=singleSite, x=x, y=y, duration=duration) #if sequental, add puff duration to time if self.getValue('puffsSequential'): endTime = startTime + duration else: endTime = startTime #else use duration from GUI else: startTime = startTime + self.getValue('nFrames') duration = self.getValue('nFrames') #add puff at time self.addPuff(time=startTime, singleSite=singleSite, x=x, y=y) #if sequental, add puff duration to time if self.getValue('puffsSequential'): endTime = startTime + duration else: endTime = startTime #update puff time log self.timesAdded = self.timesAdded.append( { 'time of puff': startTime, 'duration': duration, 'site': int(self.siteNumber) }, ignore_index=True) puffsAdded += 1 except: puffsOutsideOfRange += 1 print('{} puffs added, {} puffs out of range'.format( puffsAdded, puffsOutsideOfRange)) if self.plotHistoTimes.isChecked(): plt.hist(self.timesAdded) plt.xlabel('Time puff added (frames)') plt.ylabel('Number of puffs added') plt.show() self.randomPuffsAdded = True if singleSite: self.siteNumber += 1 return def addMultipleRandomPuffs(self): nSites = self.getValue('nSites') if self.currentWin == None: g.alert('First select window') return #select current ROI self.currentROI = self.currentWin.currentROI if self.currentWin.currentROI == None: g.alert('First draw an ROI') return bounds = self.currentROI.parentBounds() topLeft_x = bounds.topLeft().x() topLeft_y = bounds.topLeft().y() bottomRight_x = bounds.bottomRight().x() bottomRight_y = bounds.bottomRight().y() print('adding puffs to {} sites from {},{} to {},{}'.format( nSites, topLeft_x, topLeft_y, bottomRight_x, bottomRight_y)) sites = self.getRandomSites(topLeft_x, bottomRight_x, topLeft_y, bottomRight_y, nSites) for site in sites: print("Puff site: ", self.siteNumber) self.addRandomPuffs(singleSite=False, x=site[0], y=site[1]) self.siteNumber += 1 print('Finished adding sites') return def getRandomSites(self, xStart, xEnd, yStart, yEnd, qty, radius=0): import random rangeX = (xStart, xEnd) rangeY = (yStart, yEnd) deltas = set() for x in range(-radius, radius + 1): for y in range(-radius, radius + 1): if x * x + y * y <= radius * radius: deltas.add((x, y)) randPoints = [] excluded = set() i = 0 while i < qty: x = random.randrange(*rangeX) y = random.randrange(*rangeY) if (x, y) in excluded: continue randPoints.append((x, y)) i += 1 excluded.update((x + dx, y + dy) for (dx, dy) in deltas) return randPoints def exportTimes(self): if self.getValue('active_window') == None: g.alert('First select window') return if self.randomPuffsAdded == False: g.alert('Add puffs first') return #set export path savePath, _ = QFileDialog.getSaveFileName(None, "Save file", "", "Text Files (*.csv)") #write file self.timesAdded.to_csv(savePath) print('List of times saved to: {}'.format(savePath)) # #write file # try: # # opening the csv file in 'w+' mode # file = open(savePath, 'w+', newline ='') # # writing the data into the file # with file: # write = csv.writer(file) # write.writerows(map(lambda x: [x], self.timesAdded)) # print('List of times saved to: {}'.format(savePath)) # except BaseException as e: # print(e) # print('Export of times failed, printing times to console') # print(self.timesAdded) def previewPuff(self): '''preview blip to be added''' sigma = self.getValue('sigma') amp = self.getValue('puffAmplitude') if self.randomDuration.isChecked(): #get random duration duration = np.random.exponential( scale=self.getValue('meanDuration'), size=1) #scale puff amplitude to account for durations <1 frame or spread across 2 frames spread = ceil(duration) if spread < 2: amp = amp * (duration / spread) #round duration to nearest integer number of frames duration = ceil(duration) else: duration = self.getValue('nFrames') blip = generateBlip(sigma=sigma, amplitude=amp, duration=duration) Window(blip) return def generateBlip(sigma=1, amplitude=1, duration=1): sigma = int(sigma) width = sigma * 8 + 1 xorigin = sigma * 4 yorigin = sigma * 4 x = np.arange(width) y = np.arange(width) x = x[:, None] y = y[None, :] gaussian = amplitude * (np.exp(-(x - xorigin)**2 / (2. * sigma**2)) * np.exp(-(y - yorigin)**2 / (2. * sigma**2))) blip = np.repeat(gaussian[None, :, :], repeats=duration, axis=0) return blip
class Light_Sheet_Analyzer(BaseProcess): """ light_Sheet_Analyzer(nSteps, shift_factor, triangle_scan, interpolate, trim_last_frame, keepSourceWindow=False) Makes a 3D viewer for data acquired using a light sheet microscope. Parameters: | nSteps (int) -- How many stacks per volume | shift_factor (int) -- How many pixels (measured along the width of the light sheet) the sample moves per frame | triangle_scan (bool) -- If the scan moves back and forth this is true. If the scan moves like a typewriter, this is false. | interpolate (bool) -- This will upsample the data before the transformation to prevent information loss, but is slow | trim_last_frame (bool) -- This removes the last frame of each volume. Returns: Volume_Viewer """ def __init__(self): if g.settings[ 'light_sheet_analyzer'] is None or 'trim_last_frame' not in g.settings[ 'light_sheet_analyzer']: s = dict() s['nSteps'] = 1 s['shift_factor'] = 1 s['triangle_scan'] = False s['interpolate'] = False s['trim_last_frame'] = False g.settings['light_sheet_analyzer'] = s super().__init__() def __call__(self, nSteps, shift_factor, triangle_scan, interpolate, trim_last_frame, keepSourceWindow=False): g.settings['light_sheet_analyzer']['nSteps'] = nSteps g.settings['light_sheet_analyzer']['shift_factor'] = shift_factor g.settings['light_sheet_analyzer']['triangle_scan'] = triangle_scan g.settings['light_sheet_analyzer']['interpolate'] = interpolate g.settings['light_sheet_analyzer']['trim_last_frame'] = trim_last_frame g.m.statusBar().showMessage("Generating 4D movie ...") t = time() self.start(keepSourceWindow) A = np.copy(self.tif) # A = A[1:] # Ian Parker said to hard code removal of the first frame. mt, mx, my = A.shape if triangle_scan: for i in np.arange(mt // (nSteps * 2)): t0 = i * nSteps * 2 + nSteps tf = (i + 1) * nSteps * 2 A[t0:tf] = A[tf:t0:-1] mv = mt // nSteps # number of volumes A = A[:mv * nSteps] B = np.reshape(A, (mv, nSteps, mx, my)) if trim_last_frame: B = B[:, :-1, :, :] #D = perform_shear_transform_old(B, shift_factor, interpolate, A.dtype) D = perform_shear_transform(B, shift_factor, interpolate, A.dtype) g.m.statusBar().showMessage( "Successfully generated movie ({} s)".format(time() - t)) w = Window(np.squeeze(D[:, 0, :, :]), name=self.oldname) w.volume = D Volume_Viewer(w) return def closeEvent(self, event): self.ui.close() event.accept() def gui(self): s = g.settings['light_sheet_analyzer'] self.gui_reset() self.nSteps = pg.SpinBox(int=True, step=1) self.nSteps.setMinimum(1) self.nSteps.setValue(s['nSteps']) self.shift_factor = pg.SpinBox(int=False, step=.1) self.shift_factor.setValue(s['shift_factor']) self.triangle_scan = CheckBox() self.triangle_scan.setValue(s['triangle_scan']) self.interpolate = CheckBox() self.interpolate.setValue(s['interpolate']) self.trim_last_frame = CheckBox() self.trim_last_frame.setValue(s['trim_last_frame']) self.items.append({ 'name': 'nSteps', 'string': 'Number of steps per volume', 'object': self.nSteps }) self.items.append({ 'name': 'shift_factor', 'string': 'Shift Factor', 'object': self.shift_factor }) self.items.append({ 'name': 'triangle_scan', 'string': 'Trangle Scan', 'object': self.triangle_scan }) self.items.append({ 'name': 'interpolate', 'string': 'Interpolate', 'object': self.interpolate }) self.items.append({ 'name': 'trim_last_frame', 'string': 'Trim Last Frame', 'object': self.trim_last_frame }) super().gui()
class VolumeSliderBase(BaseProcess_noPriorWindow): """ Start Volume Slider from differnt sources |Select source (current window or saved numpy array) Returns volumeSlider GUI """ def __init__(self): if g.settings['volumeSlider'] is None or 'overlay' not in g.settings[ 'volumeSlider']: s = dict() s['inputChoice'] = 'Current Window' s['keepOriginalWindow'] = False s['slicesPerVolume'] = 1 s['slicesDeletedPerVolume'] = 0 s['slicesDeletedPerMovie'] = 0 s['baselineValue'] = 0 s['f0Start'] = 0 s['f0End'] = 0 s['multiplicationFactor'] = 100 s['currentDataType'] = 0 s['newDataType'] = 0 s['theta'] = 45 s['shiftFactor'] = 1 s['trimLastFrame'] = False s['inputArrayOrder'] = 4 s['displayArrayOrder'] = 16 s['f0VolStart'] = 0 s['f0VolEnd'] = 0 s['IMS_fname'] = 'IMS_export.ims' s['IMS_subsamp'] = '((1, 1, 1), (1, 2, 2))' s['IMS_chunks'] = '((16, 128, 128), (64, 64, 64))' s['IMS_compression'] = 'gzip' s['IMS_thumbsize'] = '256' s['IMS_dx'] = 0.1 s['IMS_dz'] = 0.25 s['IMS_Unit'] = 'um' s['IMS_GammaCorrection'] = 1 s['IMS_ColorRange'] = '0 255' s['IMS_LSMEmissionWavelength'] = 0 s['IMS_LSMExcitationWavelength'] = 0 s['preProcess'] = False s['overlayStart'] = 1 s['overlay'] = False g.settings['volumeSlider'] = s BaseProcess_noPriorWindow.__init__(self) def __call__(self, inputChoice, keepOriginalWindow, preProcess, slicesPerVolume, slicesDeletedPerVolume, slicesDeletedPerMovie, overlay, overlayStart, keepSourceWindow=False): g.settings['volumeSlider']['inputChoice'] = inputChoice g.settings['volumeSlider']['keepOriginalWindow'] = keepOriginalWindow g.settings['volumeSlider']['preProcess'] = preProcess g.settings['volumeSlider']['slicesPerVolume'] = slicesPerVolume g.settings['volumeSlider'][ 'slicesDeletedPerVolume'] = slicesDeletedPerVolume g.settings['volumeSlider'][ 'slicesDeletedPerMovie'] = slicesDeletedPerMovie g.settings['volumeSlider']['overlay'] = overlay g.settings['volumeSlider']['overlayStart'] = overlayStart g.m.statusBar().showMessage("Starting Volume Slider...") if inputChoice == 'Current Window': windowName = g.win.filename #Get overlay if overlay: A = np.array(deepcopy(g.win.image)) print(A.shape) endFrame = g.win.mt - 1 g.win.close() #overlayWin = Window(A[overlayStart:endFrame,:,:],'Overlay') dataWin = Window(A[0:overlayStart, :, :], 'Overlay') #Trim movie if preProcess and slicesDeletedPerMovie != 0: trim(0, slicesDeletedPerMovie, delete=True) camVolumeSlider.setFileName(windowName) #start volumeSlider if overlay: camVolumeSlider.startVolumeSlider( keepWindow=keepOriginalWindow, preProcess=preProcess, framesPerVol=slicesPerVolume, framesToDelete=slicesDeletedPerVolume, overlayEmbeded=True, A_overlay=A[overlayStart:endFrame, :, :]) else: camVolumeSlider.startVolumeSlider( keepWindow=keepOriginalWindow, preProcess=preProcess, framesPerVol=slicesPerVolume, framesToDelete=slicesDeletedPerVolume) #print('loading:',windowName) elif inputChoice == 'Numpy Array': A_path = open_file_gui(directory=os.path.expanduser("~/Desktop"), filetypes='*.npy') g.m.statusBar().showMessage("Importing Array: " + A_path) A = np.load(str(A_path)) camVolumeSlider.setFileName(A_path) camVolumeSlider.startVolumeSlider(A=A, keepWindow=keepOriginalWindow) elif inputChoice == 'Batch Process': g.m.statusBar().showMessage("Starting Batch Processing...") camVolumeSlider.startVolumeSlider(batch=True) elif inputChoice == 'Load file': g.m.statusBar().showMessage("Loading file...") #Open file using tiff loader load_tiff.gui() #Get overlay if overlay: A = np.array(deepcopy(g.win.image)) print(A.shape) endFrame = g.win.mt - 1 g.win.close() #overlayWin = Window(A[overlayStart:endFrame,:,:],'Overlay') dataWin = Window(A[0:overlayStart, :, :], 'Overlay') #Trim movie if preProcess and slicesDeletedPerMovie != 0: trim(0, slicesDeletedPerMovie, delete=True) #start volumeSlider camVolumeSlider.setFileName(load_tiff.getFileName()) if overlay: camVolumeSlider.startVolumeSlider( keepWindow=keepOriginalWindow, preProcess=preProcess, framesPerVol=slicesPerVolume, framesToDelete=slicesDeletedPerVolume, overlayEmbeded=True, A_overlay=A[overlayStart:endFrame, :, :]) else: camVolumeSlider.startVolumeSlider( keepWindow=keepOriginalWindow, preProcess=preProcess, framesPerVol=slicesPerVolume, framesToDelete=slicesDeletedPerVolume) return def closeEvent(self, event): BaseProcess_noPriorWindow.closeEvent(self, event) def gui(self): self.gui_reset() #combobox inputChoice = ComboBox() inputChoice.addItem('Current Window') inputChoice.addItem('Load file') inputChoice.addItem('Numpy Array') inputChoice.addItem('Batch Process') #checkbox self.keepOriginalWindow = CheckBox() self.keepOriginalWindow.setValue(False) self.preProcess = CheckBox() self.preProcess.setValue(g.settings['volumeSlider']['preProcess']) self.framesPerVolume = pg.SpinBox(int=True, step=1) self.framesPerVolume.setValue( g.settings['volumeSlider']['slicesPerVolume']) self.framesRemoved = pg.SpinBox(int=True, step=1) self.framesRemoved.setValue( g.settings['volumeSlider']['slicesDeletedPerVolume']) self.framesRemovedStart = pg.SpinBox(int=True, step=1) self.framesRemovedStart.setValue( g.settings['volumeSlider']['slicesDeletedPerMovie']) self.overlay = CheckBox() self.overlay.setValue(g.settings['volumeSlider']['overlay']) self.overlayStart = pg.SpinBox(int=True, step=1) self.overlayStart.setValue(g.settings['volumeSlider']['overlayStart']) #populate GUI self.items.append({ 'name': 'inputChoice', 'string': 'Choose Input Data:', 'object': inputChoice }) self.items.append({ 'name': 'keepOriginalWindow', 'string': 'Keep Original Window', 'object': self.keepOriginalWindow }) self.items.append({ 'name': 'spacer', 'string': '------------ Preprocessing Options --------------', 'object': None }) self.items.append({ 'name': 'preProcess', 'string': 'Preprocess Image Stack', 'object': self.preProcess }) self.items.append({ 'name': 'slicesPerVolume', 'string': 'Slices per Volume', 'object': self.framesPerVolume }) self.items.append({ 'name': 'slicesDeletedPerVolume', 'string': 'Frames to Remove per Volume', 'object': self.framesRemoved }) self.items.append({ 'name': 'slicesDeletedPerMovie', 'string': 'Frames to Remove From Start of Stack', 'object': self.framesRemovedStart }) self.items.append({ 'name': 'spacer', 'string': '------------ Overlay Options --------------', 'object': None }) self.items.append({ 'name': 'overlay', 'string': 'Overlay Image in Stack', 'object': self.overlay }) self.items.append({ 'name': 'overlayStart', 'string': '1st Frame of Overlay', 'object': self.overlayStart }) super().gui()
class VolumeSliderBase(BaseProcess_noPriorWindow): """ Start Volume Slider from differnt sources |Select source (current window or saved numpy array) Returns volumeSlider GUI """ def __init__(self): if g.settings['volumeSlider'] is None or 'UPDATE' not in g.settings[ 'volumeSlider']: s = dict() s['inputChoice'] = 'Current Window' s['keepOriginalWindow'] = False s['slicesPerVolume'] = 1 s['baselineValue'] = 0 s['f0Start'] = 0 s['f0End'] = 0 s['multiplicationFactor'] = 100 s['currentDataType'] = 0 s['newDataType'] = 0 s['theta'] = 45 s['shiftFactor'] = 1 s['trimLastFrame'] = False s['inputArrayOrder'] = 4 s['displayArrayOrder'] = 16 s['f0VolStart'] = 0 s['f0VolEnd'] = 0 s['IMS_fname'] = 'IMS_export.ims' s['IMS_subsamp'] = '((1, 1, 1), (1, 2, 2))' s['IMS_chunks'] = '((16, 128, 128), (64, 64, 64))' s['IMS_compression'] = 'gzip' s['IMS_thumbsize'] = '256' s['IMS_dx'] = 0.1 s['IMS_dz'] = 0.25 s['IMS_Unit'] = 'um' s['IMS_GammaCorrection'] = 1 s['IMS_ColorRange'] = '0 255' s['IMS_LSMEmissionWavelength'] = 0 s['IMS_LSMExcitationWavelength'] = 0 g.settings['volumeSlider'] = s BaseProcess_noPriorWindow.__init__(self) def __call__(self, inputChoice, keepOriginalWindow, keepSourceWindow=False): g.settings['volumeSlider']['inputChoice'] = inputChoice g.settings['volumeSlider']['keepOriginalWindow'] = keepOriginalWindow g.m.statusBar().showMessage("Starting Volume Slider...") if inputChoice == 'Current Window': camVolumeSlider.startVolumeSlider(keepWindow=keepOriginalWindow) elif inputChoice == 'Numpy Array': A_path = open_file_gui(directory=os.path.expanduser("~/Desktop"), filetypes='*.npy') g.m.statusBar().showMessage("Importing Array: " + A_path) A = np.load(str(A_path)) camVolumeSlider.startVolumeSlider(A=A, keepWindow=keepOriginalWindow) elif inputChoice == 'Batch Process': g.m.statusBar().showMessage("Starting Batch Processing...") camVolumeSlider.startVolumeSlider(batch=True) return def closeEvent(self, event): BaseProcess_noPriorWindow.closeEvent(self, event) def gui(self): self.gui_reset() #combobox inputChoice = ComboBox() inputChoice.addItem('Current Window') inputChoice.addItem('Numpy Array') inputChoice.addItem('Batch Process') #checkbox self.keepOriginalWindow = CheckBox() self.keepOriginalWindow.setValue(False) #populate GUI self.items.append({ 'name': 'inputChoice', 'string': 'Choose Input Data:', 'object': inputChoice }) self.items.append({ 'name': 'keepOriginalWindow', 'string': 'Keep Original Window', 'object': self.keepOriginalWindow }) super().gui()
class Flash_remover(BaseProcess_noPriorWindow): """ Remove flash artifact from movies. """ def __init__(self): if g.settings[ 'flash_remover'] is None or 'windowSize' not in g.settings[ 'flash_remover']: s = dict() s['flashRangeStart'] = 0 s['flashRangeEnd'] = 1000 s['windowSize'] = 100 g.settings['flash_remover'] = s super().__init__() def __call__(self, keepSourceWindow=False): g.settings['flash_remover']['flashRangeStart'] = self.getValue( 'flashRangeStart') g.settings['flash_remover']['flashRangeEnd'] = self.getValue( 'flashRangeEnd') g.settings['flash_remover']['windowSize'] = self.getValue('windowSize') return def removeFlash(self): method = self.getValue('method') if method == 1: #interpolation method print('linear interpolation') self.removeFlash_interpolate() elif method == 2: #subtraction method print('scale using noise') self.removeFlash_noiseScaling() else: print('no method') return def autodetectFlash(self): rangeStart = self.getValue('flashRangeStart') rangeEnd = self.getValue('flashRangeEnd') windowSize = self.getValue('windowSize') showAverage = self.getValue('showAverage') useROI = self.getValue('useROI') #get data window dataWindow = self.getValue('window') #get image array A = dataWindow.image #get array shape frames, height, width = A.shape #plot roi in center if useROI: if dataWindow.currentROI == None: print('No ROI detected: generating center ROI') centerROI = makeROI('rectangle', [[10, 10], [height - 20, width - 20]], window=dataWindow) else: centerROI = dataWindow.currentROI else: centerROI = makeROI('rectangle', [[10, 10], [height - 20, width - 20]], window=dataWindow) #plot roi average trace if showAverage: plot = centerROI.plot() #get trace data trace = centerROI.getTrace() #define function to get moving average from trace def moving_average(x, n=windowSize): return np.convolve(x, np.ones((n, )) / n, mode='valid') #get trace moving average movingAverage = moving_average(trace, n=windowSize) #set moving average values <= 0 to 0.0000001 movingAverage[movingAverage <= 0] = 0.0000001 #add moving average trace to plot if showAverage: plot.p1.plot(movingAverage, pen=(1, 3), symbol=None) #identify peak of trace - first frame of flash flashStart = rangeStart + np.argmax(movingAverage[rangeStart:rangeEnd]) #identify 1st drop after peak - end of flash flashEnd = flashStart + np.argmin(movingAverage[flashStart:rangeEnd]) #plot flash start and end if showAverage: plot.p1.plot(np.array([flashStart]), np.array([movingAverage[flashStart]]), pen=None, symbol='o', symbolSize=20) plot.p1.plot(np.array([flashEnd]), np.array([movingAverage[flashEnd]]), pen=None, symbol='o', symbolSize=20) #remove center ROI if showAverage == False: centerROI.delete() return flashStart, flashEnd def removeFlash_noiseScaling(self): #print('Not implemented') #return img = deepcopy(self.getValue('window').image) if self.getValue('manualFlash'): #manual flashStart = self.getValue('flashStart') flashEnd = self.getValue('flashEnd') else: #autodetect flashStart, flashEnd = self.autodetectFlash() #buffer flash time ends flashStart = flashStart - 1 flashEnd = flashEnd + 2 flash = img[flashStart:flashEnd] #TODO #get baseline from 100 frames before flash baseline = np.mean(img[flashStart - 102:flashStart - 2], axis=0) #self.baseline_win = Window(baseline,'baseline') #determine noise of baseline baseNoise = np.std(img[flashStart - 102:flashStart - 2]) print('baseNoise: ', baseNoise) #get mean inital flash increase flashIncrease = np.mean(flash[2:12], axis=0) - baseline #self.flashIncrease_win = Window(flashIncrease,'flashIncrease') #get noise of flash flashNoise = np.std(flash[2:12]) print('flashNoise: ', flashNoise) #flashNoise:baseNoise ratio noiseRatio = flashNoise / baseNoise #subtract flashIncrease from img #flashReplace = flash - flashIncrease #self.flashReplace_win = Window(flashReplace,'flashReplace') #scaled reduction of flash flashReplace = np.divide(img[flashStart + 1:flashEnd - 1], noiseRatio) #self.flashReplace_win = Window(flashReplace,'flashReplace') img[flashStart + 1:flashEnd - 1] = flashReplace #display stack in new window self.flashRemoved_win = Window(img, 'Flash Removed (noise scaling)') return def removeFlash_interpolate(self): img = deepcopy(self.getValue('window').image) if self.getValue('manualFlash'): #manual flashStart = self.getValue('flashStart') flashEnd = self.getValue('flashEnd') else: #autodetect flashStart, flashEnd = self.autodetectFlash() #buffer flash time ends flashStart = flashStart - 1 flashEnd = flashEnd + 2 flash = img[flashStart:flashEnd] n, r, c = flash.shape flashReplace = np.zeros_like(flash) # update each pixel in image with interpolated values for row in range(r): for col in range(c): points = range(0, n) xp = [0, n] fp = [flash[0, row, col], flash[-1, row, col]] interp_data = np.interp(points, xp, fp) flashReplace[0:n, row, col] = interp_data #add noise if self.getValue('addNoise'): flashLength = flashEnd - flashStart if flashStart - flashLength < 0: print('Not enough trace to sample before flash to get noise') noise = np.zeros_like(flash) else: noise = self.generateNoise(flashStart - flashLength, flashStart) else: noise = np.zeros_like(flash) img[flashStart:flashEnd] = (flashReplace + (noise - np.mean(noise, axis=0))) #display stack in new window self.flashRemoved_win = Window(img, 'Flash Removed (linear interpolation)') return def generateNoise(self, start, end): img = deepcopy(self.getValue('window').image) beforeFlashImg = img[start:end] #TODO - change TOO SLOW # #simulating noise # n, r, c = beforeFlashImg.shape # randomImg = np.zeros_like(beforeFlashImg) # print('Generating Noise') # for row in tqdm(range(r)): # for col in range(c): # for pixel in range(n): # minVal = min(beforeFlashImg[0:n,row,col]) # maxVal = max(beforeFlashImg[0:n,row,col]) # randomNoise = np.random.randint(minVal,maxVal) # randomImg[pixel,row,col] = randomNoise #return randomImg #for now returning stack before flash as noise substitue return beforeFlashImg def gui(self): s = g.settings['flash_remover'] self.gui_reset() self.window = WindowSelector() self.removeFlash_button = QPushButton('Remove Flash') self.removeFlash_button.pressed.connect(self.removeFlash) self.manuallySetFlash_check = CheckBox() self.manuallySetFlash_check.setValue(False) self.addNoise_check = CheckBox() self.addNoise_check.setValue(True) self.flashStart_slider = pg.SpinBox(int=True, step=1) self.flashStart_slider.setValue(0) self.flashEnd_slider = pg.SpinBox(int=True, step=1) self.flashEnd_slider.setValue(1) self.flashRangeStart_slider = pg.SpinBox(int=True, step=1) self.flashRangeStart_slider.setValue(s['flashRangeStart']) self.flashRangeEnd_slider = pg.SpinBox(int=True, step=1) self.flashRangeEnd_slider.setValue(s['flashRangeEnd']) self.removeMethod = pg.ComboBox() self.methods = {'linear interpolation': 1, 'scaling by noise': 2} self.removeMethod.setItems(self.methods) self.movingAverageWindow_slider = pg.SpinBox(int=True, step=1) self.movingAverageWindow_slider.setValue(s['windowSize']) self.plotAverage_check = CheckBox() self.plotAverage_check.setValue(False) self.useROI_check = CheckBox() self.useROI_check.setValue(False) self.items.append({ 'name': 'window', 'string': 'Select Window', 'object': self.window }) self.items.append({ 'name': 'method', 'string': 'Select Method', 'object': self.removeMethod }) self.items.append({ 'name': 'addNoise', 'string': 'Add noise (linear interpolation only)', 'object': self.addNoise_check }) self.items.append({ 'name': 'blank', 'string': '----- Manual Flash -----', 'object': None }) self.items.append({ 'name': 'manualFlash', 'string': 'Manualy Set Flash', 'object': self.manuallySetFlash_check }) self.items.append({ 'name': 'flashStart', 'string': 'Select Flash Start', 'object': self.flashStart_slider }) self.items.append({ 'name': 'flashEnd', 'string': 'Select Flash End', 'object': self.flashEnd_slider }) self.items.append({ 'name': 'blank', 'string': '----- Automatic Flash Detection -----', 'object': None }) self.items.append({ 'name': 'flashRangeStart', 'string': 'Select Flash Range Start', 'object': self.flashRangeStart_slider }) self.items.append({ 'name': 'flashRangeEnd', 'string': 'Select Flash Range End', 'object': self.flashRangeEnd_slider }) self.items.append({ 'name': 'windowSize', 'string': 'Select Moving Average Window Size', 'object': self.movingAverageWindow_slider }) self.items.append({ 'name': 'useROI', 'string': 'User defined ROI for average', 'object': self.useROI_check }) self.items.append({ 'name': 'showAverage', 'string': 'Plot flash detection result', 'object': self.plotAverage_check }) self.items.append({ 'name': 'removeFlash_button', 'string': '', 'object': self.removeFlash_button }) super().gui()