예제 #1
0
    def __init__(self, master, get_gain, set_gain, label=''):
        Frame.__init__(self, master, width=FADER_WIDTH, height=FADER_HEIGHT)
        self.get_gain = get_gain
        self._set_gain = set_gain

        if isinstance(label, StringVar):
            Label(self, textvar=label, width=15).pack()
        else:
            Label(self, text=label, width=15).pack()
        self.gain_label = Label(self)

        gain_scale = Scale(self, from_=1, to=0, command=self.set_gain, orient='vertical')
        gain_scale.set(self.get_gain())
        gain_scale.pack()

        self.gain_label.pack()
예제 #2
0
    def __init__(self, master, sequencer):
        Frame.__init__(self, master)
        self.sequencer = sequencer

        self.control_label = Label(self, text="Control")

        self.start_button = Button(self, text="Start")
        self.stop_button = Button(self, text="Stop")

        self.start_button.config(command=self.sequencer.play)
        self.stop_button.config(command=self.sequencer.stop)

        self.control_label.pack()
        self.start_button.pack()
        self.stop_button.pack()

        Label(self, text='Tempo').pack()
        self.tempo_label = Label(self)
        self.tempo_label.pack()

        def set_tempo(v):
            tempo = float(v)
            self.sequencer.set_speed(tempo)
            self.tempo_label.config(text='%3.0f' % tempo)

        tempo_scale = Scale(self, from_=400, to=5, command=set_tempo, orient='vertical')
        tempo_scale.set(self.sequencer.speed)
        tempo_scale.pack()

        measure_control_frame = Frame(self)
        measure_control_frame.pack()

        self.measure_resolution = StringVar(measure_control_frame)
        self.measure_resolution.set(self.sequencer.measure_resolution)
        self.beats_per_measure = StringVar(measure_control_frame)
        self.beats_per_measure.set(self.sequencer.beats_per_measure)

        Label(measure_control_frame, text='Resolution').grid(row=0, column=0, sticky='E')
        measure_resolution_entry = Entry(measure_control_frame, textvariable=self.measure_resolution, width=3)
        measure_resolution_entry.grid(row=0, column=1)

        Label(measure_control_frame, text='Beats').grid(row=1, column=0, sticky='E')
        beats_per_measure_entry = Entry(measure_control_frame, textvariable=self.beats_per_measure, width=3)
        beats_per_measure_entry.grid(row=1, column=1)

        change_measure_update = Button(measure_control_frame, text='Update Measure', command=self.change_measures)
        change_measure_update.grid(row=2, columnspan=2)
