Skip to content
Snippets Groups Projects
GUI_main.py 70.8 KiB
Newer Older
lpbsscientist's avatar
lpbsscientist committed
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
This script is the main script used to produce a GUI which should help for
cell segmentation. This script can only read .nd2 files containing the 
lpbsscientist's avatar
lpbsscientist committed
images of cells, especially it displays for each recorded positions (field
of view) the pictures in the time axis.

The script opens first a window which allows you to load an nd2 file and
to load or create an hdf file. The hdf file contains all the masks, so if
it is the first the user segments an nd2 file, a new one should be created.
And it can be then loaded for later use.  Along with new hdf file, created
by the name entered by the user (say filename), it creates three other hdf 
files (filename_predicted.h5, filename_thresholded.h5 and 
filename_segmented.h5) these contain all the steps of the NN to get to the 
segmented picture. 
After the first window is finished a second one opens, where at each time 
index, three pictures 
lpbsscientist's avatar
lpbsscientist committed
are displayed the t-1 picture, the t picture (current frame which can be
edited) and the t+1 picture. Using the arrows one can navigate through time.
On top of the picture, there is always a mask which is displayed, if no cells
are present in the mask then the mask is blank and the user does not see it. 
lpbsscientist's avatar
lpbsscientist committed
If one wants to hand anmotate the pictures, one can just start to draw on the
picture using the different functions (New Cell, Add Region, Brush, Eraser,
mattminder's avatar
mattminder committed
Save Mask, ...) and the informations will be saved in the mask overlayed on 
top of the pictures. 
lpbsscientist's avatar
lpbsscientist committed

If one wants to segment using a neural network, one can press the
corresponding button (Launch CNN) and select the time range and 
lpbsscientist's avatar
lpbsscientist committed
the field of views on which the neural network is applied.

Once the neural network has finished predicting, there are still no visible
masks, but on the field of views and time indices where the NN has been
applied, the threshold and segment buttons are enabled. By checking these
two buttons one can either display the thresholded image of the prediction or
display the segmentation of the thresholded prediction.

At this stage, one can correct the segmentation of the prediction using
the functions (New Cell, Add Region, etc..) by selecting the Segment
checkbox and then save them using the Save Seg button.
If the user is happy with the segmentation, the Cell Correspondance button 
lpbsscientist's avatar
lpbsscientist committed
can be clicked. Until then, the cells get random numbers attributed by
the segmentation algorithm. In order to keep track of the cell through time,
the same cells should have the same number between two different time pictures.
This can be (with some errors) achieved by the Cell Correspondance button,
which tries to attribute the same number to corresponding cells in time.
After that, the final mask is saved and it is always visible when you go on
the corresponding picture. This mask can also be corrected using the 
usual buttons (because the Cell Correspondance makes also mistakes). 
lpbsscientist's avatar
lpbsscientist committed
import sys
import numpy as np
import pandas as pd
import h5py
# For writing excel files
#from openpyxl import load_workbook
#from openpyxl import Workbook
lpbsscientist's avatar
lpbsscientist committed

# Import everything for the Graphical User Interface from the PyQt5 library.
from PyQt5.QtWidgets import (QApplication, QMainWindow, QDialog, QFileDialog, 
mattminder's avatar
mattminder committed
    QMessageBox, QPushButton, QCheckBox, QAction, QStatusBar, QLabel)
lpbsscientist's avatar
lpbsscientist committed
from PyQt5 import QtGui

#Import from matplotlib to use it to display the pictures and masks.
mattminder's avatar
mattminder committed
from matplotlib.backends.qt_compat import QtWidgets
mattminder's avatar
mattminder committed
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from sklearn.decomposition import PCA
import imageio
#append all the paths where the modules are stored. Such that this script
#looks into all of these folders when importing modules.
sys.path.append("./unet")
sys.path.append("./disk")
sys.path.append("./icons")
sys.path.append("./init")
sys.path.append("./misc")
lpbsscientist's avatar
lpbsscientist committed

#Import all the other python files
#this file handles the interaction with the disk, so loading/saving images
#and masks and it also runs the neural network.
import InteractionDisk_temp as nd
lpbsscientist's avatar
lpbsscientist committed
#this file contains a dialog window that takes two integers as entry to swap
#two cell values
import ExchangeCellValues as ecv
lpbsscientist's avatar
lpbsscientist committed
#this file contains a dialog window which is opened before the main program
#and allows to load the nd2 and hdf files by browsing through the computer.
import DialogFileBrowser as dfb
#this file contains a window that opens to change the value of one cell. It 
lpbsscientist's avatar
lpbsscientist committed
#is opened as soon as the user presses with the left click on a specific cell.
import ChangeOneCellValue as cocv
lpbsscientist's avatar
lpbsscientist committed
#this file contains a dialog window where a time range and the field of views
#can be selected to then launch a prediction of the neural network on
#a specific range of pictures.
import LaunchBatchPrediction as lbp

