diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..93f30b3230e4fda8d8f65da4c3d3c33f6c217552 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*SJR_old* +unet_weights_* +*pycache* diff --git a/GUI_main.py b/GUI_main.py index f8ebf561374e816e37464a358618b50c1e3315b3..6732a302fd755097e2872cfaac2316f4bec662da 100644 --- a/GUI_main.py +++ b/GUI_main.py @@ -198,7 +198,14 @@ class App(QMainWindow): # loading the first images of the cells from the nd2 file self.currentframe = self.reader.LoadOneImage(self.Tindex,self.FOVindex) - self.nextframe = self.reader.LoadOneImage(self.Tindex+1, 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]) @@ -206,7 +213,14 @@ class App(QMainWindow): # 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]) - self.mask_next = self.reader.LoadMask(self.Tindex+1, self.FOVindex) + + #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 @@ -1103,19 +1117,24 @@ class App(QMainWindow): 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. - self.m.nextpicture = self.reader.LoadOneImage(self.Tindex+1, self.FOVindex) - self.m.nextplotmask = self.reader.LoadMask(self.Tindex+1, self.FOVindex) - - +# 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. self.m.UpdateBckgrndPicture() - -# enables the next frame button in case it was disabled when the -# fov/channel was changed - self.button_nextframe.setEnabled(True) # disables the previous frame button in case it was active before # changing fov/channel. self.button_previousframe.setEnabled(False) @@ -1394,8 +1413,8 @@ class App(QMainWindow): # self.button_nextframe.setShortcut(Qt.Key_Right) # self.button_nextframe.pressed.connect(self.Test) # self.button_nextframe.setChecked(False) - - self.button_nextframe.setEnabled(True) + if self.Tindex + 1 < self.reader.sizet: + self.button_nextframe.setEnabled(True) # self.button_nextframe.pressed.connect(self.Test) # self.button_nextframe.setChecked(False) @@ -1424,8 +1443,11 @@ class App(QMainWindow): # self.button_nextframe.disconnect() self.Disable(self.button_nextframe) + print("self.Tindex",self.Tindex) + print("self.reader.sizet",self.reader.sizet) if self.Tindex + 1 < self.reader.sizet - 1 : + print('if') self.reader.SaveMask(self.Tindex, self.FOVindex, self.m.plotmask) self.m.prevpicture = self.m.currpicture.copy() @@ -1446,6 +1468,7 @@ class App(QMainWindow): # else: + print('else') self.reader.SaveMask(self.Tindex, self.FOVindex, self.m.plotmask) self.m.prevpicture = self.m.currpicture.copy() @@ -1647,7 +1670,7 @@ class App(QMainWindow): self.m.titlecurr.set_text('Time index {}'.format(self.Tindex)) self.m.titleprev.set_text('No frame {}'.format('')) - self.m.titlenext.set_text('Next Time index {}'.format(self.Tindex+1)) + self.m.titlenext.set_text('Next time index {}'.format(self.Tindex+1)) # self.m.ax.set_title('Time index {}'.format(self.Tindex)) @@ -1674,7 +1697,7 @@ class App(QMainWindow): else: 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('Next Time index {}'.format(self.Tindex+1)) + self.m.titlenext.set_text('Next time index {}'.format(self.Tindex+1)) # self.m.ax.set_title('Time index {}'.format(self.Tindex)) @@ -1976,7 +1999,7 @@ class PlotCanvas(FigureCanvas): self.titlecurr = self.ax.set_title('Time index {}'.format(parent.Tindex)) self.titleprev = self.ax2.set_title('No frame {}'.format('')) - self.titlenext = self.ax3.set_title('Next Time index {}'.format(parent.Tindex+1)) + self.titlenext = self.ax3.set_title('Next time index {}'.format(parent.Tindex+1)) # these variables are just set to test the states of the buttons @@ -2234,6 +2257,7 @@ class PlotCanvas(FigureCanvas): background coordinates, setting the background to 0 again. """ if flag: +# print("plotmask",self.plotmask.shape) self.currmask.set_data((self.plotmask%10+1)*(self.plotmask!=0)) else : self.currmask.set_data((self.tempmask%10+1)*(self.tempmask!=0)) @@ -2303,9 +2327,13 @@ class PlotCanvas(FigureCanvas): if self.button_showval_check.isChecked(): vals = np.unique(self.plotmask) + vals = np.delete(vals,np.where(vals==0)) #SJR: for some reason are floats and contains background (0) + xtemp = [] + ytemp = [] + val = [] for k in vals: - x,y = (self.plotmask==k).nonzero() - sample = np.random.choice(len(x), size=20, replace=False) + y,x = (self.plotmask==k).nonzero() # this was wrong x,y I believe + sample = np.random.choice(len(x), size=20, replace=True) meanx = np.mean(x[sample]) meany = np.mean(y[sample]) xtemp.append(int(round(meanx))) @@ -2331,7 +2359,7 @@ class PlotCanvas(FigureCanvas): ## val.append(k) if xtemp: for i in range(0,len(xtemp)): - ann = self.ax.annotate(str(val[i]), (xtemp[i], ytemp[i])) + ann = self.ax.annotate(str(int(val[i])), (xtemp[i], ytemp[i])) self.ann_list.append(ann) @@ -2365,7 +2393,7 @@ class PlotCanvas(FigureCanvas): if self.button_showval_check.isChecked(): - maxval = np.amax(self.prevplotmask) + maxval = int(np.amax(self.prevplotmask)) minval = 1 xtemp = [] ytemp = [] @@ -2422,7 +2450,7 @@ class PlotCanvas(FigureCanvas): if self.button_showval_check.isChecked(): - maxval = np.amax(self.nextplotmask) + maxval = int(np.amax(self.nextplotmask)) minval = 1 xtemp = [] ytemp = [] diff --git a/disk/DialogFileBrowser.py b/disk/DialogFileBrowser.py index 2cb50bb8e6e1ba354a7ca13eaee7a72c5cdc97f0..e645820909eb79ef2d8eabbb75a50671e2b903a4 100644 --- a/disk/DialogFileBrowser.py +++ b/disk/DialogFileBrowser.py @@ -18,26 +18,27 @@ class FileBrowser(QDialog): self.setGeometry(100,100, 800,200) - self.button_opennd2 = QPushButton('Open Image File') + self.button_opennd2 = QPushButton('Open image file') self.button_opennd2.setEnabled(True) self.button_opennd2.clicked.connect(self.getnd2path) self.button_opennd2.setToolTip("Browse for an image file") self.button_opennd2.setMaximumWidth(150) - self.button_openfolder = QPushButton('Open Image Folder') + self.button_openfolder = QPushButton('Open image folder') self.button_openfolder.setEnabled(True) self.button_openfolder.clicked.connect(self.getfolder) self.button_openfolder.setToolTip("Browse for folder with images") self.button_openfolder.setMaximumWidth(150) - self.button_openhdf = QPushButton('Open hdf file') + self.button_openhdf = QPushButton('Open mask file') self.button_openhdf.setEnabled(True) self.button_openhdf.clicked.connect(self.gethdfpath) - self.button_openhdf.setToolTip("Browse for an hdf file containing the masks") + self.button_openhdf.setToolTip("Browse for a mask file") self.button_openhdf.setMaximumWidth(150) self.newhdfentry = QLineEdit() # self.newhdfentry(Qt.AlignLeft) + self.newhdfentry.setText("newmaskfile") @@ -56,10 +57,10 @@ class FileBrowser(QDialog): self.labelnd2 = QLabel() - self.labelnd2.setText('No nd2 file selected') + self.labelnd2.setText('No image file (.nd2, .tif, .tiff) selected') self.labelhdf = QLabel() - self.labelhdf.setText('No hdf file selected') + self.labelhdf.setText('No mask file (.h5, .tif, .tiff) selected') self.labelfolder = QLabel() self.labelfolder.setText('No folder selected') @@ -78,15 +79,19 @@ class FileBrowser(QDialog): def getnd2path(self): - self.nd2name,_ = QFileDialog.getOpenFileName(self, 'Open .nd2 File','', 'Image Files (*.nd2 *.tif *.tiff)') + self.nd2name,_ = QFileDialog.getOpenFileName(self, 'Open image file','', 'Image files (*.nd2 *.tif *.tiff)') # print(self.nd2name) # print(self.nd2name) - self.labelnd2.setText(self.nd2name) + if self.nd2name != '': + self.labelnd2.setText(self.nd2name) def gethdfpath(self): - self.hdfname,_ = QFileDialog.getOpenFileName(self,'Open .hdf File','', 'hdf Files (*.h5)') - self.labelhdf.setText(self.hdfname) + self.hdfname,_ = QFileDialog.getOpenFileName(self,'Open mask file','', 'Mask files (*.h5 *.tif *.tiff)') + if self.hdfname != '': + self.labelhdf.setText(self.hdfname) + self.newhdfentry.setText("") def getfolder(self): self.nd2name = QFileDialog.getExistingDirectory(self, ("Select Image Folder")) - self.labelnd2.setText(self.nd2name) \ No newline at end of file + if self.nd2name != '': + self.labelnd2.setText(self.nd2name) diff --git a/disk/InteractionDisk_temp.py b/disk/InteractionDisk_temp.py index a52672b078190ae1499255f8c516642bd4088f19..2295e451f816f757c36f035265a0a6da64d8c4e1 100644 --- a/disk/InteractionDisk_temp.py +++ b/disk/InteractionDisk_temp.py @@ -49,25 +49,33 @@ class Reader: self.sizey = images.sizes['y'] self.sizec = images.sizes['c'] self.sizet = images.sizes['t'] + print("Debug: self.sizet",self.sizet) self.Npos = images.sizes['v'] self.channel_names = images.metadata['channels'] elif self.istiff: with pytiff.Tiff(self.nd2path) as handle: - self.sizex, self.sizey = handle.shape + self.sizey, self.sizex = handle.shape #SJR: changed by me self.sizec = 1 self.sizet = handle.number_of_pages + print("Debug: handle.number_of_pages",handle.number_of_pages) self.Npos = 1 self.channel_names = ['Channel1'] elif self.isfolder: + filelist = os.listdir(self.nd2path) + + for f in filelist: + if f.startswith('.'): + filelist.remove(f) + im = skimage.io.imread(self.nd2path + '/' + filelist[0]) - self.sizex, self.sizey = im.shape + self.sizey, self.sizex = im.shape #SJR: changed by me self.sizec = 1 self.Npos = 1 self.sizet = len(filelist) - print(self.sizet) + print("Debug: self.sizet",self.sizet) self.channel_names = ['Channel1'] #create the labels which index the masks with respect to time and @@ -118,14 +126,57 @@ class Reader: if not self.hdfpath: return self.Createhdf() else: -# - temp = self.hdfpath[:-3] - self.thresholdname = temp + '_thresholded' + '.h5' - self.segmentname = temp + '_segmented' + '.h5' - self.predictname = temp + '_predicted' + '.h5' + filenamewithpath, extension = os.path.splitext(self.hdfpath) + + if extension == ".h5": + temp = self.hdfpath[:-3] + + self.thresholdname = temp + '_thresholded' + '.h5' + self.segmentname = temp + '_segmented' + '.h5' + self.predictname = temp + '_predicted' + '.h5' + #SJR: Mask is a tiff file + elif extension == '.tiff' or extension == '.tif': + #SJR: Careful, self.hdfpath is a tif file + im = skimage.io.imread(self.hdfpath) + print('Inithdf',im.shape) + imdims = im.shape + if len(imdims) == 3 and imdims[2] < imdims[0] and imdims[2] < imdims[1]: # num pages should be smaller than x or y dimension, very unlikely not to be the case + im = np.moveaxis(im, -1, 0) # move last axis to first + + with h5py.File(filenamewithpath + '.h5', 'w') as hf: + hf.create_group('FOV0') + + if im.ndim==2: + hf.create_dataset('/FOV0/T0', data = im, compression = 'gzip') + elif im.ndim==3: + nim = im.shape[0] + for i in range(nim): + hf.create_dataset('/FOV0/T{}'.format(i), + data = im[i,:,:], compression = 'gzip') + + #SJR addition: + self.thresholdname = filenamewithpath + '_thresholded' + '.h5' + hf = h5py.File(self.thresholdname,'w') + hf.create_group('FOV0') + hf.close() + + self.segmentname = filenamewithpath + '_segmented' + '.h5' + hf = h5py.File(self.segmentname,'w') + hf.create_group('FOV0') + hf.close() + + self.predictname = filenamewithpath + '_predicted' + '.h5' + hf = h5py.File(self.predictname,'w') + hf.create_group('FOV0') + hf.close() + + self.hdfpath = filenamewithpath + '.h5' + + + + -# def Createhdf(self): @@ -206,10 +257,8 @@ class Reader: mask = np.array(file['/{}/{}'.format(self.fovlabels[currentFOV], self.tlabels[currentT])], dtype = np.uint16) file.close() - return mask - else: # change with Matthias code! @@ -322,6 +371,8 @@ class Reader: with ND2Reader(self.nd2path) as images: images.default_coords['v'] = currentfov images.default_coords['c'] = self.default_channel + print('Debug in InteractionDisk_temp',currentfov) + print('Debug in InteractionDisk_temp',self.default_channel) images.iter_axes = 't' im = images[currentT] @@ -329,31 +380,35 @@ class Reader: with pytiff.Tiff(self.nd2path) as handle: handle.set_page(currentT) im = handle[:] + print('Debug in InteractionDisk_temp',im.shape) +# print('Debug in InteractionDisk_temp',im[0,0],np.amin(im),np.amax(im)) elif self.isfolder: filelist = os.listdir(self.nd2path) + for f in filelist: + if f.startswith('.'): + filelist.remove(f) im = skimage.io.imread(self.nd2path + '/' + filelist[currentT]) - - return np.array(im, dtype = np.uint16) + + # be careful here, the output is converted to 16, not sure it's a good idea. + outputarray = np.array(im, dtype = np.uint16) + print("Time point", currentT, ". Image properties: ", np.mean(outputarray), " (mean), ", np.std(outputarray), " (std), ", np.median(outputarray), " (median).") + return outputarray def LoadSeg(self, currentT, currentFOV): - - + file = h5py.File(self.segmentname, 'r+') if self.TestTimeExist(currentT,currentFOV,file): mask = np.array(file['/{}/{}'.format(self.fovlabels[currentFOV], self.tlabels[currentT])], dtype = np.uint16) file.close() - return mask - - + else: zeroarray = np.zeros([self.sizey, self.sizex],dtype = np.uint16) file.create_dataset('/{}/{}'.format(self.fovlabels[currentFOV], self.tlabels[currentT]), data = zeroarray, compression = 'gzip', compression_opts = 7) - file.close() return zeroarray @@ -452,6 +507,7 @@ class Reader: im = self.LoadOneImage(currentT, currentFOV) + im = im*1.0; # SJR: for some reason has to be float64 pred = nn.prediction(im) file.create_dataset('/{}/{}'.format(self.fovlabels[currentFOV], self.tlabels[currentT]), data = pred, compression = 'gzip', diff --git a/init/InitButtons.py b/init/InitButtons.py index 538ff22745ca4af58909be80fcdcc110b76d9b5c..ff5a288d04fa02cc7579a268c793d43e90bd4e30 100644 --- a/init/InitButtons.py +++ b/init/InitButtons.py @@ -5,6 +5,8 @@ Initializing all the buttons in this file. from PyQt5.QtWidgets import QWidget, QPushButton, QShortcut, QComboBox, QCheckBox, QLineEdit, QStatusBar from PyQt5 import QtGui from PyQt5.QtCore import pyqtSignal, QObject, Qt +import numpy as np + def Init(parent): @@ -44,6 +46,9 @@ def Init(parent): parent.button_nextframe.setToolTip("Use right arrow key for shortcut") parent.button_nextframe.setMaximumWidth(150) parent.button_nextframe.setShortcut(Qt.Key_Right) + # if there is only one picture than this button is disabled + if np.all(parent.nextframe == 0): + parent.button_nextframe.setEnabled(False) # parent.buttonlist.append(parent.button_nextframe) # parent.button_nextframe.setShortcutAutoRepeat(False) diff --git a/packages b/packages.txt similarity index 88% rename from packages rename to packages.txt index 8e27001716ac8e7e3c2dd4c04b7973366962e3e4..656250e1c91619483f60f53fc866116f8a23d048 100644 --- a/packages +++ b/packages.txt @@ -7,4 +7,4 @@ install scikit-image install openpyxl install Tensorflow==1.9.0 install Keras -install pytiff +install opencv-python diff --git a/tmp/test/image/0.png b/tmp/test/image/0.png new file mode 100644 index 0000000000000000000000000000000000000000..d4ea70ffa96e99a8336fca5710645b653023abf0 Binary files /dev/null and b/tmp/test/image/0.png differ diff --git a/to-do.txt b/to-do.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f5d1b57fb751bd4712748e9fa2868854c197137 --- /dev/null +++ b/to-do.txt @@ -0,0 +1 @@ +if user chooses .tif mask, check whether .h5 mask exists and warn that will be overwritten diff --git a/unet/data.py b/unet/data.py index 2f37a4a0caa59bbc0b953616f05d9deea7d98951..215a1ecb82f784bda1dfe322a300260318b162d7 100644 --- a/unet/data.py +++ b/unet/data.py @@ -22,6 +22,11 @@ Pedestrian = [64,64,0] Bicyclist = [0,128,192] Unlabelled = [0,0,0] +# SJR: +import matplotlib.pyplot as plt +import matplotlib.image as mpimg + + COLOR_DICT = np.array([Sky, Building, Pole, Road, Pavement, Tree, SignSymbol, Fence, Car, Pedestrian, Bicyclist, Unlabelled]) diff --git a/unet/neural_network.py b/unet/neural_network.py index 5a73bdf28b00371a3c3f481e4bd2a44d525d1211..7d56dfee6bac7e0b6c2f55dbd9ce5ae004eb09e4 100644 --- a/unet/neural_network.py +++ b/unet/neural_network.py @@ -14,6 +14,10 @@ import numpy as np import skimage from skimage import io +# SJR: +import matplotlib.pyplot as plt +import matplotlib.image as mpimg + def create_directory_if_not_exists(path): """ Create in the file system a new directory if it doesn't exist yet. @@ -50,6 +54,12 @@ def prediction(im): Return: res: the predicted distribution of probability of the labels (numpy array) """ + + + imsize=im.shape + im = im[0:2048,0:2048] #crop image if too large + im = np.pad(im,((0, 2048 - imsize[0] ),(0, 2048 - imsize[1] )),constant_values=0) # pad with zeros if too small + path_test = './tmp/test/image/' create_directory_if_not_exists(path_test) @@ -65,61 +75,16 @@ def prediction(im): model = unet( pretrained_weights = None, input_size = (2048,2048,1) ) - model.load_weights('./unet_weights_batchsize_25_Nepochs_100_full.hdf5') +# model.load_weights('unet/unet_weights_batchsize_25_Nepochs_100_full.hdf5') + model.load_weights('unet/unet_weights_batchsize_25_Nepochs_100_SJR0_9.hdf5') results = model.predict_generator(testGene, 1, verbose=1) -# res = reconstruct_result(236, results[:,10:246,10:246,0], resized_shape,original_shape) -# if the size of the image is not 2048x2048, the difference between 2048x2048 -# and the original size is cut off here. (in the prediction it is -# artificially augmented from the original size to 2048x2048) - - index_x = 2048-len(im[:,0]) - index_y = 2048-len(im[0,:]) - #this bolean values are true if index_x(y)/2 else they are false. - #they are initialized to false. - flagx = False - flagy = False - - #test if x dimension of im is not already the max size - if index_x != 0: - #if index_x not the 0 (im has not max size in x axis) then the - #the difference is divided by two, index_x is the difference between - #size of im in x axis and max size 2048 - ind_x = index_x/2 - if index_x%2 == 0: - ind_x = int(ind_x) - flagx = True - else: - #if already max size, it is set to 0 - ind_x = 0 - flagx = True - - #test if y dimension of im is not already the max size - if index_y != 0: - #if index_y not the 0 (im has not max size in y axis) then the - #the difference is divided by two, index_y is the difference between - #size of im in y axis and max size 2048 - ind_y = index_y/2 - if index_y%2 == 0: - ind_y = int(ind_y) - flagy = True - else: - ind_y = 0 - flagy = True - - - if flagx and flagy: - res = results[0,ind_x:2048-ind_x,ind_y:2048-ind_y,0] - return res - elif not(flagx) and flagy: - res = results[0,int(ind_x):2048-(int(ind_x)+1),ind_y:2048-ind_y,0] - return res - elif flagx and not(flagy): - res = results[0,ind_x:2048-ind_x, int(ind_y):2048-(int(ind_y)+1),0] - return res - else: - res = results[0, int(ind_x):2048-(int(ind_x)+1),int(ind_y):2048-(int(ind_y)+1),0] - return res + res = results[0,:,:,0] #get rid of strange 1st and 4th indices + res = res[0:imsize[0],0:imsize[1]] #crop if needed, e.g., im was smaller than 2048x2048 + res = np.pad(res,((0, max(0,imsize[0] - 2048) ),(0, max(0,imsize[0] - 2048) )),constant_values=0) # pad with zeros if too small + + return res + diff --git a/unet/segment.py b/unet/segment.py old mode 100755 new mode 100644 index 8a4c805b522b43f1a0eaba283deaac5550d1cd32..59545e1cb6c158e8cadb4d79c06fcf8e595d3cf4 --- a/unet/segment.py +++ b/unet/segment.py @@ -87,10 +87,13 @@ def segment(th, pred, min_distance=10, topology=None): #SJR: added pred to evalu objcoords[obj1,1] = max(objcoords[obj1,1],objcoords[obj2,1]) objcoords[obj1,2] = min(objcoords[obj1,2],objcoords[obj2,2]) objcoords[obj1,3] = max(objcoords[obj1,3],objcoords[obj2,3]) + print("Merged cell ",obj1+1," and ",obj2+1,".") + wshclean = wshclean + maskoriobj1*objcounter #else: # display(obj1+1,' no longer there.') return wshclean +# return wsh