예제 #3
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)
예제 #4
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()
예제 #5
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)
예제 #6
0
class qual_window(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)
        self.parent = parent
        self.initUI(parent)

    def initUI(self, parent):
        # initalising some variables
        self.Quality_e = None
        self.scale = None
        self.fmemory_e = None
        self.memory_e = None

        self.style = Style()
        self.style.theme_use("classic")
        Style().configure("TEntry", font='serif 10')
        Style().configure("TLabel", font='serif 10')

        # creating menubar
        menubar = Menu(self.parent)
        self.parent.config(menu=menubar)

        fileMenu = Menu(menubar)
        fileMenu.add_command(label="Restart", command=self.re_start)
        menubar.add_cascade(label="Options", menu=fileMenu)

        # creating layout from frames
        self.frame3 = Frame(parent, relief="sunken")
        self.frame3.pack(side="bottom", fill=X)
        self.frame1 = Frame(parent, relief="sunken")
        self.frame1.pack(side="left", fill=Y)
        self.frame2 = Frame(parent,
                            width=gbl.x2 - gbl.x1,
                            height=max(gbl.y2 - gbl.y1, 200),
                            relief="flat",
                            bg="#333")
        self.frame2.pack(side="right", fill="both", expand="True")

        # creating canvas in frame 2
        self.canvas = Canvas(self.frame2)
        self.canvas.pack(fill="both", expand="True")

        # creating save and next Button
        self.b9 = Button(self.frame1,
                         text="Save and Next>>",
                         state="active",
                         font='serif 10',
                         command=self.save_next)
        self.b9.pack(side="bottom", pady=5)
        self.b9.bind('<Return>', self.save_next)
        self.b8 = Button(self.frame1,
                         text="<<Back",
                         state="active",
                         font='serif 10',
                         command=self.go_back)
        self.b8.pack(side="bottom", pady=5)
        self.b8.bind('<Return>', self.go_back)
        self.parent.bind('<Return>', self.save_next)

        # track for editable entries
        self.e1s = StringVar(self.frame1)
        self.e2s = StringVar(self.frame1)
        self.e1s.trace("w", self.check)
        self.e2s.trace("w", self.check)

        # creating editable format and quality entries
        # self.format_e = self.make_entry(gbl.out_format, "Format (Default JPEG)")
        self.format_e = Entry(self.frame1,
                              textvariable=self.e1s,
                              bg="white",
                              bd=4,
                              cursor="xterm",
                              fg="Black",
                              justify="center",
                              relief="ridge")
        self.format_e.insert(0, "JPEG")
        self.format_e.pack(side="top")
        Label(self.frame1, text="Format (Default JPEG)").pack(side="top")

        # self.Quality_e = self.make_entry(gbl.Quality, "Format (Default 80)")
        self.Quality_e = Entry(self.frame1,
                               textvariable=self.e2s,
                               bg="white",
                               bd=4,
                               cursor="xterm",
                               fg="Black",
                               justify="center",
                               relief="ridge")
        self.Quality_e.insert(0, gbl.Quality)
        self.Quality_e.pack(side="top")
        Label(self.frame1, text="Quality (Default 80)").pack(side="top")
        # self.format_e.config(textvariable=self.e1s)
        # self.Quality_e.config(textvariable=self.e2s)

        # creating sliding bar
        self.var = IntVar()
        self.scale = Scale(self.frame1,
                           from_=1,
                           to=100,
                           orient="horizontal",
                           length=168,
                           command=self.onScale)
        self.scale.set(gbl.Quality)
        self.scale.pack(side="top")

        self.l1 = Label(self.frame1, textvariable=self.var)
        self.l1.pack(side="top")
        self.var.set(gbl.Quality)

        # saving and putting PIL.Image in canvas
        self.save_put_image()

        # creating memory entries
        self.fmemory_e = self.set_memory_entry(self.frame1, "Final",
                                               gbl.output_file)
        self.memory_e = self.set_memory_entry(self.frame1, "Initial",
                                              gbl.input_file)

        # creating status bar
        Label(self.frame3, text=gbl.output_file).pack(side="left", anchor="w")
        Label(self.frame3, text=str(gbl.cu_ind) + "/" +
              str(gbl.total_files)).pack(side="right", anchor="e")

    # def make_entry(self, data, text_):
    # 	temp_entry = Entry(self.frame1, textvariable=None, bg="white", bd=4, cursor="xterm", fg="Black", justify="center", relief="ridge")
    # 	temp_entry.insert(0,data)
    # 	temp_entry.pack(side="top")
    # 	Label(self.frame1, text=text_).pack(side="top")
    # 	return temp_entry

    def quality_entered(self):
        gbl.out_format = str(self.format_e.get())
        gbl.Quality = int(self.Quality_e.get())
        if (self.scale != None):
            self.scale.set(gbl.Quality)
            self.var.set(gbl.Quality)
            self.save_put_image()

    def onScale(self, val):
        v = int(float(val))
        self.var.set(v)
        self.Quality_e.delete(0, 'end')
        self.Quality_e.insert(0, v)

    def check(self, *args):
        if (self.Quality_e != None):
            e1_data = self.e1s.get()
            e2_data = self.e2s.get()
            if (e1_data in ["JPEG", "PNG"]) and e2_data.isdigit(
            ) and int(e2_data) <= 100 and int(e2_data) > 0:
                self.b9.config(state="active")
                self.b9.bind('<Return>', self.save_next)
                self.quality_entered()
            else:
                self.b9.config(state="disabled")
                self.b9.unbind('<Return>')

    def save_next(self, *args):
        if (os.path.isfile(gbl.output_file + "temp")):
            os.remove(gbl.output_file + "temp")
        self.quit()

    def go_back(self, *args):
        if (os.path.isfile(gbl.output_file + "temp")):
            os.remove(gbl.output_file + "temp")
        gbl.back = 1
        gbl.cu_ind -= 1
        self.quit()

    def save_put_image(self):
        if (os.path.isfile(gbl.output_file)):
            os.remove(gbl.output_file)
        if (os.path.isfile(gbl.output_file + "temp")):
            os.remove(gbl.output_file + "temp")
        gbl.crop_im.save(gbl.output_file + "temp",
                         gbl.out_format,
                         quality=gbl.Quality,
                         progressive=True,
                         optimize=True)
        gbl.main_crop_im.save(gbl.output_file,
                              gbl.out_format,
                              quality=gbl.Quality,
                              progressive=True,
                              optimize=True)
        self.temp_im = PIL.Image.open(gbl.output_file + "temp")
        self.fc_im = PIL.ImageTk.PhotoImage(self.temp_im)
        gbl.crop_im_canv = self.canvas.create_image(
            (gbl.x2 - gbl.x1) / 2,
            max(gbl.y2 - gbl.y1, 600) / 2,
            image=self.fc_im)
        if (self.fmemory_e != None):
            self.memory = (os.path.getsize(gbl.output_file) * 1.0) / 1024
            self.fmemory_e.config(state="normal")
            self.fmemory_e.delete(0, 'end')
            self.fmemory_e.insert(0, self.memory)
            self.fmemory_e.config(state="readonly")

    def set_memory_entry(self, framei, text_, file_name):
        temp_entry = Entry(framei,
                           bg="white",
                           bd=4,
                           cursor="xterm",
                           fg="Black",
                           justify="center",
                           relief="ridge")
        memory = (os.path.getsize(file_name) * 1.0) / 1024
        temp_entry.insert(0, memory)
        temp_entry.config(state="readonly")
        temp_entry.pack(side="top")
        Label(framei, text=text_ + " Memory (KB)").pack(side="top")
        return temp_entry

    def crop_size(self):
        if ((gbl.w * 1.0) / gbl.h >= (int(gbl.width) * 1.0) / int(gbl.height)):
            cropx = ((gbl.height * gbl.w) -
                     (gbl.width * gbl.h)) / (gbl.height * 2)
            cropy = 0
        else:
            cropx = 0
            cropy = ((gbl.width * gbl.h) -
                     (gbl.height * gbl.w)) / (gbl.width * 2)
        return cropx, cropy

    def re_start(self):
        gbl.go_restart = 1
        self.quit()