From 251882dbf0892fb17227124873be7e38323fc12d Mon Sep 17 00:00:00 2001
From: lpbsscientist <lpbsscientist@gmail.com>
Date: Thu, 14 Jan 2021 11:04:24 +0100
Subject: [PATCH] Sahand: New Merge Cells tool.

---
 GUI_main.py         | 76 ++++++++++++++++++++++++++++++++++++++++++++-
 init/InitButtons.py | 12 ++++++-
 init/InitLayout.py  |  1 +
 3 files changed, 87 insertions(+), 2 deletions(-)

diff --git a/GUI_main.py b/GUI_main.py
index f755688..1dbc1f8 100644
--- a/GUI_main.py
+++ b/GUI_main.py
@@ -228,9 +228,12 @@ class App(QMainWindow):
         self.button_hidemask = QCheckBox('Hide mask')
         self.buttonlist.append(self.button_hidemask)
         
-        self.button_split = QPushButton('Split Cell')
+        self.button_split = QPushButton('Split cell')
         self.buttonlist.append(self.button_split)
         
+        self.button_mergewithneighbors = QPushButton('Merge cells')
+        self.buttonlist.append(self.button_mergewithneighbors)
+        
         self.button_nextframe = QPushButton("Next time frame")
         self.buttonlist.append(self.button_nextframe)
         
@@ -1475,6 +1478,77 @@ class App(QMainWindow):
             self.SaveMask()
             
             
+    def MergeWithNeighbors(self):
+        """This function is called when the button Merge With Neighbors 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.PerformMergeWithNeighbors. 
+        This function will then merge the cell selected by the user with
+        the click with all (touching) neighbors.
+        """
+        
+        # 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_mergewithneighbors)
+        
+        # connects the event "press mouse button" in the matplotlib plot 
+        # (picture) to the function self.PerformMergeWithNeighbors
+        self.id = self.m.mpl_connect('button_press_event', self.PerformMergeWithNeighbors)
+        
+        
+    def PerformMergeWithNeighbors(self, event):
+        """This function is called after the user has selected
+        the button Merge With Neighbors and clicked in the picture to select
+        the desired cell to start the merger.
+        
+        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)
+            # get the ID of the selected cell
+            selectedcell_ID = self.m.plotmask[newy,newx]
+            # binarize the existing mask and number ("label") each component
+            labeled_binarized_mask = skimage.measure.label(self.m.plotmask > 0)
+            # select the component pixels that corresponds to the selected point
+            flood_indices=(labeled_binarized_mask==labeled_binarized_mask[newy,newx])
+            # set the mask pixels that correspond to the component to the cell ID
+            self.m.plotmask[flood_indices] = selectedcell_ID
+                    
+            # updates the plot to see the modification.
+            self.m.updatedata()
+                    
+        self.Enable(self.button_mergewithneighbors)
+        self.button_mergewithneighbors.setChecked(False)
+        self.m.ShowCellNumbers()
+        self.SaveMask()
+        self.ClearStatusBar()
+        
+        
 # -----------------------------------------------------------------------------
 # BUTTON ENABLE / DISABLE
     
diff --git a/init/InitButtons.py b/init/InitButtons.py
index f4d013b..3dff210 100644
--- a/init/InitButtons.py
+++ b/init/InitButtons.py
@@ -161,7 +161,7 @@ def Init(parent):
 #    parent.button_changecellvalue.setStatusTip('')
     parent.button_changecellvalue.setStatusTip('Change ID value of one cell. Use left click to select one cell and enter a new ID value.')
 
-    # EXCHANGE CELL VALUES
+    # SPLIT CELLS
     parent.button_split.toggle()
     parent.button_split.setCheckable(True)
     parent.button_split.setEnabled(True)
@@ -171,6 +171,16 @@ def Init(parent):
     parent.button_split.setToolTip("Shortcut: X")
     parent.button_split.setStatusTip('Split a selected cell into two. First left-click to select the cell, then draw a polygon around an area to split it off.')
 
+    # MERGE CELLS
+    parent.button_mergewithneighbors.toggle()
+    parent.button_mergewithneighbors.setCheckable(True)
+    parent.button_mergewithneighbors.setEnabled(True)
+    parent.button_mergewithneighbors.clicked.connect(parent.MergeWithNeighbors)
+    parent.button_mergewithneighbors.setMaximumWidth(150)
+    parent.button_mergewithneighbors.setShortcut("F")
+    parent.button_mergewithneighbors.setToolTip("Shortcut: F")
+    parent.button_mergewithneighbors.setStatusTip('Merge a cell with its immediate neighbors. Left-click to select the cell or right-click to abort.')
+
     # MAKE THE CELL Correspondence
     parent.button_cellcorrespondence.setEnabled(False)
     parent.button_cellcorrespondence.setCheckable(True)
diff --git a/init/InitLayout.py b/init/InitLayout.py
index 18af51f..06e73da 100644
--- a/init/InitLayout.py
+++ b/init/InitLayout.py
@@ -44,6 +44,7 @@ def Init(parent):
     hboxcorrectionsbuttons.addWidget(parent.button_add_region)
     hboxcorrectionsbuttons.addWidget(parent.button_newcell)
     hboxcorrectionsbuttons.addWidget(parent.button_split)
+    hboxcorrectionsbuttons.addWidget(parent.button_mergewithneighbors)
     hboxcorrectionsbuttons.addWidget(parent.button_drawmouse)
     hboxcorrectionsbuttons.addWidget(parent.button_eraser)
     hboxcorrectionsbuttons.addWidget(parent.label_brushsize)
-- 
GitLab