Newer
Older
#!/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
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
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.
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,
Save Mask, ...) and the informations will be saved in the mask overlayed on
If one wants to segment using a neural network, one can press the
corresponding button (Launch CNN) and select the time range and
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
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).
import pandas as pd
import h5py
#from openpyxl import load_workbook
#from openpyxl import Workbook
# Import everything for the Graphical User Interface from the PyQt5 library.
from PyQt5.QtWidgets import (QApplication, QMainWindow, QDialog, QFileDialog,
QMessageBox, QPushButton, QCheckBox, QAction, QStatusBar, QLabel)
from PyQt5 import QtGui
#Import from matplotlib to use it to display the pictures and masks.
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from sklearn.decomposition import PCA
#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")
#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
#this file contains a dialog window that takes two integers as entry to swap
#two cell values
import ExchangeCellValues as ecv
#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
#is opened as soon as the user presses with the left click on a specific cell.
import ChangeOneCellValue as cocv
#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
#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
# PlotCanvas for fast plotting
from PlotCanvas import PlotCanvas
import Extract as extr
from image_loader import load_image
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.
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')]
class App(QMainWindow):
"""This class creates the main window.
"""
def __init__(self, nd2pathstr, hdfpathstr, newhdfstr):
super().__init__()
# 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.
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)
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)
# loading the first images of the cells from the nd2 file
self.currentframe = self.reader.LoadOneImage(self.Tindex,self.FOVindex)
# check if the t+1 time frame exists, avoid failure if there is only
# one picture in the folder/nd2 file
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])
self.previousframe = np.zeros([self.reader.sizey, self.reader.sizex])
# loading the first masks from the hdf5 file
self.mask_curr = self.reader.LoadMask(self.Tindex, self.FOVindex)
self.mask_previous = np.zeros([self.reader.sizey, self.reader.sizex])
# check if the t+1 mask exists, avoid failure if there is only
# one mask in the hdf file
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.
# 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.
self.button_newcell = QPushButton("New cell")
self.buttonlist.append(self.button_newcell)
self.button_add_region = QPushButton("Add region")
self.buttonlist.append(self.button_add_region)
self.button_savemask = QPushButton("Save Mask")
self.buttonlist.append(self.button_savemask)
self.button_drawmouse = QPushButton('Brush')
self.buttonlist.append(self.button_drawmouse)
self.button_eraser = QPushButton('Eraser')
self.buttonlist.append(self.button_eraser)
self.button_exval = QPushButton('Exchange Cell Values')
self.buttonlist.append(self.button_exval)
self.button_showval = QCheckBox('Show Cell Values')
self.buttonlist.append(self.button_showval)
self.button_hidemask = QCheckBox('Hide Mask')
self.buttonlist.append(self.button_hidemask)
self.button_nextframe = QPushButton("Next Time Frame")
self.buttonlist.append(self.button_nextframe)
self.button_previousframe = QPushButton("Previous Time Frame")
self.buttonlist.append(self.button_previousframe)
self.button_cnn = QPushButton('Launch CNN')
self.buttonlist.append(self.button_cnn)
self.button_threshold = QCheckBox('Threshold prediction')
self.buttonlist.append(self.button_threshold)
self.button_segment = QCheckBox('Segment')
self.buttonlist.append(self.button_segment)
self.button_cellcorespondance = QPushButton('Tracking')
self.buttonlist.append(self.button_cellcorespondance)
self.button_changecellvalue = QPushButton('Change cell value')
self.buttonlist.append(self.button_changecellvalue)
self.button_extractfluorescence = QPushButton('Extract')
self.buttonlist.append(self.button_extractfluorescence)
self.button_hide_show = QPushButton('CNN')
self.buttonlist.append(self.button_hide_show)
"""Initializing the widgets contained in the window.
Especially, it creates the widget to plot the
pictures/masks by creating an object of the PlotCanvas class self.m.
Every interaction with the masks or the pictures (loading new
frames/editing the frames/masks) occurs through this class.
This method initializes all the buttons with the InitButtons file.
It connects the buttons to the functions that they should trigger,
it sets the shortcuts to the buttons, a tool tip,
eventually a message on the status bar when the user hovers
This function also sets all the layout in the InitLayout file. It
takes and places the widgets (buttons, canvas, toolbar).
The function initializes a Menu Bar to have a menu which can be
improved later on.
It sets a toolbar of the matplotlib library and hides it. But it allows
to connect to the functions of this toolbar through "homemade"
QPushButtons instead of the ones provided by matplotlib.
Finally, it sets a StatusBar which displays some text to describe
the use of some buttons, or to show that the program is working on
something (running the neural network, loading frames, etc...)
After all this has been initialized, the program is ready to be used.
"""
self._main = QtWidgets.QWidget()
self.setCentralWidget(self._main)
# Here our canvas is created where using matplotlib,
# one can plot data to display the pictures and masks.
# Initialize all the buttons that are needed and the functions that are
# connected when the buttons are triggered.
# MENU, TOOLBAR AND STATUS BAR
# creates a menu just in case, some other functions can be added later
# in this menu.
self.saveactionmenu = QAction('Save')
self.fileMenu.addAction(self.saveactionmenu)
self.saveactionmenu.triggered.connect(self.ButtonSaveMask)
# hide the toolbar and instead of the original buttons of matplotlib,
# QPushbuttons are used and are connected to the functions of the toolbar
# it is than easier to interact with these buttons (for example to
# to disable them and so on..)
self.Nvgtlbar = NavigationToolbar(self.m, self)
self.addToolBar(self.Nvgtlbar)
self.Nvgtlbar.hide()
# creates a status bar with user instructions
self.statusBar = QStatusBar()
self.setStatusBar(self.statusBar)
self.statusBarText = QLabel()
self.statusBar.addWidget(self.statusBarText)
"""this function is implemented just to have the QLineButtons of the
change time index button, setthreshold button and the setsegmentation
button out of focus when the user clicks somewhere
on the gui. (to unfocus the buttons)
"""
self.button_timeindex.clearFocus()
if self.button_SetThreshold.isEnabled():
self.button_SetThreshold.clearFocus()
if self.button_SetSegmentation.isEnabled():
self.button_SetSegmentation.clearFocus()
# -----------------------------------------------------------------------------
# FUNCTIONS LINKED TO NAVIGATION
# connect the functions of the toolbar to our custom QPushbuttons.
"""The button_zoom is connected to the zoom function of the toolbar
Depending on the buttons that are active or checked, when the zoom
function is used, it does not disable all the buttons.
If the segment and threshold button are not checked or used
when the zoom button is clicked, it disables all the button
using self.Disable which disables everything except the button passed
in argument (in this case button_zoom).
If the zoom button is used while the segment button is checked,
it disables all the buttons (1st elif) except the segment button
but once it is finished (so the zoom button becomes unchecked)
then it enables only the editing buttons (as long as the segment
button is still checked) such as New Cell, Add Region, Eraser,
Brush,etc.. and the other toolbar buttons (3rd elif)
If the zoom button is clicked while the threshold button is checked,
it disables all the button except the threshold button (2nd elif).
Once the zoom button is unchecked, it enables the toolbar buttons
(4th elif)
In any other case, it just enables all the buttons again.
"""
self.Nvgtlbar.zoom()
if (self.button_zoom.isChecked() and not(self.button_segment.isChecked()
or self.button_threshold.isChecked())):
elif self.button_zoom.isChecked() and self.button_segment.isChecked():
self.Disable(self.button_zoom)
self.button_segment.setEnabled(True)
elif self.button_zoom.isChecked() and self.button_threshold.isChecked():
self.Disable(self.button_zoom)
self.button_threshold.setEnabled(True)
elif self.button_zoom.isChecked() == False and self.button_segment.isChecked():
self.button_pan.setEnabled(True)
self.button_home.setEnabled(True)
self.button_back.setEnabled(True)
self.button_forward.setEnabled(True)
self.EnableCorrectionsButtons()
elif self.button_zoom.isChecked() == False and self.button_threshold.isChecked():
self.button_pan.setEnabled(True)
self.button_home.setEnabled(True)
self.button_back.setEnabled(True)
self.button_forward.setEnabled(True)
"""
connects the home button to the home function of the matplotlib
toolbar. It sets the view to the original view (no zoom)
"""
"""
It calls the back function of the matplotlib toolbar which sets the
view to the previous one (if the user does several zooms/pans,
this button allows to go back in the "history of views")
"""
"""
It calls the forward function of the matplotlib toolbar which sets the
view to the next one (if the user does several zooms/pans,
this button allows to go forward in the "history of views"
"""
"""The button_pan is connected to the pan function of the toolbar
Depending on the buttons that are active or checked, when the pan
function is used, it does not disable all the buttons.
If the segment and threshold button are not checked or used
when the pan button is clicked, it disables all the button
using self.Disable which disables everything except the button passed
in argument (in this case button_pan).
If the pan button is used while the segment button is checked,
it disables all the buttons (1st elif) except the segment button
but once it is finished (so the zoom button becomes unchecked)
then it enables only the editing buttons (as long as the segment
button is still checked) such as New Cell, Add Region, Eraser,
Brush,etc.. and the other toolbar buttons (3rd elif)
If the pan button is clicked while the threshold button is checked,
it disables all the button except the threshold button (2nd elif).
Once the pan button is unchecked, it enables the toolbar buttons
(4th elif)
In any other case, it just enables all the buttons again.
"""
self.Nvgtlbar.pan()
if (self.button_pan.isChecked() and not(self.button_segment.isChecked()
or self.button_threshold.isChecked())):
elif self.button_pan.isChecked() and self.button_segment.isChecked():
self.Disable(self.button_pan)
self.button_segment.setEnabled(True)
elif self.button_pan.isChecked() and self.button_threshold.isChecked():
self.Disable(self.button_pan)
self.button_threshold.setEnabled(True)
elif not(self.button_pan.isChecked()) and self.button_segment.isChecked():
self.button_zoom.setEnabled(True)
self.button_home.setEnabled(True)
self.button_back.setEnabled(True)
self.button_forward.setEnabled(True)
elif not(self.button_pan.isChecked()) and self.button_threshold.isChecked():
self.button_zoom.setEnabled(True)
self.button_home.setEnabled(True)
self.button_back.setEnabled(True)
self.button_forward.setEnabled(True)
"""This function is called everytime the Extract Fluorescence button is
clicked (self.button_extractfluorescence).
self.Disable(self.button_extractfluorescence)
self.WriteStatusBar('Extracting ...')
# Get last image with mask
for time_index in range(self.reader.sizet-1, -1, -1):
# Test if time has a mask
file = h5py.File(self.reader.hdfpath, 'r+')
time_exist = self.reader.TestTimeExist(time_index, self.FOVindex, file)
file.close()
if not time_exist:
continue
# load picture and sheet
image = self.reader.LoadImageChannel(time_index, self.FOVindex,
self.reader.default_channel)
mask = self.reader.LoadMask(time_index, self.FOVindex)
# Break if mask is non-empty
if mask.sum()>0:
break
if time_index==0:
QMessageBox(self, 'Error', 'No mask found')
self.Enable(self.button_extractfluorescence)
self.ClearStatusBar()
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
# Launch dialog with last image
dlg = extr.Extract(image, mask, self.reader.channel_names)
dlg.exec()
if dlg.exit_code == 1: # Fluorescence
self.ExtractFluo(dlg.cells, dlg.outfile, dlg.file_list)
elif dlg.exit_code == 2: # Mask
self.ExtractMask(dlg.cells, dlg.outfile)
self.Enable(self.button_extractfluorescence)
self.ClearStatusBar()
def ExtractMask(self, cell_list, outfile):
"""Extract the mask to the specified tiff file. Only take cells
specified by the cell_list"""
mask_list = []
for time_index in range(0, self.reader.sizet):
# Test if time has a mask
file = h5py.File(self.reader.hdfpath, 'r+')
time_exist = self.reader.TestTimeExist(time_index, self.FOVindex, file)
file.close()
if not time_exist:
continue
mask = self.reader.LoadMask(time_index, self.FOVindex)
all_cells = np.unique(mask)
for cell in set(all_cells)-set(cell_list):
mask[mask==cell] = 0
mask_list.append(mask)
imageio.mimwrite(outfile, np.array(mask_list, dtype=np.uint16))
def ExtractFluo(self, cells_to_use, csv_filename, channel_list):
"""This is the function that takes as argument the filepath to the xls
file and writes in the file.
It iterates over the different channels (or the sheets of the file,
each channel has one sheet.), and reads the image corresponding
to the time, field of view and channel index. It reads the already
existing file and makes a copy in which the data will be written in it.
The first step of calculating the data is to iterate through each
cell/segment of the mask (so each cell is a submatrix of one value
in the matrix of the mask).
For each of these value /cell, the area is extracted as being
the number of pixels corresponding to this cell/value.
(it is known from the microscope settings how to convert
the pixel in area).
The total intensity is just the value of the pixel and it is added over
all the pixels corresonding to the cell/value.
The mean is then calculated as being the total intensity divided by
the number of pixels (which here is equal to the area also).
With the mean it is then possible to calculate the variance of the
Then, it is checked if the value of the cell (cell number) already
exists in the first column, if it already exists it continues to
find the column corresponding to the time index where the values
should be written. It sets the flag to True such that it does not
write the cell as new one and adds it at the end of the column
If the value is not found in the cell number column (new cell or
first time writing in the file), the flag is False, thus it adds the
cell number at the end of the column.
It then saves the xls file.
# List of cell properties
cell_list = []
for time_index in range(0, self.reader.sizet):
# Test if time has a mask
file = h5py.File(self.reader.hdfpath, 'r+')
time_exist = self.reader.TestTimeExist(time_index, self.FOVindex, file)
file.close()
if not time_exist:
continue
mask = self.reader.LoadMask(time_index, self.FOVindex)
for channel in channel_list:
# check if channel is in list of nd2 channels
try:
channel_ix = self.reader.channel_names.index(channel)
image = self.reader.LoadImageChannel(time_index, self.FOVindex, channel_ix)
# channel is a file
except ValueError:
image = load_image(channel, ix=time_index)
for val in np.unique(mask):
# bg is not cell
if val == 0:
continue
# disregard cells not in cell_list
if not (val in cells_to_use):
continue
# Calculate stats
stats = self.cell_statistics(image, mask == val)
stats['Time'] = time_index
stats['Channel'] = channel
stats['Cell'] = val
cell_list.append(stats)
# Use Pandas to write csv
df = pd.DataFrame(cell_list)
df.to_csv(csv_filename, index=False)
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
def cell_statistics(self, image, mask):
"""Calculate statistics about cells. Passing None to image will
create dictionary to zeros, which allows to extract dictionary keys"""
if image is not None:
cell_vals = image[mask]
area = mask.sum()
tot_intensity = cell_vals.sum()
mean = tot_intensity/area if area > 0 else 0
var = np.var(cell_vals)
# Center of mass
y,x = mask.nonzero()
# sample = np.random.choice(len(x), size=50, replace=True)
com_x = np.mean(x)
com_y = np.mean(y)
# PCA only works for multiple points
if area > 1:
pca = PCA().fit(np.array([y,x]).T)
pc1_x, pc1_y = pca.components_[0,:]
angle = np.arctan(pc1_y / pc1_x) / np.pi * 360
v1, v2 = pca.explained_variance_
roundness = v2 / v1
else:
angle = 0
roundness = 1
else:
mean = 0
var = 0
tot_intensity = 0
com_x = 0
com_y = 0
angle = 0
roundness = 0
return {'Mean': mean,
'Variance': var,
'Total Intensity': tot_intensity,
'Center of Mass X': com_x,
'Center of Mass Y': com_y,
'Cell Angle': angle,
'Roundness': roundness}
# -----------------------------------------------------------------------------
# NEURAL NETWORK
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
def ShowHideCNNbuttons(self):
"""hide and show the buttons corresponding to the neural network.
this function is called by the button CNN which is hidden. But
if activated in the InitLayout.py then you can have a button
which hides the CNN buttons (which are now on the normal also
hidden...).
"""
if self.button_hide_show.isChecked():
self.button_cnn.setVisible(True)
self.button_segment.setVisible(True)
self.button_savesegmask.setVisible(True)
self.button_threshold.setVisible(True)
self.button_SetThreshold.setVisible(True)
self.button_savethresholdmask.setVisible(True)
self.button_SetSegmentation.setVisible(True)
else:
self.button_cnn.setVisible(False)
self.button_segment.setVisible(False)
self.button_savesegmask.setVisible(False)
self.button_threshold.setVisible(False)
self.button_SetThreshold.setVisible(False)
self.button_savethresholdmask.setVisible(False)
self.button_SetSegmentation.setVisible(False)
def LaunchBatchPrediction(self):
"""This function is called whenever the button Launch CNN is pressed.
It allows to run the neural network over a time range and selected
field of views.
It creates a dialog window with two entries, that define the time range
and a list where the user can select the desired fields of view.
Once it reads all the value, it calls the neural network function
inside of self.PredThreshSeg and it does the prediction of the neural
network, thresholds this prediction and then segments it.
"""
self.WriteStatusBar('Running the neural network...')
self.Disable(self.button_cnn)
# creates a dialog window from the LaunchBatchPrediction.py file
# this if tests if the user pressed 'ok' in the dialog window
if dlg.exec_() == QDialog.Accepted:
# it tests if the user has entered some values
# if not it ignores and returns.
if not (dlg.entry1.text()!= '' and dlg.entry2.text() != ''):
QMessageBox.critical(self, "Error", "No Time Specified")
return
# reads out the entry given by the user and converts the index
# to integers
time_value1 = int(dlg.entry1.text())
time_value2 = int(dlg.entry2.text())
# it tests if the first value is smaller or equal such that
# time_value1 is the lower range of the time range
# and time_value2 the upper boundary of the range.
if time_value1 > time_value2 :
QMessageBox.critical(self, "Error", 'Invalid Time Constraints')
return
# displays that the neural network is running
self.WriteStatusBar('Running the neural network...')
#it iterates in the list of the user-selected fields
#of view, to return the corresponding index, the function
#dlg.listfov.row(item) is used which gives an integer
if len(dlg.listfov.selectedItems())==0:
QMessageBox.critical(self, "Error", "No FOV Selected")
for item in dlg.listfov.selectedItems():
#iterates over the time indices in the range
for t in range(time_value1, time_value2+1):
#calls the neural network for time t and selected
#fov
if dlg.entry_threshold.text() != '':
thr_val = float(dlg.entry_threshold.text())
else:
thr_val = None
if dlg.entry_segmentation.text() != '':
seg_val = int(dlg.entry_segmentation.text())
else:
seg_val = 10
self.PredThreshSeg(t, dlg.listfov.row(item), thr_val, seg_val)
# if tracker has been checked then apply it
if dlg.tracking_checkbox.isChecked():
if t != time_value1:
temp_mask = self.reader.CellCorrespondance(t, dlg.listfov.row(item))
self.reader.SaveMask(t,dlg.listfov.row(item), temp_mask)
else:
temp_mask = self.reader.LoadSeg(t, dlg.listfov.row(item))
self.reader.SaveMask(t,dlg.listfov.row(item), temp_mask)
self.ReloadThreeMasks()
self.m.UpdatePlots()
self.ClearStatusBar()
self.EnableCNNButtons()
self.Enable(self.button_cnn)
def PredThreshSeg(self, timeindex, fovindex, thr_val, seg_val):
"""
This function is called in the LaunchBatchPrediction function.
This function calls the neural network function in the
InteractionDisk.py file and then thresholds the result
of the prediction, saves this thresholded prediction.
Then it segments the thresholded prediction and saves the
"""
self.reader.LaunchPrediction(timeindex, fovindex)
self.m.ThresholdMask = self.reader.ThresholdPred(thr_val, timeindex,fovindex)
self.reader.SaveThresholdMask(timeindex, fovindex, self.m.ThresholdMask)
self.m.SegmentedMask = self.reader.Segment(seg_val, timeindex,fovindex)
self.reader.SaveSegMask(timeindex, fovindex, self.m.SegmentedMask)
self.reader.SaveMask(timeindex, fovindex, self.m.SegmentedMask)
def SelectChannel(self, index):
"""This function is called when the button to select different channels
is used. From the displayed list in the button, the chosen index
corresponnds to the same index in the list of channels from the reader.
So, it sets the default channel with the new index (called index below)
"""
self.reader.default_channel = index
# update the pictures using the same function as the one used to
# change the fields of view.
"""This function is called when the button containing the list of
fields od view is used.
The index correspondds to the field of view selected in the list.
"""
# mask is automatically saved.
self.reader.SaveMask(self.Tindex, self.FOVindex, self.m.plotmask)
# it updates the fov in the plot with the new index.
def ChangeFOV(self):
"""
it changes the fov or channel according to the choice of the user
and it updates the plot shown and it initializes the new fov/channel
at t=0 by default.
"""
# load the image and mask for the current plot
self.m.currpicture = self.reader.LoadOneImage(self.Tindex,self.FOVindex)
self.m.plotmask = self.reader.LoadMask(self.Tindex,self.FOVindex)
# sets the image and the mask to 0 for the previous plot
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)
# load the image and the mask for the next plot, check if it exists
if self.Tindex+1 < self.reader.sizet:
self.m.nextpicture = self.reader.LoadOneImage(self.Tindex+1, self.FOVindex)
self.m.nextplotmask = self.reader.LoadMask(self.Tindex+1, self.FOVindex)
# enables the next frame button in case it was disabled when the
# fov/channel was changed
self.button_nextframe.setEnabled(True)
else:
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)
# disables the next frame button if the mask or the picture
# does not exist.
self.button_nextframe.setEnabled(False)
# once the images and masks are loaded into the variables, they are
# displaye in the gui.
# disables the previous frame button in case it was active before
# changing fov/channel.
# updates the title of the plots to display the right time indices
# aboves the plots.
# if the button to hide the mask was checked before changing fov/channel,
# it hides the mask again.
if self.button_hidemask.isChecked():
self.m.HideMask()
# the button to set the time index is also set to 0/default again.
# enables the neural network buttons if there is already an
# existing prediction for the current image.
def ReloadThreeMasks(self):
"""
A function which replots all the masks at the current time and fov
indices. Needed after the batch prediction is completed to display
the result of the NN.
"""
if self.Tindex >= 0 and self.Tindex <= self.reader.sizet-1:
if self.Tindex == 0:
self.button_nextframe.setEnabled(True)
if self.Tindex < self.reader.sizet-1:
self.m.nextplotmask = self.reader.LoadMask(self.Tindex+1, self.FOVindex)
else:
np.zeros([self.reader.sizey, self.reader.sizex], dtype = np.uint16)
self.m.plotmask = self.reader.LoadMask(self.Tindex, self.FOVindex)
self.m.prevplotmask = np.zeros([self.reader.sizey, self.reader.sizex], dtype = np.uint16)
self.button_previousframe.setEnabled(False)
elif self.Tindex == self.reader.sizet-1:
self.button_previousframe.setEnabled(True)
self.m.prevplotmask = self.reader.LoadMask(self.Tindex-1, self.FOVindex)
self.m.plotmask = self.reader.LoadMask(self.Tindex, self.FOVindex)
self.m.nextplotmask = np.zeros([self.reader.sizey, self.reader.sizex], dtype = np.uint16)
self.button_nextframe.setEnabled(False)
else:
self.button_nextframe.setEnabled(True)
self.button_previousframe.setEnabled(True)
self.m.prevplotmask = self.reader.LoadMask(self.Tindex-1, self.FOVindex)
self.m.plotmask = self.reader.LoadMask(self.Tindex, self.FOVindex)
self.m.nextplotmask = self.reader.LoadMask(self.Tindex+1, self.FOVindex)
if self.button_hidemask.isChecked():
self.m.HideMask()
self.EnableCNNButtons()
else:
return
"""This funcion is called whenever the user gives a new time index,
to jump to the new given index, once "enter" button is pressed.
# it reads out the text in the button and converts it to an int.
newtimeindex = int(self.button_timeindex.text())
if newtimeindex >= 0 and newtimeindex <= self.reader.sizet-1:
self.reader.SaveMask(self.Tindex, self.FOVindex, self.m.plotmask)
if self.Tindex == 0:
self.button_nextframe.setEnabled(True)
self.m.nextpicture = self.reader.LoadOneImage(self.Tindex+1,self.FOVindex)
self.m.nextplotmask = self.reader.LoadMask(self.Tindex+1, self.FOVindex)
self.m.currpicture = self.reader.LoadOneImage(self.Tindex, self.FOVindex)
self.m.plotmask = self.reader.LoadMask(self.Tindex, self.FOVindex)
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)
elif self.Tindex == self.reader.sizet-1:
self.button_previousframe.setEnabled(True)
self.m.prevpicture = self.reader.LoadOneImage(self.Tindex-1, self.FOVindex)
self.m.prevplotmask = self.reader.LoadMask(self.Tindex-1, self.FOVindex)
self.m.currpicture = self.reader.LoadOneImage(self.Tindex, self.FOVindex)
self.m.plotmask = self.reader.LoadMask(self.Tindex, self.FOVindex)
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)
else:
self.button_nextframe.setEnabled(True)
self.button_previousframe.setEnabled(True)
self.m.prevpicture = self.reader.LoadOneImage(self.Tindex-1, self.FOVindex)
self.m.prevplotmask = self.reader.LoadMask(self.Tindex-1, self.FOVindex)
self.m.currpicture = self.reader.LoadOneImage(self.Tindex, self.FOVindex)
self.m.plotmask = self.reader.LoadMask(self.Tindex, self.FOVindex)
self.m.nextpicture = self.reader.LoadOneImage(self.Tindex+1,self.FOVindex)
self.m.nextplotmask = self.reader.LoadMask(self.Tindex+1, self.FOVindex)
self.UpdateTitleSubplots()
self.button_timeindex.clearFocus()
self.button_timeindex.setText(str(self.Tindex)+'/'+str(self.reader.sizet-1))
if self.button_hidemask.isChecked():
self.m.HideMask()
self.EnableCNNButtons()
else:
self.button_timeindex.clearFocus()
return
self.Disable(self.button_cellcorespondance)
self.WriteStatusBar('Doing the cell correspondance')
if self.Tindex != 0:
self.m.plotmask = self.reader.CellCorrespondance(self.Tindex, self.FOVindex)
self.m.updatedata()
else: