Skip to content
Snippets Groups Projects
GUI_main.py 63.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • lpbsscientist's avatar
    lpbsscientist committed
            if self.button_nextframe.isEnabled():
                self.button_nextframe.setEnabled(False)
                self.ForwardTime()
    
    lpbsscientist's avatar
    lpbsscientist committed
                if self.Tindex + 1 < self.reader.sizet:
                    self.button_nextframe.setEnabled(True)
    
    lpbsscientist's avatar
    lpbsscientist committed
            else:
                return
    
    
    lpbsscientist's avatar
    lpbsscientist committed
        def ForwardTime(self):
            """This function switches the frame in forward time index. And it tests
            several conditions if t == lastTimeIndex-1, because then the next frame
            button has to be disabled. It also tests if the show value of cells
    
            button and hidemask are active in order to hide/show the mask or to 
    
    lpbsscientist's avatar
    lpbsscientist committed
            show the cell values.
            """
    
            # the t frame is defined as the currently shown frame on the display.
            # If the button "Next time frame" is pressed, this function is called
    
            self.WriteStatusBar('Loading the next frame...')
    
    lpbsscientist's avatar
    lpbsscientist committed
            self.Disable(self.button_nextframe)
    
            if self.Tindex + 1 < self.reader.sizet - 1 :
    
                self.reader.SaveMask(self.Tindex, self.FOVindex, self.m.plotmask)
                
                self.m.prevpicture = self.m.currpicture.copy()
                self.m.prevplotmask = self.m.plotmask.copy()
                
                self.m.currpicture = self.m.nextpicture.copy()
                self.m.plotmask = self.m.nextplotmask.copy()
                
                self.m.nextpicture = self.reader.LoadOneImage(self.Tindex+2, self.FOVindex)
                self.m.nextplotmask = self.reader.LoadMask(self.Tindex+2, self.FOVindex)
    
                self.m.UpdatePlots()
    
                if self.Tindex + 1 == 1:
                    self.button_previousframe.setEnabled(True)
                    
    
    lpbsscientist's avatar
    lpbsscientist committed
            else:
    
                self.reader.SaveMask(self.Tindex, self.FOVindex, self.m.plotmask)
            
                self.m.prevpicture = self.m.currpicture.copy()
                self.m.prevplotmask = self.m.plotmask.copy()
                self.m.currpicture = self.m.nextpicture.copy()
                self.m.plotmask = self.m.nextplotmask.copy()
    
                self.m.nextpicture = np.zeros([self.reader.sizey, self.reader.sizex], 
                                              dtype = np.uint16)
                self.m.nextplotmask = np.zeros([self.reader.sizey,self.reader.sizex], 
                                               dtype = np.uint16)
                self.m.UpdatePlots()
    
                self.button_nextframe.setEnabled(False)
    
    lpbsscientist's avatar
    lpbsscientist committed
    
            self.Tindex = self.Tindex+1
            self.UpdateTitleSubplots()
    
    lpbsscientist's avatar
    lpbsscientist committed
            if self.button_hidemask.isChecked():
                self.m.HideMask()
    
            self.Enable(self.button_nextframe)
    
            self.ClearStatusBar()
    
    lpbsscientist's avatar
    lpbsscientist committed
            self.button_timeindex.setText(str(self.Tindex)+'/'+str(self.reader.sizet-1))
    
    lpbsscientist's avatar
    lpbsscientist committed
        def BackwardTime(self):
    
            """This function switches the frame in backward time index. And it 
    
    lpbsscientist's avatar
    lpbsscientist committed
            several conditions if t == 1, because then the button previous frame has to
    
            be disabled. It also tests if the show value of cells button and 
    
    lpbsscientist's avatar
    lpbsscientist committed
            hidemask are active in order to hide/show the mask or to show the cell
            values.
            """
    
            # the t frame is defined as the currently shown frame on the display.
            # If the button "Previous time frame" is pressed, this function is called
    
            self.WriteStatusBar('Loading the previous frame...')
    
    lpbsscientist's avatar
    lpbsscientist committed
            self.Disable(self.button_previousframe)
    
            
            self.reader.SaveMask(self.Tindex, self.FOVindex, self.m.plotmask)
    
            self.m.nextpicture = self.m.currpicture.copy()
            self.m.nextplotmask = self.m.plotmask.copy()
            self.m.currpicture = self.m.prevpicture.copy()
            self.m.plotmask = self.m.prevplotmask.copy()
    
            if self.Tindex == 1:
    
    lpbsscientist's avatar
    lpbsscientist committed
                self.m.prevpicture = np.zeros([self.reader.sizey, self.reader.sizex], dtype = np.uint16)
                self.m.prevplotmask = np.zeros([self.reader.sizey, self.reader.sizex], dtype = np.uint16)
                self.button_previousframe.setEnabled(False)
    
    lpbsscientist's avatar
    lpbsscientist committed
            else:
                self.m.prevpicture = self.reader.LoadOneImage(self.Tindex-2, self.FOVindex)
                self.m.prevplotmask = self.reader.LoadMask(self.Tindex-2, self.FOVindex)
    
            self.m.UpdatePlots()
    
            if self.Tindex-1 == self.reader.sizet-2:
                self.button_nextframe.setEnabled(True)            
            
    
    lpbsscientist's avatar
    lpbsscientist committed
            if self.button_hidemask.isChecked():
                self.m.HideMask()
    
            
            self.Tindex -= 1
            self.UpdateTitleSubplots()
    
    lpbsscientist's avatar
    lpbsscientist committed
            self.Enable(self.button_previousframe)
    
    lpbsscientist's avatar
    lpbsscientist committed
            if self.Tindex > 0:
    
                self.button_previousframe.setEnabled(True)          
                
    
            self.ClearStatusBar()
    
    lpbsscientist's avatar
    lpbsscientist committed
            self.button_timeindex.setText(str(self.Tindex)+'/' + str(self.reader.sizet-1))
    
    
    # -----------------------------------------------------------------------------
    # MANUAL MASK CORRECTIONS
                
        def ChangeOneValue(self):
            """This function is called when the button Change cell value is
            clicked. It displays the instructions on the status bar.
            And if the user clicks in the graph where the current mask is displayed
            it connects the event of the click (meaning that user has clicked on
            one cell) to the function self.DialogBoxChangeOneValue. 
            This function will then replaces the cell selected by the user with
            the click with a new value entered by the user.
            """
            
            # displaying the instructions on the statusbar
    
            self.WriteStatusBar((
    
                'Left-click to select cell, right-click to abort.'))
    
    
            # disables all the buttons
            self.Disable(self.button_changecellvalue)
            
            # connects the event "press mouse button" in the matplotlib plot 
            # (picture) to the function self.DialogBoxChangeOneValue
            self.id = self.m.mpl_connect('button_press_event', self.DialogBoxChangeOneValue)
            
    
        def DialogBoxChangeOneValue(self, event):
            """This function is called when the user after the user has selected
            the button Change cell value and clicked in the picture to select
            the desired cell to change.
            
            It first deconnects the mouse click event in matplotlib with this 
            function to not generate any other dialog window.
            
            It then tests if the click is inside the matplotlib plot (if it is
            outside it equals to None) and if it is the current and editable plot
            (the one in the middle of the gui, self.m.ax)
            
            If is true, then it sets the coordinates to int. and creates a dialog
            window where the user is asked to type a value to set it to the cell.
            
            If the user presses ok, it tests if the entry is valid (>0 and not 
            empty) and looks for the old cell value and replaces it. And then
            it updates the plot such that the result of the change can be seen.
            """
            # the function is disconnected from the matplotlib event.
            self.m.mpl_disconnect(self.id)
            
            # test if the button is a left click and if the coordinates
            # chosen by the user click is inside of the current matplotlib plot
            # which is given by self.m.ax
    
            if (event.button == 1 
                and (event.xdata != None and event.ydata != None) 
                and self.m.ax == event.inaxes):
    
                newx = int(event.xdata)
                newy = int(event.ydata)
                
                # creates a dialog window
                dlg = cocv.CustomDialog(self)
                
                #if the user presses 'ok' in the dialog window it executes the code
                #else it does nothing
                if dlg.exec_():
                    #it tests that the user has entered some value, that it is not
                    #empty and that it is equal or bigger to 0.
                    if dlg.entry1.text() != '' and int(dlg.entry1.text()) >= 0:
                        #reads the new value to set and converts it from str to int
                        value = int(dlg.entry1.text())
                        
                        # gives the coordinates where it is equal to the value
                        # selected by the user. And it replaces it with the new
                        # value.
                        self.m.plotmask[self.m.plotmask == self.m.plotmask[newy,newx]] = value
                        
                        # updates the plot to see the modification.
                        self.m.updatedata()
                        
            self.Enable(self.button_changecellvalue)
            self.button_changecellvalue.setChecked(False)
    
            self.m.ShowCellNumbers()
    
            
            
        def DialogBoxECV(self, s):
            """This functions creates from the ExchangeCellValues.py file a 
            window which takes two integer entries and then swaps the cells having
            the given integer values.
            """
            # creates a dialog window from the ExchangeCellValues.py file
            dlg = ecv.CustomDialog(self)
            
            # if the user presses 'ok', it executes the code
            if dlg.exec_():
    
                # it tests if both value to be swapped are not empty.
                if dlg.entry1.text()!= '' and dlg.entry2.text() != '':
                    
                    # reads out the values and converts it into integers.
                    value1 = int(dlg.entry1.text())
                    value2 = int(dlg.entry2.text())
                    
                    # calls the function which does the swap
    
                    try:
                        self.m.ExchangeCellValue(value1,value2)
                    except ValueError as e:
                        QMessageBox.critical(self, 'Error', str(e))
    
                    self.m.ShowCellNumbers()
    
    lpbsscientist's avatar
    lpbsscientist committed
            """
            This function is called whenever the brush or the eraser button is
            pressed. On the first press event it calls the self.m.OneClick, which
            tests whether it is a right click or a left click. If it a right click
            it assigns the value of the pixel which has been right clicked
            to self.cellval, meaning that the next drawn pixels will be set to this
            value.
            If it is left clicked, then it draws a 3x3 square with the current
            value of self.cellval.
    
            If after left clicking you drag the mouse, then you start drawing 
    
    lpbsscientist's avatar
    lpbsscientist committed
            using the mouse and it stops once you release the left click.
    
    lpbsscientist's avatar
    lpbsscientist committed
            Same for the eraser button, it sets directly the value of self.cellval
            to 0.
            """
    
    mattminder's avatar
    mattminder committed
            do_draw = self.button_drawmouse.isChecked()
            do_erase = self.button_eraser.isChecked()
    
    mattminder's avatar
    mattminder committed
            if do_draw or do_erase:
    
    lpbsscientist's avatar
    lpbsscientist committed
                self.m.tempmask = self.m.plotmask.copy()
    
    mattminder's avatar
    mattminder committed
                if do_draw:
                    self.WriteStatusBar(('Draw using the brush, right click to select '
                                         'the cell to draw.'))
                    self.Disable(self.button_drawmouse)
                    pixmap = QtGui.QPixmap('./icons/brush2.png')
                    
                elif do_erase:
                    self.WriteStatusBar('Erasing by setting the values to 0.')
                    self.Disable(self.button_eraser)
                    pixmap = QtGui.QPixmap('./icons/eraser.png')
                    self.m.cellval = 0
    
    mattminder's avatar
    mattminder committed
                radius = self.spinbox_brushsize.value()
                self.id2 = self.m.mpl_connect('button_press_event', 
                                              lambda e: self.m.OneClick(e, radius))
                self.id = self.m.mpl_connect('motion_notify_event', 
                                             lambda e: self.m.PaintBrush(e, radius))
                self.id3 = self.m.mpl_connect('button_release_event', self.m.ReleaseClick)
                    
                cursor = QtGui.QCursor(pixmap, 0,9)
    
    lpbsscientist's avatar
    lpbsscientist committed
                QApplication.setOverrideCursor(cursor)
    
    mattminder's avatar
    mattminder committed
                            
    
    lpbsscientist's avatar
    lpbsscientist committed
            else:
                self.m.mpl_disconnect(self.id3)
                self.m.mpl_disconnect(self.id2)
                self.m.mpl_disconnect(self.id)
                QApplication.restoreOverrideCursor()
                self.Enable(self.button_drawmouse)
                self.Enable(self.button_eraser)
    
                self.ClearStatusBar()
    
    lpbsscientist's avatar
    lpbsscientist committed
        def UpdateTitleSubplots(self):
    
            """This function updates the title of the plots according to the 
    
    lpbsscientist's avatar
    lpbsscientist committed
            current time index. So it called whenever a frame or a fov is changed.
            """
            if self.Tindex == 0:
                self.m.titlecurr.set_text('Time index {}'.format(self.Tindex))
                self.m.titleprev.set_text('No frame {}'.format(''))
    
    lpbsscientist's avatar
    lpbsscientist committed
                self.m.titlenext.set_text('Next time index {}'.format(self.Tindex+1))
    
    lpbsscientist's avatar
    lpbsscientist committed
                self.m.draw()
    
            elif self.Tindex == self.reader.sizet-1:
    
    lpbsscientist's avatar
    lpbsscientist committed
                self.m.titlecurr.set_text('Time index {}'.format(self.Tindex))
                self.m.titleprev.set_text('Previous time index {}'.format(self.Tindex-1))
    
                self.m.titlenext.set_text('No frame {}'.format(''))            
    
    lpbsscientist's avatar
    lpbsscientist committed
                self.m.draw()
    
    lpbsscientist's avatar
    lpbsscientist committed
            else:
                self.m.titlecurr.set_text('Time index {}'.format(self.Tindex))
                self.m.titleprev.set_text('Previous time index {}'.format(self.Tindex-1))
    
    lpbsscientist's avatar
    lpbsscientist committed
                self.m.titlenext.set_text('Next time index {}'.format(self.Tindex+1))
    
    lpbsscientist's avatar
    lpbsscientist committed
                self.m.draw()
    
    lpbsscientist's avatar
    lpbsscientist committed
        def ClickNewCell(self):
    
    lpbsscientist's avatar
    lpbsscientist committed
            this method is called when the button New Cell is clicked. If the button
    
            state corresponds to True (if is activated) then it connects the mouse 
    
    lpbsscientist's avatar
    lpbsscientist committed
            clicks on the pyqt window to the canvas (so to the matplolib figure).
            The connection has an "id" which is given by the integer self.id
            After the connections is made, it calls the Disable function with argument 0
            which turns off the other button(s).
    
            
            If the button is clicked but it is deactivated then it disconnects the 
    
    lpbsscientist's avatar
    lpbsscientist committed
            connection between the canvas and the window (the user can not interact
    
            with the plot anymore). 
    
    lpbsscientist's avatar
    lpbsscientist committed
            Storemouseclicks is a list corresponding to the coordinates of all mouse
            clicks between the activation and the deactivation of the button.
            So if it is empty, it does not draw anything because no clicks
    
            were registered. 
    
    lpbsscientist's avatar
    lpbsscientist committed
            But if it has some coordinates, it will draw a polygon where the vertices
            are the coordinates of all the mouseclicks.
            Once the figure has been updated with a new polygon, the other button(s)
    
            are again enabled. 
            
    
    lpbsscientist's avatar
    lpbsscientist committed
            """
            if self.button_newcell.isChecked():
    
                self.WriteStatusBar(('Draw a new cell. Use the left click to '
                                     'produce a polygon with a new cell value. '
                                     'Click the button again to confirm.'))
    
    lpbsscientist's avatar
    lpbsscientist committed
                self.m.tempmask = self.m.plotmask.copy()
                self.id = self.m.mpl_connect('button_press_event', self.m.MouseClick)
                self.Disable(self.button_newcell)
    
    lpbsscientist's avatar
    lpbsscientist committed
            else:
                self.m.mpl_disconnect(self.id)
                if  self.m.storemouseclicks and self.TestSelectedPoints():
                    self.m.DrawRegion(True)
                else:
                    self.m.updatedata()
                self.Enable(self.button_newcell)
    
                self.m.ShowCellNumbers()
    
                self.ClearStatusBar()
    
    lpbsscientist's avatar
    lpbsscientist committed
        def TestSelectedPoints(self):
            """This function is just used to catch an exception, when the new cell
            or the add region function is called. If all the dots drawn by the user
    
            are located on one line (horizontal or vertical) the DrawRegion 
            function calls a method to create a polygon and 
    
    lpbsscientist's avatar
    lpbsscientist committed
            it can not make a polygon out of straight line so it gives an error.
            In order to prevent this error, this function avoids to attempt to draw
            by returning False if the square are all on one line.
            """
    
    lpbsscientist's avatar
    lpbsscientist committed
            allx = list(np.array(self.m.storemouseclicks)[:,0])
            ally = list(np.array(self.m.storemouseclicks)[:,1])
    
    lpbsscientist's avatar
    lpbsscientist committed
            resultx = all(elem == allx[0] for elem in allx)
            resulty = all(elem == ally[0] for elem in ally)
    
    lpbsscientist's avatar
    lpbsscientist committed
            if resultx or resulty:
                return False
            else:
                return True
    
    lpbsscientist's avatar
    lpbsscientist committed
        def clickmethod(self):
    
    lpbsscientist's avatar
    lpbsscientist committed
            this method is called when the button Add region is clicked. If the button
    
            state corresponds to True (if is activated) then it connects the mouse 
    
    lpbsscientist's avatar
    lpbsscientist committed
            clicks on the pyqt window to the canvas (so to the matplolib figure).
            The connection has an "id" which is given by the integer self.id
            After the connections is made, it calls the Disable function with argument 1
            which turns off the other button(s).
    
            
            If the button is clicked and it is deactivated then it disconnects the 
    
    lpbsscientist's avatar
    lpbsscientist committed
            connection between the canvas and the window (the user can not interact
    
            with the plot anymore). 
    
    lpbsscientist's avatar
    lpbsscientist committed
            Storemouseclicks is a list corresponding to the coordinates of all mouse
            clicks between the activation and the deactivation of the button.
            So if it is empty, it does not draw anything because no clicks
    
            were registered. 
    
    lpbsscientist's avatar
    lpbsscientist committed
            But if it has some coordinates, it will draw a polygon where the vertices
            are the coordinates of all the mouseclicks.
            Once the figure has been updated with a new polygon, the other button(s)
    
            are again enabled. 
            
    
    lpbsscientist's avatar
    lpbsscientist committed
            """
            if self.button_add_region.isChecked():
    
                self.WriteStatusBar(('Select the cell with the first click, '
                                     'then draw polygon with subsequent '
                                     'clicks. Reclick the button to confirm.'))
    
    lpbsscientist's avatar
    lpbsscientist committed
                self.m.tempmask = self.m.plotmask.copy()
    
                self.id = self.m.mpl_connect('button_press_event', self.m.MouseClick)           
                self.Disable(self.button_add_region) 
                
    
    lpbsscientist's avatar
    lpbsscientist committed
            else:
                self.m.mpl_disconnect(self.id)
    
                # test if the list is not empty and if the dots are not all in the same line
                if self.m.storemouseclicks and self.TestSelectedPoints():
    
    lpbsscientist's avatar
    lpbsscientist committed
                    self.m.DrawRegion(False)
    
                else:
                    self.m.updatedata()
    
    lpbsscientist's avatar
    lpbsscientist committed
                self.Enable(self.button_add_region)
    
                self.m.ShowCellNumbers()
    
                self.ClearStatusBar()
    
    # -----------------------------------------------------------------------------
    # BUTTON ENABLE / DISABLE
        
    
    lpbsscientist's avatar
    lpbsscientist committed
        def Enable(self, button):
             """
             this functions turns on buttons all the buttons, depending on the time
    
             index. (next and previous buttons should not be turned on if t = 0 
    
    lpbsscientist's avatar
    lpbsscientist committed
             or t = lasttimeindex)
             """
    
             for k in range(0, len(self.buttonlist)):
                 if button != self.buttonlist[k]:
                     self.buttonlist[k].setEnabled(True)
    
    lpbsscientist's avatar
    lpbsscientist committed
             if self.Tindex == 0:
                 self.button_previousframe.setEnabled(False)
    
    lpbsscientist's avatar
    lpbsscientist committed
             if self.Tindex == self.reader.sizet-1:
                 self.button_nextframe.setEnabled(False)
    
    lpbsscientist's avatar
    lpbsscientist committed
             self.EnableCNNButtons()
    
    lpbsscientist's avatar
    lpbsscientist committed
        def Disable(self, button):
             """
    
             this functions turns off all the buttons except the one given in 
    
    lpbsscientist's avatar
    lpbsscientist committed
             argument.
             """
    
             for k in range(0,len(self.buttonlist)):
                 if button != self.buttonlist[k]:
                     self.buttonlist[k].setEnabled(False)
    
    
    lpbsscientist's avatar
    lpbsscientist committed
        def EnableCNNButtons(self):
    
    mattminder's avatar
    mattminder committed
            if self.reader.TestTimeExist(self.Tindex, self.FOVindex):
    
    lpbsscientist's avatar
    lpbsscientist committed
                self.button_cellcorespondance.setEnabled(True)
                self.button_extractfluorescence.setEnabled(True)
            else:
                self.button_cellcorespondance.setEnabled(False)
                self.button_extractfluorescence.setEnabled(False)
    
    lpbsscientist's avatar
    lpbsscientist committed
        def EnableCorrectionsButtons(self):
            self.button_newcell.setEnabled(True)
            self.button_add_region.setEnabled(True)
            self.button_drawmouse.setEnabled(True)
            self.button_eraser.setEnabled(True)
            self.button_exval.setEnabled(True)
            self.button_changecellvalue.setEnabled(True)
            self.button_showval.setEnabled(True)
    
    lpbsscientist's avatar
    lpbsscientist committed
        def DisableCorrectionsButtons(self):
            self.button_newcell.setEnabled(False)
            self.button_add_region.setEnabled(False)
            self.button_drawmouse.setEnabled(False)
            self.button_eraser.setEnabled(False)
            self.button_exval.setEnabled(False)
            self.button_changecellvalue.setEnabled(False)
            self.button_showval.setEnabled(False)
    
    lpbsscientist's avatar
    lpbsscientist committed
            """
            When this function is called, it saves the current mask
            (self.m.plotmask)
            """
            self.reader.SaveMask(self.Tindex, self.FOVindex, self.m.plotmask)
    
            
        def WriteStatusBar(self, text):
            """Writes text to status bar"""
            self.statusBarText.setText(text)
            
            
        def ClearStatusBar(self):
            """Removes text from status bar"""
            self.statusBarText.setText('')
    
    
    lpbsscientist's avatar
    lpbsscientist committed
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
    
        
        # If two arguments are given, make them nd2name and hdfname
        if len(sys.argv)==3:
            nd2name1 = sys.argv[1]
            hdfname1 = sys.argv[2]
            ex = App(nd2name1, hdfname1, '')
    
    lpbsscientist's avatar
    lpbsscientist committed
            sys.exit(app.exec_())
    
        
        # Launch file browser otherwise
    
    lpbsscientist's avatar
    lpbsscientist committed
        else:
    
            wind = dfb.FileBrowser()
            if wind.exec_():
                nd2name1 = wind.nd2name
                hdfname1 = wind.hdfname
                hdfnewname = wind.newhdfentry.text()
                ex = App(nd2name1, hdfname1, hdfnewname)
                sys.exit(app.exec_())
            else:
                app.exit()