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()
Esempio n. 2
0
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()
Esempio n. 5
0
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()
Esempio n. 7
0
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()
Esempio n. 9
0
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()