예제 #1
0
    def initUI(self):
        self.parent.title("Gripper Demo")
        self.style = Style()
        self.style.theme_use("default")
        self.pack(fill=BOTH, expand=1)

        #scale1 - Gripper Pos
        ScaleGripperPos = Scale(self,
                                from_=0,
                                to=100,
                                orient=HORIZONTAL,
                                length=300,
                                resolution=1,
                                command=self.onScaleGripperPos)
        ScaleGripperPos.grid(row=1, column=2)

        self.label = Label(self, text="Gripper Pos ")
        self.label.grid(row=1, column=1)

        self.GripperPos = IntVar()
        self.labelScaleGripperPos = Label(self,
                                          text=0,
                                          textvariable=self.GripperPos)
        self.labelScaleGripperPos.grid(row=1, column=3)

        #scale2 - X ROTATION
        scaleRotX = Scale(self,
                          from_=0,
                          to=650,
                          orient=HORIZONTAL,
                          length=300,
                          resolution=1,
                          command=self.onScaleXAxisRot)
        scaleRotX.grid(row=2, column=2)
        scaleRotX.set(450)

        self.label = Label(self, text="X Axis Rotation ")
        self.label.grid(row=2, column=1)

        self.labelRotX = Label(self)
        self.labelRotX.grid(row=2, column=3)

        #Entry1 - Force
        self.entryForce = Entry(self)
        self.entryForce.grid(row=3, column=2)
        self.entryForce.insert(0, "50")  #35=700

        #self.forceString = StringVar()
        #self.forceString.set(1023);
        self.labelForce = Label(self)
        self.labelForce.grid(row=3, column=3)
        #self.entryForce.insert(1023,self.force.get())
        #self.entry1.delete(0,END) #delete entry text
        #entry.bind("<Return>", callback) #calls callback function after hit "enter"

        self.label = Label(self, text="Current (A)")
        self.label.grid(row=6, column=1)
        self.labelCurrent = Label(self)
        self.labelCurrent.grid(row=6, column=3)

        #Entry2 - Speed
        self.entrySpeed = Entry(self)
        self.entrySpeed.grid(row=4, column=2)
        self.entrySpeed.insert(0, "4000")
        self.labelSpeed = Label(self)
        self.labelSpeed.grid(row=4, column=3)

        #Entry2 - Active Distance
        self.entryDistance = Entry(self)
        self.entryDistance.grid(row=5, column=2)

        #Entry3 - Send Command
        self.entrySendCommand = Entry(self)
        self.entrySendCommand.grid(row=8, column=2)

        self.activeDistance = IntVar()
        self.activeDistance.set(15)
        self.labelActiveDistance = Label(self)
        self.labelActiveDistance.grid(row=5, column=3)
        self.entryDistance.insert(0, self.activeDistance.get())

        #Button1 - close
        self.button1 = Button(self, text="close", command=self.gripperClose)
        self.button1.grid(row=7, column=1)
        #Button2 - open
        self.button2 = Button(self, text="open", command=self.gripperOpen)
        self.button2.grid(row=7, column=2)
        #Button3 - home
        self.button3 = Button(self,
                              text="home",
                              command=self.gripperHomeRoutine)
        self.button3.grid(row=7, column=3)
        #Button4 - send command
        self.button4 = Button(self, text="send", command=self.sendCommand)
        self.button4.grid(row=8, column=3)
        #Button3
        self.buttonForce = Button(self,
                                  text="forceSetPoint (mg)",
                                  command=self.gripperSetForce)
        self.buttonForce.grid(row=3, column=1)
        #Button4
        self.buttonSpeed = Button(self,
                                  text="speedSetPoint (mseg/close)",
                                  command=self.gripperSetSpeed)
        #80degree each finger = to move 40 degree to close
        self.buttonSpeed.grid(row=4, column=1)
        #Button5
        self.buttonDistance = Button(self,
                                     text="distanceSetPoint (Cm)",
                                     command=self.gripperSetDistance)
        self.buttonDistance.grid(row=5, column=1)
예제 #2
0
    def configure_images(self,
                         pic_frame,
                         image_paths):
        """Create widgets to place images, descriptions and slice scrollers."""

        # create a sub frame to display the images
        self._imagelabel = [None for _ in range(self.image_nb)]
        self._image_view = [None for _ in range(self.image_nb)]
        _descrlabel = [None for _ in range(self.image_nb)]

        # descriptions of the images defaults to their path basenames
        descriptions = [os.path.basename(image_paths[i]) 
                        for i in range(self.image_nb)]

        self.histogram_sliders = []
        for i in range(self.image_nb):

            _sub_pic_frame = Frame(pic_frame)
            _sub_pic_frame.grid(column=int(i%2),
                                row=int(i/2),
                                pady=5)

            # set Label for a description above the images
            _descrlabel[i] = Label(_sub_pic_frame,
                                   text=descriptions[i])
            _descrlabel[i].grid(column=0, row=0)


            # set Label to depict the images
            self._imagelabel[i] = Label(_sub_pic_frame)
            self._imagelabel[i].grid(column=0, row=1)


            # set Scales for the intensity slides
            _sub_sub_frame = Frame(_sub_pic_frame)
            _sub_sub_frame.grid(column=0,
                                row=2)

            min_val = np.min(self.images_original[i])
            max_val = np.max(self.images_original[i])

            intensity_scale1 = Scale(_sub_sub_frame,
                                     from_=min_val,
                                     to=max_val/2,
                                     orient=HORIZONTAL)
            intensity_scale1.set(min_val)
            intensity_scale1.grid(column=0,
                                  row=0,
                                  sticky=['e', 'w', 's'])

            intensity_scale2 = Scale(_sub_sub_frame,
                                     from_=max_val/2,
                                     to=max_val,
                                     orient=HORIZONTAL)
            intensity_scale2.set(max_val)
            intensity_scale2.grid(column=1,
                                  row=0,
                                  sticky=['e', 'w', 's'])

            self.histogram_sliders.append(intensity_scale1)
            self.histogram_sliders.append(intensity_scale2)
            intensity_scale1.bind("<B1-Motion>", self.change_intensity)
            intensity_scale2.bind("<B1-Motion>", self.change_intensity)

            # Attach commands to the image frames
            self._imagelabel[i].bind("<Button-1>", self.click_image)
            self._imagelabel[i].bind("<Button-3>", self.label_dropdown)
            self._imagelabel[i].bind("<Button 4>", self.slice_up)
            self._imagelabel[i].bind("<Button 5>", self.slice_down)
            self._imagelabel[i].bind("<B1-Motion>", self.motion_image)
            self._imagelabel[i].bind("<Double-Button-1>", self.select_connected)