#this file initializes all the buttons present in the gui, sets the shortcuts
#to these buttons and also connect the buttons to the function that are 
lpbsscientist's avatar
lpbsscientist committed
#triggered when the buttons are pressed.
import InitButtons

#this file contains the layout of the main window so it justs puts the buttons
#and the pictures at the desired position in the main window.
import InitLayout
mattminder's avatar
mattminder committed

# PlotCanvas for fast plotting
from PlotCanvas import PlotCanvas

import Extract as extr
from image_loader import load_image
lpbsscientist's avatar
lpbsscientist committed

class NavigationToolbar(NavigationToolbar):
    """This is the standard matplotlib toolbar but only the buttons
    that are of interest for this gui are loaded. These buttons allow 
    to zoom into the pictures/masks and to navigate in the zoomed picture. 
lpbsscientist's avatar
lpbsscientist committed
    A Home button can be used to set the view back to the original view.
    """
    toolitems = [t for t in NavigationToolbar.toolitems if
                 t[0] in ('Home', 'Pan', 'Zoom','Back', 'Forward')]
lpbsscientist's avatar
lpbsscientist committed
class App(QMainWindow):
    """This class creates the main window.
    """

    def __init__(self, nd2pathstr, hdfpathstr, newhdfstr):
        super().__init__()
lpbsscientist's avatar
lpbsscientist committed
        self.title = 'YeaZ 1.0'
        # all these ids are integers which are used to set a connection between
        # the button and the function that this button calls.
        # There are three of them because it happens that one can trigger three 
        # different functions with one button.        
lpbsscientist's avatar
lpbsscientist committed
        self.id = 0
        self.id2 = 0
        self.id3 = 0 
lpbsscientist's avatar
lpbsscientist committed

        self.reader = nd.Reader(hdfpathstr, newhdfstr, nd2pathstr)
        # these variables are used to create/read/load the excel file used
        # to write the fluorescence values extracted. For each field of view,
        # the user will be asked each time to create a new xls file for the 
        # field of view or to load an existing field of view (this is the role
        # of the boolean variable)
lpbsscientist's avatar
lpbsscientist committed
        self.xlsfilename = ''
        self.nd2path = nd2pathstr
        # Set the indices for the time axis and the field of view index. These
        # indices represent everywhere the current picture (the one that can be
        # edited, i.e. the time t frame)
lpbsscientist's avatar
lpbsscientist committed
        self.Tindex = 0
        self.FOVindex = 0
        # loading the first images of the cells from the nd2 file
lpbsscientist's avatar
lpbsscientist committed
        self.currentframe = self.reader.LoadOneImage(self.Tindex,self.FOVindex)
lpbsscientist's avatar
lpbsscientist committed
        
        # check if the t+1 time frame exists, avoid failure if there is only
        # one picture in the folder/nd2 file
lpbsscientist's avatar
lpbsscientist committed
        if self.Tindex+1 < self.reader.sizet:
            self.nextframe = self.reader.LoadOneImage(self.Tindex+1, self.FOVindex)
        else:
            self.nextframe = np.zeros([self.reader.sizey, self.reader.sizex])
        
lpbsscientist's avatar
lpbsscientist committed
        self.previousframe = np.zeros([self.reader.sizey, self.reader.sizex])

        # loading the first masks from the hdf5 file
lpbsscientist's avatar
lpbsscientist committed
        self.mask_curr = self.reader.LoadMask(self.Tindex, self.FOVindex)
        self.mask_previous = np.zeros([self.reader.sizey, self.reader.sizex])
lpbsscientist's avatar
lpbsscientist committed
        
        # check if the t+1 mask exists, avoid failure if there is only
        # one mask in the hdf file
lpbsscientist's avatar
lpbsscientist committed
        if self.Tindex+1 < self.reader.sizet:
            self.mask_next = self.reader.LoadMask(self.Tindex+1, self.FOVindex)
        else:
            self.mask_next = np.zeros([self.reader.sizey, self.reader.sizex])
        
        # creates a list of all the buttons, which will then be used in order
        # to disable all the other buttons at once when one button/function
        # is pressed/used in the gui.
lpbsscientist's avatar
lpbsscientist committed
        self.buttonlist = []
        # setting buttons as attributes
        # the shortcuts for the buttons, the functions to which they are
        # connected to,... are all set up in the ButtonInit file which is called
        # in the self.initUI() method below.
lpbsscientist's avatar
lpbsscientist committed
        self.button_newcell = QPushButton("New cell")
        self.buttonlist.append(self.button_newcell)
lpbsscientist's avatar
lpbsscientist committed
        self.button_add_region = QPushButton("Add region")
        self.buttonlist.append(self.button_add_region)
lpbsscientist's avatar
lpbsscientist committed
        self.button_savemask = QPushButton("Save Mask")
Loading
Loading full blame...