예제 #3
0
class VisualVolumes(MyFrame):
    #Paths need to be changed when used in a different environment
    #Also segmentation accepts only one file now!
    
    def __init__(self,
                 image_paths=None,
                 segm_path=None,
                 supervoxel_id_path=None,
                 topframe=None):

        MyFrame.__init__(self,
                         topframe=None)
        Style().theme_use('clam')
        self.set_title('Visualise Volumes')


        self.set_variables(image_paths,
                           segm_path=segm_path,
                           supervoxel_id_path=supervoxel_id_path)

        self.create_ui(image_paths=image_paths,
                       supervoxel_id_path=supervoxel_id_path)


    ########## variable setting ###########################F

    def set_variables(self,
                      image_paths,
                      segm_path=None,
                      supervoxel_id_path=None):
        """Set initial alpha for opacity, boundaries, undo-redo stacks,
        and paths for modalities, segmentation and supervoxels"""

        #Alpha value for opacity initialization
        self.alpha = 0.2

        self._axis = 0

        self.show_supervoxels = True

        self._set_images(segm_path, image_paths, supervoxel_id_path)

        # set boundaries for all images:
        self.boundaries = ms.get_boundaries_series(image_paths)

        # set stacks for CTRL+Z and CTRL+Y
        # CTRL+Z to undo
        # CTRL+Y to redo
        self.undo_stack = []
        self.redo_stack = []
        self.image_nb = len(image_paths)
        self.selected_id_list = []
        #Keybindings for undo and redo actions
        self.bind('<Control-z>', self.undo_action)
        self.bind('<Control-y>', self.redo_action)
        self.bind('<t>', self.toggle_segm)     
        self.bind("<h>", self.set_healthy)
        self.bind("<r>", self.unselect_all)
        self.bind("<c>", self.print_com)
        self.bind("<i>", self.inverse_selection)
        for j in range(len(label_hot_keys)):
            self.bind("<%s>" % label_hot_keys[j],
                     lambda event, arg0=j : self.change_label(arg0))   
        self.bind("<Right>", self.slice_up)
        self.bind("<Left>", self.slice_down)
        self.focus_set()

    def _set_images(self, segm_path, image_paths, supervoxel_id_path):
        """ Set and check image and segmentation arrays and dimensions. """

        # Shapes for all modalities
        shapes = [oitk.get_itk_array(path).shape \
                  for path in image_paths]
        if len(set(shapes)) != 1:
            err = 'Images are not of same dimension'
            raise  ValueError(err)
        self.dim = shapes[0]

        # set the images and the image paths
        self.images = [oitk.get_itk_array(path) \
                       for path in image_paths]
        self.images_original = np.copy(self.images)

        # Get segmentation from segmentation path if given
        self.segm = None
        self.segm_path = None
        if segm_path is not None:
            self.segm = oitk.get_itk_array(segm_path)
            self.segm_path = segm_path

        # Get supervoxels from supervoxel path if given
        self.supervoxel_border = None
        self.supervoxel_id = None
        if supervoxel_id_path is not None:

            # get supervoxels and adapt if segmentation is at hand
            self.supervoxel_id = oitk.get_itk_array(supervoxel_id_path)
            if self.segm is not None:
                self.supervoxel_id = utils.adapt_borders(self.segm, 
                                                         self.supervoxel_id)

            # get borders of the supervoxels
            self.supervoxel_border = utils.get_borders(self.supervoxel_id)

    ########## Frame setting ############

    def create_ui(self, image_paths, supervoxel_id_path):
        """This function creates the UI elements."""

        sub_frame = Frame(self)
        sub_frame.grid(column=1,
                       row=0,
                       columnspan=self.image_nb)

        # create a sub frame to select the image slices that are displayed
        slice_frame = Frame(sub_frame)
        slice_frame.grid(column=0,
                         row=1,
                         columnspan=self.image_nb)

        pic_frame = Frame(sub_frame)
        pic_frame.grid(column=0,
                       row=0,
                       columnspan=self.image_nb)

        self.configure_images(pic_frame, image_paths)
        self.add_slice_bar(slice_frame)
        self.set_optional_buttons(supervoxel_id_path)


    def configure_images(self,
                         pic_frame,
                         image_paths):
        """Create widgets to place images, descriptions and slice scrollers."""

        # create a sub frame to display the images
        self._imagelabel = [None for _ in range(self.image_nb)]
        self._image_view = [None for _ in range(self.image_nb)]
        _descrlabel = [None for _ in range(self.image_nb)]

        # descriptions of the images defaults to their path basenames
        descriptions = [os.path.basename(image_paths[i]) 
                        for i in range(self.image_nb)]

        self.histogram_sliders = []
        for i in range(self.image_nb):

            _sub_pic_frame = Frame(pic_frame)
            _sub_pic_frame.grid(column=int(i%2),
                                row=int(i/2),
                                pady=5)

            # set Label for a description above the images
            _descrlabel[i] = Label(_sub_pic_frame,
                                   text=descriptions[i])
            _descrlabel[i].grid(column=0, row=0)


            # set Label to depict the images
            self._imagelabel[i] = Label(_sub_pic_frame)
            self._imagelabel[i].grid(column=0, row=1)


            # set Scales for the intensity slides
            _sub_sub_frame = Frame(_sub_pic_frame)
            _sub_sub_frame.grid(column=0,
                                row=2)

            min_val = np.min(self.images_original[i])
            max_val = np.max(self.images_original[i])

            intensity_scale1 = Scale(_sub_sub_frame,
                                     from_=min_val,
                                     to=max_val/2,
                                     orient=HORIZONTAL)
            intensity_scale1.set(min_val)
            intensity_scale1.grid(column=0,
                                  row=0,
                                  sticky=['e', 'w', 's'])

            intensity_scale2 = Scale(_sub_sub_frame,
                                     from_=max_val/2,
                                     to=max_val,
                                     orient=HORIZONTAL)
            intensity_scale2.set(max_val)
            intensity_scale2.grid(column=1,
                                  row=0,
                                  sticky=['e', 'w', 's'])

            self.histogram_sliders.append(intensity_scale1)
            self.histogram_sliders.append(intensity_scale2)
            intensity_scale1.bind("<B1-Motion>", self.change_intensity)
            intensity_scale2.bind("<B1-Motion>", self.change_intensity)

            # Attach commands to the image frames
            self._imagelabel[i].bind("<Button-1>", self.click_image)
            self._imagelabel[i].bind("<Button-3>", self.label_dropdown)
            self._imagelabel[i].bind("<Button 4>", self.slice_up)
            self._imagelabel[i].bind("<Button 5>", self.slice_down)
            self._imagelabel[i].bind("<B1-Motion>", self.motion_image)
            self._imagelabel[i].bind("<Double-Button-1>", self.select_connected)

    def add_slice_bar(self, slice_frame):
        """Add a slice selection options to slice_frame.

        Returns
        -------
        this_slice_label_number : Label
            the field displaying the current slice number
        this_new_slice : Entry
            the field allowing the user to fill in a slice number
        new_value : int
            the initial slice number to be set

        """

        # Have a line displaying slice number
        _slice_label = Label(slice_frame, text='Slice displayed : ')
        _slice_label.grid(column=0, row=0, sticky=['w', 'e'])
        this_slice_label_number = Label(slice_frame)
        this_slice_label_number.grid(column=1, row=0,
                                     sticky=['w', 'e'])

        # Allow to change slice number
        _goto = Label(slice_frame, text=' - go to slice :')
        _goto.grid(column=2, row=0, sticky=['w', 'e'])

        this_new_slice = Entry(slice_frame, width=6)
        this_new_slice.bind('<Return>', self.goto_slice)
        this_new_slice.bind('<KP_Enter>', self.goto_slice)
        this_new_slice.grid(column=3, row=0, sticky=['w', 'e'])

        self.image_scale = (self.screen_width - 200) / 4

        # Allow to scroll through the slices
        self._slice_scroll = lsb.LinkedScrollBar(master=slice_frame,
                                                 command=self.disp_im,
                                                 minVal=self._get_min_slice(),
                                                 maxVal=self._get_max_slice(),
                                                 step=1,
                                                 orient='horizontal')
        self._slice_scroll.grid(column=0,
                                row=1,
                                columnspan=self.image_nb,
                                sticky=['e', 'w', 's'])


        self._slice_label_number = this_slice_label_number
        self._new_slice = this_new_slice
        self.reset_slice_scroll()

    ##### allow to show segmentations, change axis and quit #########

    def set_optional_buttons(self, supervoxel_id_path=None):
        """ Set bottoms to quit, change axis, show and hide segmentation, ...
        at the upper row of the main frame.
        """

        _sub_frame1 = Frame(self)
        _sub_frame1.grid(column=0,
                         row=0,
                         padx=10,
                         sticky=['n', 'e', 'w'])

        _sub_sub_frame1 = Frame(_sub_frame1)
        _sub_sub_frame1.grid(column=0,
                             row=0,
                             sticky=['e', 'w'],
                             pady=10)

        ind = 0
        self.button_axis = Button(_sub_sub_frame1,
                                  text="Change axis",
                                  command=self.change_axis)
        self.button_axis.grid(column=0, row=ind, pady=3)
        
        ind += 1
        self.button_axis = Button(_sub_sub_frame1,
                                  text="Mirror Images",
                                  command=self.mirror_image)
        self.button_axis.grid(column=0, row=ind, pady=3)

        ind = 0
        if self.segm is not None:

            _sub_sub_frame2 = Frame(_sub_frame1)
            _sub_sub_frame2.grid(column=0,
                                 row=1,
                                 sticky=['e', 'w'],
                                 pady=10)

            _sub_sub_frame3 = Frame(_sub_frame1)
            _sub_sub_frame3.grid(column=0,
                                 row=2,
                                 sticky=['e', 'w'],
                                 pady=10)

            self.button_supervoxels = Button(_sub_sub_frame2,
                                             text="Show/Hide supervoxels",
                                             command=self.change_supervoxels)
            self.button_supervoxels.grid(column=0,
                                         row=ind,
                                         sticky=['w', 'n', 'e'])

            if supervoxel_id_path is None:
                self.button_supervoxels['state'] = 'disabled'
            ind += 1

            self.tumor_checkbox_label = Label(_sub_sub_frame2,
                                              text="Display tumor type: ",
                                              relief=FLAT)
            self.tumor_checkbox_label.grid(column=0, row=ind)

            ind += 1
            self.tumor_cb = []
            for i in range(len(labels)):
                tumor_button = IntVar()
                this_text = '%s (%s <%s>)' % (labels[i], 
                                              label_colors_d[i], 
                                              label_hot_keys[i+1])
                button = Checkbutton(_sub_sub_frame2,
                                        text=this_text,
                                        variable=tumor_button,
                                        command=lambda arg0=i: self.change_segm(arg0))
                button.grid(column=0, row=ind, sticky=['w', 'n', 'e'])
                self.tumor_cb.append(tumor_button)
                ind += 1
                
            self.all_tumor_bc = IntVar()
            button = Checkbutton(_sub_sub_frame2,
                                    text="All tumors",
                                    variable=self.all_tumor_bc,
                                    command=lambda : self.change_segm(3))
            button.grid(column=0,
                        row=ind,
                        sticky=['w', 'n', 'e'])

            ind += 1
            self.no_tumor_bc = IntVar()
            button = Checkbutton(_sub_sub_frame2,
                                    text="No tumors",
                                    variable=self.no_tumor_bc,
                                    command=lambda : self.change_segm(4))
            button.grid(column=0,
                           row=ind,
                           sticky=['w', 'n', 'e'])

            ind += 1
            alpha_label = Label(_sub_sub_frame2, text="Opacity:")
            alpha_label.grid(column=0, row=ind)
            self.alpha_scale = Scale(_sub_sub_frame2,
                                     from_=0.0,
                                     to=1.0,
                                     command=self.set_alpha,
                                     orient=HORIZONTAL)
            ind += 1
            self.alpha_scale.set(self.alpha)
            self.alpha_scale.grid(column=0,
                                  row=ind,
                                  columnspan=self.image_nb,
                                  sticky=['w', 'n', 'e'])

            ind = 0
            self.button_save_segm = Button(_sub_sub_frame3,
                                           text="Save segmentation",
                                           command=self.save_segm)
            self.button_save_segm.grid(column=0, row=ind, sticky=['w', 'n', 'e'])

            ind += 1
            self.button_open_segm = Button(_sub_sub_frame3,
                                           text="Open segmentation",
                                           command=self.open_segm)
            self.button_open_segm.grid(column=0, row=ind, sticky=['w', 'n', 'e'])


    #################### Display images ###########################

    def disp_im(self):
        """use the size, slice and zoom to display the image"""
        self.focus_set()
        slice_index = int(self._slice_scroll.val)

        for i in range(self.image_nb):
            pix = np.array(\
                    ms.get_slice(self.images[i],
                                 boundaries=self.boundaries,
                                 visual_center=slice_index,
                                 axis=self._axis),
                    dtype='float')

            temp_im, im_size = pil.get_image_pil(pix, 
                                                 self.image_scale, 
                                                 return_image_size=True)
            self.image_size = im_size
            temp_im = temp_im.convert('RGB')

            if self.segm is not None:
                temp_im = self.add_segmentation(temp_im, slice_index)
                
            if self.show_supervoxels and type(self.supervoxel_border) is np.ndarray:
                temp_im = self.add_supervoxels(temp_im, slice_index)

            # create the 2d view with or without the bounding box
            self._image_view[i] = ImageTk.PhotoImage(temp_im)
            self._imagelabel[i]['image'] = self._image_view[i]

        # update slice label
        self._slice_label_number['text'] = str(int(self._slice_scroll.val))

    def add_segmentation(self, image, slice_ind=None):
        """ Add a segmentation to the image (colors will be overlaid). """

        #Segmentation is separated into binary segmentations
        #Also, segm contains 3 binary segmentations
        if len(self.selected_id_list) > 0:
            segm = utils.get_separate_labels(self.segm_disp, length=len(labels)+1)
        else:
            segm = utils.get_separate_labels(self.segm, length=len(labels))
        r, g, b = image.convert('RGB').split()
        rgb = [r, g, b]

        #Variable that contains selected colors
        colors = [None for _ in range(len(segm))]

        #Add labels if their check box is selected
        if hasattr(self, 'tumor_cb'):
            for i in range(len(labels)):
                if self.tumor_cb[i].get() == 1:
                    colors[i] = label_colors[i]

        if len(colors)==4:
            colors[3] = selected

        #Do the painting with respect to colors variable
        for i in range(len(segm)):
            if colors[i] is None:
                continue
            pix = np.array(ms.get_slice(segm[i],
                                        boundaries=self.boundaries,
                                        visual_center=slice_ind,
                                        axis=self._axis))
            pix[pix > 0.5] = 1
            pix = pix.astype('uint8')

            if np.any(pix):
                color_region = pil.get_image_pil(pix, self.image_scale)
                rgb = pil.set_color_custom(color_region, colors[i], rgb=rgb)

        #Merge operation for all
        segm_im = ImagePIL.merge("RGB", rgb)
        return ImagePIL.blend(image, segm_im, self.alpha)
    
    def add_supervoxels(self, image, slice_ind=None):
        """ Add supervoxels to the image (boundaries will be drawn)."""

        r, g, b = image.convert('RGB').split()
        pix = np.array(ms.get_slice(self.supervoxel_id,
                                    boundaries=self.boundaries,
                                    visual_center=slice_ind,
                                    axis=self._axis))

        self.supervoxel_id_slice = pix

        if np.any(pix):
            pix = pix *50000

        #Get image with supervoxels that has borders calculated with contours
        sup_im = pil.get_image_pil(pix, self.image_scale)\
                        .convert("RGB")\
                         .filter(ImageFilter.CONTOUR)\
                         .filter(ImageFilter.EDGE_ENHANCE_MORE)\
                         .filter(ImageFilter.EDGE_ENHANCE_MORE)

        r_border, g_border, b_border = sup_im.split()
        r = pil.set_color_empty(r, r_border)
        g = pil.set_color_empty(g, g_border)
        b = pil.set_color_empty(b, b_border)

        #Merge operation for all colors
        sup_im = ImagePIL.merge("RGB", (r, g, b))
        return ImagePIL.blend(image, sup_im, self.alpha)

    #################### EVENTS: Change slice ######################
        
    def reset_slice_scroll(self):

        max_slice = self._get_max_slice()
        min_slice = self._get_min_slice()
        diff = max_slice - min_slice
        new_value = int(min_slice + np.floor(diff / 2))
        self._slice_scroll.set_value(new_value)
        
    def slice_up(self, *args):
        """increase slice number"""
        new_value = self._slice_scroll.val + 1
        if new_value <= self._get_max_slice(in_boundaries=True):
            self._slice_scroll.set_value(new_value)

    def slice_down(self, *args):
        """decrease slice number"""
        new_value = self._slice_scroll.val - 1
        if new_value >= self._get_min_slice(in_boundaries=True):
            self._slice_scroll.set_value(new_value)

    def _get_max_slice(self, in_boundaries=True):
        """Gets the maximum slice of the numpy array."""
        if in_boundaries:
            return self.boundaries[self._axis][1]
        else:
            return self.dim[self._axis] - 1

    def _get_min_slice(self, in_boundaries=True):
        """Gets the minimum slice of the numpy array."""
        if in_boundaries:
            return self.boundaries[self._axis][0]
        else:
            return 0
        
    def change_axis(self):
        """It changes the axis of the image."""
        self._axis = (self._axis + 1) % 3
        self.reset_slice_scroll()
        self.disp_im()

    def mirror_image(self):
        """It mirrors the image."""
        for i in range(self.image_nb):
            self.images[i] = np.flip(self.images[i], axis=(self._axis + 1) % 3)
            self.images_original[i] = np.flip(self.images_original[i], axis=(self._axis + 1) % 3)
        if self.segm is not None:
            self.segm = np.flip(self.segm, axis=(self._axis + 1) % 3)

        if self.show_supervoxels and type(self.supervoxel_border) is np.ndarray:
            self.supervoxel_id = np.flip(self.supervoxel_id, axis=(self._axis + 1) % 3)
            self.boundaries = ms.get_boundaries_series(self.images)
        self.disp_im()
        
    def goto_slice(self, *args):
        """moves to the desired slice"""

        z = self._new_slice.get()
        max_valid_z = self._get_max_slice(in_boundaries=True)
        min_valid_z = self._get_min_slice(in_boundaries=True)
        # if not an integer
        try:
            z = int(z)
            # if out of range
            if z < 0:
                msg = 'Please select a positive slice index. ' +\
                        'Lowest non-zero slice is shown.'
                self._slice_scroll.set_value(min_valid_z)
                self._new_slice.delete(0, END)
            elif z < min_valid_z:
                msg = 'Slice %d has only zeros. ' % z
                msg += 'Lowest non-zero slice is shown.'
                self._slice_scroll.set_value(min_valid_z)
                self._new_slice.delete(0, END)
            elif z > self._get_max_slice(in_boundaries=False):
                msg = 'Slice %d exceeds the image dimension. ' % z
                msg += 'Highest non-zero slice is shown.'
                self._slice_scroll.set_value(max_valid_z)
                self._new_slice.delete(0, END)
            elif z > max_valid_z:
                msg = 'Slice %d consists of zeros. ' % z
                msg += 'Highest non-zero slice is shown.'
                self._slice_scroll.set_value(max_valid_z)
                self._new_slice.delete(0, END)
            else:
                self._slice_scroll.set_value(z)
                self._new_slice.delete(0, END)
        except ValueError as e:
            print e
            self._new_slice.delete(0, END)   
            
    ############### EVENTS : select and change #########################
    
    def click_image(self, event):
        """ Select a supervoxel and color it in blue. 
        Called when clicked on an image. """
        
        supervoxel_id = self._get_supervoxel_id(event.x, event.y)
        self._update_selected_id_list(supervoxel_id)
        
    def motion_image(self, event):
        """ Select multiple supervoxels and color it in blue. 
        Called when clicked and motioned on an image. """
        
        supervoxel_id = self._get_supervoxel_id(event.x, event.y)
        self._update_selected_id_list(supervoxel_id, unselect=False)
        
    def select_connected(self, event):
        
        supervoxel_id = self._get_supervoxel_id(event.x, event.y)
        label = self.segm[self.supervoxel_id == supervoxel_id][0]
        
        im = sitk.GetImageFromArray((self.segm==label).astype(np.int))
        connected = sitk.GetArrayFromImage(sitk.ConnectedComponent(im))
        clabel = connected[self.supervoxel_id == supervoxel_id][0]
        supervoxel_ids = list(np.unique(self.supervoxel_id[connected==clabel]))
        self._update_selected_id_list(supervoxel_ids)
        
    def unselect_all(self, *args):
        """ Unselect all selected supervoxels. """
         
        print 'Emptying selection'
        self.selected_id_list = []
        self.disp_im()
        
    def set_healthy(self, *args):
        """ Select all supervoxels in this slice and set them to 
        background. """
         
        print 'Setting all supervoxels in slice to background'
        supervoxel_ids = list(np.unique(self.supervoxel_id_slice))
        if 0 in supervoxel_ids:
            supervoxel_ids.remove(0)
        self.change_label(0, supervoxel_ids=supervoxel_ids)
        
    def inverse_selection(self, *args):
        
        all_ids = np.unique(self.supervoxel_id)
        new_ids = [sup_id for sup_id in all_ids 
                   if id not in self.selected_id_list]
        self.selected_id_list = new_ids
        self.update_segm_display()        
        
    def _get_supervoxel_id(self, eventx, eventy):
        """ Get the supervoxel id of the given mouse position. """
        
        #the size of the image:
        #0 element of image corresponds to 1 element
        #of supervoxel_id_slice and vice versa

        #converting the coordinates on the clicked image into the 
        #coordinates of the voxel
        #Since the displayed pixels range from 1 to lenght+1,
        #need to subtract 1 from the coordinates
#         print self.supervoxel_id_slice.shape
        x_coordinate_supervoxel = (eventx - 1) *\
                                  len(self.supervoxel_id_slice[0]) /\
                                  self.image_size[0]

        y_coordinate_supervoxel = (eventy - 1) *\
                                  len(self.supervoxel_id_slice) /\
                                  self.image_size[1]

        z_coordinate_supervoxel = int(self._slice_scroll.val)

        coordinates = [x_coordinate_supervoxel,
                       y_coordinate_supervoxel,
                       z_coordinate_supervoxel]
        
        selected_id = self.supervoxel_id_slice[coordinates[1], coordinates[0]]

        return selected_id
        
    def _update_selected_id_list(self, selected_id, add_to_undo=True, unselect=True):
        """ Depending whether this supervoxel is already selected, mark
        or unmark the supervoxel. """
        
        if isinstance(selected_id, list):
            if unselect:
                if all([sid in self.selected_id_list for sid in selected_id]):
                    map(self.selected_id_list.remove, selected_id)
                else:
                    self.selected_id_list.extend(selected_id)
            else:
                if not all([sid in self.selected_id_list for sid in selected_id]):
                    self.selected_id_list.extend(selected_id)
                else:
                    return #nothing changed                    
        else:
            if unselect:
                if selected_id in self.selected_id_list:
                    self.selected_id_list.remove(selected_id)
                else:
                    self.selected_id_list.append(selected_id)
            else:
                if selected_id not in self.selected_id_list:
                    self.selected_id_list.append(selected_id)
                else:
                    return #nothing changed
        print 'Selected supervoxels: %s' % str(self.selected_id_list)
            
        if add_to_undo:
            action = selected_id, None, None
            self.undo_stack.append(action)
            
        self.update_segm_display()
        
    def update_segm_display(self):
        """ Color all supervoxels with ids in self.selected_id_list blue
        in self.segm_disp. """
        
        #Selection is updated for visualisation
        self.segm_disp = self.segm.copy()
        if len(self.selected_id_list) == 1:
            mask = self.supervoxel_id == self.selected_id_list[0]            
        elif len(self.selected_id_list) > 1:
            ind1d = np.in1d(self.supervoxel_id.flatten(), self.selected_id_list)
            mask = np.reshape(ind1d, self.supervoxel_id.shape)
        else:
            mask = np.zeros_like(self.supervoxel_id)
        
        selected_idx = np.where(mask)
        self.segm_disp[selected_idx[0], selected_idx[1], selected_idx[2]] = 4
            
        self.disp_im()
        
    def print_com(self, *args):
        
        ind1d = np.in1d(self.supervoxel_id.flatten(), self.selected_id_list)
        ind3d = np.reshape(ind1d, self.supervoxel_id.shape)        
        com = spim.measurements.center_of_mass(ind3d)
        print 'Center of mass'
        print '\t com : %s' % str(com)
        if self.segm_path is not None:
            ID = os.path.basename(self.segm_path).split('.')[0]
            print '\t path : %s' % ID
            print 'com_dict["%s"] = %s' % (ID, str(com))
            
    def label_dropdown(self, event):
        """When clicking right on a supervoxel, give a drop-down list
        with labels to change to."""

        if len(self.selected_id_list) == 0:
            return

        # Adding the selection menu with radio  buttons.
        self.menu = Menu(self, tearoff=0)
        self.menu\
            .add_radiobutton(label="Background",
                             value=0,
                             command=lambda arg0=0: \
                                        self.change_label(arg0))

        self.menu\
            .add_radiobutton(label=labels[0],
                             value=3,
                             command=lambda arg0=1: \
                                        self.change_label(arg0))

        self.menu\
            .add_radiobutton(label=labels[1],
                             value=2,
                             command=lambda arg0=2: \
                                        self.change_label(arg0))
        self.menu\
            .add_radiobutton(label=labels[2],
                             value=1,
                             command=lambda arg0=3: \
                                        self.change_label(arg0))
        self.menu.tk_popup(event.x_root, event.y_root)

    def change_label(self, new_label, supervoxel_ids=None):
        """Changing the label of the supervoxel

        new label is the type of pixel 0 - background,
        #3 - edema, 2 - Non-active tumor and 1 - Active tumor

        self.segm is the array with segmentations
        self.supervoxel_ids is the the array with the supervoxels

        """
        
        empty_selected_id_list = False
        if supervoxel_ids is None:
            empty_selected_id_list = True
            supervoxel_ids = self.selected_id_list

        #Empty the redo_stack whenever segmentation is changed by user
        self.redo_stack = []

        for selected_id in (supervoxel_ids):
            #Segmentation is updated with new labels
            #Old label is saved for undo and redo actions
            region = self.supervoxel_id == selected_id
            old_label = self.segm[region]
            old_label = old_label[0]
            self.segm[region] = new_label
    
            # if the checkboxes are unselected but changed, they are automatically checked.
            if new_label > 0:
                self.tumor_cb[new_label-1].set(1)
                self.no_tumor_bc.set(0)
    
            #Actions as coordinates, old_label and new_label to go switch between segmentation states
            action = selected_id, old_label, new_label
            self.undo_stack.append(action)
            
        if empty_selected_id_list:
            self.selected_id_list = []
        self.disp_im()

    def change_intensity(self, event):
        """ Change the intensity of the images based on the hist slider."""
        slider = event.widget
        i = self.histogram_sliders.index(slider)

        # find the image index based on the slider
        image_i = 3
        if i == 0 or i == 1:
            image_i = 0
        elif i == 2 or i == 3:
            image_i = 1
        elif i == 4 or i == 5:
            image_i = 2

        original_image = self.images_original[image_i]
        image = self.images[image_i]

        if (i + 1) % 2 == 0:
            slider_upper = slider
            slider_lower = self.histogram_sliders[i - 1]
        else:
            slider_lower = slider
            slider_upper = self.histogram_sliders[i + 1]

        lower = slider_lower.get()
        upper = slider_upper.get()
        lower = np.float(lower)
        upper = np.float(upper)
        np.clip(original_image, lower, upper, image)

        np.subtract(image, lower, out=image, casting='unsafe')
        self.disp_im()

    def change_segm(self, button_ind):
        """ Show or hide the segmentation from the images."""

        # if tumor type is (un)selected, set all_tumors and no_tumors 
        # accordingly
        if button_ind <= 2:
            checked = [self.tumor_cb[i].get() for i in range(len(labels))]
            checked_sum = sum(checked)
            if checked_sum < len(labels):
                self.all_tumor_bc.set(0)
            else:
                self.all_tumor_bc.set(1)
            if checked_sum > 0:
                self.no_tumor_bc.set(0)
            else:
                self.no_tumor_bc.set(1)

        # if all_tumors or no_tumors is (un)selected, allign the other
        # buttons
        if button_ind == 3:
            for i in range(len(labels)):
                self.tumor_cb[i].set(1)
            self.all_tumor_bc.set(1)
            self.no_tumor_bc.set(0)
        if button_ind == 4:
            for i in range(len(labels)):
                self.tumor_cb[i].set(0)
            self.all_tumor_bc.set(0)
            self.no_tumor_bc.set(1)
        self.disp_im()
        
    def toggle_segm(self, *args):
        
        # if at least one tumor type is visualized, 
        # remove all tumors (set no_tumors) and supervoxels
        checked = [self.tumor_cb[i].get() for i in range(len(labels))]
        checked_sum = sum(checked)
        if checked_sum > 0:
            print 'Visualizing no tumors'
            self.change_segm(4)
        # if no tumor type is visualized, set all_tumors
        # visualize all tumors (set all_tumors) and supervoxels
        else:
            print 'Visualizing all tumors'
            self.change_segm(3)
        
    def change_supervoxels(self):
        """ Toggle between showing supervoxels or not."""
        self.show_supervoxels = not self.show_supervoxels
        self.disp_im()

    def set_alpha(self, *args):
        """ Change the opacity level."""
        self.alpha = self.alpha_scale.get()
        self.disp_im()

    def undo_action(self, *args):
        """ Execute undo action on CTRL-Z."""

        #If respective stack is not empty
        #Go to the last state of segmentation
        #and update the redo_stack
        print 'undo!'
        if len(self.undo_stack) > 0:
            action = self.undo_stack.pop()
            self.redo_stack.append(action)
            selected_id, old_label, _ = action
            if old_label is not None:
                self._change_label_supervoxel(old_label, selected_id)
            else:
                self._update_selected_id_list(selected_id, add_to_undo=False)
            self.disp_im()

    def redo_action(self, *args):
        """Execute redo action on CTRL-Y"""

        #If respective stack is not empty
        #Go to the last state of segmentation
        #and update the undo_stack
        print 'redo!'
        if len(self.redo_stack) > 0:
            action = self.redo_stack.pop()
            self.undo_stack.append(action)
            selected_id, _, new_label = action
            if new_label is not None:
                self._change_label_supervoxel(new_label, selected_id)
            else:
                self._update_selected_id_list(selected_id, add_to_undo=False)
            self.disp_im()    
            
    def _change_label_supervoxel(self, new_label, selected_id):
        """ Change the label of the supervoxel

        cooordinates is a list of the ids of the selected voxel.
        coordinates[0] - x coordinate, coordinate[1] - y coordinate, coordinate[2] - z coordinate
        new label is the type of pixel 0 - background,
        3 - edema, 2 - Non-active tumor and 1 - Active tumor
        self.segms is the array with segmentations
        self.supervoxel_ids is the the array with the supervoxels"""
        #Segmentation is updated with new labels
        self.segm[self.supervoxel_id == selected_id] = new_label
        self.disp_im()   
        
    #################### Save or load a segmentation ###################        

    def save_segm(self):
        """ Save the current custom segmentation into a file."""
        kwargs = {}
        if self.segm_path is not None:
            dirname, basename = os.path.split(self.segm_path)
            if not basename.startswith('corrected_'):
                basename = 'corrected_'+basename
            kwargs['initialfile'] = basename
            kwargs['initialdir'] = dirname
        path = asksaveasfilename(title="Please select a path to save your segmentation",
                                 filetypes=[('Image files',
                                             ('.nii',
                                              '.mha',
                                              '.nii.gz'))],
                                 **kwargs)

        #TODO: change here self.segm_path
        if self.segm_path is not None:
            old_segm = oitk.get_itk_image(self.segm_path)
        image = oitk.make_itk_image(self.segm, old_segm)
        oitk.write_itk_image(image, path)

    def open_segm(self):
        """ Open a new custom segmentation from a file."""
        kwargs = {}
        kwargs['initialdir'] = os.environ.get('HOME')
        if self.segm_path is not None:
            dirname, basename = os.path.split(self.segm_path)
            if not basename.startswith('corrected_'):
                basename = 'corrected_'+basename
            kwargs['initialfile'] = basename
            kwargs['initialdir'] = dirname
        msg = 'Please select a segmentation'
        segm_path = askopenfilename(title=msg,
                                    filetypes=[('Image files',
                                                ('.nii',
                                                 '.mha',
                                                 '.nii.gz'))],
                                     **kwargs)
        if os.path.exists(segm_path):
            self.segm_path = segm_path
            self.segm = oitk.get_itk_array(self.segm_path)
            self.disp_im()
예제 #4
0
class ActionModulation(Frame):
    def __init__(self,parent):
        Frame.__init__(self,parent)
        self.parent = parent
        self.intensityValue = 0.0
        self.initUI()
        
    def initUI(self):
        self.frame = Frame(self.parent, relief=RAISED,borderwidth=1)
        #panel with the information to be introduced
        #self.grid(row=0,column=0)
        self.position = PanelInformation.PanelInformation(self.frame)
        self.position.getFrame().grid(row=0,column=0)
        self.position.setLabelXLabel("Position X:")
        self.position.setLabelYLabel("Position Y:")
        self.position.setLabelThetaLabel("Position Theta:")
        self.velocity = PanelInformation.PanelInformation(self.frame)
        self.velocity.getFrame().grid(row=1,column=0)
        self.velocity.setLabelXLabel("Walk Shoulder:")
        self.velocity.setLabelYLabel("Walk torso:")
        self.velocity.setLabelThetaLabel("Pose:")
        #panel for the emotion intensity
        self.frameIntensity =  Frame(self.frame, relief=RAISED,borderwidth=1)
        self.frameIntensity.grid(row = 4, column = 0)
        self.labelIntensity = Label(self.frameIntensity,text="Intensity:")
        self.labelIntensity.grid(row=0,column=0)
        self.intensity = Scale(self.frameIntensity, from_=0, to = 1,command=self.onScale)
        self.intensity.grid(row = 1, column = 0)
        self.var = IntVar()
        self.labelInfoIntensity = Label(self.frameIntensity, text=0, textvariable=self.var)
        self.labelInfoIntensity.grid(row = 2, column = 0)
        
        #panel with the robot's information
        self.positionInfo = PanelInformation.PanelInformation(self.frame)
        self.positionInfo.setDisableEntry()
        self.positionInfo.getFrame().grid(row=0,column=2)
        self.positionInfo.setLabelXLabel("Position X:")
        self.positionInfo.setLabelYLabel("Position Y:")
        self.positionInfo.setLabelThetaLabel("Position Theta:")
        self.velocityInfo = PanelInformation.PanelInformation(self.frame)
        self.velocityInfo.setDisableEntry()
        self.velocityInfo.getFrame().grid(row=1,column=2)
        self.velocityInfo.setLabelXLabel("Velocity X:")
        self.velocityInfo.setLabelYLabel("Velocity Y:")
        self.velocityInfo.setLabelThetaLabel("Velocity Theta:")
        #emotions and actions
        self.frameEmotionAction = Frame(self.frame, relief=RAISED,borderwidth=1)
        self.frameEmotionAction.grid(row=2,column=0,columnspan=3)
        self.labelEmotion = Label(self.frameEmotionAction,text="Emotion:")
        self.labelEmotion.grid(row=0,column=0)
        scrollbar = Scrollbar(self.frameEmotionAction, orient=VERTICAL)
        scrollbar.grid(row=0,column=3)
        self.listEmotion = Listbox(self.frameEmotionAction,height=4)
        self.listEmotion.grid(row=0,column=2)
        self.listEmotion.bind("<<ListboxSelect>>", self.onSelectEmotion)
        #the new emotions should be added here
        self.emotions = ['neutral','angry','happy','sad','fear','content']
        for item in self.emotions:
            self.listEmotion.insert(END,item)
        self.listEmotion.config(yscrollcommand=scrollbar.set)
        scrollbar.config(command=self.listEmotion.yview)
        self.labelAction = Label(self.frameEmotionAction,text="Action:")
        self.labelAction.grid(row=0,column=4)
        scrollbar2 = Scrollbar(self.frameEmotionAction, orient=VERTICAL)
        scrollbar2.grid(row=0,column=6)
        self.listAction = Listbox(self.frameEmotionAction,height=4)
        self.listAction.grid(row=0,column=5)
        #the new actions should be added here
        self.actions = ['not_do_anything','oscillate_shoulder','oscillate_body','move_shoulder','move_body','move_torso','oscillate_torso','walk']
        for item in self.actions:
            self.listAction.insert(END,item)
        self.listAction.config(yscrollcommand=scrollbar2.set)
        self.listAction.bind("<<ListboxSelect>>", self.onSelectAction)
        scrollbar2.config(command=self.listAction.yview)
        
        self.actionSelected = "do_nothing"
        self.emotionSelected = "neutral"
    
    def getFrame(self):
        return self.frame
    
    def onScale(self, val): 
        v = format(float(val),'.2f')
        self.intensityValue = v
        self.var.set(v) 
        
    def getIntensity(self):
        return self.intensityValue
        
    def onSelectAction(self,val):
        sender = val.widget
        idx = sender.curselection()
        self.actionSelected = sender.get(idx)
        
    def onSelectEmotion(self,val):
        sender = val.widget
        idx = sender.curselection()
        self.emotionSelected = sender.get(idx)
    
    def getListEmotion(self):
        return self.emotionSelected
        
    def getListAction(self):
        return self.actionSelected
    
    def getPanelPosition(self):
        return self.position
    
    def getPanelVelocity(self):
        return self.velocity    
    
    def getPanelInfoPosition(self):
        return self.positionInfo
    
    def getPanelInfoVelocity(self):
        return self.velocityInfo