Exemple #1
0
class click_xrange:
    '''An interactive xrange selector.  Given an axis and a starting
   x0 location, draw a full-height rectange that follows the mouise.
   Similar to click_window, but more appropriate for selecting out
   an x-range.'''
    def __init__(self, ax, x0):
        self.ax = ax
        self.x0 = x0
        y0, y1 = ax.get_ybound()
        self.rect = Rectangle((x0, y0), width=0, height=(y1 - y0), alpha=0.1)
        ax.add_artist(self.rect)

    def connect(self):
        self.cidmotion = self.rect.figure.canvas.mpl_connect(
            'motion_notify_event', self.on_motion)

    def on_motion(self, event):
        # Have we left the axes?
        if event.inaxes != self.rect.axes: return

        self.rect.set_width(event.xdata - self.x0)
        self.ax.figure.canvas.draw()

    def close(self):
        self.rect.figure.canvas.mpl_disconnect(self.cidmotion)
        self.rect.remove()
        self.ax.figure.canvas.draw()
        return (self.x0, self.rect.get_x() + self.rect.get_width())
Exemple #2
0
    def place(self, item: Rectangle) -> tuple:
        item_width = (item.get_width() + self.gap_width)

        for i in range(len(self.shelves)):
            pass

        return ()
Exemple #3
0
    def ask_ROI(self):

        if self.data == []: return

        plt.figure()
        r = self.picture.ROI

        ROI = Rectangle((r[0], r[2]),
                        r[1] - r[0],
                        r[3] - r[2],
                        alpha=1,
                        fc='none',
                        ec='green',
                        linewidth=5)
        plt.imshow(self.data,
                   extent=(self.xm.min(), self.xm.max(), self.ym.max(),
                           self.ym.min()))
        plt.gca().add_patch(ROI)

        ed_ROI = EditableRectangle(ROI, fixed_aspect_ratio=False)
        ed_ROI.connect()

        plt.show()

        self.picture.ROI = (ROI.xy[0], ROI.xy[0] + ROI.get_width(), ROI.xy[1],
                            ROI.xy[1] + ROI.get_height())
Exemple #4
0
class click_xrange:
   '''An interactive xrange selector.  Given an axis and a starting
   x0 location, draw a full-height rectange that follows the mouise.
   Similar to click_window, but more appropriate for selecting out
   an x-range.'''

   def __init__(self, ax, x0):
      self.ax = ax
      self.x0 = x0
      y0,y1 = ax.get_ybound()
      self.rect = Rectangle((x0,y0), width=0, height=(y1-y0), alpha=0.1)
      ax.add_artist(self.rect)

   def connect(self):
      self.cidmotion = self.rect.figure.canvas.mpl_connect(
            'motion_notify_event', self.on_motion)

   def on_motion(self, event):
      # Have we left the axes?
      if event.inaxes != self.rect.axes:  return

      self.rect.set_width(event.xdata - self.x0)
      self.ax.figure.canvas.draw()

   def close(self):
      self.rect.figure.canvas.mpl_disconnect(self.cidmotion)
      self.rect.remove()
      self.ax.figure.canvas.draw()
      return(self.x0, self.rect.get_x()+self.rect.get_width())
def show_image(image, labels):
    rect = Rectangle((labels[0], labels[1]),
                     labels[2] - labels[0],
                     labels[3] - labels[1],
                     edgecolor='r',
                     fill=False)
    plt.imshow(image)
    gca = plt.gca()
    gca.add_patch(rect)
    return rect.get_x(), rect.get_y(), rect.get_width(), rect.get_height()
Exemple #6
0
	def draw_rectangle(self, lower, upper, node):
		r = Rectangle(lower, upper[0] - lower[0], upper[1]-lower[1], 
			edgecolor='k',
			facecolor = (0,0,0))
		self.ax.add_patch(r)
		if node.is_leaf():
			rx, ry = r.get_xy()
			cx = rx + r.get_width()/2.0
			cy = ry + r.get_height()/2.0
			r.set_facecolor( node.get_colour())
			self.ax.annotate(node.get_weight(), (cx, cy), color=(0,0,0), fontsize = 10, ha='center', va='center')
			print node.name, rx, ry, cx, cy
Exemple #7
0
    def draw_label(self, bar: Rectangle, fmt: str) -> plt.Annotation:
        w, h = bar.get_width(), bar.get_height()

        x = bar.get_x() + w * 0.5
        y = bar.get_y() + h

        label = self._ax.annotate(format(h, fmt), (x, y),
                                  xytext=(0.0, 4.0), textcoords='offset points',
                                  ha='center', va='bottom')
        label.draggable()
        label.set_rotation(self.label_rot)

        return label
Exemple #8
0
def add_box(ax,box_bounds,clrs, fill = False, linewidth = 2):
    
    # lonmin,lonmax, latmin, latmax 
    from matplotlib.patches import Rectangle
    for ii, box in enumerate(box_bounds): 
        p = Rectangle(
        (box[0], box[2]), box[1]-box[0], box[3]-box[2],
        linewidth=linewidth,fill=False,color=clrs[ii], zorder = 3)

        ax.add_patch(p)
        rx, ry = p.get_xy()
        cx = rx + p.get_width()/2.0
        cy = ry + p.get_height()/2.0
    def demo(self):
        model = self.model()
        model.load_weights('./checkpoints/model')

        test_dataset = self.database.get_tf_dataset(partition='test',
                                                    batch_size=1,
                                                    all_info=True)
        for i, item in enumerate(test_dataset):
            img, annot, orig_img, y1, y2, x1, x2 = item
            x1 = x1[0, ...].numpy()
            x2 = x2[0, ...].numpy()
            y1 = y1[0, ...].numpy()
            y2 = y2[0, ...].numpy()

            prediction = model.predict(img)
            prediction = 1 / (1 + np.exp(prediction))

            prediction = prediction[0, 0]
            if annot == 1:
                prediction = 1 - prediction
                text = f'with_mask\n{prediction:0.2f}'
            else:
                text = f'no_mask\n{prediction:0.2f}'

            if prediction > 0.5:
                color = 'g'
            else:
                color = 'r'

            rect = Rectangle((y1, x1),
                             y2 - y1,
                             x2 - x1,
                             fill=False,
                             linewidth=4,
                             edgecolor=color)

            position = list(rect.get_xy())
            position[0] += rect.get_width() / 2
            position[1] -= 20
            plt.imshow(orig_img[0, ...])
            plt.gca().add_patch(rect)
            plt.gca().annotate(text,
                               position,
                               color='w',
                               weight='bold',
                               fontsize=18,
                               ha='center',
                               va='center')

            plt.show()
Exemple #10
0
    def place(self, item: Rectangle) -> tuple:
        item_width = item.get_width() + self.gap_width

        for shelve in self.shelves:
            w, x, y, ingots = shelve
            if item_width <= w:
                shelve[0] -= item_width
                to = (x, y)
                shelve[1] += item_width

                ingots.append(item)

                return to

        return None
def draw_trip(base_line, start, duration, color, text):
    rect_w = duration * 0.1
    rect_h = 0.08
    x = start * 0.1
    y = base_line + 0.1
    rect = Rectangle((x, y), rect_w, rect_h, alpha=1, facecolor=color)
    rx, ry = rect.get_xy()
    cx = rx + rect.get_width() / 2.0
    cy = ry + rect.get_height() / 2.0
    currentAxis.annotate(str(start), (cx, cy),
                         color='w',
                         weight='bold',
                         fontsize=6,
                         ha='center',
                         va='center')
    currentAxis.add_patch(rect)
def draw_days(base_line, number):
    rect_w = 0.1
    rect_h = 0.08
    for day in range(0, number):
        x = day * 0.1
        y = base_line
        rect = Rectangle((x, y), rect_w, rect_h, alpha=1, fill=None)
        rx, ry = rect.get_xy()
        cx = rx + rect.get_width() / 2.0
        cy = ry + rect.get_height() / 2.0
        currentAxis.annotate(day, (cx, cy),
                             color='b',
                             weight='bold',
                             fontsize=6,
                             ha='center',
                             va='center')
        currentAxis.add_patch(rect)
Exemple #13
0
    def ask_Hole(self):

        if self.data == []: return
        if self.picture.ROI == []: return

        if self.hole == []: self.hole = self.picture.ROI
        xm = self.xm
        ym = self.ym
        data_fit = self.data

        # Restrict to region of Interest :

        x = xm[1, :]
        y = ym[:, 1]

        ix_start = x[x <= self.picture.ROI[0]].argmax()
        ix_stop = x[x <= self.picture.ROI[1]].argmax()
        iy_start = y[y <= self.picture.ROI[2]].argmax()
        iy_stop = y[y <= self.picture.ROI[3]].argmax()

        xm = xm[iy_start:iy_stop, ix_start:ix_stop]
        ym = ym[iy_start:iy_stop, ix_start:ix_stop]
        data_fit = data_fit[iy_start:iy_stop, ix_start:ix_stop]

        plt.figure('Hole')
        r = self.hole

        hole = Rectangle((r[0], r[2]),
                         r[1] - r[0],
                         r[3] - r[2],
                         alpha=1,
                         fc='none',
                         ec='red',
                         linewidth=2)
        plt.imshow(data_fit, extent=(xm.min(), xm.max(), ym.max(), ym.min()))
        plt.gca().add_patch(hole)

        ed_hole = EditableRectangle(hole, fixed_aspect_ratio=False)
        ed_hole.connect()

        plt.show()

        self.hole = (hole.xy[0], hole.xy[0] + hole.get_width(), hole.xy[1],
                     hole.xy[1] + hole.get_height())
Exemple #14
0
    class ChipSelector(object):

        def __init__(self, image_name, chip, **kwargs):
            plt.ioff()
            self.chip = chip
            fig, ax = plt.subplots()
            im, extent = create_image_for_viewer(image_name, chip)
            plt.imshow(np.flipud(im), extent=extent)
            xy = (chip['coordinates']['xmin'], chip['coordinates']['ymin'])
            width = chip['coordinates']['xmax'] - chip['coordinates']['xmin']
            height = chip['coordinates']['ymax'] - chip['coordinates']['ymin']

            from matplotlib.patches import Rectangle
            self.__rect = Rectangle(xy, width, height, fill=False, color='r')
            ax.add_patch(self.__rect)
            drr = DraggableResizeableRectangle(self.__rect, fixed_aspect_ratio=False)
            drr.connect()

            plt.subplots_adjust(bottom=0.2)

            ax.axes.get_xaxis().set_visible(False)
            ax.axes.get_yaxis().set_visible(False)
            ax_reject = plt.axes([0.2, 0.05, 0.1, 0.075])
            ax_accept = plt.axes([0.75, 0.05, 0.1, 0.075])
            self._b_reject = Button(ax_reject, 'Reject')
            self._b_accept = Button(ax_accept, "Accept")
            self._b_reject.on_clicked(self.answer)
            self._b_accept.on_clicked(self.answer)
            plt.show()

        def answer(self, event):
            if event.inaxes.texts[0]._text == 'Accept':
                self.chip = {'name': self.chip['name'],
                             'coordinates': {'xmin': self.__rect.get_x(),
                                             'ymin': self.__rect.get_y(),
                                             'xmax': self.__rect.get_x()+self.__rect.get_width(),
                                             'ymax': self.__rect.get_y()+self.__rect.get_height()}
                             }
            else:
                self.chip = None
            plt.close()
Exemple #15
0
    def draw_rectangle(self, lower, upper, node):
        r = Rectangle(lower,
                      upper[0] - lower[0],
                      upper[1] - lower[1],
                      edgecolor='k',
                      facecolor=node.get_color(),
                      label=node.name)
        self.ax.add_patch(r)

        rx, ry = r.get_xy()
        rw = r.get_width()
        rh = r.get_height()
        cx = rx + rw / 2.0
        cy = ry + rh / 2.0
        if isinstance(node, PathNode):
            t = node.name
            if rw * 3 < rh:
                t += ", "
            else:
                t += "\n"
            t += str(node.size) + ", " + node.stype
            c = 'w'
            if rw < rh:
                o = "vertical"
            else:
                o = "horizontal"

        else:
            t = node.name
            if node.isfile:
                c = 'k'
                o = 45
            else:
                return
        self.ax.annotate(t, (cx, cy),
                         color=c,
                         weight='bold',
                         ha='center',
                         va='center',
                         rotation=o)
Exemple #16
0
    def draw_rectangle(self, lower, upper, node):
        r = Rectangle( lower, upper[0]-lower[0], upper[1] - lower[1],
                   edgecolor='k',
                   facecolor= node.get_color(),
                   label=node.name)
        self.ax.add_patch(r)

        rx, ry = r.get_xy()
        rw = r.get_width()
        rh = r.get_height()
        cx = rx + rw/2.0
        cy = ry + rh/2.0
        if isinstance(node, PathNode):
            t = node.name
            if rw * 3 < rh:
                t += ", "
            else:
                t += "\n"
            t += str(node.size) + ", " + node.stype
            c='w'
            if rw < rh:
                o = "vertical"
            else:
                o = "horizontal"

        else:
            t = node.name
            if node.isfile:
                c='k'
                o = 45
            else:
                return
        self.ax.annotate(
                t,
                (cx,cy),
                color=c,
                weight='bold', ha='center', va='center',
                rotation=o
                )
Exemple #17
0
def plot_rectangle(startTime, endTime, low, high, color, text):
    #print("plot rectangle: startTime {} endTime {} low {} high {} color {}".format(startTime, endTime, low, high, color))
    from matplotlib.patches import Rectangle
    #convert to matplotlib date representation
    start = mdates.date2num(startTime)
    end = mdates.date2num(endTime)
    width = (end - start)
    height = high - low

    rect = Rectangle((start, low), width, height, color=color, alpha=0.4)
    rx, ry = rect.get_xy()
    cx = rx + rect.get_width() / 2.0
    cy = ry + rect.get_height() / 2.0
    ax = plt.gca()
    ax.annotate(text, (cx, cy),
                color='w',
                weight='bold',
                fontsize=6,
                ha='center',
                va='center')

    ax.add_patch(rect)
Exemple #18
0
class ZoneInteret:
    @staticmethod
    def verifier_presence_fichier_ini():
        return os.path.isfile('./zi/param.ini')

    @staticmethod
    def supprimer_ZI(window):
        if os.path.isfile('./zi/param.ini'):
            try:
                os.remove("./zi/param.ini")
                os.remove("./zi/image_modele.png")
                os.remove("./zi/image_zone_interet.png")
                QMessageBox.information(
                    window, "Information",
                    "Supprimer la Zone d'intérêt avec succès", QMessageBox.Ok)
            except OSError:
                QMessageBox.warning(
                    window, "Erreur",
                    "Impossible de supprimer les fichiers dans le repertoire /zi",
                    QMessageBox.Ok)
        else:
            QMessageBox.warning(
                window, "Erreur",
                "Impossible de trouver les fichiers dans le repertoire /zi",
                QMessageBox.Ok)

    # Initialise les variables nécessaires à l'affichage de l'image et aux événements
    def __init__(self, video):

        self.flag = False
        self.get_one_image_from_video(video)

        # On se sert de l'image extraite précédemment
        self.img = mpimg.imread('./zi/image_modele.png')

        # On initialise le titre de la fenêtre
        fig = plt.figure(1)
        fig.canvas.set_window_title("Zone Interet")

        # On récupère les infos des axes
        self.ax = plt.gca()

        # On initialise le futur rectangle dessiné (non rempli aux bordures rouges)
        self.rect = Rectangle((0, 0), 1, 1, fill=False, edgecolor="red")

        # Initialisation des points du rectangle
        self.x0 = None
        self.y0 = None
        self.x1 = None
        self.y1 = None
        self.ax.add_patch(self.rect)

        # Liaison des événements
        self.ax.figure.canvas.mpl_connect('button_press_event',
                                          self.on_mouseclick_press)
        self.ax.figure.canvas.mpl_connect('button_release_event',
                                          self.on_mouseclick_release)
        self.ax.figure.canvas.mpl_connect('key_press_event',
                                          self.on_keyboard_press)

        # Affichage de l'image dans la fenêtre
        self.imgplot = plt.imshow(self.img)

        self.show_window()

    # Un click gauche -> sauvegarde des coordonnées du pointeur
    def on_mouseclick_press(self, event):
        self.x0 = event.xdata
        self.y0 = event.ydata

    # Click gauche relâché -> dessin du rectangle
    def on_mouseclick_release(self, event):
        self.x1 = event.xdata
        self.y1 = event.ydata
        self.rect.set_width(self.x1 - self.x0)
        self.rect.set_height(self.y1 - self.y0)
        self.rect.set_xy((self.x0, self.y0))
        self.ax.figure.canvas.draw()

    # Si la touche "enter" est appuyée, on sauvegarde la zone d'intérêt
    def on_keyboard_press(self, event):
        if event.key == 'enter':
            self.flag = True
            with open("./zi/param.ini", "w") as file:
                file.write(str(int(self.rect.get_x())) + ",")
                file.write(str(int(self.rect.get_y())) + ",")
                file.write(str(int(self.rect.get_width())) + ",")
                file.write(str(int(self.rect.get_height())))

            # On cache les axes avant d'enregistrer l'image modele avec la zone d'interet
            self.ax.get_xaxis().set_visible(False)
            self.ax.get_yaxis().set_visible(False)
            plt.title("Zone interet")
            plt.savefig("./zi/image_zone_interet.png")
            plt.close()

    def show_window(self):
        plt.title(
            "Selectionner la zone interet avec la souris. Appuyez sur entrer pour valider."
        )
        plt.show()

    # extrait une image de la vidéo selectionnée
    def get_one_image_from_video(self, video):
        video_capture = cv2.VideoCapture(video)
        # TODO : bien récupérer la dernière frame
        nb_frame = video_capture.get(cv2.CAP_PROP_FRAME_COUNT)
        video_capture.set(cv2.CAP_PROP_FRAME_COUNT, int(nb_frame - 1))
        success, self.image = video_capture.read()
        print(success)
        cv2.imwrite("zi/image_modele.png", self.image)
Exemple #19
0
class main_gui(wx.Frame):
    '''Setting up the placement and '''
    def __init__(self, parent, file_path):
        if args.debug: print('main_gui.__init__')
        self.args = args
        self.initialize_controls(parent)
        self.box_sizer.Add(self.panel1, 0, wx.EXPAND)

        ## Initialize GUI plot
        self.figure = Figure()
        self.canvas = FigureCanvas(self, -1, self.figure)
        self.box_sizer.Add(self.canvas, 1, wx.EXPAND)

        ## Default rectangle variable
        self.pressed = False

        ## Initialize bottom text bar
        self.box_sizer.Add(self.status_bar, 0, border=0, flag=0)
        self.status_bar.SetStatusText('Ready', 0)
        rect = self.status_bar.GetFieldRect(0)

        ## Set up names
        self.video_file = file_path

        ## Create a dialog box at the beginning if the video path is not a real file
        if self.args.video_file == None:
            openFileDialog = wx.FileDialog(self, "Open Video file", "", "",
                                           "Video files (*.*)|*.*",
                                           wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)

            ## Closing program if Browse box is closed
            if openFileDialog.ShowModal() == wx.ID_CANCEL:
                print(
                    '\nExiting Program. Must select a video from box or enter path into command line\n'
                )
                raise SystemExit

            ## Setting video name from dialog box selection
            self.video_file = openFileDialog.GetPath()

        ## Passing individual inputs from GUI to a list
        self.update_names()
        self.input_names = [
            'x', 'y', 'w', 'h', 'check_frame', 'blank_0', 'blank_n', 'crop_0',
            'crop_n', 'threshold', 'diameter', 'minmass', 'maxsize', 'ecc_low',
            'ecc_high', 'vials', 'window', 'pixel_to_cm', 'frame_rate',
            'vial_id_vars', 'outlier_TB', 'outlier_LR', 'naming_convention',
            'path_project', 'file_suffix', 'convert_to_cm_sec', 'trim_outliers'
        ]
        self.parameter_names = [
            'self.input_' + item for item in self.input_names
        ]
        self.input_values = [  ## int
            self.input_x,
            self.input_y,
            self.input_w,
            self.input_h,
            self.input_check_frame,
            self.input_blank_0,
            self.input_blank_n,
            self.input_crop_0,
            self.input_crop_n,
            self.input_threshold,
            self.input_diameter,
            self.input_minmass,
            self.input_maxsize,
            self.input_ecc_low,
            self.input_ecc_high,
            self.input_vials,
            self.input_window,
            self.input_pixel_to_cm,
            self.input_frame_rate,
            self.input_vial_id_vars,
            self.input_outlier_TB,
            self.input_outlier_LR,
            ## str
            self.input_naming_convention,
            self.input_path_project,
            self.input_file_suffix,
            ## bool
            self.input_convert_to_cm_sec,
            self.input_checkBox_trim_outliers
        ]

        ## Enable all buttons
        button_list = [
            'browse_video', 'reload_video', 'test_parameters',
            'store_parameters'
        ]
        for button in button_list:
            exec('self.button_' + button + '.Enable(True)')

        ## Load video
        self.load_video()
        self.status_bar.SetStatusText("Ready...", 0)
        if args.debug: print('End of init')
        return

    def update_variables(self):
        '''Updates the detection variables'''
        if args.debug: print('main_gui.update_variables')
        variables = []

        ## Including integers
        for item, jtem in zip(self.input_names[:22], self.input_values[:22]):
            #             print('int',item,jtem)
            phrase = str(item + '=' + jtem.GetValue())
            if args.debug: print('    ' + phrase)
            variables.append(phrase)

        ## Including strings - type I
        for item, jtem in zip(self.input_names[22:24],
                              self.input_values[22:24]):
            #             print('str-I',item,jtem)
            phrase = str(item + '="' + jtem.GetValue() + '"')
            if args.debug: print('    ' + phrase)
            variables.append(phrase)

        ## Including strings - type II
        for item, jtem in zip(self.input_names[24:25],
                              self.input_values[24:25]):
            #             print('str-II',item,jtem)
            phrase = str(item + '="' + str(jtem) + '"')
            if args.debug: print(phrase)
            variables.append(phrase)

        ## Including booleans
        for item, jtem in zip(self.input_names[25:], self.input_values[25:]):
            #             print('bool',item,jtem)
            phrase = str(item + '=%s' % str(jtem.GetValue()))
            if args.debug: print('    ' + phrase)
            variables.append(phrase)

        return variables

    def load_video(self):
        '''Function for loading the video when the respective button is pressed'''
        if args.debug: print('main_gui.load_video')

        ## Set up
        self.status_bar.SetStatusText("Loading video", 0)
        self.figure.clear()
        self.axes = [
            self.figure.add_subplot(111),
        ]

        ## Confirm file is a path, or folder has specified suffix
        status = self.check_specified_video()
        if status:
            print("Loading:", self.video_file)
            self.update_names()
            for item in self.input_values[:4]:
                item.SetEditable(True)
                item.Enable(True)
            self.checkBox_fixed_ROI.Enable(True)
            self.input_convert_to_cm_sec.Enable(True)

            ## Busy cursor while the detector object is called and initialized
            wx.BeginBusyCursor()
            try:
                vars = self.update_variables()
                self.detector = detector(self.video_file,
                                         gui=True,
                                         variables=vars)

                self.axes[0].imshow(self.detector.image_stack[0])
                self.figure.canvas.draw()
            finally:
                wx.EndBusyCursor()

            ## Setting mechanism for drawing the ROI rectangle
            self.canvas.Bind(wx.EVT_ENTER_WINDOW, self.ChangeCursor)
            self.canvas.mpl_connect('button_press_event', self.draw_rectangle)
            self.canvas.mpl_connect('button_release_event', self.on_release)
            self.canvas.mpl_connect('motion_notify_event', self.on_motion)
            self.rect = Rectangle((0, 0), 1, 1, fill=False, ec='r')
            self.axes[0].add_patch(self.rect)

            ## Auto-set GUI parameters from the video
            self.input_blank_0.SetValue('0')
            self.input_blank_n.SetValue(str(self.detector.n_frames))
            self.input_crop_0.SetValue('0')
            self.input_crop_n.SetValue(str(self.detector.n_frames))
            self.input_check_frame.SetValue('0')
            self.input_ecc_low.SetValue('0')
            self.input_ecc_high.SetValue('1')
            self.input_ecc_high.SetValue('1')
            self.input_path_project.SetValue(self.folder)
            self.input_naming_convention.SetValue(self.name)
            self.input_vial_id_vars.SetValue(
                str(len(self.input_naming_convention.GetValue().split('_'))))

            ## Display the 0th and frame corresponding with (most likely) t = 2 seconds
            try:
                self.input_frame_rate = int(self.input_frame_rate.GetValue())
            except:
                pass
            if self.detector.n_frames < self.input_frame_rate * 2:
                self.input_check_frame.SetValue(str(self.detector.n_frames))

            ## Try to make the local linear regression window size 2 seconds, but if not then 35% of the frames in the video
            if self.detector.n_frames < self.input_frame_rate * 2:
                self.input_window.SetValue(
                    str(int(len(self.detector.image_stack) * .35)))
            else:
                self.input_window.SetValue(str(int(self.input_frame_rate) * 2))

            ## Enable Test parameter button if disabled from prior testing
            self.button_test_parameters.Enable(True)
            self.x0, self.y0 = 0, 0
            self.x1, self.y1 = self.detector.width, self.detector.height

            ## Display the first frame of the video in the GUI
            self.update_ROIdisp()
            self.canvas.draw()
        else:
            return

    def update_names(self):
        '''Updates the names of variables within the program. Generally variables set for naming files.'''
        if args.debug: print('main_gui.update_names')
        self.status_bar.SetStatusText("Updating file names...", 0)
        self.text_video_path.SetLabelText(self.video_file)
        self.folder, self.name = os.path.split(self.video_file)
        self.name, self.input_file_suffix = self.name.split('.')

        ## Naming files to be generated
        self.name_noext = os.path.join(self.folder, self.name)
        self.path_data = self.name_noext + '.raw.csv'
        self.path_filter = self.name_noext + '.filter.csv'
        self.path_plot = self.name_noext + '.diag.png'
        self.path_slope = self.name_noext + '.slopes.csv'
        if args.debug: print('name:', self.name_noext, "+ file suffixes")

        ## Set path_project default to the folder of the selected video file
        if self.input_path_project == '': self.input_path_project = self.folder
        return

    def check_specified_video(self):
        if args.debug: print('main_gui.check_specified_video')
        self.status_bar.SetStatusText("Checking specified video...", 0)

        ## Check file path and update names
        if os.path.isfile(self.video_file):
            self.button_reload_video.Enable(True)
            self.button_test_parameters.Enable(True)
            self.update_names()
            self.input_file_suffix = '.' + self.video_file.split(
                '/')[-1].split('.')[-1]
            return True

        else:
            self.video_file = "No or invalid file entered. Please change the file path"
            self.button_browse_video.Enable(True)
            return False

    ## Commands for drawing the ROI rectangle
    def ChangeCursor(self, event):
        '''Change cursor into crosshair type when enter the plot area'''
        self.canvas.SetCursor(wx.Cursor(wx.CURSOR_CROSS))
        return

    def draw_rectangle(self, event):
        '''Draw ROI rectangle'''
        self.status_bar.SetStatusText(
            "Draw rectangle from upper-left to lower-right", 0)
        self.pressed = True
        if self.checkBox_fixed_ROI.Enabled:
            try:
                self.x0 = int(event.xdata)
                self.y0 = int(event.ydata)

                ## If the fixed_ROI box is checked, handle values differently
                if self.checkBox_fixed_ROI.GetValue():
                    self.x1 = self.x0 + int(eval(self.input_w.GetValue()))
                    self.y1 = self.y0 + int(eval(self.input_h.GetValue()))
                    self.rect.set_width(self.x1 - self.x0)
                    self.rect.set_height(self.y1 - self.y0)
                    self.rect.set_xy((self.x0, self.y0))
                    self.canvas.draw()

                ## Set the values in the GUI and program to drawn rectangle
                self.input_x.SetValue(str(self.x0))
                self.input_y.SetValue(str(self.y0))
                self.input_h.SetValue(str(self.rect.get_height()))
                self.input_w.SetValue(str(self.rect.get_width()))
            except:
                pass
        return

    def on_release(self, event):
        '''When mouse is on plot and button is released, redraw ROI rectangle, update ROI values'''
        self.status_bar.SetStatusText("Specify the detector parameters...", 0)
        self.pressed = False
        if self.checkBox_fixed_ROI.Enabled:
            if self.checkBox_fixed_ROI.GetValue():
                pass
            else:
                self.redraw_rect(event)
            self.update_ROIdisp()
        return

    def on_motion(self, event):
        '''If the mouse is on plot and if the mouse button is pressed, redraw ROI rectangle'''
        if self.pressed & self.checkBox_fixed_ROI.Enabled & (
                not self.checkBox_fixed_ROI.GetValue()):
            # Redraw the rectangle
            self.redraw_rect(event)
            self.update_ROIdisp()
        return

    def redraw_rect(self, event):
        '''Draw the ROI rectangle overlay'''
        try:
            x1 = int(event.xdata)
            y1 = int(event.ydata)
            if any([self.x1 != x1, self.y1 != y1]):
                self.x1 = x1
                self.y1 = y1
                self.rect.set_xy((self.x0, self.y0))
                self.rect.set_width(self.x1 - self.x0)
                self.rect.set_height(self.y1 - self.y0)

                self.canvas.draw()
            else:
                pass
        except:
            pass
        return

    def update_ROIdisp(self):
        '''Updates the ROI coordinates as the rectangle is drawn.'''
        self.input_x.SetValue(str(self.x0))
        self.input_y.SetValue(str(self.y0))
        self.input_h.SetValue(str(int(self.y1) - int(self.y0)))
        self.input_w.SetValue(str(int(self.x1) - int(self.x0)))
        return

    def OnButton_testParButton(self, event):
        '''Tests the entered parameters when the `Test parameters` button is pressed'''
        if args.debug: print('main_gui.OnButton_testParButton')
        self.status_bar.SetStatusText("Testing parameters...", 0)

        #Prep the parameters
        variables = self.update_variables()
        self.checkBox_fixed_ROI.Enable(False)

        ## Set up figure for plots
        self.figure.clear()
        self.axes = [
            self.figure.add_subplot(231),
            self.figure.add_subplot(232),
            self.figure.add_subplot(233),
            self.figure.add_subplot(234),
            self.figure.add_subplot(235),
            self.figure.add_subplot(236)
        ]

        ## Busy cursor while the main function runs
        wx.BeginBusyCursor()
        try:
            variables = variables + ['debug=' + str(args.debug)]
            self.detector.parameter_testing(variables, self.axes)
        finally:
            wx.EndBusyCursor()

        ## Renders plots in the GUI
        self.figure.tight_layout()
        self.figure.canvas.draw()

        # Enable buttons and print statements once parameter testing is complete
        self.button_reload_video.Enable(True)
        self.button_store_parameters.Enable(True)
        if args.debug: print('Parameter testing complete')
        self.status_bar.SetStatusText(
            "Refine detector parameters by reloading the video, or finish optimization by pressing 'Save configuration'",
            0)
        return

    def OnButton_strParButton(self, event):
        '''Runs the 'save_parameter' function for creating the configuration file'''
        if args.debug: print('main_gui.OnButton_strParButton')
        self.save_parameter()
        self.button_store_parameters.SetBackgroundColour(
            wx.Colour(241, 241, 241))

    def set_config_file(self):
        '''Set path for the project folder'''
        if args.debug: print('main_gui.OnButton_strParButton')
        ## Figure out where to save configuration file
        if os.path.isdir(self.input_path_project):
            if not self.input_path_project.endswith('/'):
                self.input_path_project = self.input_path_project + '/'
            self.path_parameters = self.input_path_project + self.name + '.cfg'
        else:
            self.path_parameters = self.path_noext + '.cfg'
        return self.path_parameters

    def save_parameter(self):
        if args.debug: print('main_gui.save_parameter')
        '''
        Save parameters as python list.
        New parameter sets appended to the config file.
        Each parameter sets come with a comment line, contain the datetime of analysis
        '''

        variables = self.update_variables()
        try:
            self.input_path_project = self.input_path_project.GetValue()
        except:
            pass

        self.path_parameters = self.set_config_file()

        ## Printing output to configuration file
        print('Saving parameters to:', self.path_parameters)
        with open(self.path_parameters, 'w') as f:
            print('## FreeClimber ##', file=f)
        f.close()

        now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        with open(self.path_parameters, 'a') as f:
            print('## Generated from file: ' + self.video_file, file=f)
            print('##     @ ' + now, file=f)
            print('##', file=f)
            print('## Analysis parameters:', file=f)
            for item in variables:
                print(item, file=f)
        f.close()
        print("Configuration settings saved")
        return

    def OnButton_Browse(self, event):
        if args.debug: print('main_gui.OnButton_Browse')
        openFileDialog = wx.FileDialog(self, "Open Video file", "", "",
                                       "Video files (*.*)|*.*",
                                       wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
        if openFileDialog.ShowModal() == wx.ID_CANCEL:
            pass
        else:
            self.video_file = openFileDialog.GetPath()
            self.update_names()
            self.load_video()
        self.figure.clear()
        return

    def OnButton_LoadVideo(self, event):
        '''Calls function to load the video when the `reload` button is pressed'''
        if args.debug: print('main_gui.OnButton_LoadVideo')
        self.load_video()
        return

    def initialize_sizers(self):
        '''Initializes the GUI window orientation'''
        if args.debug: print('main_gui.initialize_sizers')
        # Generated method, do not edit
        self.box_sizer = wx.BoxSizer(orient=wx.VERTICAL)
        self.SetSizer(self.box_sizer)
        return

    def initialize_controls(self, prnt):
        '''Initializes the GUI controls, for which there are many'''
        if args.debug: print('main_gui.initialize_controls')
        # Generated method, do not edit
        wx.Frame.__init__(self,
                          id=wxID_text_title,
                          name='',
                          parent=prnt,
                          pos=wx.Point(100, 30),
                          size=wx.Size(950, 759),
                          style=wx.DEFAULT_FRAME_STYLE,
                          title='FreeClimber')
        self.SetClientSize(wx.Size(950, 737))

        ######
        ## Inputs for ROI Rectangle
        self.panel1 = wx.Panel(id=wxID_panel_1,
                               name='panel1',
                               parent=self,
                               pos=wx.Point(0, 0),
                               size=wx.Size(950, 231),
                               style=wx.TAB_TRAVERSAL)

        ## Step 1 boxes
        self.text_step_1a = wx.StaticText(id=wxID_text_step_1a,
                                          label=u'Step 1a: Specify a video',
                                          name='text_step_1a',
                                          parent=self.panel1,
                                          pos=wx.Point(col1, 10),
                                          size=wx.Size(box_dimensions),
                                          style=wx.ALIGN_CENTER)

        ## Browse
        self.button_browse_video = wx.Button(id=wxID_browse_video,
                                             label=u'Browse...',
                                             name=u'button_browse_video',
                                             parent=self.panel1,
                                             pos=wx.Point(col1, 30),
                                             size=wx.Size(box_dimensions),
                                             style=0)
        self.button_browse_video.Bind(wx.EVT_BUTTON,
                                      self.OnButton_Browse,
                                      id=wxID_browse_video)

        self.text_step_1b = wx.StaticText(id=wxID_text_step_1b,
                                          label=u'Step 1b: Define options',
                                          name='text_step_1b',
                                          parent=self.panel1,
                                          pos=wx.Point(col1, 65),
                                          size=wx.Size(box_dimensions),
                                          style=wx.ALIGN_CENTER)

        ## Pixel to cm
        self.text_pixel_to_cm = wx.StaticText(
            id=wxID_text_pixel_to_cm,
            label=u"Pixels / cm:",
            name='text_pixel_to_cm',
            parent=self.panel1,
            pos=wx.Point(col1, 85),
            size=wx.Size(medium_box_dimensions),
            style=0)
        self.input_pixel_to_cm = wx.TextCtrl(
            id=wxID_input_pixel_to_cm,
            name=u'input_pixel_to_cm',
            parent=self.panel1,
            pos=wx.Point(col1 + 95, 85),
            size=wx.Size(medium_box_dimensions),
            style=0,
            value=u"1")

        ## Frame Rate
        self.text_frame_rate = wx.StaticText(id=wxID_frame_rate,
                                             label=u'Frames / sec:',
                                             name='text_frame_rate',
                                             parent=self.panel1,
                                             pos=wx.Point(col1, 115),
                                             size=wx.Size(box_dimensions),
                                             style=0)
        self.input_frame_rate = wx.TextCtrl(
            id=wxID_frame_rate,
            name=u'input_frame_rate',
            parent=self.panel1,
            pos=wx.Point(col1 + 95, 115),
            size=wx.Size(medium_box_dimensions),
            style=0,
            value='25')

        ## Check box to convert final slope to cm
        self.input_convert_to_cm_sec = wx.CheckBox(
            id=wxID_input_convert_to_cm_sec,
            label=u'Convert to cm / sec',
            name=u'input_convert_to_cm_sec',
            parent=self.panel1,
            pos=wx.Point(col1, 145),
            size=wx.Size(250, 22),
            style=0)

        ## Step 2 boxes
        self.text_step_2 = wx.StaticText(id=wxID_text_step_2,
                                         label=u'Step 2: Select ROI',
                                         name='text_step_2',
                                         parent=self.panel1,
                                         pos=wx.Point(col2, 10),
                                         size=wx.Size(box_dimensions),
                                         style=wx.ALIGN_LEFT)
        ## X
        self.text_x = wx.StaticText(id=wxID_text_x,
                                    label=u'x-pos.',
                                    name='text_x',
                                    parent=self.panel1,
                                    pos=wx.Point(col2, 30),
                                    size=wx.Size(medium_box_dimensions),
                                    style=wx.ALIGN_LEFT)
        self.input_x = wx.TextCtrl(id=wxID_input_x,
                                   name=u'input_x',
                                   parent=self.panel1,
                                   style=0,
                                   value=u'0',
                                   pos=wx.Point(col2 + 55, 30),
                                   size=wx.Size(medium_box_dimensions))

        ## Y
        self.text_y = wx.StaticText(id=wxID_text_y,
                                    label=u'y-pos.',
                                    name='text_y',
                                    parent=self.panel1,
                                    pos=wx.Point(col2, 55),
                                    size=wx.Size(medium_box_dimensions),
                                    style=wx.ALIGN_LEFT)
        self.input_y = wx.TextCtrl(id=wxID_input_y,
                                   name=u'input_y',
                                   parent=self.panel1,
                                   pos=wx.Point(col2 + 55, 55),
                                   size=wx.Size(medium_box_dimensions),
                                   style=0,
                                   value=u'0')

        ## Width
        self.text_w = wx.StaticText(id=wxID_text_w,
                                    label=u'Width:',
                                    name='text_w',
                                    parent=self.panel1,
                                    pos=wx.Point(col2, 80),
                                    size=wx.Size(medium_box_dimensions),
                                    style=wx.ALIGN_LEFT)
        self.input_w = wx.TextCtrl(id=wxID_input_w,
                                   name=u'input_w',
                                   parent=self.panel1,
                                   pos=wx.Point(col2 + 55, 80),
                                   size=wx.Size(medium_box_dimensions),
                                   style=0,
                                   value=u'0')

        ## Height
        self.text_h = wx.StaticText(id=wxID_text_h,
                                    label=u'Height:',
                                    name='text_h',
                                    parent=self.panel1,
                                    pos=wx.Point(col2, 105),
                                    size=wx.Size(medium_box_dimensions),
                                    style=wx.ALIGN_LEFT)
        self.input_h = wx.TextCtrl(id=wxID_input_h,
                                   name=u'input_h',
                                   parent=self.panel1,
                                   pos=wx.Point(col2 + 55, 105),
                                   size=wx.Size(medium_box_dimensions),
                                   style=0,
                                   value=u'0')

        ## ROI rectangle stays same dimensions but can be redrawn. Not critical to keep
        self.checkBox_fixed_ROI = wx.CheckBox(id=wxID_check_box_ROI,
                                              label=u'Fixed ROI Size?',
                                              name=u'checkBox_fixed_ROI',
                                              parent=self.panel1,
                                              pos=wx.Point(col2, 145),
                                              size=wx.Size(250, 22),
                                              style=0)
        self.checkBox_fixed_ROI.SetValue(False)
        ######

        ## Detection parameters
        self.text_step_3 = wx.StaticText(
            id=wxID_text_step_3,
            label=u'Step 3: Specify spot parameters',
            name='text_step_3',
            parent=self.panel1,
            pos=wx.Point(col3, 10),
            size=wx.Size(100, 22),
            style=wx.ALIGN_LEFT)

        ## Expected spot diameter
        self.text_diameter = wx.StaticText(id=wxID_text_diameter,
                                           label=u'Diameter:',
                                           name='text_diameter',
                                           parent=self.panel1,
                                           pos=wx.Point(col3, 30),
                                           size=wx.Size(medium_box_dimensions),
                                           style=0)
        self.input_diameter = wx.TextCtrl(id=wxID_input_diameter,
                                          name=u'input_diameter',
                                          parent=self.panel1,
                                          pos=wx.Point(col3 + 100, 30),
                                          size=wx.Size(medium_box_dimensions),
                                          style=0,
                                          value=u'7')

        ## Maximum spot diameter
        self.text_maxsize = wx.StaticText(id=wxID_text_maxsize,
                                          label=u'MaxDiameter:',
                                          name='text_maxsize',
                                          parent=self.panel1,
                                          pos=wx.Point(col3, 55),
                                          size=wx.Size(medium_box_dimensions),
                                          style=0)
        self.input_maxsize = wx.TextCtrl(id=wxID_input_maxsize,
                                         name=u'input_maxsize',
                                         parent=self.panel1,
                                         pos=wx.Point(col3 + 100, 55),
                                         size=wx.Size(medium_box_dimensions),
                                         style=0,
                                         value=u'11')

        ## Minimum spot 'mass'
        self.text_minmass = wx.StaticText(id=wxID_text_minmass,
                                          label=u'MinMass:',
                                          name='text_minmass',
                                          parent=self.panel1,
                                          pos=wx.Point(col3, 80),
                                          size=wx.Size(medium_box_dimensions),
                                          style=0)
        self.input_minmass = wx.TextCtrl(id=wxID_input_minmass,
                                         name=u'input_minmass',
                                         parent=self.panel1,
                                         pos=wx.Point(col3 + 100, 80),
                                         size=wx.Size(medium_box_dimensions),
                                         style=0,
                                         value=u'100')

        ## Spot threshold
        self.text_threshold = wx.StaticText(
            id=wxID_text_threshold,
            label=u'Threshold:',
            name='text_threshold',
            parent=self.panel1,
            pos=wx.Point(col3, 105),
            size=wx.Size(medium_box_dimensions),
            style=0)
        self.input_threshold = wx.TextCtrl(id=wxID_input_threshold,
                                           name=u'input_threshold',
                                           parent=self.panel1,
                                           pos=wx.Point(col3 + 100, 105),
                                           size=wx.Size(medium_box_dimensions),
                                           style=0,
                                           value=u'"auto"')

        ## Eccentricity range
        self.text_ecc = wx.StaticText(id=wxID_text_ecc,
                                      label=u'Ecc/circularity:',
                                      name='text_ecc',
                                      parent=self.panel1,
                                      pos=wx.Point(col3, 130),
                                      size=wx.Size(medium_box_dimensions),
                                      style=0)
        self.input_ecc_low = wx.TextCtrl(id=wxID_input_ecc_low,
                                         name=u'input_ecc_low',
                                         parent=self.panel1,
                                         pos=wx.Point(col3 + 100, 130),
                                         size=wx.Size(small_box_dimensions),
                                         style=0,
                                         value=u'0')
        self.input_ecc_high = wx.TextCtrl(id=wxID_input_ecc_high,
                                          name=u'input_ecc_high',
                                          parent=self.panel1,
                                          pos=wx.Point(col3 + 140, 130),
                                          size=wx.Size(small_box_dimensions),
                                          style=0,
                                          value=u'0')

        #### Step 4 arguments
        ## Check frames
        self.text_step_4 = wx.StaticText(
            id=wxID_text_step_4,
            label=u'Step 4: Additional parameters',
            name='text_step_4',
            parent=self.panel1,
            pos=wx.Point(col4, 10),
            size=wx.Size(100, 22),
            style=wx.ALIGN_LEFT)

        ## Background frames
        self.text_background_frames = wx.StaticText(
            id=wxID_text_background_frames,
            label=u'Background frames:',
            name='text_background_frames',
            parent=self.panel1,
            pos=wx.Point(col4, 30),
            size=wx.Size(medium_box_dimensions),
            style=0)
        self.input_blank_0 = wx.TextCtrl(id=wxID_input_blank_0,
                                         name=u'input_blank_0',
                                         parent=self.panel1,
                                         pos=wx.Point(col4 + 130, 30),
                                         size=wx.Size(small_box_dimensions),
                                         style=0,
                                         value=u'0')
        self.input_blank_n = wx.TextCtrl(id=wxID_input_blank_n,
                                         name=u'input_blank_n',
                                         parent=self.panel1,
                                         pos=wx.Point(col4 + 170, 30),
                                         size=wx.Size(small_box_dimensions),
                                         style=0,
                                         value=u'0')

        ## crop frames
        self.text_crop_frames = wx.StaticText(
            id=wxID_text_crop_frames,
            label=u'Crop frames:',
            name='text_crop_frames',
            parent=self.panel1,
            pos=wx.Point(col4, 55),
            size=wx.Size(medium_box_dimensions),
            style=0)
        self.input_crop_0 = wx.TextCtrl(id=wxID_input_crop_0,
                                        name=u'input_crop_0',
                                        parent=self.panel1,
                                        pos=wx.Point(col4 + 130, 55),
                                        size=wx.Size(small_box_dimensions),
                                        style=0,
                                        value=u'0')
        self.input_crop_n = wx.TextCtrl(id=wxID_input_crop_n,
                                        name=u'input_crop_n',
                                        parent=self.panel1,
                                        pos=wx.Point(col4 + 170, 55),
                                        size=wx.Size(small_box_dimensions),
                                        style=0,
                                        value=u'0')

        ## Check frames
        self.text_check_frames = wx.StaticText(id=wxID_text_check_frames,
                                               label=u'Check frame:',
                                               name='text_check_frames',
                                               parent=self.panel1,
                                               pos=wx.Point(col4, 80),
                                               size=wx.Size(115, 17),
                                               style=0)

        self.input_check_frame = wx.TextCtrl(
            id=wxID_input_check_frame,
            name=u'input_check_frame',
            parent=self.panel1,
            pos=wx.Point(col4 + 130, 80),
            size=wx.Size(small_box_dimensions),
            style=0,
            value=u'0')

        ## Vials
        self.text_vials = wx.StaticText(id=wxID_text_vials,
                                        label=u'Number of vials:',
                                        name='text_vials',
                                        parent=self.panel1,
                                        pos=wx.Point(col4, 105),
                                        size=wx.Size(133, 22),
                                        style=0)
        self.input_vials = wx.TextCtrl(id=wxID_input_vials,
                                       name=u'input_vials',
                                       parent=self.panel1,
                                       pos=wx.Point(col4 + 130, 105),
                                       size=wx.Size(small_box_dimensions),
                                       style=0,
                                       value=u'1')

        ## Window size
        self.text_window = wx.StaticText(id=wxID_text_window,
                                         label=u'Window size:',
                                         name='text_window',
                                         parent=self.panel1,
                                         pos=wx.Point(col4, 130),
                                         size=wx.Size(133, 22),
                                         style=0)
        self.input_window = wx.TextCtrl(id=wxID_input_window,
                                        name=u'input_window',
                                        parent=self.panel1,
                                        pos=wx.Point(col4 + 130, 130),
                                        size=wx.Size(small_box_dimensions),
                                        style=0,
                                        value='1')

        ## Edge trim
        self.input_checkBox_trim_outliers = wx.CheckBox(
            id=wxID_check_box_outlier,
            label=u'Trim outliers? (TB                      LR)',
            name=u'checkBox_outlier',
            parent=self.panel1,
            pos=wx.Point(col4, 155),
            size=wx.Size(250, 22),
            style=0)
        self.input_checkBox_trim_outliers.SetValue(False)
        self.input_outlier_TB = wx.TextCtrl(id=wxID_outlier_TB,
                                            name=u'input_outlier_TB',
                                            parent=self.panel1,
                                            pos=wx.Point(col4 + 130, 155),
                                            size=wx.Size(small_box_dimensions),
                                            style=0,
                                            value=u'1')
        self.input_outlier_LR = wx.TextCtrl(id=wxID_outlier_LR,
                                            name=u'input_outlier_LR',
                                            parent=self.panel1,
                                            pos=wx.Point(col4 + 170, 155),
                                            size=wx.Size(small_box_dimensions),
                                            style=0,
                                            value=u'3')

        self.text_step_5 = wx.StaticText(id=wxID_text_step_5,
                                         label=u'Step 5: Naming parameters',
                                         name='text_step_5',
                                         parent=self.panel1,
                                         pos=wx.Point(col5, 10),
                                         size=wx.Size(100, 22),
                                         style=wx.ALIGN_LEFT)

        ## Naming convention
        self.text_naming_convention = wx.StaticText(
            id=wxID_text_naming_convention,
            label=u"Naming pattern:",
            name='text_naming_convention',
            parent=self.panel1,
            pos=wx.Point(col5, 30),
            size=wx.Size(medium_box_dimensions),
            style=0)
        self.input_naming_convention = wx.TextCtrl(
            id=wxID_input_naming_convention,
            name=u'input_naming_convention',
            parent=self.panel1,
            pos=wx.Point(col5, 50),
            size=wx.Size(large_box_dimensions),
            style=0,
            value='')

        ## Variables
        self.text_vial_id_vars = wx.StaticText(id=wxID_text_vial_id_vars,
                                               label=u'Vial_ID variables:',
                                               name='text_vial_id_vars',
                                               parent=self.panel1,
                                               pos=wx.Point(col5, 80),
                                               size=wx.Size(133, 22),
                                               style=0)
        self.input_vial_id_vars = wx.TextCtrl(
            id=wxID_input_vial_id_vars,
            name=u'input_vial_id_vars',
            parent=self.panel1,
            pos=wx.Point(col5 + 130, 80),
            size=wx.Size(small_box_dimensions),
            style=0,
            value=u'2')

        self.text_path_project = wx.StaticText(
            id=wxID_text_path_project,
            label=u"Project path:",
            name='text_path_project',
            parent=self.panel1,
            pos=wx.Point(col4 - 45, 180),
            size=wx.Size(medium_box_dimensions),
            style=0)
        self.input_path_project = wx.TextCtrl(id=wxID_input_path_project,
                                              name=u'input_path_project',
                                              parent=self.panel1,
                                              pos=wx.Point(col4 + 40, 180),
                                              size=wx.Size(350, 22),
                                              style=0,
                                              value='')

        ## Bottom panels
        self.text_video_path = wx.StaticText(id=wxID_video_path,
                                             label='Video Path',
                                             name='text_video_path',
                                             parent=self.panel1,
                                             pos=wx.Point(10, 205),
                                             size=wx.Size(930, 22),
                                             style=0)
        self.text_video_path.SetBackgroundColour(wx.Colour(241, 241, 241))

        self.button_test_parameters = wx.Button(id=wxID_test_parameters,
                                                label=u'Test parameters',
                                                name=u'button_test_parameters',
                                                parent=self.panel1,
                                                pos=wx.Point(col1, 180),
                                                size=wx.Size(140, 22),
                                                style=wx.ALIGN_CENTER)
        self.button_test_parameters.Bind(wx.EVT_BUTTON,
                                         self.OnButton_testParButton,
                                         id=wxID_test_parameters)

        self.button_reload_video = wx.Button(id=wxID_reload_video,
                                             label=u'Reload video',
                                             name=u'button_reload_video',
                                             parent=self.panel1,
                                             pos=wx.Point(col1 + 160 * 1, 180),
                                             size=wx.Size(140, 22),
                                             style=wx.ALIGN_CENTER)
        self.button_reload_video.Bind(wx.EVT_BUTTON,
                                      self.OnButton_LoadVideo,
                                      id=wxID_reload_video)

        self.button_store_parameters = wx.Button(
            id=wxID_store_parameters,
            label=u'Save configuration',
            name=u'button_store_parameters',
            parent=self.panel1,
            pos=wx.Point(col1 + 160 * 2, 180),
            size=wx.Size(140, 22),
            style=wx.ALIGN_CENTER)
        self.button_store_parameters.Bind(wx.EVT_BUTTON,
                                          self.OnButton_strParButton,
                                          id=wxID_store_parameters)

        ## Text box at the bottom
        self.status_bar = wx.StatusBar(id=wxID_status_bar,
                                       name='status_bar',
                                       parent=self,
                                       style=0)
        self.initialize_sizers()
        return
class WindowSelectionRectangle(object):
    def __init__(self, event, axis, on_window_selection_callback):
        self.axis = axis
        if event.inaxes != self.axis:
            return
        # Store the axes it has been initialized in.
        self.axes = event.inaxes
        ymin, ymax = self.axes.get_ylim()
        self.min_x = event.xdata
        self.intial_selection_active = True
        self.rect = Rectangle((event.xdata, ymin), 0, ymax - ymin, color="0.3",
            alpha=0.5, edgecolor="0.5")
        self.axes.add_patch(self.rect)
        # Get the canvas.
        self.canvas = self.rect.figure.canvas

        # Use blittig for fast animations.
        self.rect.set_animated(True)
        self.background = self.canvas.copy_from_bbox(self.rect.axes.bbox)

        self._connect()

        self.on_window_selection_callback = on_window_selection_callback

    #def __del__(self):
        #"""
        #Disconnect the events upon deallocating.
        #"""
        #self.canvas.mpl_disconnect(self.conn_button_press)
        #self.canvas.mpl_disconnect(self.conn_button_release)
        #self.canvas.mpl_disconnect(self.conn_mouse_motion)

    def _connect(self):
        """
        Connect to the necessary events.
        """
        self.conn_button_press = self.rect.figure.canvas.mpl_connect(
            'button_press_event', self.on_button_press)
        self.conn_button_release = self.rect.figure.canvas.mpl_connect(
            'button_release_event', self.on_button_release)
        self.conn_mouse_motion = self.rect.figure.canvas.mpl_connect(
            'motion_notify_event', self.on_mouse_motion)

    def on_button_press(self, event):
        pass

    def on_button_release(self, event):
        if event.inaxes != self.axis:
            return

        if event.button != 1:
            return
        # turn off the rect animation property and reset the background
        self.rect.set_animated(False)
        self.background = None

        self.intial_selection_active = False
        self.canvas.draw()

        x = self.rect.get_x()
        width = self.rect.get_width()

        if width < 0:
            x = x + width
            width = abs(width)

        self.on_window_selection_callback(x, width, self.axis)

    def on_mouse_motion(self, event):
        if event.button != 1 or \
                self.intial_selection_active is not True:
            return
        if event.xdata is not None:
            self.rect.set_width(event.xdata - self.min_x)

        # restore the background region
        self.canvas.restore_region(self.background)
        # redraw just the current rectangle
        self.axes.draw_artist(self.rect)
        # blit just the redrawn area
        self.canvas.blit(self.axes.bbox)
Exemple #21
0
class ZoneInteret:

    """
    Cette classe permet de gérer les information de zone interet
    Une zone interet est un cadre d'image sur l'image entière.
    On se concentre sur cette zone interet pour faire le traitement.
    C'est une manière de réduire le bruit sur le résultat de traitement
    @version 2.0
    """

    @staticmethod
    def verifier_presence_fichier_ini():
        """
        Vérifier si les fichiers de zone interet sont déjà présents dans le dossier
        :return: true si présent, false sinon
        """
        return os.path.isfile('./zi/param.ini')

    @staticmethod
    def supprimer_ZI(window):
        """
        La méthode pour gérer la suppresion de zone interet
        :param window: le fenetre principale
        :return:
        """
        if os.path.isfile('./zi/param.ini'):
            try:
                os.remove("./zi/param.ini")
                os.remove("./zi/image_modele.png")
                os.remove("./zi/image_zone_interet.png")
                QMessageBox.information(window, "Information", "Supprimer la Zone d'intérêt avec succès", QMessageBox.Ok)
            except OSError:
                QMessageBox.warning(window, "Erreur", "Impossible de supprimer les fichiers dans le repertoire /zi",
                                    QMessageBox.Ok)
        else:
            QMessageBox.warning(window, "Erreur", "Impossible de trouver les fichiers dans le repertoire /zi",
                                QMessageBox.Ok)


    def __init__(self, video):
        """
        Initialise les variables nécessaires à l'affichage de l'image et aux événements
        :param video: la vidéo à traiter
        """
        self.flag = False
        self.get_one_image_from_video(video)

        # On se sert de l'image extraite précédemment
        self.img = mpimg.imread('./zi/image_modele.png')

        # On initialise le titre de la fenêtre
        fig = plt.figure(1)
        fig.canvas.set_window_title("Zone Interet")

        # On récupère les infos des axes
        self.ax = plt.gca()

        # On initialise le futur rectangle dessiné (non rempli aux bordures rouges)
        self.rect = Rectangle((0, 0), 1, 1, fill=False, edgecolor="red")

        # Initialisation des points du rectangle
        self.x0 = None
        self.y0 = None
        self.x1 = None
        self.y1 = None
        self.ax.add_patch(self.rect)

        # Liaison des événements
        self.ax.figure.canvas.mpl_connect('button_press_event', self.on_mouseclick_press)
        self.ax.figure.canvas.mpl_connect('button_release_event', self.on_mouseclick_release)
        self.ax.figure.canvas.mpl_connect('key_press_event', self.on_keyboard_press)

        # Affichage de l'image dans la fenêtre
        self.imgplot = plt.imshow(self.img)

        self.show_window()

    def on_mouseclick_press(self, event):
        """
        Un click gauche -> sauvegarde des coordonnées du pointeur
        :param event: évènement de clique
        :return:
        """
        self.x0 = event.xdata
        self.y0 = event.ydata


    def on_mouseclick_release(self, event):
        """
        Click gauche relâché -> dessin du rectangle
        :param event: évènement de souris
        :return:
        """
        self.x1 = event.xdata
        self.y1 = event.ydata
        self.rect.set_width(self.x1 - self.x0)
        self.rect.set_height(self.y1 - self.y0)
        self.rect.set_xy((self.x0, self.y0))
        self.ax.figure.canvas.draw()


    def on_keyboard_press(self, event):
        """
        Si la touche "enter" est appuyée, on sauvegarde la zone d'intérêt
        :param event: évenenment de keyboard
        :return:
        """
        if event.key == 'enter':
            self.flag = True
            with open("./zi/param.ini", "w") as file:
                file.write(str(int(self.rect.get_x())) + ",")
                file.write(str(int(self.rect.get_y())) + ",")
                file.write(str(int(self.rect.get_width())) + ",")
                file.write(str(int(self.rect.get_height())))

            # On cache les axes avant d'enregistrer l'image modele avec la zone d'interet
            self.ax.get_xaxis().set_visible(False)
            self.ax.get_yaxis().set_visible(False)
            plt.title("Zone interet")
            plt.savefig("./zi/image_zone_interet.png")
            plt.close()


    def show_window(self):
        """
        Pour afficher la fenêtre qui est utilisée pour choisir une zone interet
        :return:
        """
        plt.title("Selectionner la zone interet avec la souris. Appuyez sur entrer pour valider.")
        plt.show()

    def get_one_image_from_video(self, video):
        """
        Extrait une image de la vidéo selectionnée
        Cette image est utilisée pour choisir une zone interet
        :param video: la vidéo choisie
        :return:
        """
        video_capture = cv2.VideoCapture(video)
        nb_frame = video_capture.get(cv2.CAP_PROP_FRAME_COUNT)
        video_capture.set(cv2.CAP_PROP_FRAME_COUNT, int(nb_frame - 1))
        success, self.image = video_capture.read()
        #sauvegarder l'image
        cv2.imwrite("zi/image_modele.png", self.image)
Exemple #22
0
def handle_event():
    global command
    global command_meta
    global main_pic
    global history
    global patch
    global patches
    global click_handlers
    global G

    if command == "horizontal_line" or command == "vertical_line":
        h, w = main_pic.shape[:2]
        if patch is not None:
            w1, h1 = patch.get_xy()
            if command == "horizontal_line":
                line = Line(0, int(h1), w, int(h1), int(patch.get_height()),
                            magenta)
            else:
                line = Line(int(w1), 0, int(w1), h, int(patch.get_width()),
                            magenta)
            main_pic = draw_line_on_picture(main_pic, line)
            patch = None
        else:
            if command == "horizontal_line":
                patch = Rectangle((0, 0), w, 1, edgecolor='magenta', alpha=1)
            else:
                patch = Rectangle((0, 0), 1, h, edgecolor='magenta', alpha=1)

    if command == "needle" or command == "angle_needle":
        G["needle"]["active"] = True
        just_added_patch = False
        if "pt1" in G["needle"] and "pt2" in G["needle"]:
            if patch is None:
                print "Drawing needle patch"
                pt1 = G["needle"]["pt1"]
                pt2 = G["needle"]["pt2"]
                if command == "needle":
                    patch = Rectangle((pt1[0], pt1[1]),
                                      abs(pt2[0] - pt1[0]),
                                      abs(pt2[1] - pt1[1]),
                                      edgecolor='magenta',
                                      alpha=1,
                                      facecolor='magenta')
                else:
                    patch = Polygon(np.array([pt1, pt2,
                                              p(pt1), p(pt2)]),
                                    closed=False,
                                    edgecolor='magenta',
                                    alpha=1,
                                    facecolor='magenta')
                    angle = get_angle(pt1, pt2)
                    print("Angle :{}".format(angle))
                    # how to add text?
                just_added_patch = True

        if patch is not None and not just_added_patch:
            if isinstance(patch, Polygon):
                patches.append(patch)
                patch = None
            else:
                print "finalize"
                w1, h1 = patch.get_xy()
                w = patch.get_width()
                h = patch.get_height()

                if w > h:
                    print("horizontal patch")
                    line = Line(int(w1), int(h1), int(w1 + w), int(h1), 3,
                                magenta)
                else:
                    line = Line(int(w1), int(h1), int(w1), int(h1 + h), 3,
                                magenta)

                main_pic = draw_line_on_picture(main_pic, line)
            G["needle"] = {}

    if command == "divide":
        divide(command_meta.xdata, command_meta.ydata)
    if command == "brighten":
        main_pic = do_brighten(main_pic)
    if command == "mirror":
        main_pic = np.fliplr(main_pic)
    if command == "zoom":
        click_handlers = not click_handlers
    if command == "darken":
        main_pic = do_darken(main_pic)
    if command == "edge":
        main_pic = edge_detect(main_pic)
    if command == "resize_patch":
        if patch is not None:
            h = patch.get_height()
            w = patch.get_width()
            patch.set_width(int(w * 0.9))
            patch.set_height(int(h * 0.9))

    if command == "crop":
        if patch is not None:
            # apply patch
            # crop main_pic
            h = patch.get_height()
            w = patch.get_width()
            w1, h1 = patch.get_xy()
            main_pic = main_pic[slice(h1, h1 + h),
                                slice(w1, w1 + w),
                                slice(None)]
            patch = None

        else:
            # create patch
            # TODO: can read this from settings :))
            portrait_ratio = 14.8 / 20.8
            if orientation == "portrait":
                w_to_h = portrait_ratio
            else:
                w_to_h = 1.0 / portrait_ratio
            shape = main_pic.shape
            border = 15
            hp = shape[0] - border
            wp = shape[1] - border

            if w_to_h * hp > wp:
                tw = wp
                th = wp / w_to_h
            else:
                th = hp
                tw = w_to_h * hp
            print th, tw
            patch = Rectangle((0, 0),
                              tw,
                              th,
                              edgecolor='magenta',
                              alpha=1,
                              facecolor='none')
    if command == "undo":
        print "Undoing"
        print len(history)
        if len(history) >= 2:
            main_pic, cmd = history[-2]
            print cmd
            history = history[:-1]

    if command != "undo":
        history.append((np.copy(main_pic), command))
    if command not in [
            "crop", "horizontal_line", "vertical_line", "needle",
            "angle_needle", "resize_patch"
    ]:
        patch = None
    command = None
    command_meta = None
    plot(patch=patch, click_handlers=click_handlers)
    if command is not None:
        handle_event()
Exemple #23
0
def handle_event():
    global command
    global command_meta
    global main_pic
    global history
    global patch
    global patches
    global click_handlers
    global G


    if command=="horizontal_line" or command=="vertical_line":
        h,w = main_pic.shape[:2]
        if patch is not None:
            w1,h1 = patch.get_xy()
            if command=="horizontal_line":
                line = Line(0,int(h1),w,int(h1), int(patch.get_height()), magenta)
            else:
                line = Line(int(w1),0,int(w1),h, int(patch.get_width()), magenta)
            main_pic = draw_line_on_picture(main_pic, line)
            patch=None
        else:
            if command=="horizontal_line":
                patch = Rectangle((0,0), w, 1, edgecolor='magenta', alpha=1)
            else:
                patch = Rectangle((0,0), 1, h, edgecolor='magenta', alpha=1)

    if command=="needle" or command=="angle_needle":
        G["needle"]["active"] = True
        just_added_patch = False
        if "pt1" in G["needle"] and "pt2" in G["needle"]: 
            if patch is None:
                print "Drawing needle patch"
                pt1 = G["needle"]["pt1"]
                pt2 = G["needle"]["pt2"]
                if command=="needle":
                    patch = Rectangle((pt1[0], pt1[1]), abs(pt2[0]-pt1[0]), abs(pt2[1]-pt1[1]), edgecolor='magenta', alpha=1, facecolor='magenta')
                else:
                    patch = Polygon(np.array([pt1, pt2, p(pt1), p(pt2)]), closed=False,
                            edgecolor='magenta', alpha=1, facecolor='magenta')
                    angle = get_angle(pt1, pt2)
                    print ("Angle :{}".format(angle)) 
                    # how to add text?
                just_added_patch = True

        if patch is not None and not just_added_patch:
            if isinstance(patch, Polygon):
                patches.append(patch)
                patch=None
            else:
                print "finalize"
                w1,h1 = patch.get_xy()
                w = patch.get_width()
                h = patch.get_height()

                if w>h:
                    print("horizontal patch")
                    line = Line(int(w1),int(h1),int(w1+w),int(h1), 3, magenta)
                else:
                    line = Line(int(w1),int(h1),int(w1),int(h1+h), 3, magenta)

                main_pic = draw_line_on_picture(main_pic, line)
            G["needle"] = {}

    if command == "divide":
        divide(command_meta.xdata, command_meta.ydata)
    if command == "brighten":
        main_pic = do_brighten(main_pic)
    if command == "mirror":
	main_pic = np.fliplr(main_pic)
    if command == "zoom":
        click_handlers = not click_handlers
    if command == "darken":
        main_pic = do_darken(main_pic)
    if command == "edge":
        main_pic = edge_detect(main_pic)
    if command == "resize_patch":
        if patch is not None:
            h = patch.get_height()
            w = patch.get_width()
            patch.set_width(int(w * 0.9))
            patch.set_height(int(h * 0.9))

    if command == "crop":
        if patch is not None:
            # apply patch
            # crop main_pic
            h = patch.get_height()
            w = patch.get_width()
            w1,h1 = patch.get_xy()
            main_pic = main_pic[slice(h1,h1+h),slice(w1,w1+w),slice(None)]
            patch=None

        else:
            # create patch
            # TODO: can read this from settings :))
            portrait_ratio = 14.8/20.8
            if orientation=="portrait":
                w_to_h = portrait_ratio
            else:
                w_to_h = 1.0/portrait_ratio
            shape = main_pic.shape
            border = 15
            hp = shape[0] - border
            wp = shape[1] - border

            if w_to_h * hp >wp:
                tw = wp
                th = wp / w_to_h 
            else:
                th = hp
                tw = w_to_h * hp
            print th,tw
            patch = Rectangle((0,0), tw, th, edgecolor='magenta', alpha=1, facecolor='none')
    if command == "undo":
        print "Undoing"
        print len(history)
        if len(history)>=2:
            main_pic,cmd = history[-2]
            print cmd
            history = history[:-1]

    if command!="undo":
        history.append((np.copy(main_pic),command))
    if command not in ["crop","horizontal_line","vertical_line","needle","angle_needle","resize_patch"]:
        patch = None
    command = None
    command_meta = None
    plot(patch=patch, click_handlers=click_handlers)
    if command is not None:
        handle_event()
Exemple #24
0
class PixelInteractor(QObject):

    epsilon = 10
    showverts = True
    mySignal = pyqtSignal(str)
    modSignal = pyqtSignal(str)

    
    def __init__(self,ax,corner,width,angle=0.):
        super().__init__()
        from matplotlib.patches import Rectangle
        from matplotlib.lines import Line2D
        # from matplotlib.artist import Artist
        # To avoid crashing with maximum recursion depth exceeded
        import sys
        sys.setrecursionlimit(10000) # 10000 is 10x the default value

        self.type = 'Pixel'
        height = width
        self.ax = ax
        self.angle  = angle
        self.width  = width
        self.height = width
        # print('corner is ', corner)
        self.rect = Rectangle(corner,width,height,edgecolor='Lime',facecolor='none',angle=angle,fill=False,animated=True)
        self.ax.add_patch(self.rect)
        self.canvas = self.rect.figure.canvas

        x,y = self.compute_markers()
        self.line = Line2D(x, y, marker='s', linestyle=None, linewidth=0., markerfacecolor='g', animated=True)
        self.ax.add_line(self.line)

        self.cid = self.rect.add_callback(self.rectangle_changed)
        self._ind = None  # the active point

        self.connect()

        self.aperture = self.rect
        self.press = None
        self.lock = None


    def compute_markers(self):

        # theta0 = self.rect.angle / 180.*np.pi
        w0 = self.rect.get_width()
        # h0 = self.rect.get_height()
        x0,y0 = self.rect.get_xy()
        angle0 = self.rect.angle

        x = [x0+w0/np.sqrt(2.)*np.sin((45.-angle0)*np.pi/180.)]
        y = [y0+w0/np.sqrt(2.)*np.cos((45.-angle0)*np.pi/180.)]

        self.xy = [(x,y)]
        return x, y

    def connect(self):
        self.cid_draw = self.canvas.mpl_connect('draw_event', self.draw_callback)
        self.cid_press = self.canvas.mpl_connect('button_press_event', self.button_press_callback)
        self.cid_release = self.canvas.mpl_connect('button_release_event', self.button_release_callback)
        self.cid_motion = self.canvas.mpl_connect('motion_notify_event', self.motion_notify_callback)
        self.cid_key = self.canvas.mpl_connect('key_press_event', self.key_press_callback)
        self.canvas.draw_idle()

        
    def disconnect(self):
        self.canvas.mpl_disconnect(self.cid_draw)
        self.canvas.mpl_disconnect(self.cid_press)
        self.canvas.mpl_disconnect(self.cid_release)
        self.canvas.mpl_disconnect(self.cid_motion)
        self.canvas.mpl_disconnect(self.cid_key)
        self.rect.remove()
        self.line.remove()
        self.canvas.draw_idle()
        self.aperture = None
        
    def draw_callback(self, event):
        self.background = self.canvas.copy_from_bbox(self.ax.bbox)
        self.ax.draw_artist(self.rect)
        self.ax.draw_artist(self.line)


    def rectangle_changed(self, rect):
        'this method is called whenever the polygon object is called'
        # only copy the artist props to the line (except visibility)
        vis = self.line.get_visible()
        Artist.update_from(self.line, rect)
        self.line.set_visible(vis)  

        
    def get_ind_under_point(self, event):
        'get the index of the point if within epsilon tolerance'

        x, y = self.xy[0]
        d = np.hypot(x - event.xdata, y - event.ydata)

        if d >= self.epsilon:
            ind = None
        else:
            ind = 0
            
        return ind

    def button_press_callback(self, event):
        'whenever a mouse button is pressed'
        if not self.showverts:
            return
        if event.inaxes is None:
            return
        if event.button != 1:
            return
        self._ind = self.get_ind_under_point(event)
        x0, y0 = self.rect.get_xy()
        w0, h0 = self.rect.get_width(), self.rect.get_height()
        theta0 = self.rect.angle/180*np.pi
        self.press = x0, y0, w0, h0, theta0, event.xdata, event.ydata
        self.xy0 = self.xy

        self.lock = "pressed"


    def key_press_callback(self, event):
        'whenever a key is pressed'
        if not event.inaxes:
            return

        if event.key == 't':
            self.showverts = not self.showverts
            self.line.set_visible(self.showverts)
            if not self.showverts:
                self._ind = None
        elif event.key == 'd':
            self.mySignal.emit('rectangle deleted')

        self.canvas.draw_idle()

    def button_release_callback(self, event):
        'whenever a mouse button is released'
        if not self.showverts:
            return
        if event.button != 1:
            return
        self._ind = None
        self.press = None
        self.lock = "released"
        self.background = None
        # To get other aperture redrawn
        self.canvas.draw_idle()
        

    def motion_notify_callback(self, event):
        'on mouse movement'

        if not self.showverts:
            return
        if self._ind is None:
            return
        if event.inaxes is None:
            return
        if event.button != 1:
            return

        x0, y0, w0, h0, theta0, xpress, ypress = self.press
        self.dx = event.xdata - xpress
        self.dy = event.ydata - ypress
        self.update_rectangle()

        # Redraw rectangle and points
        self.canvas.restore_region(self.background)
        self.ax.draw_artist(self.rect)
        self.ax.draw_artist(self.line)
        self.canvas.update()
        self.canvas.flush_events()
        
        # alternative (slower)
        # self.canvas.draw_idle()

        # Notify callback
        self.modSignal.emit('rectangle modified')

    def update_rectangle(self):

        x0, y0, w0, h0, theta0, xpress, ypress = self.press
        dx, dy = self.dx, self.dy
        
        if self.lock == "pressed":
            self.lock = "move"
        elif self.lock == "move":
            if x0+dx < 0:
                xn = x0
                dx = 0
            else:
                xn = x0+dx
            if y0+dy < 0:
                yn = y0
                dy = 0
            else:
                yn = y0+dy
            self.rect.set_xy((xn,yn))
            # update line
            self.xy = [(i+dx,j+dy) for (i,j) in self.xy0]
            # Redefine line
            self.line.set_data(zip(*self.xy))
            self.updateMarkers()

    def updateMarkers(self):
        # update points
        x,y = self.compute_markers()
        self.line.set_data(x,y)
class WindowSelectionRectangle(object):
    def __init__(self, event, axis, on_window_selection_callback):
        self.axis = axis
        if event.inaxes != self.axis:
            return
        # Store the axes it has been initialized in.
        self.axes = event.inaxes
        ymin, ymax = self.axes.get_ylim()
        self.min_x = event.xdata
        self.intial_selection_active = True
        self.rect = Rectangle((event.xdata, ymin),
                              0,
                              ymax - ymin,
                              color="0.3",
                              alpha=0.5,
                              edgecolor="0.5")
        self.axes.add_patch(self.rect)
        # Get the canvas.
        self.canvas = self.rect.figure.canvas

        # Use blittig for fast animations.
        self.rect.set_animated(True)
        self.background = self.canvas.copy_from_bbox(self.rect.axes.bbox)

        self._connect()

        self.on_window_selection_callback = on_window_selection_callback

    #def __del__(self):
    #"""
    #Disconnect the events upon deallocating.
    #"""
    #self.canvas.mpl_disconnect(self.conn_button_press)
    #self.canvas.mpl_disconnect(self.conn_button_release)
    #self.canvas.mpl_disconnect(self.conn_mouse_motion)

    def _connect(self):
        """
        Connect to the necessary events.
        """
        self.conn_button_press = self.rect.figure.canvas.mpl_connect(
            'button_press_event', self.on_button_press)
        self.conn_button_release = self.rect.figure.canvas.mpl_connect(
            'button_release_event', self.on_button_release)
        self.conn_mouse_motion = self.rect.figure.canvas.mpl_connect(
            'motion_notify_event', self.on_mouse_motion)

    def on_button_press(self, event):
        pass

    def on_button_release(self, event):
        if event.inaxes != self.axis:
            return

        if event.button != 1:
            return
        # turn off the rect animation property and reset the background
        self.rect.set_animated(False)
        self.background = None

        self.intial_selection_active = False
        self.canvas.draw()

        x = self.rect.get_x()
        width = self.rect.get_width()

        if width < 0:
            x = x + width
            width = abs(width)

        self.on_window_selection_callback(x, width, self.axis)

    def on_mouse_motion(self, event):
        if event.button != 1 or \
                self.intial_selection_active is not True:
            return
        if event.xdata is not None:
            self.rect.set_width(event.xdata - self.min_x)

        # restore the background region
        self.canvas.restore_region(self.background)
        # redraw just the current rectangle
        self.axes.draw_artist(self.rect)
        # blit just the redrawn area
        self.canvas.blit(self.axes.bbox)
Exemple #26
0
class Obstacle(Element):
    def __str__(self):
        pars = self.type, self.x_0, self.y_0, abs(self.x_1 - self.x_0), abs(
            self.y_1 - self.x_1), self._id, self._label
        fmt = "%s at (%g, %g) with width %g and height %g, ID: %s, Label: %s"
        return fmt % pars

    def __init__(self, x0, y0):
        Element.__init__(self)

        self.type = "Obstacle"
        self.x_0 = float(x0 if not Mode.snap_to_grid else round(x0))
        self.y_0 = float(y0 if not Mode.snap_to_grid else round(y0))
        self.x_1 = None
        self.y_1 = None

        self.drawing_started = False
        self.finalized = False

        self.rect = Rectangle((0, 0), 1, 1, zorder=2, picker=5)
        Graph.obstacles.append(self)

    def setID(self, ID=None):
        if ID == None:
            ## The ID of the obstacle simply is its index in the obstacles array
            self._id = "obst_" + str(getHighestIndex(Graph.obstacles) +
                                     1).zfill(MAX_OBST)
        else:
            self._id = ID
        ## The label is initially assigned equal to the ID
        self.setLabel(self._id)

    def setLabel(self, label, drawNow=False, addGraphLabel=False):
        self._label = label

        if addGraphLabel:
            if self.matplotlib_label == None:
                x = self.x_0 + self.matplotlib_element.get_width() / 2
                y = self.y_0 + self.matplotlib_element.get_height() / 2
                self.matplotlib_label = self.axes.text(
                    x,
                    y,
                    label,
                    color='black',
                    fontsize=FONTSIZE,
                    bbox={
                        'facecolor': 'white',
                        'edgecolor': 'none',
                        'alpha': 0.9,
                        'pad': 0.2
                    },
                    horizontalalignment='center',
                    verticalalignment='center',
                    zorder=2)
            else:
                self.matplotlib_label.set_text(label)

            if drawNow: self.canvas.draw()

    def addDrawing(self, axes, canvas, x1, y1, drawNow=False):
        self.axes = axes
        self.canvas = canvas
        if not self.drawing_started:
            self.axes.add_patch(self.rect)
            self.drawing_started = True
        if not self.finalized:
            x_1 = float(x1 if not Mode.snap_to_grid else round(x1))
            y_1 = float(y1 if not Mode.snap_to_grid else round(y1))
            self.rect.set_width(x_1 - self.x_0)
            self.rect.set_height(y_1 - self.y_0)
            self.rect.set_xy((self.x_0, self.y_0))
            if drawNow: self.canvas.draw()

    def finalizeDrawing(self, x1, y1):
        self.x_1 = self.rect.get_width() + self.x_0
        self.y_1 = self.rect.get_height() + self.y_0

        self.matplotlib_element = self.rect

    def delete(self, now=True):
        ## Delete graphic elements
        # - Label
        if not self.matplotlib_label == None:
            self.matplotlib_label.remove()
        # - Obstacle
        if not self.matplotlib_element == None:
            self.matplotlib_element.remove()
        # Finally update the canvas
        if now: self.canvas.draw()

        ## Remove array elements
        Graph.obstacles.remove(self)
Exemple #27
0
class usb1Windows(QWidget):
    def __del__(self):
        if hasattr(self, "camera"):
            self.camera.release()  # 释放资源

    def init_fun(self):
        self.window = Ui_Form()
        self.window.setupUi(self)

        self.timer = QTimer()  # 定义一个定时器对象
        self.timer.timeout.connect(self.timer_fun)  #计时结束调用方法

        # 1. open usb and show
        self.window.pushButton_2.clicked.connect(self.timer_start)
        # 2. catch one picture
        self.window.pushButton.clicked.connect(self.catch_picture)

        self.window.comboBox.currentIndexChanged.connect(
            self.set_width_and_height)
        self.window.checkBox.clicked.connect(self.get_faces_flag_fun)

        self.window.pushButton_5.clicked.connect(self.preview_picture)
        self.window.pushButton_4.clicked.connect(self.save_picture)

        self.window.pic_figure.canvas.mpl_connect('button_press_event',
                                                  self.on_press)
        self.window.pic_figure.canvas.mpl_connect('button_release_event',
                                                  self.on_release)

        self.getface_flag = False

        fm = open("./identiffun/faces.conf", 'r')
        self.names = fm.read().split(";")
        fm.close()
        self.my_get_face = Get_Faces(self.names)

    def on_press(self, event):
        self.on_x0 = event.xdata
        self.on_y0 = event.ydata
        if not hasattr(self, "rectload"):
            self.rectload = Rectangle((0, 0),
                                      0,
                                      0,
                                      linestyle='solid',
                                      fill=False,
                                      edgecolor='red')
            self.window.pic_figaxes.add_patch(self.rectload)

    def on_release(self, event):
        self.on_x1 = event.xdata
        self.on_y1 = event.ydata
        x_start = int(min(self.on_x0, self.on_x1))
        x_end = int(max(self.on_x0, self.on_x1))
        y_start = int(min(self.on_y0, self.on_y1))
        y_end = int(max(self.on_y0, self.on_y1))
        self.rectload.set_xy((x_start, y_start))
        self.rectload.set_height(y_end - y_start + 1)
        self.rectload.set_width(x_end - x_start + 1)
        self.window.pic_figaxes.figure.canvas.draw()

    def save_picture(self):
        if hasattr(self, 'preview_res'):
            tmp_save_picture = self.preview_res
        else:
            if hasattr(self, 'raw_frame'):
                tmp_save_picture = self.raw_frame
            else:
                return  # no pic
        cv2.imwrite("./image/save.jpg", tmp_save_picture)
        if hasattr(self, "rectload"):
            x, y = self.rectload.get_xy()
            w = self.rectload.get_width()
            h = self.rectload.get_height()
            cv2.imwrite("./image/ret.jpg", tmp_save_picture[y:y + h, x:x + w])
        # filename, filetype = QFileDialog.getSaveFileName(self, "save", "jpg Files(*.jpg)::All Files(*)")
        # if filename:
        #     cv2.imwrite(filename, tmp_save_picture)

    def preview_picture(self):
        if hasattr(self, 'raw_frame'):
            width = self.window.spinBox.value()
            height = self.window.spinBox_2.value()
            # self.raw_frame.reszie((width, height))
            self.preview_res = cv2.resize(self.raw_frame, (width, height),
                                          interpolation=cv2.INTER_CUBIC)
            self.showimg2figaxes2(self.preview_res)

    def get_faces_flag_fun(self):
        if self.window.checkBox.isChecked():
            self.getface_flag = True
        else:
            self.getface_flag = False
        # print(self.getface_flag)

    def set_width_and_height(self):
        # print(self.window.comboBox.currentText())
        width, height = self.window.comboBox.currentText().split('*')
        if hasattr(self, "camera"):
            self.camera.set(cv2.CAP_PROP_FRAME_WIDTH, int(width))
            self.camera.set(cv2.CAP_PROP_FRAME_HEIGHT, int(height))

    def catch_picture(self):
        if hasattr(self, "camera") and self.camera.isOpened():
            ret, frame = self.camera.read()
            if ret:
                self.raw_frame = copy.deepcopy(frame)
                if hasattr(self, 'preview_res'):
                    del self.preview_res
                self.showimg2figaxes2(frame)
            else:
                pass  # get faild

    def timer_fun(self):
        ret, frame = self.camera.read()
        if ret:
            self.showimg2figaxes(frame)
        else:
            self.timer.stop()

    def timer_start(self):
        if hasattr(self, "camera"):
            if not self.camera.isOpened():
                self.camera.open(0)
                # self.camera = cv2.VideoCapture(0)
        else:
            self.camera = cv2.VideoCapture(0)
        if self.camera.isOpened():
            pass
        else:
            self.camera.open(0)
        # get
        width = self.camera.get(cv2.CAP_PROP_FRAME_WIDTH)
        print(width)
        height = self.camera.get(cv2.CAP_PROP_FRAME_HEIGHT)
        print(int(height))
        self.window.comboBox.setCurrentText("%d*%d" %
                                            (int(width), int(height)))

        fps = self.camera.get(cv2.CAP_PROP_FPS)
        if fps == float('inf'):
            pass
        else:
            print(fps)

        brightness = self.camera.get(cv2.CAP_PROP_BRIGHTNESS)
        if brightness == float('inf'):
            self.window.doubleSpinBox_2.setValue(0.0)
        else:
            self.window.doubleSpinBox_2.setValue(brightness)

        contrast = self.camera.get(cv2.CAP_PROP_CONTRAST)
        if contrast == float('inf'):
            self.window.doubleSpinBox.setValue(0.0)
        else:
            self.window.doubleSpinBox.setValue(contrast)

        hue = self.camera.get(cv2.CAP_PROP_HUE)
        if hue == float('inf'):
            self.window.doubleSpinBox_3.setValue(0.0)
        else:
            self.window.doubleSpinBox_3.setValue(hue)

        exposure = self.camera.get(cv2.CAP_PROP_EXPOSURE)
        if exposure == float('inf'):
            self.window.doubleSpinBox_4.setValue(0.0)
        else:
            self.window.doubleSpinBox_4.setValue(exposure)  # inf

        saturation = self.camera.get(cv2.CAP_PROP_SATURATION)
        if saturation == float('inf'):
            self.window.doubleSpinBox_5.setValue(0.0)
        else:
            self.window.doubleSpinBox_5.setValue(saturation)  # inf

        self.timer.start(101)  #设置计时间隔并启动

    def showimg2figaxes2(self, frame):
        b, g, r = cv2.split(frame)
        imgret = cv2.merge([r, g, b])
        if hasattr(self, "rectload"):
            self.rectload.remove()
            del self.rectload
        self.window.pic_figaxes.clear()
        self.window.pic_figaxes.imshow(imgret)
        self.window.pic_figure.canvas.draw()

    def showimg2figaxes(self, img):
        if self.getface_flag:
            tmp_img = self.my_get_face.get_face_fun(img)
        else:
            tmp_img = img
        b, g, r = cv2.split(tmp_img)
        imgret = cv2.merge([r, g, b])  # 这个就是前面说书的,OpenCV和matplotlib显示不一样,需要转换
        self.window.video_figaxes.clear()
        self.window.video_figaxes.imshow(imgret)
        self.window.video_figure.canvas.draw()
Exemple #28
0
class StatsPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, wx.ID_ANY, wx.DefaultPosition,
                          wx.DefaultSize)
        self.ztv_frame = self.GetTopLevelParent()
        self.ztv_frame.primary_image_panel.popup_menu_cursor_modes.append(
            'Stats box')
        self.ztv_frame.primary_image_panel.available_cursor_modes[
            'Stats box'] = {
                'set-to-mode': self.set_cursor_to_stats_box_mode,
                'on_button_press': self.on_button_press,
                'on_motion': self.on_motion,
                'on_button_release': self.on_button_release
            }

        self.stats_info = None

        self.last_string_values = {
            'x0': '',
            'xsize': '',
            'x1': '',
            'y0': '',
            'ysize': '',
            'y1': ''
        }
        self.stats_rect = Rectangle((0, 0),
                                    10,
                                    10,
                                    color='magenta',
                                    fill=False,
                                    zorder=100)
        # use self.stats_rect as where we store/retrieve the x0,y0,x1,y1
        # x0,y0,x1,y1 should be limited to range of 0 to shape-1
        # but, stats should be calculated over e.g. x0:x1+1  (so that have pixels to do stats on even if x0==x1)
        # and, width/height of stats_rect should always be >= 0

        textentry_font = wx.Font(14, wx.FONTFAMILY_MODERN, wx.NORMAL,
                                 wx.FONTWEIGHT_LIGHT, False)

        values_sizer = wx.FlexGridSizer(10, 5, 0, 0)
        values_sizer.SetFlexibleDirection(wx.BOTH)
        values_sizer.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED)

        values_sizer.AddSpacer((0, 0), 0, wx.EXPAND)

        self.low_static_text = wx.StaticText(self, wx.ID_ANY, u"Low",
                                             wx.DefaultPosition,
                                             wx.DefaultSize, wx.ALIGN_RIGHT)
        self.low_static_text.Wrap(-1)
        values_sizer.Add(self.low_static_text, 0,
                         wx.ALL | wx.ALIGN_CENTER_HORIZONTAL, 0)

        self.low_static_text = wx.StaticText(self, wx.ID_ANY, u"# pix",
                                             wx.DefaultPosition,
                                             wx.DefaultSize, 0)
        self.low_static_text.Wrap(-1)
        values_sizer.Add(self.low_static_text, 0,
                         wx.ALL | wx.ALIGN_CENTER_HORIZONTAL, 0)

        self.high_static_text = wx.StaticText(self, wx.ID_ANY, u"High",
                                              wx.DefaultPosition,
                                              wx.DefaultSize, 0)
        self.high_static_text.Wrap(-1)
        values_sizer.Add(self.high_static_text, 0,
                         wx.ALL | wx.ALIGN_CENTER_HORIZONTAL, 0)

        values_sizer.AddSpacer((0, 0), 0, wx.EXPAND)

        self.x_static_text = wx.StaticText(self, wx.ID_ANY, u"x",
                                           wx.DefaultPosition, wx.DefaultSize,
                                           0)
        self.x_static_text.Wrap(-1)
        values_sizer.Add(self.x_static_text, 0,
                         wx.ALL | wx.ALIGN_CENTER_VERTICAL, 0)

        self.x0_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString,
                                       wx.DefaultPosition, wx.DefaultSize,
                                       wx.TE_PROCESS_ENTER)
        self.x0_textctrl.SetFont(textentry_font)
        values_sizer.Add(self.x0_textctrl, 0, wx.ALL, 2)
        self.x0_textctrl.Bind(wx.EVT_TEXT, self.x0_textctrl_changed)
        self.x0_textctrl.Bind(wx.EVT_TEXT_ENTER, self.x0_textctrl_entered)

        self.xsize_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString,
                                          wx.DefaultPosition, wx.DefaultSize,
                                          wx.TE_PROCESS_ENTER)
        self.xsize_textctrl.SetFont(textentry_font)
        values_sizer.Add(self.xsize_textctrl, 0, wx.ALL, 2)
        self.xsize_textctrl.Bind(wx.EVT_TEXT, self.xsize_textctrl_changed)
        self.xsize_textctrl.Bind(wx.EVT_TEXT_ENTER,
                                 self.xsize_textctrl_entered)

        self.x1_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString,
                                       wx.DefaultPosition, wx.DefaultSize,
                                       wx.TE_PROCESS_ENTER)
        self.x1_textctrl.SetFont(textentry_font)
        values_sizer.Add(self.x1_textctrl, 0, wx.ALL, 2)
        self.x1_textctrl.Bind(wx.EVT_TEXT, self.x1_textctrl_changed)
        self.x1_textctrl.Bind(wx.EVT_TEXT_ENTER, self.x1_textctrl_entered)

        self.npix_static_text = wx.StaticText(self, wx.ID_ANY, u"# pixels",
                                              wx.DefaultPosition,
                                              wx.DefaultSize, 0)
        self.npix_static_text.Wrap(-1)
        values_sizer.Add(self.npix_static_text, 0,
                         wx.ALL | wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_BOTTOM,
                         0)

        self.y_static_text = wx.StaticText(self, wx.ID_ANY, u"y",
                                           wx.DefaultPosition, wx.DefaultSize,
                                           0)
        self.y_static_text.Wrap(-1)
        values_sizer.Add(self.y_static_text, 0,
                         wx.ALL | wx.ALIGN_CENTER_VERTICAL, 0)

        self.y0_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString,
                                       wx.DefaultPosition, wx.DefaultSize,
                                       wx.TE_PROCESS_ENTER)
        self.y0_textctrl.SetFont(textentry_font)
        values_sizer.Add(self.y0_textctrl, 0, wx.ALL, 2)
        self.y0_textctrl.Bind(wx.EVT_TEXT, self.y0_textctrl_changed)
        self.y0_textctrl.Bind(wx.EVT_TEXT_ENTER, self.y0_textctrl_entered)

        self.ysize_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString,
                                          wx.DefaultPosition, wx.DefaultSize,
                                          wx.TE_PROCESS_ENTER)
        self.ysize_textctrl.SetFont(textentry_font)
        values_sizer.Add(self.ysize_textctrl, 0, wx.ALL, 2)
        self.ysize_textctrl.Bind(wx.EVT_TEXT, self.ysize_textctrl_changed)
        self.ysize_textctrl.Bind(wx.EVT_TEXT_ENTER,
                                 self.ysize_textctrl_entered)

        self.y1_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString,
                                       wx.DefaultPosition, wx.DefaultSize,
                                       wx.TE_PROCESS_ENTER)
        self.y1_textctrl.SetFont(textentry_font)
        values_sizer.Add(self.y1_textctrl, 0, wx.ALL, 2)
        self.y1_textctrl.Bind(wx.EVT_TEXT, self.y1_textctrl_changed)
        self.y1_textctrl.Bind(wx.EVT_TEXT_ENTER, self.y1_textctrl_entered)

        self.npix_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString,
                                         wx.DefaultPosition, wx.DefaultSize,
                                         wx.TE_READONLY)
        self.npix_textctrl.SetFont(textentry_font)
        self.npix_textctrl.SetBackgroundColour(
            textctrl_output_only_background_color)
        values_sizer.Add(self.npix_textctrl, 0,
                         wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT, 0)

        values_sizer.AddSpacer((0, 15), 0, wx.EXPAND)
        values_sizer.AddSpacer((0, 0), 0, wx.EXPAND)
        values_sizer.AddSpacer((0, 0), 0, wx.EXPAND)
        values_sizer.AddSpacer((0, 0), 0, wx.EXPAND)
        values_sizer.AddSpacer((0, 0), 0, wx.EXPAND)

        values_sizer.AddSpacer((0, 0), 0, wx.EXPAND)
        self.median_static_text = wx.StaticText(self, wx.ID_ANY, u"Median",
                                                wx.DefaultPosition,
                                                wx.DefaultSize, 0)
        self.median_static_text.Wrap(-1)
        values_sizer.Add(self.median_static_text, 0,
                         wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT, 0)
        self.median_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString,
                                           wx.DefaultPosition, wx.DefaultSize,
                                           wx.TE_READONLY)
        self.median_textctrl.SetFont(textentry_font)
        self.median_textctrl.SetBackgroundColour(
            textctrl_output_only_background_color)
        values_sizer.Add(self.median_textctrl, 0, wx.ALL, 2)
        self.robust_static_text = wx.StaticText(self, wx.ID_ANY, u"Robust",
                                                wx.DefaultPosition,
                                                wx.DefaultSize, 0)
        self.robust_static_text.Wrap(-1)
        values_sizer.Add(self.robust_static_text, 0,
                         wx.ALL | wx.ALIGN_BOTTOM | wx.ALIGN_CENTER_HORIZONTAL,
                         0)
        values_sizer.AddSpacer((0, 0), 0, wx.EXPAND)

        values_sizer.AddSpacer((0, 0), 0, wx.EXPAND)
        self.mean_static_text = wx.StaticText(self, wx.ID_ANY, u"Mean",
                                              wx.DefaultPosition,
                                              wx.DefaultSize, 0)
        self.mean_static_text.Wrap(-1)
        values_sizer.Add(self.mean_static_text, 0,
                         wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT, 0)
        self.mean_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString,
                                         wx.DefaultPosition, wx.DefaultSize,
                                         wx.TE_READONLY)
        self.mean_textctrl.SetFont(textentry_font)
        self.mean_textctrl.SetBackgroundColour(
            textctrl_output_only_background_color)
        values_sizer.Add(self.mean_textctrl, 0, wx.ALL, 2)
        self.robust_mean_textctrl = wx.TextCtrl(self, wx.ID_ANY,
                                                wx.EmptyString,
                                                wx.DefaultPosition,
                                                wx.DefaultSize, wx.TE_READONLY)
        self.robust_mean_textctrl.SetFont(textentry_font)
        self.robust_mean_textctrl.SetBackgroundColour(
            textctrl_output_only_background_color)
        values_sizer.Add(self.robust_mean_textctrl, 0, wx.ALL, 2)
        values_sizer.AddSpacer((0, 0), 0, wx.EXPAND)

        values_sizer.AddSpacer((0, 0), 0, wx.EXPAND)
        self.stdev_static_text = wx.StaticText(self, wx.ID_ANY, u"Stdev",
                                               wx.DefaultPosition,
                                               wx.DefaultSize, 0)
        self.stdev_static_text.Wrap(-1)
        values_sizer.Add(self.stdev_static_text, 0,
                         wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT, 0)
        self.stdev_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString,
                                          wx.DefaultPosition, wx.DefaultSize,
                                          wx.TE_READONLY)
        self.stdev_textctrl.SetFont(textentry_font)
        self.stdev_textctrl.SetBackgroundColour(
            textctrl_output_only_background_color)
        values_sizer.Add(self.stdev_textctrl, 0, wx.ALL, 2)
        self.robust_stdev_textctrl = wx.TextCtrl(self, wx.ID_ANY,
                                                 wx.EmptyString,
                                                 wx.DefaultPosition,
                                                 wx.DefaultSize,
                                                 wx.TE_READONLY)
        self.robust_stdev_textctrl.SetFont(textentry_font)
        self.robust_stdev_textctrl.SetBackgroundColour(
            textctrl_output_only_background_color)
        values_sizer.Add(self.robust_stdev_textctrl, 0, wx.ALL, 2)
        values_sizer.AddSpacer((0, 0), 0, wx.EXPAND)

        values_sizer.AddSpacer((0, 15), 0, wx.EXPAND)
        values_sizer.AddSpacer((0, 0), 0, wx.EXPAND)
        values_sizer.AddSpacer((0, 0), 0, wx.EXPAND)
        values_sizer.AddSpacer((0, 0), 0, wx.EXPAND)
        values_sizer.AddSpacer((0, 0), 0, wx.EXPAND)

        values_sizer.AddSpacer((0, 0), 0, wx.EXPAND)
        self.min_static_text = wx.StaticText(self, wx.ID_ANY, u"Min",
                                             wx.DefaultPosition,
                                             wx.DefaultSize, 0)
        self.min_static_text.Wrap(-1)
        values_sizer.Add(self.min_static_text, 0,
                         wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT, 0)
        self.minval_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString,
                                           wx.DefaultPosition, wx.DefaultSize,
                                           wx.TE_READONLY)
        self.minval_textctrl.SetFont(textentry_font)
        self.minval_textctrl.SetBackgroundColour(
            textctrl_output_only_background_color)
        values_sizer.Add(self.minval_textctrl, 0, wx.ALL, 2)
        self.minpos_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString,
                                           wx.DefaultPosition, wx.DefaultSize,
                                           wx.TE_READONLY)
        self.minpos_textctrl.SetFont(textentry_font)
        self.minpos_textctrl.SetBackgroundColour(
            textctrl_output_only_background_color)
        values_sizer.Add(self.minpos_textctrl, 0, wx.ALL, 2)
        values_sizer.AddSpacer((0, 0), 0, wx.EXPAND)

        values_sizer.AddSpacer((0, 0), 0, wx.EXPAND)
        self.max_static_text = wx.StaticText(self, wx.ID_ANY, u"Max",
                                             wx.DefaultPosition,
                                             wx.DefaultSize, 0)
        self.max_static_text.Wrap(-1)
        values_sizer.Add(self.max_static_text, 0,
                         wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT, 0)
        self.maxval_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString,
                                           wx.DefaultPosition, wx.DefaultSize,
                                           wx.TE_READONLY)
        self.maxval_textctrl.SetFont(textentry_font)
        self.maxval_textctrl.SetBackgroundColour(
            textctrl_output_only_background_color)
        values_sizer.Add(self.maxval_textctrl, 0, wx.ALL, 2)
        self.maxpos_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString,
                                           wx.DefaultPosition, wx.DefaultSize,
                                           wx.TE_READONLY)
        self.maxpos_textctrl.SetFont(textentry_font)
        self.maxpos_textctrl.SetBackgroundColour(
            textctrl_output_only_background_color)
        values_sizer.Add(self.maxpos_textctrl, 0, wx.ALL, 2)

        self.hideshow_button = wx.Button(self, wx.ID_ANY, u"Show",
                                         wx.DefaultPosition, wx.DefaultSize, 0)
        values_sizer.Add(
            self.hideshow_button, 0,
            wx.ALL | wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL, 2)
        self.hideshow_button.Bind(wx.EVT_BUTTON, self.on_hideshow_button)

        v_sizer1 = wx.BoxSizer(wx.VERTICAL)
        v_sizer1.AddStretchSpacer(1.0)
        v_sizer1.Add(values_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL)
        v_sizer1.AddStretchSpacer(1.0)
        self.SetSizer(v_sizer1)
        pub.subscribe(self.queue_update_stats, 'recalc-display-image-called')
        pub.subscribe(self._set_stats_box_parameters,
                      'set-stats-box-parameters')
        pub.subscribe(self.publish_stats_to_stream, 'get-stats-box-info')

    def publish_stats_to_stream(self, msg=None):
        wx.CallAfter(send_to_stream, sys.stdout,
                     ('stats-box-info', self.stats_info))

    def on_button_press(self, event):
        self.select_panel()
        self.stats_start_timestamp = event.guiEvent.GetTimestamp()  # millisec
        self.update_stats_box(event.xdata, event.ydata, event.xdata,
                              event.ydata)
        self.redraw_overplot_on_image()
        self.cursor_stats_box_x0, self.cursor_stats_box_y0 = event.xdata, event.ydata

    def on_motion(self, event):
        self.update_stats_box(self.cursor_stats_box_x0,
                              self.cursor_stats_box_y0, event.xdata,
                              event.ydata)
        self.redraw_overplot_on_image()
        self.update_stats()

    def on_button_release(self, event):
        self.redraw_overplot_on_image()
        self.update_stats()

    def set_cursor_to_stats_box_mode(self, event):
        self.ztv_frame.primary_image_panel.cursor_mode = 'Stats box'
        self.ztv_frame.stats_panel.select_panel()
        self.ztv_frame.stats_panel.highlight_panel()

    def queue_update_stats(self, msg=None):
        """
        wrapper to call update_stats from CallAfter in order to make GUI as responsive as possible.
        """
        wx.CallAfter(self.update_stats, msg=None)

    def _set_stats_box_parameters(self, msg):
        """
        wrapper to update_stats_box to receive messages & translate them correctly
        """
        x0, x1, y0, y1 = [None] * 4
        if msg['xrange'] is not None:
            x0, x1 = msg['xrange']
        if msg['yrange'] is not None:
            y0, y1 = msg['yrange']
        if msg['xrange'] is not None or msg['yrange'] is not None:
            self.update_stats_box(x0, y0, x1, y1)
        if msg['show_overplot'] is not None:
            if msg['show_overplot']:
                self.redraw_overplot_on_image()
            else:
                self.remove_overplot_on_image()
        send_to_stream(sys.stdout, ('set-stats-box-parameters-done', True))

    def update_stats_box(self, x0=None, y0=None, x1=None, y1=None):
        if x0 is None:
            x0 = self.stats_rect.get_x()
        if y0 is None:
            y0 = self.stats_rect.get_y()
        if x1 is None:
            x1 = self.stats_rect.get_x() + self.stats_rect.get_width()
        if y1 is None:
            y1 = self.stats_rect.get_y() + self.stats_rect.get_height()
        if x0 > x1:
            x0, x1 = x1, x0
        if y0 > y1:
            y0, y1 = y1, y0
        x0 = min(max(0, x0), self.ztv_frame.display_image.shape[1] - 1)
        y0 = min(max(0, y0), self.ztv_frame.display_image.shape[0] - 1)
        x1 = min(max(0, x1), self.ztv_frame.display_image.shape[1] - 1)
        y1 = min(max(0, y1), self.ztv_frame.display_image.shape[0] - 1)
        self.stats_rect.set_bounds(x0, y0, x1 - x0, y1 - y0)
        self.ztv_frame.primary_image_panel.figure.canvas.draw()
        self.update_stats()

    def remove_overplot_on_image(self):
        if self.stats_rect in self.ztv_frame.primary_image_panel.axes.patches:
            self.ztv_frame.primary_image_panel.axes.patches.remove(
                self.stats_rect)
        self.ztv_frame.primary_image_panel.figure.canvas.draw()
        self.hideshow_button.SetLabel(u"Show")

    def redraw_overplot_on_image(self):
        if self.stats_rect not in self.ztv_frame.primary_image_panel.axes.patches:
            self.ztv_frame.primary_image_panel.axes.add_patch(self.stats_rect)
        self.ztv_frame.primary_image_panel.figure.canvas.draw()
        self.hideshow_button.SetLabel(u"Hide")

    def on_hideshow_button(self, evt):
        if self.hideshow_button.GetLabel() == 'Hide':
            self.remove_overplot_on_image()
        else:
            self.redraw_overplot_on_image()

    def get_x0y0x1y1_from_stats_rect(self):
        x0 = self.stats_rect.get_x()
        y0 = self.stats_rect.get_y()
        x1 = x0 + self.stats_rect.get_width()
        y1 = y0 + self.stats_rect.get_height()
        return x0, y0, x1, y1

    def update_stats(self, msg=None):
        x0, y0, x1, y1 = self.get_x0y0x1y1_from_stats_rect()
        x0, y0 = int(np.round(x0)), int(np.round(y0))
        x1, y1 = int(np.round(x1)), int(np.round(y1))
        self.last_string_values['x0'] = str(int(x0))
        self.x0_textctrl.SetValue(self.last_string_values['x0'])
        self.last_string_values['y0'] = str(int(y0))
        self.y0_textctrl.SetValue(self.last_string_values['y0'])

        x_npix = int(x1 - x0 + 1)
        self.last_string_values['xsize'] = str(x_npix)
        self.xsize_textctrl.SetValue(self.last_string_values['xsize'])
        y_npix = int(y1 - y0 + 1)
        self.last_string_values['ysize'] = str(y_npix)
        self.ysize_textctrl.SetValue(self.last_string_values['ysize'])

        self.last_string_values['x1'] = str(int(x1))
        self.x1_textctrl.SetValue(self.last_string_values['x1'])
        self.last_string_values['y1'] = str(int(y1))
        self.y1_textctrl.SetValue(self.last_string_values['y1'])

        self.npix_textctrl.SetValue(str(x_npix * y_npix))

        stats_data = self.ztv_frame.display_image[y0:y1 + 1, x0:x1 + 1]
        finite_mask = np.isfinite(stats_data)
        if finite_mask.max() is np.True_:
            stats_data_mean = stats_data[finite_mask].mean()
            stats_data_median = np.median(stats_data[finite_mask])
            stats_data_std = stats_data[finite_mask].std()
            robust_mean, robust_median, robust_std = sigma_clipped_stats(
                stats_data[finite_mask])
        else:
            stats_data_mean = np.nan
            stats_data_median = np.nan
            stats_data_std = np.inf
            robust_mean, robust_median, robust_std = np.nan, np.nan, np.inf
        self.stats_info = {
            'xrange': [x0, x1],
            'yrange': [y0, y1],
            'mean': stats_data_mean,
            'median': stats_data_median,
            'std': stats_data_std,
            'min': stats_data.min(),
            'max': stats_data.max()
        }  # want min/max to reflect any Inf/NaN
        self.mean_textctrl.SetValue("{:0.4g}".format(self.stats_info['mean']))
        self.median_textctrl.SetValue("{:0.4g}".format(
            self.stats_info['median']))
        self.stdev_textctrl.SetValue("{:0.4g}".format(self.stats_info['std']))
        self.stats_info['robust-mean'] = robust_mean
        self.stats_info['robust-median'] = robust_median
        self.stats_info['robust-std'] = robust_std
        self.robust_mean_textctrl.SetValue("{:0.4g}".format(robust_mean))
        self.robust_stdev_textctrl.SetValue("{:0.4g}".format(robust_std))
        self.minval_textctrl.SetValue("{:0.4g}".format(self.stats_info['min']))
        self.maxval_textctrl.SetValue("{:0.4g}".format(self.stats_info['max']))
        wmin = np.where(stats_data == stats_data.min())
        wmin = [(wmin[1][i] + x0, wmin[0][i] + y0)
                for i in np.arange(wmin[0].size)]
        if len(wmin) == 1:
            wmin = wmin[0]
        self.minpos_textctrl.SetValue("{}".format(wmin))
        self.stats_info['wmin'] = wmin
        wmax = np.where(stats_data == stats_data.max())
        wmax = [(wmax[1][i] + x0, wmax[0][i] + y0)
                for i in np.arange(wmax[0].size)]
        if len(wmax) == 1:
            wmax = wmax[0]
        self.maxpos_textctrl.SetValue("{}".format(wmax))
        self.stats_info['wmax'] = wmax
        set_textctrl_background_color(self.x0_textctrl, 'ok')
        set_textctrl_background_color(self.x1_textctrl, 'ok')
        set_textctrl_background_color(self.xsize_textctrl, 'ok')
        set_textctrl_background_color(self.y0_textctrl, 'ok')
        set_textctrl_background_color(self.y1_textctrl, 'ok')
        set_textctrl_background_color(self.ysize_textctrl, 'ok')

    def x0_textctrl_changed(self, evt):
        validate_textctrl_str(self.x0_textctrl, int,
                              self.last_string_values['x0'])

    def x0_textctrl_entered(self, evt):
        if validate_textctrl_str(self.x0_textctrl, int,
                                 self.last_string_values['x0']):
            self.last_string_values['x0'] = self.x0_textctrl.GetValue()
            self.update_stats_box(int(self.last_string_values['x0']), None,
                                  None, None)
            self.x0_textctrl.SetSelection(-1, -1)
            self.redraw_overplot_on_image()

    def xsize_textctrl_changed(self, evt):
        validate_textctrl_str(self.xsize_textctrl, int,
                              self.last_string_values['xsize'])

    def xsize_textctrl_entered(self, evt):
        if validate_textctrl_str(self.xsize_textctrl, int,
                                 self.last_string_values['xsize']):
            self.last_string_values['xsize'] = self.xsize_textctrl.GetValue()
            xsize = int(self.last_string_values['xsize'])
            sys.stderr.write("\n\nxsize = {}\n\n".format(xsize))
            x0, y0, x1, y1 = self.get_x0y0x1y1_from_stats_rect()
            xc = (x0 + x1) / 2.
            x0 = max(0, int(xc - xsize / 2.))
            x1 = x0 + xsize - 1
            x1 = min(x1, self.ztv_frame.display_image.shape[1] - 1)
            x0 = x1 - xsize + 1
            x0 = max(0, int(xc - xsize / 2.))
            self.update_stats_box(x0, y0, x1, y1)
            self.xsize_textctrl.SetSelection(-1, -1)
            self.redraw_overplot_on_image()

    def x1_textctrl_changed(self, evt):
        validate_textctrl_str(self.x1_textctrl, int,
                              self.last_string_values['x1'])

    def x1_textctrl_entered(self, evt):
        if validate_textctrl_str(self.x1_textctrl, int,
                                 self.last_string_values['x1']):
            self.last_string_values['x1'] = self.x1_textctrl.GetValue()
            self.update_stats_box(None, None,
                                  int(self.last_string_values['x1']), None)
            self.x1_textctrl.SetSelection(-1, -1)
            self.redraw_overplot_on_image()

    def y0_textctrl_changed(self, evt):
        validate_textctrl_str(self.y0_textctrl, int,
                              self.last_string_values['y0'])

    def y0_textctrl_entered(self, evt):
        if validate_textctrl_str(self.y0_textctrl, int,
                                 self.last_string_values['y0']):
            self.last_string_values['y0'] = self.y0_textctrl.GetValue()
            self.update_stats_box(None, int(self.last_string_values['y0']),
                                  None, None)
            self.y0_textctrl.SetSelection(-1, -1)
            self.redraw_overplot_on_image()

    def ysize_textctrl_changed(self, evt):
        validate_textctrl_str(self.ysize_textctrl, int,
                              self.last_string_values['ysize'])

    def ysize_textctrl_entered(self, evt):
        if validate_textctrl_str(self.ysize_textctrl, int,
                                 self.last_string_values['ysize']):
            self.last_string_values['ysize'] = self.ysize_textctrl.GetValue()
            ysize = int(self.last_string_values['ysize'])
            x0, y0, x1, y1 = self.get_x0y0x1y1_from_stats_rect()
            yc = (y0 + y1) / 2.
            y0 = max(0, int(yc - ysize / 2.))
            y1 = y0 + ysize - 1
            y1 = min(y1, self.ztv_frame.display_image.shape[0] - 1)
            y0 = y1 - ysize + 1
            y0 = max(0, int(yc - ysize / 2.))
            self.update_stats_box(x0, y0, x1, y1)
            self.ysize_textctrl.SetSelection(-1, -1)
            self.redraw_overplot_on_image()

    def y1_textctrl_changed(self, evt):
        validate_textctrl_str(self.y1_textctrl, int,
                              self.last_string_values['y1'])

    def y1_textctrl_entered(self, evt):
        if validate_textctrl_str(self.y1_textctrl, int,
                                 self.last_string_values['y1']):
            self.last_string_values['y1'] = self.y1_textctrl.GetValue()
            self.update_stats_box(None, None, None,
                                  int(self.last_string_values['y1']))
            self.y1_textctrl.SetSelection(-1, -1)
            self.redraw_overplot_on_image()
Exemple #29
0
class StatsPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize)
        self.ztv_frame = self.GetTopLevelParent()
        self.ztv_frame.primary_image_panel.popup_menu_cursor_modes.append('Stats box')
        self.ztv_frame.primary_image_panel.available_cursor_modes['Stats box'] = {
                'set-to-mode':self.set_cursor_to_stats_box_mode,
                'on_button_press':self.on_button_press,
                'on_motion':self.on_motion,
                'on_button_release':self.on_button_release}
        self.textentry_font = wx.Font(14, wx.FONTFAMILY_MODERN, wx.NORMAL, wx.FONTWEIGHT_LIGHT, False)

        self.stats_info = None
        
        self.last_string_values = {'x0':'', 'xsize':'', 'x1':'', 'y0':'', 'ysize':'', 'y1':''}
        self.stats_rect = Rectangle((0, 0), 10, 10, color='magenta', fill=False, zorder=100)
        # use self.stats_rect as where we store/retrieve the x0,y0,x1,y1
        # x0,y0,x1,y1 should be limited to range of 0 to shape-1
        # but, stats should be calculated over e.g. x0:x1+1  (so that have pixels to do stats on even if x0==x1)
        # and, width/height of stats_rect should always be >= 0
        
        values_sizer = wx.FlexGridSizer( 10, 5, 0, 0 )
        values_sizer.SetFlexibleDirection( wx.BOTH )
        values_sizer.SetNonFlexibleGrowMode( wx.FLEX_GROWMODE_SPECIFIED )

        values_sizer.AddSpacer((0,0), 0, wx.EXPAND)

        self.low_static_text = wx.StaticText( self, wx.ID_ANY, u"Low", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_RIGHT )
        self.low_static_text.Wrap( -1 )
        values_sizer.Add(self.low_static_text, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 0)

        self.low_static_text = wx.StaticText( self, wx.ID_ANY, u"# pix", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.low_static_text.Wrap( -1 )
        values_sizer.Add(self.low_static_text, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 0)

        self.high_static_text = wx.StaticText( self, wx.ID_ANY, u"High", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.high_static_text.Wrap( -1 )
        values_sizer.Add(self.high_static_text, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 0)

        values_sizer.AddSpacer((0,0), 0, wx.EXPAND)

        self.x_static_text = wx.StaticText( self, wx.ID_ANY, u"x", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.x_static_text.Wrap( -1 )
        values_sizer.Add(self.x_static_text, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 0)

        self.x0_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize,
                                       wx.TE_PROCESS_ENTER)
        self.x0_textctrl.SetFont(self.textentry_font)
        values_sizer.Add(self.x0_textctrl, 0, wx.ALL, 2)
        self.x0_textctrl.Bind(wx.EVT_TEXT, self.x0_textctrl_changed)
        self.x0_textctrl.Bind(wx.EVT_TEXT_ENTER, self.x0_textctrl_entered)

        self.xsize_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize,
                                          wx.TE_PROCESS_ENTER)
        self.xsize_textctrl.SetFont(self.textentry_font)
        values_sizer.Add(self.xsize_textctrl, 0, wx.ALL, 2)
        self.xsize_textctrl.Bind(wx.EVT_TEXT, self.xsize_textctrl_changed)
        self.xsize_textctrl.Bind(wx.EVT_TEXT_ENTER, self.xsize_textctrl_entered)

        self.x1_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize,
                                       wx.TE_PROCESS_ENTER)
        self.x1_textctrl.SetFont(self.textentry_font)
        values_sizer.Add(self.x1_textctrl, 0, wx.ALL, 2)
        self.x1_textctrl.Bind(wx.EVT_TEXT, self.x1_textctrl_changed)
        self.x1_textctrl.Bind(wx.EVT_TEXT_ENTER, self.x1_textctrl_entered)

        self.npix_static_text = wx.StaticText( self, wx.ID_ANY, u"# pixels", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.npix_static_text.Wrap( -1 )
        values_sizer.Add(self.npix_static_text, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_BOTTOM, 0)

        self.y_static_text = wx.StaticText( self, wx.ID_ANY, u"y", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.y_static_text.Wrap( -1 )
        values_sizer.Add(self.y_static_text, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 0)

        self.y0_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize,
                                       wx.TE_PROCESS_ENTER)
        self.y0_textctrl.SetFont(self.textentry_font)
        values_sizer.Add(self.y0_textctrl, 0, wx.ALL, 2)
        self.y0_textctrl.Bind(wx.EVT_TEXT, self.y0_textctrl_changed)
        self.y0_textctrl.Bind(wx.EVT_TEXT_ENTER, self.y0_textctrl_entered)

        self.ysize_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize,
                                          wx.TE_PROCESS_ENTER)
        self.ysize_textctrl.SetFont(self.textentry_font)
        values_sizer.Add(self.ysize_textctrl, 0, wx.ALL, 2)
        self.ysize_textctrl.Bind(wx.EVT_TEXT, self.ysize_textctrl_changed)
        self.ysize_textctrl.Bind(wx.EVT_TEXT_ENTER, self.ysize_textctrl_entered)

        self.y1_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize,
                                       wx.TE_PROCESS_ENTER)
        self.y1_textctrl.SetFont(self.textentry_font)
        values_sizer.Add(self.y1_textctrl, 0, wx.ALL, 2)
        self.y1_textctrl.Bind(wx.EVT_TEXT, self.y1_textctrl_changed)
        self.y1_textctrl.Bind(wx.EVT_TEXT_ENTER, self.y1_textctrl_entered)
        
        self.npix_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize,
                                         wx.TE_READONLY)
        self.npix_textctrl.SetFont(self.textentry_font)
        self.npix_textctrl.SetBackgroundColour(textctrl_output_only_background_color)
        values_sizer.Add(self.npix_textctrl, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, 0)
  
        values_sizer.AddSpacer((0,15), 0, wx.EXPAND)
        values_sizer.AddSpacer((0,0), 0, wx.EXPAND)
        values_sizer.AddSpacer((0,0), 0, wx.EXPAND)
        values_sizer.AddSpacer((0,0), 0, wx.EXPAND)
        values_sizer.AddSpacer((0,0), 0, wx.EXPAND)

        values_sizer.AddSpacer((0,0), 0, wx.EXPAND)
        self.median_static_text = wx.StaticText( self, wx.ID_ANY, u"Median", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.median_static_text.Wrap( -1 )
        values_sizer.Add(self.median_static_text, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, 0)
        self.median_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize,
                                       wx.TE_READONLY)
        self.median_textctrl.SetFont(self.textentry_font)
        self.median_textctrl.SetBackgroundColour(textctrl_output_only_background_color)
        values_sizer.Add(self.median_textctrl, 0, wx.ALL, 2)
        self.robust_static_text = wx.StaticText( self, wx.ID_ANY, u"Robust", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.robust_static_text.Wrap( -1 )
        values_sizer.Add(self.robust_static_text, 0, wx.ALL|wx.ALIGN_BOTTOM|wx.ALIGN_CENTER_HORIZONTAL, 0)
        values_sizer.AddSpacer((0,0), 0, wx.EXPAND)

        values_sizer.AddSpacer((0,0), 0, wx.EXPAND)
        self.mean_static_text = wx.StaticText( self, wx.ID_ANY, u"Mean", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.mean_static_text.Wrap( -1 )
        values_sizer.Add(self.mean_static_text, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, 0)
        self.mean_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize,
                                       wx.TE_READONLY)
        self.mean_textctrl.SetFont(self.textentry_font)
        self.mean_textctrl.SetBackgroundColour(textctrl_output_only_background_color)
        values_sizer.Add(self.mean_textctrl, 0, wx.ALL, 2)
        self.robust_mean_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize,
                                       wx.TE_READONLY)
        self.robust_mean_textctrl.SetFont(self.textentry_font)
        self.robust_mean_textctrl.SetBackgroundColour(textctrl_output_only_background_color)
        values_sizer.Add(self.robust_mean_textctrl, 0, wx.ALL, 2)
        values_sizer.AddSpacer((0,0), 0, wx.EXPAND)

        values_sizer.AddSpacer((0,0), 0, wx.EXPAND)
        self.stdev_static_text = wx.StaticText( self, wx.ID_ANY, u"Stdev", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.stdev_static_text.Wrap( -1 )
        values_sizer.Add(self.stdev_static_text, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, 0)
        self.stdev_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize,
                                       wx.TE_READONLY)
        self.stdev_textctrl.SetFont(self.textentry_font)
        self.stdev_textctrl.SetBackgroundColour(textctrl_output_only_background_color)
        values_sizer.Add(self.stdev_textctrl, 0, wx.ALL, 2)
        self.robust_stdev_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize,
                                       wx.TE_READONLY)
        self.robust_stdev_textctrl.SetFont(self.textentry_font)
        self.robust_stdev_textctrl.SetBackgroundColour(textctrl_output_only_background_color)
        values_sizer.Add(self.robust_stdev_textctrl, 0, wx.ALL, 2)
        values_sizer.AddSpacer((0,0), 0, wx.EXPAND)

        values_sizer.AddSpacer((0,15), 0, wx.EXPAND)
        values_sizer.AddSpacer((0,0), 0, wx.EXPAND)
        values_sizer.AddSpacer((0,0), 0, wx.EXPAND)
        values_sizer.AddSpacer((0,0), 0, wx.EXPAND)
        values_sizer.AddSpacer((0,0), 0, wx.EXPAND)

        values_sizer.AddSpacer((0,0), 0, wx.EXPAND)
        self.min_static_text = wx.StaticText( self, wx.ID_ANY, u"Min", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.min_static_text.Wrap( -1 )
        values_sizer.Add(self.min_static_text, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, 0)
        self.minval_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize,
                                           wx.TE_READONLY)
        self.minval_textctrl.SetFont(self.textentry_font)
        self.minval_textctrl.SetBackgroundColour(textctrl_output_only_background_color)
        values_sizer.Add(self.minval_textctrl, 0, wx.ALL, 2)
        self.minpos_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize,
                                           wx.TE_READONLY)
        self.minpos_textctrl.SetFont(self.textentry_font)
        self.minpos_textctrl.SetBackgroundColour(textctrl_output_only_background_color)
        values_sizer.Add(self.minpos_textctrl, 0, wx.ALL, 2)
        values_sizer.AddSpacer((0,0), 0, wx.EXPAND)

        values_sizer.AddSpacer((0,0), 0, wx.EXPAND)
        self.max_static_text = wx.StaticText( self, wx.ID_ANY, u"Max", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.max_static_text.Wrap( -1 )
        values_sizer.Add(self.max_static_text, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, 0)
        self.maxval_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize,
                                           wx.TE_READONLY)
        self.maxval_textctrl.SetFont(self.textentry_font)
        self.maxval_textctrl.SetBackgroundColour(textctrl_output_only_background_color)
        values_sizer.Add(self.maxval_textctrl, 0, wx.ALL, 2)
        self.maxpos_textctrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize,
                                           wx.TE_READONLY)
        self.maxpos_textctrl.SetFont(self.textentry_font)
        self.maxpos_textctrl.SetBackgroundColour(textctrl_output_only_background_color)
        values_sizer.Add(self.maxpos_textctrl, 0, wx.ALL, 2)
             
        self.hideshow_button = wx.Button(self, wx.ID_ANY, u"Show", wx.DefaultPosition, wx.DefaultSize, 0)
        values_sizer.Add(self.hideshow_button, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 2)
        self.hideshow_button.Bind(wx.EVT_BUTTON, self.on_hideshow_button)

        v_sizer1 = wx.BoxSizer(wx.VERTICAL)
        v_sizer1.AddStretchSpacer(1.0)
        v_sizer1.Add(values_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL)
        v_sizer1.AddStretchSpacer(1.0)
        self.SetSizer(v_sizer1)
        pub.subscribe(self.queue_update_stats, 'recalc-display-image-called')
        pub.subscribe(self._set_stats_box_parameters, 'set-stats-box-parameters')
        pub.subscribe(self.publish_stats_to_stream, 'get-stats-box-info')

    def publish_stats_to_stream(self, msg=None):
        wx.CallAfter(send_to_stream, sys.stdout, ('stats-box-info', self.stats_info))

    def on_button_press(self, event):
        self.select_panel()
        self.update_stats_box(event.xdata, event.ydata, event.xdata, event.ydata)
        self.redraw_overplot_on_image()
        self.cursor_stats_box_x0, self.cursor_stats_box_y0 = event.xdata, event.ydata

    def on_motion(self, event):
        if event.button is not None:
            self.update_stats_box(self.cursor_stats_box_x0, self.cursor_stats_box_y0, event.xdata, event.ydata)
            self.redraw_overplot_on_image()
            self.update_stats()

    def on_button_release(self, event):
        self.redraw_overplot_on_image()
        self.update_stats()

    def set_cursor_to_stats_box_mode(self, event):
        self.ztv_frame.primary_image_panel.cursor_mode = 'Stats box'
        self.ztv_frame.stats_panel.select_panel()
        self.ztv_frame.stats_panel.highlight_panel()

    def queue_update_stats(self, msg=None):  
        """
        wrapper to call update_stats from CallAfter in order to make GUI as responsive as possible.
        """
        wx.CallAfter(self.update_stats, msg=None)

    def _set_stats_box_parameters(self, msg):
        """
        wrapper to update_stats_box to receive messages & translate them correctly
        """
        x0,x1,y0,y1 = [None]*4
        if msg['xrange'] is not None:
            x0,x1 = msg['xrange']
        if msg['yrange'] is not None:
            y0,y1 = msg['yrange']
        if msg['xrange'] is not None or msg['yrange'] is not None:
            self.update_stats_box(x0, y0, x1, y1)
        if msg['show_overplot'] is not None:
            if msg['show_overplot']:
                self.redraw_overplot_on_image()
            else:
                self.remove_overplot_on_image()
        send_to_stream(sys.stdout, ('set-stats-box-parameters-done', True))

    def update_stats_box(self, x0=None, y0=None, x1=None, y1=None):
        if x0 is None:
            x0 = self.stats_rect.get_x()
        if y0 is None:
            y0 = self.stats_rect.get_y()
        if x1 is None:
            x1 = self.stats_rect.get_x() + self.stats_rect.get_width()
        if y1 is None:
            y1 = self.stats_rect.get_y() + self.stats_rect.get_height()
        if x0 > x1:
            x0, x1 = x1, x0
        if y0 > y1:
            y0, y1 = y1, y0
        x0 = min(max(0, x0), self.ztv_frame.display_image.shape[1] - 1)
        y0 = min(max(0, y0), self.ztv_frame.display_image.shape[0] - 1)
        x1 = min(max(0, x1), self.ztv_frame.display_image.shape[1] - 1)
        y1 = min(max(0, y1), self.ztv_frame.display_image.shape[0] - 1)
        self.stats_rect.set_bounds(x0, y0, x1 - x0, y1 - y0)
        if self.hideshow_button.GetLabel() == 'Hide':  
            self.ztv_frame.primary_image_panel.figure.canvas.draw()
        self.update_stats()

    def remove_overplot_on_image(self):
        self.ztv_frame.primary_image_panel.remove_patch('stats_panel:stats_rect')
        self.hideshow_button.SetLabel(u"Show")

    def redraw_overplot_on_image(self):
        self.ztv_frame.primary_image_panel.add_patch('stats_panel:stats_rect', self.stats_rect)
        self.hideshow_button.SetLabel(u"Hide")        

    def on_hideshow_button(self, evt):
        if self.hideshow_button.GetLabel() == 'Hide':
            self.remove_overplot_on_image()
        else:
            self.redraw_overplot_on_image()

    def get_x0y0x1y1_from_stats_rect(self):
        x0 = self.stats_rect.get_x()
        y0 = self.stats_rect.get_y()
        x1 = x0 + self.stats_rect.get_width()
        y1 = y0 + self.stats_rect.get_height()
        return x0,y0,x1,y1
        
    def update_stats(self, msg=None):
        x0,y0,x1,y1 = self.get_x0y0x1y1_from_stats_rect()
        x0, y0 = int(np.round(x0)), int(np.round(y0))
        x1, y1 = int(np.round(x1)), int(np.round(y1))
        self.last_string_values['x0'] = str(int(x0))
        self.x0_textctrl.SetValue(self.last_string_values['x0'])
        self.last_string_values['y0'] = str(int(y0))
        self.y0_textctrl.SetValue(self.last_string_values['y0'])

        x_npix = int(x1 - x0 + 1)
        self.last_string_values['xsize'] = str(x_npix)
        self.xsize_textctrl.SetValue(self.last_string_values['xsize'])
        y_npix = int(y1 - y0 + 1)
        self.last_string_values['ysize'] = str(y_npix)
        self.ysize_textctrl.SetValue(self.last_string_values['ysize'])

        self.last_string_values['x1'] = str(int(x1))
        self.x1_textctrl.SetValue(self.last_string_values['x1'])
        self.last_string_values['y1'] = str(int(y1))
        self.y1_textctrl.SetValue(self.last_string_values['y1'])
    
        self.npix_textctrl.SetValue(str(x_npix * y_npix))

        stats_data = self.ztv_frame.display_image[y0:y1+1, x0:x1+1]
        finite_mask = np.isfinite(stats_data)
        if finite_mask.max() is np.True_:
            stats_data_mean = stats_data[finite_mask].mean()
            stats_data_median = np.median(stats_data[finite_mask])
            stats_data_std = stats_data[finite_mask].std()
            robust_mean, robust_median, robust_std = sigma_clipped_stats(stats_data[finite_mask])
        else:
            stats_data_mean = np.nan
            stats_data_median = np.nan
            stats_data_std = np.inf
            robust_mean, robust_median, robust_std = np.nan, np.nan, np.inf
        self.stats_info = {'xrange':[x0,x1], 'yrange':[y0,y1],
                           'mean':stats_data_mean, 'median':stats_data_median, 'std':stats_data_std, 
                           'min':stats_data.min(), 'max':stats_data.max()} # want min/max to reflect any Inf/NaN
        self.mean_textctrl.SetValue("{:0.4g}".format(self.stats_info['mean']))
        self.median_textctrl.SetValue("{:0.4g}".format(self.stats_info['median']))
        self.stdev_textctrl.SetValue("{:0.4g}".format(self.stats_info['std']))
        self.stats_info['robust-mean'] = robust_mean
        self.stats_info['robust-median'] = robust_median
        self.stats_info['robust-std'] = robust_std
        self.robust_mean_textctrl.SetValue("{:0.4g}".format(robust_mean)) 
        self.robust_stdev_textctrl.SetValue("{:0.4g}".format(robust_std))
        self.minval_textctrl.SetValue("{:0.4g}".format(self.stats_info['min']))
        self.maxval_textctrl.SetValue("{:0.4g}".format(self.stats_info['max']))
        wmin = np.where(stats_data == stats_data.min())
        wmin = [(wmin[1][i] + x0,wmin[0][i] + y0) for i in np.arange(wmin[0].size)]
        if len(wmin) == 1:
            wmin = wmin[0]
        self.minpos_textctrl.SetValue("{}".format(wmin))
        self.stats_info['wmin'] = wmin
        wmax = np.where(stats_data == stats_data.max())
        wmax = [(wmax[1][i] + x0,wmax[0][i] + y0) for i in np.arange(wmax[0].size)]
        if len(wmax) == 1:
            wmax = wmax[0]
        self.maxpos_textctrl.SetValue("{}".format(wmax))
        self.stats_info['wmax'] = wmax
        set_textctrl_background_color(self.x0_textctrl, 'ok')
        set_textctrl_background_color(self.x1_textctrl, 'ok')
        set_textctrl_background_color(self.xsize_textctrl, 'ok')
        set_textctrl_background_color(self.y0_textctrl, 'ok')
        set_textctrl_background_color(self.y1_textctrl, 'ok')
        set_textctrl_background_color(self.ysize_textctrl, 'ok')
        
    def x0_textctrl_changed(self, evt):
        validate_textctrl_str(self.x0_textctrl, int, self.last_string_values['x0'])

    def x0_textctrl_entered(self, evt):
        if validate_textctrl_str(self.x0_textctrl, int, self.last_string_values['x0']):
            self.last_string_values['x0'] = self.x0_textctrl.GetValue()
            self.update_stats_box(int(self.last_string_values['x0']), None, None, None)
            self.x0_textctrl.SetSelection(-1, -1)
            self.redraw_overplot_on_image()
            
    def xsize_textctrl_changed(self, evt):
        validate_textctrl_str(self.xsize_textctrl, int, self.last_string_values['xsize'])

    def xsize_textctrl_entered(self, evt):
        if validate_textctrl_str(self.xsize_textctrl, int, self.last_string_values['xsize']):
            self.last_string_values['xsize'] = self.xsize_textctrl.GetValue()
            xsize = int(self.last_string_values['xsize'])
            sys.stderr.write("\n\nxsize = {}\n\n".format(xsize))
            x0,y0,x1,y1 = self.get_x0y0x1y1_from_stats_rect()
            xc = (x0 + x1) / 2.
            x0 = max(0, int(xc - xsize / 2.))
            x1 = x0 + xsize - 1
            x1 = min(x1, self.ztv_frame.display_image.shape[1] - 1)
            x0 = x1 - xsize + 1
            x0 = max(0, int(xc - xsize / 2.))
            self.update_stats_box(x0, y0, x1, y1)
            self.xsize_textctrl.SetSelection(-1, -1)
            self.redraw_overplot_on_image()

    def x1_textctrl_changed(self, evt):
        validate_textctrl_str(self.x1_textctrl, int, self.last_string_values['x1'])

    def x1_textctrl_entered(self, evt):
        if validate_textctrl_str(self.x1_textctrl, int, self.last_string_values['x1']):
            self.last_string_values['x1'] = self.x1_textctrl.GetValue()
            self.update_stats_box(None, None, int(self.last_string_values['x1']), None)
            self.x1_textctrl.SetSelection(-1, -1)
            self.redraw_overplot_on_image()

    def y0_textctrl_changed(self, evt):
        validate_textctrl_str(self.y0_textctrl, int, self.last_string_values['y0'])

    def y0_textctrl_entered(self, evt):
        if validate_textctrl_str(self.y0_textctrl, int, self.last_string_values['y0']):
            self.last_string_values['y0'] = self.y0_textctrl.GetValue()
            self.update_stats_box(None, int(self.last_string_values['y0']), None, None)
            self.y0_textctrl.SetSelection(-1, -1)
            self.redraw_overplot_on_image()

    def ysize_textctrl_changed(self, evt):
        validate_textctrl_str(self.ysize_textctrl, int, self.last_string_values['ysize'])

    def ysize_textctrl_entered(self, evt):
        if validate_textctrl_str(self.ysize_textctrl, int, self.last_string_values['ysize']):
            self.last_string_values['ysize'] = self.ysize_textctrl.GetValue()
            ysize = int(self.last_string_values['ysize'])
            x0,y0,x1,y1 = self.get_x0y0x1y1_from_stats_rect()
            yc = (y0 + y1) / 2.
            y0 = max(0, int(yc - ysize / 2.))
            y1 = y0 + ysize - 1
            y1 = min(y1, self.ztv_frame.display_image.shape[0] - 1)
            y0 = y1 - ysize + 1
            y0 = max(0, int(yc - ysize / 2.))
            self.update_stats_box(x0, y0, x1, y1)
            self.ysize_textctrl.SetSelection(-1, -1)
            self.redraw_overplot_on_image()

    def y1_textctrl_changed(self, evt):
        validate_textctrl_str(self.y1_textctrl, int, self.last_string_values['y1'])

    def y1_textctrl_entered(self, evt):
        if validate_textctrl_str(self.y1_textctrl, int, self.last_string_values['y1']):
            self.last_string_values['y1'] = self.y1_textctrl.GetValue()
            self.update_stats_box(None, None, None, int(self.last_string_values['y1']))
            self.y1_textctrl.SetSelection(-1, -1)
            self.redraw_overplot_on_image()
Exemple #30
0
class SpanSelector(_SelectorWidget):
    """Custom SpanSelector."""

    # pylint: disable=too-many-instance-attributes
    # pylint: disable=too-many-arguments
    # pylint: disable=attribute-defined-outside-init
    # pylint: disable=invalid-name
    def __init__(self,
                 ax,
                 onselect,
                 direction,
                 minspan=None,
                 useblit=False,
                 rectprops=None,
                 onmove_callback=None,
                 span_stays=False,
                 button=None):

        _SelectorWidget.__init__(self,
                                 ax,
                                 onselect,
                                 useblit=useblit,
                                 button=button)

        if rectprops is None:
            rectprops = dict(facecolor='red', alpha=0.5)

        rectprops['animated'] = self.useblit

        if direction not in ['horizontal', 'vertical']:
            msg = "direction must be in [ 'horizontal' | 'vertical' ]"
            raise ValueError(msg)
        self.direction = direction

        self.rect = None
        self.pressv = None

        self.rectprops = rectprops
        self.onmove_callback = onmove_callback
        self.minspan = minspan
        self.span_stays = span_stays

        # Needed when dragging out of axes
        self.prev = (0, 0)

        # Reset canvas so that `new_axes` connects events.
        self.canvas = None
        self.new_axes(ax)

    def new_axes(self, ax):
        """Set SpanSelector to operate on a new Axes"""
        self.ax = ax
        if self.canvas is not ax.figure.canvas:
            if self.canvas is not None:
                self.disconnect_events()

            self.canvas = ax.figure.canvas
            self.connect_default_events()

        if self.direction == 'horizontal':
            trans = blended_transform_factory(self.ax.transData,
                                              self.ax.transAxes)
            w, h = 0, 2
        else:
            trans = blended_transform_factory(self.ax.transAxes,
                                              self.ax.transData)
            w, h = 1, 0
        self.rect = Rectangle((0, -0.5),
                              w,
                              h,
                              transform=trans,
                              visible=False,
                              **self.rectprops)
        if self.span_stays:
            self.stay_rect = Rectangle((0, 0),
                                       w,
                                       h,
                                       transform=trans,
                                       visible=False,
                                       **self.rectprops)
            self.stay_rect.set_animated(False)
            self.ax.add_patch(self.stay_rect)

        self.ax.add_patch(self.rect)
        self.artists = [self.rect]

    def set_rectprops(self, rectprops):
        """Custom: set new rectprops."""
        self.rectprops = rectprops
        self.new_axes(self.ax)

    def ignore(self, event):
        """return *True* if *event* should be ignored"""
        return _SelectorWidget.ignore(self, event) or not self.visible

    def _press(self, event):
        """on button press event"""
        if self.ignore(event):
            return True
        self.rect.set_visible(self.visible)
        if self.span_stays:
            self.stay_rect.set_visible(False)
            # really force a draw so that the stay rect is not in
            # the blit background
            if self.useblit:
                self.canvas.draw()
        xdata, ydata = self._get_data(event)
        if self.direction == 'horizontal':
            self.pressv = xdata
        else:
            self.pressv = ydata
        return False

    def _release(self, event):
        """on button release event"""
        if self.ignore(event):
            return True
        if self.pressv is None:
            return True
        self.buttonDown = False

        self.rect.set_visible(False)

        if self.span_stays:
            self.stay_rect.set_x(self.rect.get_x())
            self.stay_rect.set_y(self.rect.get_y())
            self.stay_rect.set_width(self.rect.get_width())
            self.stay_rect.set_height(self.rect.get_height())
            self.stay_rect.set_visible(True)

        self.canvas.draw_idle()
        vmin = self.pressv
        xdata, ydata = self._get_data(event)
        if self.direction == 'horizontal':
            vmax = xdata or self.prev[0]
        else:
            vmax = ydata or self.prev[1]

        if vmin > vmax:
            vmin, vmax = vmax, vmin
        span = vmax - vmin
        if self.minspan is not None and span < self.minspan:
            return True
        self.onselect(vmin, vmax)
        self.pressv = None
        return False

    def _onmove(self, event):
        """on motion notify event"""
        if self.ignore(event):
            return True
        if self.pressv is None:
            return True
        x, y = self._get_data(event)
        if x is None:
            return True

        self.prev = x, y
        if self.direction == 'horizontal':
            v = x
        else:
            v = y

        minv, maxv = v, self.pressv
        if minv > maxv:
            minv, maxv = maxv, minv
        if self.direction == 'horizontal':
            self.rect.set_x(minv)
            self.rect.set_width(maxv - minv)
        else:
            self.rect.set_y(minv)
            self.rect.set_height(maxv - minv)

        if self.onmove_callback is not None:
            vmin = self.pressv
            xdata, ydata = self._get_data(event)
            if self.direction == 'horizontal':
                vmax = xdata or self.prev[0]
            else:
                vmax = ydata or self.prev[1]

            if vmin > vmax:
                vmin, vmax = vmax, vmin
            self.onmove_callback(vmin, vmax)

        self.update()
        return False
Exemple #31
0
class RectangleInteractor(QObject):

    epsilon = 5
    showverts = True
    mySignal = pyqtSignal(str)
    modSignal = pyqtSignal(str)
    
    def __init__(self,ax,corner,width,height=None,angle=0.):
        super().__init__()
        from matplotlib.patches import Rectangle
        from matplotlib.lines import Line2D
        # from matplotlib.artist import Artist
        # To avoid crashing with maximum recursion depth exceeded
        import sys
        sys.setrecursionlimit(10000) # 10000 is 10x the default value

        if height is None:
            self.type = 'Square'
            height = width
        else:
            self.type = 'Rectangle'
        self.ax = ax
        self.angle  = angle/180.*np.pi
        self.width  = width
        self.height = height
        self.rect = Rectangle(corner,width,height,edgecolor='Lime',facecolor='none',angle=angle,fill=False,animated=True)
        self.ax.add_patch(self.rect)
        self.canvas = self.rect.figure.canvas
        x,y = self.compute_markers()
        self.line = Line2D(x, y, marker='o', linestyle=None, linewidth=0., markerfacecolor='g', animated=True)
        self.ax.add_line(self.line)
        self.cid = self.rect.add_callback(self.rectangle_changed)
        self._ind = None  # the active point
        self.connect()
        self.aperture = self.rect
        self.press = None
        self.lock = None

    def compute_markers(self):

        theta0 = self.rect.angle / 180.*np.pi
        w0 = self.rect.get_width()
        h0 = self.rect.get_height()
        x0,y0 = self.rect.get_xy()
        c, s = np.cos(-theta0), np.sin(-theta0)
        R = np.matrix('{} {}; {} {}'.format(c, s, -s, c))

        x = [0.5*w0, w0, 0.5*w0]
        y = [0.5*h0, 0.5*h0, h0]

        self.xy = []
        x_ = []
        y_ = []
        for dx,dy in zip(x,y):
            (dx_,dy_), = np.array(np.dot(R,np.array([dx,dy])))
            self.xy.append((dx_+x0,dy_+y0))
            x_.append(dx_+x0)
            y_.append(dy_+y0)

        return x_,y_

    def connect(self):
        self.cid_draw = self.canvas.mpl_connect('draw_event', self.draw_callback)
        self.cid_press = self.canvas.mpl_connect('button_press_event', self.button_press_callback)
        self.cid_release = self.canvas.mpl_connect('button_release_event', self.button_release_callback)
        self.cid_motion = self.canvas.mpl_connect('motion_notify_event', self.motion_notify_callback)
        self.cid_key = self.canvas.mpl_connect('key_press_event', self.key_press_callback)
        self.canvas.draw_idle()
        
    def disconnect(self):
        self.canvas.mpl_disconnect(self.cid_draw)
        self.canvas.mpl_disconnect(self.cid_press)
        self.canvas.mpl_disconnect(self.cid_release)
        self.canvas.mpl_disconnect(self.cid_motion)
        self.canvas.mpl_disconnect(self.cid_key)
        self.rect.remove()
        self.line.remove()
        self.canvas.draw_idle()
        self.aperture = None
        
    def draw_callback(self, event):
        self.background = self.canvas.copy_from_bbox(self.ax.bbox)
        self.ax.draw_artist(self.rect)
        self.ax.draw_artist(self.line)

    def rectangle_changed(self, rect):
        'this method is called whenever the polygon object is called'
        # only copy the artist props to the line (except visibility)
        vis = self.line.get_visible()
        Artist.update_from(self.line, rect)
        self.line.set_visible(vis)  
        
    def get_ind_under_point(self, event):
        'get the index of the point if within epsilon tolerance'

        x, y = zip(*self.xy)
        d = np.hypot(x - event.xdata, y - event.ydata)
        indseq, = np.nonzero(d == d.min())
        ind = indseq[0]

        if d[ind] >= self.epsilon:
            ind = None

        return ind

    def button_press_callback(self, event):
        'whenever a mouse button is pressed'
        if not self.showverts:
            return
        if event.inaxes is None:
            return
        if event.button != 1:
            return
        self._ind = self.get_ind_under_point(event)
        x0, y0 = self.rect.get_xy()
        w0, h0 = self.rect.get_width(), self.rect.get_height()
        theta0 = self.rect.angle/180*np.pi
        self.press = x0, y0, w0, h0, theta0, event.xdata, event.ydata
        self.xy0 = self.xy

        self.lock = "pressed"

    def key_press_callback(self, event):
        'whenever a key is pressed'
        if not event.inaxes:
            return
        if event.key == 't':
            self.showverts = not self.showverts
            self.line.set_visible(self.showverts)
            if not self.showverts:
                self._ind = None
        elif event.key == 'd':
            #self.disconnect()
            #self.rect = None
            #self.line = None
            self.mySignal.emit('rectangle deleted')
        self.canvas.draw_idle()

    def button_release_callback(self, event):
        'whenever a mouse button is released'
        if not self.showverts:
            return
        if event.button != 1:
            return
        self._ind = None
        self.press = None
        self.lock = "released"
        self.background = None
        # To get other aperture redrawn
        self.canvas.draw_idle()

    def motion_notify_callback(self, event):
        'on mouse movement'
        if not self.showverts:
            return
        if self._ind is None:
            return
        if event.inaxes is None:
            return
        if event.button != 1:
            return
        x0, y0, w0, h0, theta0, xpress, ypress = self.press
        self.dx = event.xdata - xpress
        self.dy = event.ydata - ypress
        self.update_rectangle()

        # Redraw rectangle and points
        self.canvas.restore_region(self.background)
        self.ax.draw_artist(self.rect)
        self.ax.draw_artist(self.line)
        self.canvas.update()
        self.canvas.flush_events()

        # Notify callback
        self.modSignal.emit('rectangle modified')

    def update_rectangle(self):

        x0, y0, w0, h0, theta0, xpress, ypress = self.press
        dx, dy = self.dx, self.dy
        
        if self.lock == "pressed":
            if self._ind == 0:
                self.lock = "move"
            else:
                self.lock = "resizerotate"
        elif self.lock == "move":
            if x0+dx < 0:
                xn = x0
                dx = 0
            else:
                xn = x0+dx
            if y0+dy < 0:
                yn = y0
                dy = 0
            else:
                yn = y0+dy
            self.rect.set_xy((xn,yn))
            # update line
            self.xy = [(i+dx,j+dy) for (i,j) in self.xy0]
            # Redefine line
            self.line.set_data(zip(*self.xy))
        # otherwise rotate and resize
        elif self.lock == 'resizerotate':
            xc,yc = self.xy0[0] # center is conserved in the markers
            dtheta = np.arctan2(ypress+dy-yc,xpress+dx-xc)-np.arctan2(ypress-yc,xpress-xc)
            theta_ = (theta0+dtheta) * 180./np.pi
            c, s = np.cos(theta0), np.sin(theta0)
            R = np.matrix('{} {}; {} {}'.format(c, s, -s, c))
            (dx_,dy_), = np.array(np.dot(R,np.array([dx,dy])))

            # Avoid to pass through the center            
            if self._ind == 1:
                w_ = w0+2*dx_  if (w0+2*dx_) > 0 else w0
                if self.type == 'Square':
                    h_ = w_
                else:
                    h_ = h0
            elif self._ind == 2:
                h_ = h0+2*dy_  if (h0+2*dy_) > 0 else h0
                if self.type == 'Square':
                    w_ = h_
                else:
                    w_ = w0
            # update rectangle
            self.rect.set_width(w_)
            self.rect.set_height(h_)
            self.rect.angle = theta_
            # update markers
            self.updateMarkers()

    def updateMarkers(self):
        # update points
        x,y = self.compute_markers()
        self.line.set_data(x,y)
Exemple #32
0
class cropWidget(QWidget):
    cropDoneSignal = pyqtSignal(cropInfo)

    def __init__(self, currentFileLocation = ''):
        super().__init__()
        self.filename = currentFileLocation
        self.cropInfo = cropInfo()
        self.isPressed = False
        self.cropCheckWidget = cropCheckWidget(self.cropInfo)
        self.initUI()

    def initUI(self):
        self.hbox = QHBoxLayout()

        self.fig = plt.Figure()
        self.canvas = FigureCanvas(self.fig)
        self.ax = self.fig.add_subplot(111)

        self.canvas.mpl_connect("button_press_event", self.on_press)
        self.canvas.mpl_connect("motion_notify_event", self.on_move)
        self.canvas.mpl_connect("button_release_event", self.on_release)

        self.hbox.addWidget(self.canvas)
        self.setLayout(self.hbox)

        if (self.filename !=''):
            self.data = fits.open(Path(self.filename))[0].data
            zimshow(self.ax, self.data)
        self.canvas.draw()

    def setFileName(self, fileName):
        self.filename = fileName
        self.data = fits.open(Path(self.filename))[0].data
        zimshow(self.ax, self.data)
        self.canvas.draw()

    def on_press(self, event):
        if not event.inaxes : return
        if event.inaxes != self.ax: return
        self.rect = Rectangle((0, 0), 1, 1, alpha=0.5)
        self.ax.add_patch(self.rect)
        self.x0 = event.xdata
        self.y0 = event.ydata
        self.isPressed = True

    def on_move(self, event):
        if not event.inaxes : return
        if event.inaxes != self.ax: return
        if not self.isPressed : return

        self.x1 = event.xdata
        self.y1 = event.ydata
        self.rect.set_width(self.x1 - self.x0)
        self.rect.set_height(self.y1 - self.y0)
        self.rect.set_xy((self.x0, self.y0))
        self.ax.figure.canvas.draw()

    def on_release(self, event):
        if not event.inaxes : return
        if event.inaxes != self.ax: return
        if not self.isPressed: return
        x = int(self.rect.get_x())
        y = int(self.rect.get_y())
        width = int(self.rect.get_width())
        height = int(self.rect.get_height())

        x0 = x
        x1 = x + width
        y0 = y
        y1 = y + height
        if (x0 > x1):
            x0, x1 = x1, x0
        if (y0 > y1):
            y0, y1 = y1, y0

        self.cropInfo.x0 = x0
        self.cropInfo.x1 = x1
        self.cropInfo.y0 = y0
        self.cropInfo.y1 = y1
        self.cropInfo.filename = self.filename
        self.cropDoneSignal.emit(self.cropInfo)
        self.rect.remove()
        self.ax.figure.canvas.draw()
        self.isPressed = False
        self.cropCheckWidget.setCropInfo(self.cropInfo)
        self.cropCheckWidget.show()
        self.cropCheckWidget.raise_()
Exemple #33
0
class MplWidget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.scroll = QtWidgets.QScrollArea(self)
        self.scroll.setParent(None)
        #self.fig =Figure(tight_layout=True)
        self.fig = Figure()
        left = 0.0
        bottom = 0.0
        width = 1
        height = 1
        self.fig.add_axes([left, bottom, width, height])
        self.canvas = FigureCanvas(self.fig)
        self.fig.set_facecolor([0.23, 0.23, 0.23, 0.5])
        self.canvas.axes = self.canvas.figure.gca()

        #self.canvas.figure.tight_layout(pad=0)
        self.vertical_layout = QVBoxLayout()
        self.vertical_layout.addWidget(self.canvas)
        self.mpl_toolbar = my_toolbar(self.canvas, self)
        self.mpl_toolbar.setParentClass(self)
        self.mpl_toolbar.setMinimumWidth(100)

        self.mpl_toolbar.setFixedHeight(26)
        self.mpl_toolbar.setStyleSheet(
            "QToolBar { opacity: 1;border: 0px; background-color: rgb(133, 196, 65); border-bottom: 1px solid #19232D;padding: 2px;  font-weight: bold;spacing: 2px; } "
        )
        self.mpl_toolbar.setObjectName("myToolBar")

        #self.canvas.mpl_connect("resize_event", self.resize)
        self.vertical_layout.addWidget(self.mpl_toolbar)
        self.setLayout(self.vertical_layout)
        self.layout().setContentsMargins(0, 0, 0, 0)
        self.layout().setSpacing(0)
        self.rect = Rectangle((0, 0), 1, 1)
        self.updateSecondImage = None
        self.patchesTotal = 0
        self.typeOfAnnotation = "autoDetcted"
        self.frameAtString = "Frame 0"
        self.currentSelectedOption = None

        self.AllBoxListDictionary = {
            "eraseBox": [],
            "oneWormLive": [],
            "multiWormLive": [],
            "oneWormDead": [],
            "multiWormDead": [],
            "miscBoxes": [],
            "autoDetcted": []
        }

        self.eraseBoxXYValues = self.AllBoxListDictionary["eraseBox"]
        self.addBoxXYValues = self.AllBoxListDictionary["miscBoxes"]
        self.oneWormLiveBoxXYValues = self.AllBoxListDictionary["oneWormLive"]
        self.multiWormLiveBoxXYValues = self.AllBoxListDictionary[
            "multiWormLive"]
        self.oneWormDeadBoxXYValues = self.AllBoxListDictionary["oneWormDead"]
        self.multiWormDeadBoxXYValues = self.AllBoxListDictionary[
            "multiWormDead"]
        self.autoDetectedBoxXYValues = self.AllBoxListDictionary["autoDetcted"]
        self.tempList = []

    def resetAllBoxListDictionary(self):
        self.AllBoxListDictionary = {
            "eraseBox": [],
            "oneWormLive": [],
            "multiWormLive": [],
            "oneWormDead": [],
            "multiWormDead": [],
            "miscBoxes": [],
            "autoDetcted": []
        }

    def updateAllBoxListDictionary(self):
        self.AllBoxListDictionary["eraseBox"] = self.eraseBoxXYValues
        self.AllBoxListDictionary["miscBoxes"] = self.addBoxXYValues
        self.AllBoxListDictionary["oneWormLive"] = self.oneWormLiveBoxXYValues
        self.AllBoxListDictionary[
            "multiWormLive"] = self.multiWormLiveBoxXYValues
        self.AllBoxListDictionary["oneWormDead"] = self.oneWormDeadBoxXYValues
        self.AllBoxListDictionary[
            "multiWormDead"] = self.multiWormDeadBoxXYValues
        self.AllBoxListDictionary["autoDetcted"] = self.autoDetectedBoxXYValues

    def updateAllListFromAllBoxListDictionary(self):
        self.eraseBoxXYValues = self.AllBoxListDictionary["eraseBox"]
        self.addBoxXYValues = self.AllBoxListDictionary["miscBoxes"]
        self.oneWormLiveBoxXYValues = self.AllBoxListDictionary["oneWormLive"]
        self.multiWormLiveBoxXYValues = self.AllBoxListDictionary[
            "multiWormLive"]
        self.oneWormDeadBoxXYValues = self.AllBoxListDictionary["oneWormDead"]
        self.multiWormDeadBoxXYValues = self.AllBoxListDictionary[
            "multiWormDead"]
        self.autoDetectedBoxXYValues = self.AllBoxListDictionary["autoDetcted"]

    def setFrameAtString(self, text):
        self.frameAtString = text

    def getFrameAtString(self):
        return self.frameAtString

    def getCurrentSelectedOption(self):
        return self.currentSelectedOption

    def setCurrentSelectedOption(self, option):
        self.currentSelectedOption = option

    def setDarkTheme(self):
        self.mpl_toolbar.setStyleSheet(
            "QToolBar#myToolBar{ border: 0px; background-color: rgb(133, 0,s 65); border-bottom: 1px solid #19232D;padding: 2px;  font-weight: bold;spacing: 2px; } "
        )
        self.fig.set_facecolor([0.23, 0.23, 0.23, 0.5])
        #self.fig.set_facecolor('grey')
        self.canvas.draw()

    def setGreenTheme(self):
        self.mpl_toolbar.setStyleSheet(
            "QToolBar { border: 0px; background-color: rgb(133, 196, 65); border-bottom: 1px solid #19232D;padding: 2px;  font-weight: bold;spacing: 2px; } "
        )
        self.fig.set_facecolor('grey')
        self.canvas.draw()

    def setTypeOfAnnotation(self, text):
        self.typeOfAnnotation = text

    def restrictCanvasMinimumSize(self, size):
        self.canvas.setMinimumSize(size)

    def unmountWidgetAndClear(self):
        self.vertical_layout.removeWidget(self.canvas)
        self.vertical_layout.removeWidget(self.scroll)
        self.scroll.setParent(None)
        self.canvas.setParent(None)
        sip.delete(self.scroll)
        del self.canvas
        self.scroll = None
        self.canvas = None
        self.canvas = FigureCanvas(Figure())
        self.canvas.axes = self.canvas.figure.gca()
        #self.canvas.figure.tight_layout()
        self.scroll = QtWidgets.QScrollArea(self)
        self.scroll.setWidgetResizable(True)

    def connectClickListnerToCurrentImageForCrop(self,
                                                 givenController,
                                                 updateSecondImage=None,
                                                 listOfControllers=None,
                                                 keyForController=None):
        self.cid1 = self.canvas.mpl_connect("button_press_event",
                                            self.on_press_for_crop)
        self.cid2 = self.canvas.mpl_connect("motion_notify_event",
                                            self.onmove_for_crop)
        self.cid3 = self.canvas.mpl_connect("button_release_event",
                                            self.on_release_for_crop)
        self.givenControllerObject = givenController
        self.updateSecondImage = updateSecondImage
        self.pressevent = None
        self.listOfControllers = listOfControllers
        self.keyForController = keyForController

    def on_press_for_crop(self, event):
        if (self.mpl_toolbar.mode):
            return

        try:
            self.rect.remove()
        except:
            pass
        self.addedPatch = None
        self.x0 = event.xdata
        self.y0 = event.ydata
        self.rect = Rectangle((self.x0, self.y0), 1, 1)
        self.rect._alpha = 0.5
        self.rect._linewidth = 2
        self.rect.set_color("C2")
        self.rect.set
        self.pressevent = 1
        self.addedPatch = self.canvas.axes.add_patch(self.rect)

    def on_release_for_crop(self, event):
        if (self.mpl_toolbar.mode):
            return

        self.pressevent = None

        minMaxVertices = [
            int(np.ceil(min(self.x0, self.x1))),
            int(np.ceil(min(self.y0, self.y1))),
            int(np.round(max(self.x0, self.x1))),
            int(np.round(max(self.y0, self.y1))),
        ]
        self.givenControllerObject.updateManualCropCoordinates(minMaxVertices)
        image = self.givenControllerObject.showManualCropImage()
        self.canvas.axes.clear()
        self.canvas.axes.axis("off")
        self.canvas.axes.imshow(image)
        self.canvas.draw()
        if self.updateSecondImage is not None:
            self.updateSecondImage.canvas.axes.clear()
            self.updateSecondImage.canvas.axes.axis("off")
            self.updateSecondImage.canvas.axes.imshow(
                self.givenControllerObject.getCroppedImage(0))
            self.updateSecondImage.canvas.draw()
            self.listOfControllers[
                self.keyForController] = self.givenControllerObject

    def onmove_for_crop(self, event):

        if self.pressevent is None:
            return
        self.x1 = event.xdata
        self.y1 = event.ydata
        self.rect.set_width(self.x1 - self.x0)
        self.rect.set_height(self.y1 - self.y0)
        self.rect.set_xy((self.x0, self.y0))
        self.canvas.draw()

    def disconnectClickListnerFromCurrentImageForCrop(self):
        try:
            self.canvas.mpl_disconnect(self.cid1)
            self.canvas.mpl_disconnect(self.cid2)
            self.canvas.mpl_disconnect(self.cid3)
            self.updateSecondImage = None
        except:
            pass

    def getCurrentScrollParam(self):
        self.currentVerticalSliderValue = self.scroll.verticalScrollBar(
        ).value()
        self.currentHorizontalSliderValue = self.scroll.horizontalScrollBar(
        ).value()

    def resetCurrentScrollParam(self):
        self.scroll.verticalScrollBar().setValue(
            self.currentVerticalSliderValue)
        self.scroll.horizontalScrollBar().setValue(
            self.currentHorizontalSliderValue)

    def resize(self, event):
        # on resize reposition the navigation toolbar to (0,0) of the axes.
        x, y = self.fig.axes[0].transAxes.transform((0, 0))
        figw, figh = self.fig.get_size_inches()
        ynew = figh * self.fig.dpi - y - self.mpl_toolbar.frameGeometry(
        ).height()
        self.mpl_toolbar.move(x, ynew)

    def connectClickListnerToCurrentImageForAnnotate(self,
                                                     givenController,
                                                     updateSecondImage=None):
        self.cid4 = self.canvas.mpl_connect("button_press_event",
                                            self.on_press_for_annotate)

        self.cid7 = self.canvas.mpl_connect('pick_event', self.onpick)
        #self.cid7 = self.canvas.mpl_connect('button_press_event', self.right_click_press_for_annotate)
        self.givenControllerObject = givenController
        self.updateSecondImage = updateSecondImage
        self.pressevent = None

    def autoAnnotateOnOverlay(self, autoDetectedObjects):

        for index, row in autoDetectedObjects.iterrows():
            print(row.bbox3)

            #if self.pressevent is None:
            #    return
            #self.x1 = event.xdata
            #self.y1 = event.ydata
            self.rect.set_width(row.bbox3 - row.bbox1)
            self.rect.set_height(row.bbox2 - row.bbox0)
            self.rect.set_xy((row.bbox1, row.bbox0))

            self.canvas.draw()

            self.rect = Rectangle((row.bbox1, row.bbox0), 1, 1, picker=True)
            self.rect._alpha = 1
            self.rect._edgecolor = (0, 1, 0, 1)
            self.rect._facecolor = (0, 0, 0, 0)

            self.rect._linewidth = 1
            self.rect.set_linestyle('dashed')
            self.rect.addName = self.typeOfAnnotation
            self.pressevent = 1
            self.canvas.axes.add_patch(self.rect)
            self.patchesTotal = self.patchesTotal + 1

            if [row.bbox1, row.bbox0, row.bbox3,
                    row.bbox2] not in self.autoDetectedBoxXYValues:
                self.autoDetectedBoxXYValues.append(
                    [row.bbox1, row.bbox0, row.bbox3, row.bbox2])

            # Update latest values
            self.updateAllBoxListDictionary()
            #print(self.typeOfAnnotation)
            '''if self.typeOfAnnotation == "eraseBox":
                if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                    self.tempList.append([self.x0, self.y0, self.x1, self.y1])

            if self.typeOfAnnotation not in ["eraseBox", "oneWormLive", "multiWormLive", "oneWormDead", "multiWormDead"]:
                if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                    self.tempList.append([self.x0, self.y0, self.x1, self.y1])

            if self.typeOfAnnotation == "oneWormLive":
                if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                    self.tempList.append([self.x0, self.y0, self.x1, self.y1])

            if self.typeOfAnnotation == "multiWormLive":
                if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                    self.tempList.append([self.x0, self.y0, self.x1, self.y1])

            if self.typeOfAnnotation == "oneWormDead":
                if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                    self.tempList.append([self.x0, self.y0, self.x1, self.y1])

            if self.typeOfAnnotation == "multiWormDead":
                if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                    self.tempList.append([self.x0, self.y0, self.x1, self.y1])'''

            #self.canvas.draw()

        #return(self.canvas)

    def on_press_for_annotate(self, event):
        # try:
        #     self.rect.remove()
        # except:
        #     pass
        if (self.mpl_toolbar.mode):
            return

        if event.button == 1:
            self.cid5 = self.canvas.mpl_connect("motion_notify_event",
                                                self.onmove_for_annotate)
            self.cid6 = self.canvas.mpl_connect("button_release_event",
                                                self.on_release_for_annotate)

            self.x0 = event.xdata
            self.y0 = event.ydata

            self.rect = Rectangle((self.x0, self.y0), 1, 1, picker=True)
            self.rect._alpha = 1
            if self.typeOfAnnotation not in [
                    "eraseBox", "oneWormLive", "multiWormLive", "oneWormDead",
                    "multiWormDead"
            ]:
                self.rect._edgecolor = (0, 1, 0, 1)
                self.rect._facecolor = (0, 0, 0, 0)
            elif self.typeOfAnnotation == "autoDetcted":
                self.rect._edgecolor = (0, 1, 0, 1)
                self.rect._facecolor = (0, 0, 0, 0)
            elif self.typeOfAnnotation == "eraseBox":
                self.rect._edgecolor = (0, 0, 0, 1)
                self.rect._facecolor = (0, 0, 0, 0)
            elif self.typeOfAnnotation == "oneWormLive":
                self.rect._edgecolor = (0, 0, 1, 1)
                self.rect._facecolor = (0, 0, 0, 0)
            elif self.typeOfAnnotation == "multiWormLive":
                self.rect._edgecolor = (1, 1, 0, 1)
                self.rect._facecolor = (0, 0, 0, 0)
            elif self.typeOfAnnotation == "oneWormDead":
                self.rect._edgecolor = (1, 0, 0, 1)
                self.rect._facecolor = (0, 0, 0, 0)
            elif self.typeOfAnnotation == "multiWormDead":
                self.rect._edgecolor = (1, 1, 1, 1)
                self.rect._facecolor = (0, 0, 0, 0)

            self.rect._linewidth = 1
            self.rect.set_linestyle('dashed')
            self.rect.addName = self.typeOfAnnotation
            self.pressevent = 1
            self.canvas.axes.add_patch(self.rect)
            self.patchesTotal = self.patchesTotal + 1

    def on_release_for_annotate(self, event):
        if (self.mpl_toolbar.mode):
            return

        if event.button == 1:
            self.canvas.mpl_disconnect(self.cid5)
            if (self.rect.get_height() == 1) and (self.rect.get_width() == 1):
                self.rect.remove()
            self.pressevent = None
            self.canvas.mpl_disconnect(self.cid6)

        if self.typeOfAnnotation == "eraseBox":
            #print(self.typeOfAnnotation)
            self.eraseBoxXYValues.append(self.tempList[-1])
            self.tempList = []

        if self.typeOfAnnotation not in [
                "eraseBox", "oneWormLive", "multiWormLive", "oneWormDead",
                "multiWormDead"
        ]:
            #print(self.typeOfAnnotation)
            self.addBoxXYValues.append(self.tempList[-1])
            self.tempList = []

        if self.typeOfAnnotation == "oneWormLive":
            self.oneWormLiveBoxXYValues.append(self.tempList[-1])
            self.tempList = []

        if self.typeOfAnnotation == "multiWormLive":
            self.multiWormLiveBoxXYValues.append(self.tempList[-1])
            self.tempList = []

        if self.typeOfAnnotation == "oneWormDead":
            self.oneWormDeadBoxXYValues.append(self.tempList[-1])
            self.tempList = []

        if self.typeOfAnnotation == "multiWormDead":
            self.multiWormDeadBoxXYValues.append(self.tempList[-1])
            self.tempList = []

        # updateAllBoxListDictionary(self)
        self.updateAllBoxListDictionary()

        # self.givenControllerObject.updateManualCropCoordinates(minMaxVertices)
        # image = self.givenControllerObject.showManualCropImage()
        # self.canvas.axes.clear()
        # self.canvas.axes.axis("off")
        # self.canvas.axes.imshow(image)
        # self.canvas.draw()
        # if self.updateSecondImage is not None:
        #     self.updateSecondImage.canvas.axes.clear()
        #     self.updateSecondImage.canvas.axes.axis("off")
        #     self.updateSecondImage.canvas.axes.imshow(self.givenControllerObject.getCroppedImage(0))
        #     self.updateSecondImage.canvas.draw()

    def onmove_for_annotate(self, event):

        if self.pressevent is None:
            return
        self.x1 = event.xdata
        self.y1 = event.ydata
        self.rect.set_width(self.x1 - self.x0)
        self.rect.set_height(self.y1 - self.y0)
        self.rect.set_xy((self.x0, self.y0))

        #print(self.typeOfAnnotation)
        if self.typeOfAnnotation == "eraseBox":
            if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                self.tempList.append([self.x0, self.y0, self.x1, self.y1])

        if self.typeOfAnnotation not in [
                "eraseBox", "oneWormLive", "multiWormLive", "oneWormDead",
                "multiWormDead"
        ]:
            if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                self.tempList.append([self.x0, self.y0, self.x1, self.y1])

        if self.typeOfAnnotation == "oneWormLive":
            if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                self.tempList.append([self.x0, self.y0, self.x1, self.y1])

        if self.typeOfAnnotation == "multiWormLive":
            if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                self.tempList.append([self.x0, self.y0, self.x1, self.y1])

        if self.typeOfAnnotation == "oneWormDead":
            if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                self.tempList.append([self.x0, self.y0, self.x1, self.y1])

        if self.typeOfAnnotation == "multiWormDead":
            if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                self.tempList.append([self.x0, self.y0, self.x1, self.y1])

        self.canvas.draw()

    def getEraseBoxXYValues(self):
        return (self.eraseBoxXYValues)

    def getAutoDetctedBoxXYValues(self):
        return (self.autoDetectedBoxXYValues)

    def getAddBoxXYValues(self):
        return (self.addBoxXYValues)

    def getOneWormLiveBoxXYValues(self):
        return (self.oneWormLiveBoxXYValues)

    def getMultiWormLiveBoxXYValues(self):
        return (self.multiWormLiveBoxXYValues)

    def getOneWormDeadBoxXYValues(self):
        return (self.oneWormDeadBoxXYValues)

    def getMultiWormDeadBoxXYValues(self):
        return (self.multiWormDeadBoxXYValues)

    def resetEraseBoxXYValues(self):
        self.eraseBoxXYValues = []

    def resetAutoDetctedBoxXYValues(self):
        self.autoDetectedBoxXYValues = []

    def resetAddBoxXYValues(self):
        self.addBoxXYValues = []

    def resetOneWormLiveBoxXYValues(self):
        self.oneWormLiveBoxXYValues = []

    def resetMultiWormLiveBoxXYValues(self):
        self.multiWormLiveBoxXYValues = []

    def resetOneWormDeadBoxXYValues(self):
        self.oneWormDeadBoxXYValues = []

    def resetMultiWormDeadBoxXYValues(self):
        self.multiWormDeadBoxXYValues = []

    def disconnectClickListnerFromCurrentImageForAnnotate(self):
        try:
            self.canvas.mpl_disconnect(self.cid4)

            self.canvas.mpl_disconnect(self.cid7)
            self.updateSecondImage = None
        except:
            pass

    def onpick(self, event):
        #if event.button == 3:       #"3" is the right button
        # print "you click the right button"
        # print 'button=%d, x=%d, y=%d, xdata=%f, ydata=%f'%(
        # event.button, event.x, event.y, event.xdata, event.ydata)
        #Get the coordinates of the mouse click
        #I create the action
        if (self.mpl_toolbar.mode):
            return
        if event.mouseevent.button == 3:
            self.objectPicked = event.artist
            noteAction_1 = QtWidgets.QAction('Delete Box', self)
            noteAction_2 = QtWidgets.QAction('Classify', self)
            #noteAction_5 = QtWidgets.QAction('Add Once',self)
            #noteAction_2 = QtWidgets.QAction('Add Through',self)
            #noteAction_3 = QtWidgets.QAction('Mask Here',self)
            #noteAction_4 = QtWidgets.QAction('Mask Through',self)
            #noteAction_6 = QtWidgets.QAction('Live here',self)
            #noteAction_7 = QtWidgets.QAction('Live all',self)
            #noteAction_8 = QtWidgets.QAction('Dead here',self)
            #noteAction_9 = QtWidgets.QAction('Dead all',self)

            #I create the context menu
            self.popMenu = QtWidgets.QMenu(self)
            self.popMenu.addAction(noteAction_1)
            self.popMenu.addAction(noteAction_2)
            # self.popMenu.addAction(noteAction_2)
            # self.popMenu.addAction(noteAction_3)
            # self.popMenu.addAction(noteAction_4)
            # self.popMenu.addAction(noteAction_5)
            # self.popMenu.addAction(noteAction_6)
            # self.popMenu.addAction(noteAction_7)
            # self.popMenu.addAction(noteAction_8)
            # self.popMenu.addAction(noteAction_9)

            cursor = QtGui.QCursor()
            #self.connect(self.figure_canvas, SIGNAL("clicked()"), self.context_menu)
            #self.popMenu.exec_(self.mapToGlobal(event.globalPos()))
            noteAction_1.triggered.connect(lambda: self.removeThisArea(1))
            noteAction_2.triggered.connect(
                lambda: self.classifyAsCurrentSelection(1))
            # noteAction_2.triggered.connect(lambda :self.removeThisArea(2))
            # noteAction_3.triggered.connect(lambda :self.removeThisArea(3))
            # noteAction_4.triggered.connect(lambda :self.removeThisArea(4))
            # noteAction_5.triggered.connect(lambda :self.removeThisArea(5))
            # noteAction_6.triggered.connect(lambda :self.removeThisArea(5))
            # noteAction_7.triggered.connect(lambda :self.removeThisArea(2))
            # noteAction_8.triggered.connect(lambda :self.removeThisArea(3))
            # noteAction_9.triggered.connect(lambda :self.removeThisArea(4))

            self.popMenu.popup(cursor.pos())
        else:
            return

    def right_click_press_for_annotate(self, event):
        if (self.mpl_toolbar.mode):
            return
        if event.button == 3:  #"3" is the right button
            # print "you click the right button"
            # print 'button=%d, x=%d, y=%d, xdata=%f, ydata=%f'%(
            # event.button, event.x, event.y, event.xdata, event.ydata)
            #Get the coordinates of the mouse click
            #I create the action
            noteAction_1 = QtWidgets.QAction('Remove', self)
            noteAction_2 = QtWidgets.QAction('Add', self)

            #I create the context menu
            self.popMenu = QtWidgets.QMenu(self)
            self.popMenu.addAction(noteAction_1)
            self.popMenu.addAction(noteAction_2)
            cursor = QtGui.QCursor()

            #self.connect(self.figure_canvas, SIGNAL("clicked()"), self.context_menu)
            #self.popMenu.exec_(self.mapToGlobal(event.globalPos()))
            noteAction_1.triggered.connect(
                lambda eventData=object: self.removeThisArea(eventData))
            noteAction_2.triggered.connect(
                lambda eventData=object: self.classifyAsCurrentSelection(
                    eventData))
            self.popMenu.popup(cursor.pos())

    def classifyAsCurrentSelection(self, caseNumber):

        # Get all the list values for this frame
        self.updateAllListFromAllBoxListDictionary()

        print("INSIDE classifyAsCurrentSelection")

        try:
            if caseNumber == 1:  # green delete
                print(type(self.objectPicked))
                X0 = self.objectPicked.get_xy()[0]
                Y0 = self.objectPicked.get_xy()[1]
                X1 = X0 + self.objectPicked.get_width()
                Y1 = Y0 + self.objectPicked.get_height()

                selectedBoxCoords = [X0, Y0, X1, Y1]

                if self.currentSelectedOption == "eraseBox":
                    #self.autoDetectedBoxXYValues.remove(selectedBoxCoords)
                    #self.eraseBoxXYValues.append(selectedBoxCoords)
                    print("Use Delte Option! Right Click -> Delete Box")

                if self.currentSelectedOption == "autoDetcted":
                    #self.autoDetectedBoxXYValues.remove(selectedBoxCoords)
                    #self.addBoxXYValues.append(selectedBoxCoords)
                    print("Already Selected!")

                if self.currentSelectedOption not in [
                        "oneWormLive", "multiWormLive", "oneWormDead",
                        "multiWormDead", "autoDetcted"
                ]:
                    self.autoDetectedBoxXYValues.remove(selectedBoxCoords)
                    self.addBoxXYValues.append(selectedBoxCoords)

                    self.rect.set_width(X1 - X0)
                    self.rect.set_height(Y1 - Y0)
                    self.rect.set_xy((X0, Y0))

                    self.rect = Rectangle((X0, Y0), 1, 1, picker=True)
                    self.rect._alpha = 1
                    self.rect._edgecolor = (0, 1, 0, 1)
                    self.rect._facecolor = (0, 0, 0, 0)

                    self.canvas.draw()

                    self.rect._linewidth = 1
                    self.rect.set_linestyle('dashed')
                    self.rect.addName = self.typeOfAnnotation
                    self.pressevent = 1
                    self.canvas.axes.add_patch(self.rect)

                if self.currentSelectedOption == "oneWormLive" and selectedBoxCoords not in self.oneWormLiveBoxXYValues:

                    self.autoDetectedBoxXYValues.remove(selectedBoxCoords)
                    self.oneWormLiveBoxXYValues.append(selectedBoxCoords)

                    self.canvas.draw()

                    self.rect.set_width(X1 - X0)
                    self.rect.set_height(Y1 - Y0)
                    self.rect.set_xy((X0, Y0))

                    self.rect = Rectangle((X0, Y0), 1, 1, picker=True)
                    self.rect._alpha = 1
                    self.rect._edgecolor = (0, 0, 1, 1)
                    self.rect._facecolor = (0, 0, 0, 0)

                    self.rect._linewidth = 1
                    self.rect.set_linestyle('dashed')
                    self.rect.addName = self.typeOfAnnotation
                    self.pressevent = 1
                    self.canvas.axes.add_patch(self.rect)

                    self.canvas.draw()

                if self.currentSelectedOption == "multiWormLive" and selectedBoxCoords not in self.multiWormLiveBoxXYValues:
                    self.autoDetectedBoxXYValues.remove(selectedBoxCoords)
                    self.multiWormLiveBoxXYValues.append(selectedBoxCoords)

                    self.rect.set_width(X1 - X0)
                    self.rect.set_height(Y1 - Y0)
                    self.rect.set_xy((X0, Y0))

                    self.rect = Rectangle((X0, Y0), 1, 1, picker=True)
                    self.rect._alpha = 1
                    self.rect._edgecolor = (1, 1, 0, 1)
                    self.rect._facecolor = (0, 0, 0, 0)

                    self.canvas.draw()

                    self.rect._linewidth = 1
                    self.rect.set_linestyle('dashed')
                    self.rect.addName = self.typeOfAnnotation
                    self.pressevent = 1
                    self.canvas.axes.add_patch(self.rect)

                if self.currentSelectedOption == "oneWormDead" and selectedBoxCoords not in self.oneWormDeadBoxXYValues:

                    self.autoDetectedBoxXYValues.remove(selectedBoxCoords)
                    self.oneWormDeadBoxXYValues.append(selectedBoxCoords)

                    self.rect.set_width(X1 - X0)
                    self.rect.set_height(Y1 - Y0)
                    self.rect.set_xy((X0, Y0))

                    self.rect = Rectangle((X0, Y0), 1, 1, picker=True)
                    self.rect._alpha = 1
                    self.rect._edgecolor = (1, 0, 0, 1)
                    self.rect._facecolor = (0, 0, 0, 0)

                    self.canvas.draw()

                    self.rect._linewidth = 1
                    self.rect.set_linestyle('dashed')
                    self.rect.addName = self.typeOfAnnotation
                    self.pressevent = 1
                    self.canvas.axes.add_patch(self.rect)

                if self.currentSelectedOption == "multiWormDead" and selectedBoxCoords not in self.multiWormDeadBoxXYValues:
                    self.autoDetectedBoxXYValues.remove(selectedBoxCoords)
                    self.multiWormDeadBoxXYValues.append(selectedBoxCoords)

                    self.rect.set_width(X1 - X0)
                    self.rect.set_height(Y1 - Y0)
                    self.rect.set_xy((X0, Y0))

                    self.rect = Rectangle((X0, Y0), 1, 1, picker=True)
                    self.rect._alpha = 1
                    self.rect._edgecolor = (1, 1, 1, 1)
                    self.rect._facecolor = (0, 0, 0, 0)

                    self.canvas.draw()

                    self.rect._linewidth = 1
                    self.rect.set_linestyle('dashed')
                    self.rect.addName = self.typeOfAnnotation
                    self.pressevent = 1
                    self.canvas.axes.add_patch(self.rect)

        except:
            print("Delete and Redraw!")
        # updateAllBoxListDictionary(self)
        self.updateAllBoxListDictionary()

    def removeThisArea(self, caseNumber):

        # Get all the list values for this frame
        self.updateAllListFromAllBoxListDictionary()

        if caseNumber == 1:  # green delete
            print(type(self.objectPicked))
            X0 = self.objectPicked.get_xy()[0]
            Y0 = self.objectPicked.get_xy()[1]
            X1 = X0 + self.objectPicked.get_width()
            Y1 = Y0 + self.objectPicked.get_height()

            removeBoxCoords = [X0, Y0, X1, Y1]
            #print(removeBoxCoords)
            self.objectPicked.remove()
            self.patchesTotal = self.patchesTotal - 1

            try:
                if removeBoxCoords in self.eraseBoxXYValues:
                    self.eraseBoxXYValues.remove(removeBoxCoords)

                if removeBoxCoords in self.addBoxXYValues:
                    self.addBoxXYValues.remove(removeBoxCoords)

                if removeBoxCoords in self.oneWormLiveBoxXYValues:
                    #print(self.oneWormLiveBoxXYValues)
                    self.oneWormLiveBoxXYValues.remove(removeBoxCoords)
                    #print(self.oneWormLiveBoxXYValues)

                if removeBoxCoords in self.multiWormLiveBoxXYValues:
                    self.multiWormLiveBoxXYValues.remove(removeBoxCoords)

                if removeBoxCoords in self.oneWormDeadBoxXYValues:
                    self.oneWormDeadBoxXYValues.remove(removeBoxCoords)

                if removeBoxCoords in self.multiWormDeadBoxXYValues:
                    self.multiWormDeadBoxXYValues.remove(removeBoxCoords)

                if removeBoxCoords in self.autoDetectedBoxXYValues:
                    print(len(self.autoDetectedBoxXYValues))
                    self.autoDetectedBoxXYValues.remove(removeBoxCoords)
                    print(len(self.autoDetectedBoxXYValues))
            except:
                pass

        # elif caseNumber == 2:     # orange add all
        #     self.objectPicked._facecolor = (1.0, 0.64, 0.0,0.5)
        #     self.objectPicked._alpha  = 0.5
        #     self.objectPicked.addName ="addAll"
        # elif caseNumber == 3:     # black
        #     self.objectPicked._facecolor = (0,0, 0, 0.8)
        #     self.objectPicked._alpha = 0.8
        #     self.objectPicked.addName ="eraseBox"
        # elif caseNumber == 4:
        #     self.objectPicked._facecolor = ( 0, 0, 0, 0.2)
        #     self.objectPicked._alpha = 0.2
        #     self.objectPicked.addName ="deleteAll"
        # elif caseNumber == 5:
        #     self.objectPicked.set_color("C2")
        #     self._edgecolor = (0, 0, 0, 0)
        #     self.objectPicked.addName ="addBox"

        self.canvas.draw()
        #print(len(self.canvas.axes.patches))
        #self.canvas.draw()
        #self.on_release_for_annotate(None)

    def initializeAnnotationDictionary(self):
        self.currentAnnotationFrame = None
        self.annotationRecordDictionary = {}

    def updateAnnotationDictionary(self):

        # When you move away from current Frame call this
        previousFrame = self.currentAnnotationFrame
        if previousFrame is not None:
            self.annotationRecordDictionary[str(
                previousFrame)] = self.canvas.axes.patches

    def getAnnotationDictionary(self):
        return self.annotationRecordDictionary

    def applyAnnotationDictionary(self, frameNumber):
        self.currentAnnotationFrame = frameNumber
        self.canvas.axes.patches = []
        if str(frameNumber) in self.annotationRecordDictionary.keys():
            for patch in self.annotationRecordDictionary[str(frameNumber)]:
                self.canvas.axes.add_patch(patch)

    def setAnnotationDictionary(self):
        pass
Exemple #34
0
class DraggableRectangle(object):
    def __init__(self, axes, rectwidth=100, lrwidth=10, recty=100):
        self.ax = axes  # plt.gca()

        self.rect_x = axes.get_xlim()[1] - rectwidth - lrwidth
        self.rect = Rectangle((self.rect_x, 0),
                              rectwidth,
                              recty,
                              facecolor='g',
                              alpha=0.2)
        self.rectl = Rectangle((self.rect_x - lrwidth, 0),
                               lrwidth,
                               recty,
                               facecolor='b',
                               alpha=0.8)
        self.rectr = Rectangle((self.rect_x + rectwidth, 0),
                               lrwidth,
                               recty,
                               facecolor='b',
                               alpha=0.8)

        self.ax.add_patch(self.rect)
        self.ax.add_patch(self.rectl)
        self.ax.add_patch(self.rectr)

        self.rect_width = rectwidth
        self.press = None  # 0,
        self.pressl = None
        self.pressr = None

        self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press)
        self.ax.figure.canvas.mpl_connect('button_release_event',
                                          self.on_release)
        self.ax.figure.canvas.mpl_connect('motion_notify_event',
                                          self.on_motion)

    def on_press(self, event):
        if event.inaxes != self.rect.axes: return

        contains, attrd = self.rect.contains(event)
        containsl, attrdl = self.rectl.contains(event)
        containsr, attrdr = self.rectr.contains(event)
        if contains:
            x0, y0 = self.rect.xy
            self.press = x0, y0, event.xdata, event.ydata
        elif containsl:
            xl, yl = self.rectl.xy
            self.pressl = xl, yl, event.xdata, event.ydata
        elif containsr:
            xr, yr = self.rectr.xy
            self.pressr = xr, yr, event.xdata, event.ydata
        else:
            return

    def on_release(self, event):
        # print ('release')
        self.press = None
        self.pressl = None
        self.pressr = None
        self.ax.figure.canvas.draw()

    def on_motion(self, event):
        'on motion we will move the rect if the mouse is over us'
        if self.press is None and self.pressl is None and self.pressr is None:
            return
        if event.inaxes != self.rect.axes and event.inaxes != self.rectl.axes and event.inaxes != self.rectr.axes:
            return

        rectwidth = self.rect_width
        if self.press != None:
            x0, y0, xpress, ypress = self.press
            dx = event.xdata - xpress
            rectl_x = x0 + dx - self.rectl.get_width()

            # to tell the left edge overriding
            if rectl_x < 0:
                rectl_x = 0
            # to tell the right edge overriding
            if rectl_x + self.rectl.get_width(
            ) + rectwidth + self.rectr.get_width() > self.ax.get_xlim()[1] - 1:
                rectl_x = self.ax.get_xlim(
                )[1] - rectwidth - self.rectr.get_width(
                ) - self.rectl.get_width()
                print("self.ax.get_xlim()[1]=",
                      self.ax.get_xlim()[1], " rectLx=", rectl_x)

            self.rect_x = rectl_x + self.rectl.get_width()
            self.rect.set_x(self.rect_x)
            self.rectl.set_x(rectl_x)
            self.rectr.set_x(self.rect_x + self.rect.get_width())
            # self.rect.figure.canvas.draw()
        elif self.pressl != None:
            if event.xdata >= self.rectr.get_x() - 10:
                self.rect_width = 10
                return

            xl, yl, xpress, ypress = self.pressl
            dx = event.xdata - xpress
            rectl_x = xl + dx  #- self.rectl.get_width()

            # to tell the left edge overriding
            if rectl_x < 0:
                self.rect_width = self.rectr.get_x() - self.rectl.get_width()
                rectl_x = 0

            self.rectl.set_x(rectl_x)
            # draw rect
            self.rect.set_x(rectl_x + self.rectl.get_width())
            xr = self.rectr.get_x()
            rectwidth = xr - rectl_x - self.rectl.get_width()
            # self.rectl.figure.canvas.draw()
        elif self.pressr != None:
            if event.xdata <= self.rectl.get_x() + self.rectl.get_width() + 10:
                self.rect_width = 10
                return

            xr, yr, xpress, ypress = self.pressr
            dx = event.xdata - xpress
            rectr_x = xr + dx

            # to tell the right edge overriding
            xlim = self.ax.get_xlim()[1]
            print('xlim=', xlim)
            if rectr_x + self.rectr.get_width() > xlim:
                self.rect_width = xlim - self.rectl.get_x(
                ) - self.rectl.get_width()
                rectr_x = xlim - self.rectr.get_width()

            self.rectr.set_x(rectr_x)
            # draw rect
            rectwidth = rectr_x - self.rectl.get_x() - self.rectl.get_width()
            # self.rectr.figure.canvas.draw()

        self.rect.set_width(rectwidth)
        self.rect_width = rectwidth
        self.ax.figure.canvas.draw()
        # self.rectl.figure.canvas.draw()  # why we just draw rect here, but rectl and rectr are drawed too ?

    def reset_rects(self, xl, xr):
        xlim = self.ax.get_xlim()[1]
        if xr > xlim: return
        if xl < 0: return

        self.rectl.set_x(xl)
        self.rectr.set_x(xr - self.rectr.get_width())
        self.rect_x = xl + self.rectl.get_width()
        self.rect.set_x(self.rect_x)
        self.rect_width = xr - self.rectr.get_width() - self.rect_x
        self.rect.set_width(self.rect_width)
        self.ax.figure.canvas.draw()

    def is_pressed(self):
        r = 0
        if self.press:
            r = 1
        elif self.pressl:
            r = 2
        elif self.pressr:
            r = 3
        else:
            r = 0
        return r

    def get_rect_x1(self):
        return int(self.rectl.get_x())

    def get_rect_x2(self):
        return int(self.rectr.get_x() + self.rectr.get_width() - 1)
class EditableRectangle:

    _angle = 0

    def __init__(self, ax):
        self.ax = ax

        # Set up main rectangle
        self.rect = Rectangle((0, 0), 0, 0, visible=False, transform=None, picker=True)
        self.ax.add_patch(self.rect)

        # Set up anchors
        self.anchors = []
        for i in range(len(RECTANGLE_ANCHOR_LOCS)):
            anchor = Rectangle((0, 0), ANCHOR_SIZE, ANCHOR_SIZE, visible=False, transform=None, facecolor='red', picker=True)
            self.anchors.append(anchor)
            self.ax.add_patch(anchor)

        self.press = None
        self.mode = None
        self.connect()

    def connect(self):
        self.cid_press = self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press)
        self.cid_release = self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release)
        self.cid_motion = self.ax.figure.canvas.mpl_connect('motion_notify_event', self.on_motion)
        self.cid_pick = self.ax.figure.canvas.mpl_connect('pick_event', self.on_pick)

    def on_pick(self, event):
        if event.artist in self.anchors:
            if event.mouseevent.key == 'r':
                self.mode = 'anchor-rotate'
                self.center_x = self.x0 + self.width * 0.5
                self.center_y = self.y0 + self.height * 0.5
                self.angle_start = self.angle
                self.angle_drag_start = np.degrees(np.arctan2(event.mouseevent.y - self.center_y, event.mouseevent.x - self.center_x))
                print(self.angle_start)
            else:
                self.mode = 'anchor-drag'
                anchor_index = self.anchors.index(event.artist)
                self.active_anchor_index = anchor_index
            self.press = True
        elif event.artist is self.rect:
            self.mode = 'rectangle-drag'
            self.drag_start_x0 = self.x0
            self.drag_start_y0 = self.y0
            self.drag_start_x = event.mouseevent.x
            self.drag_start_y = event.mouseevent.y
            self.press = True

    def on_press(self, event):

        if event.inaxes != self.ax:
            return

        if self.mode == 'create':
            self.x0 = event.x
            self.y0 = event.y
            self.rect.set_visible(True)
            self.press = True

        # contains, attrd = self.rect.contains(event)
        # if not contains: return
        # print('event contains', self.rect.xy)
        # x0, y0 = self.rect.xy
        # self.press = x0, y0, event.x, event.y

    @property
    def angle(self):
        return self._angle

    @angle.setter
    def angle(self, value):
        self._angle = value
        self.rect.angle = value
        self.rect._update_patch_transform()

    @property
    def x0(self):
        return self.rect.get_x()

    @x0.setter
    def x0(self, value):
        self.rect.set_x(value)

    @property
    def y0(self):
        return self.rect.get_y()

    @y0.setter
    def y0(self, value):
        self.rect.set_y(value)

    @property
    def width(self):
        return self.rect.get_width()

    @width.setter
    def width(self, value):
        self.rect.set_width(value)

    @property
    def height(self):
        return self.rect.get_height()

    @height.setter
    def height(self, value):
        self.rect.set_height(value)

    def on_motion(self, event):

        if self.press is None:
            return

        if event.inaxes != self.ax:
            return

        if self.mode == 'create':

            self.width = event.x - self.x0
            self.height = event.y - self.y0

            self.rect.figure.canvas.draw()

        elif self.mode == 'rectangle-drag':

            self.x0 = self.drag_start_x0 + event.x - self.drag_start_x
            self.y0 = self.drag_start_y0 + event.y - self.drag_start_y

            self.update_anchors()

            self.rect.figure.canvas.draw()

        elif self.mode == 'anchor-drag':

            px, py = RECTANGLE_ANCHOR_LOCS[self.active_anchor_index]

            if px == -1:
                self.x0, self.width = event.x, self.x0 + self.width - event.x
            elif px == 1:
                self.width = event.x - self.x0

            if py == -1:
                self.y0, self.height = event.y, self.y0 + self.height - event.y
            elif py == 1:
                self.height = event.y - self.y0

            self.update_anchors()

            self.rect.figure.canvas.draw()

        elif self.mode == 'anchor-rotate':

            angle_current = np.degrees(np.arctan2(event.y - self.center_y, event.x - self.center_x))

            self.angle = self.angle_start + (angle_current - self.angle_drag_start)

            self.update_anchors()

            self.rect.figure.canvas.draw()

    def on_release(self, event):
        if self.mode == 'create':
            self.update_anchors()
            self.set_anchor_visibility(True)
        self.press = None
        self.mode = None
        self.rect.figure.canvas.draw()

    def set_anchor_visibility(self, visible):
        for anchor in self.anchors:
            anchor.set_visible(visible)

    def update_anchors(self):
        for anchor, (dx, dy) in zip(self.anchors, RECTANGLE_ANCHOR_LOCS):
            xc = self.x0 + 0.5 * self.width
            yc = self.y0 + 0.5 * self.height
            dx = 0.5 * (dx * self.width - ANCHOR_SIZE)
            dy = 0.5 * (dy * self.height - ANCHOR_SIZE)
            dxr = dx * np.cos(np.radians(self.angle)) - dy * np.sin(np.radians(self.angle))
            dyr = dx * np.sin(np.radians(self.angle)) + dy * np.cos(np.radians(self.angle))
            anchor.set_xy((xc + dxr, yc + dyr))

    def disconnect(self):
        self.ax.figure.canvas.mpl_disconnect(self.cid_press)
        self.ax.figure.canvas.mpl_disconnect(self.cid_release)
        self.ax.figure.canvas.mpl_disconnect(self.cid_motion)
Exemple #36
0
class viewer(graphplot):
    '''
    Do:
    viewer = viewer(window)
    viewer.connect()
    To instantiate and use
    '''
    def __init__(self,
                 nodes_obj,
                 window=None,
                 figsize=None,
                 idxlist=[],
                 usekm=False):
        # window are the [xmin,xmax,ymin,ymax] dimensions of the viewer

        self.coordunits = "coords"
        if usekm: self.coordunits = "coords_km"

        # Create nodedict if nodes is a dataframe
        if "DataFrame" in str(type(nodes_obj)):
            nodedict = nodes_obj.to_dict("index")
        else:
            nodedict = nodes_obj

        self.figsize = (9, 9) if not figsize else figsize
        self.fig_main = plt.figure(figsize=self.figsize)
        self.grid = plt.GridSpec(2,
                                 2,
                                 hspace=0.1,
                                 wspace=0.1,
                                 width_ratios=[2.2, 1],
                                 height_ratios=[0.8, 1])
        self.axs = [self.fig_main.add_subplot(self.grid[:, 0])]
        self.axs.append(self.fig_main.add_subplot(self.grid[0, 1]))

        # Initialize parent graph object
        super().__init__(nodedict,
                         idxlist,
                         (self.figsize[0] * 0.75, self.figsize[1] * 0.75),
                         self.fig_main,
                         self.axs[0],
                         usekm=usekm)
        self.axs[0].set_aspect('equal', adjustable='box', anchor="NW")

        # Draw main graph
        self.drawgraph()

        # Setup viewer
        if not window:
            #    window = [self.xlims[0]+0.4*self.graphwidth,
            #              self.xlims[0]+0.6*self.graphwidth,
            #              self.ylims[0]+0.4*self.graphheight,
            #              self.ylims[0]+0.6*self.graphheight]
            dw = 1. / long2km
            if usekm: dw = 1.
            window = [
                self.xlims[0] + 0.5 * self.graphwidth - dw,
                self.xlims[0] + 0.5 * self.graphwidth + dw,
                self.ylims[0] + 0.5 * self.graphheight - dw,
                self.ylims[0] + 0.5 * self.graphheight + dw
            ]
        xmin, xmax, ymin, ymax = window[0], window[1], window[2], window[3]
        self.window = Rectangle((xmin, ymin),
                                xmax - xmin,
                                ymax - ymin,
                                fill=False,
                                linewidth=1.6,
                                edgecolor="orangered")
        self.axs[0].add_patch(self.window)

        # Create inset axis
        xmin, ymin, xmax, ymax = self.get_rect_coords(self.window)
        self.axs[1].set_ylim(ymin, ymax)
        self.axs[1].set_xlim(xmin, xmax)
        self.axs[1].set_aspect('equal', adjustable='box', anchor="NE")
        self.axs[1].set_xticks([])
        self.axs[1].set_yticks([])
        self.press = None

        self.updateinset()

    def updateinset(self):
        # Remove any artists if present
        self.axs[1].clear()

        # Collect which nodes are included
        insetnodes = {}
        xmin, ymin, xmax, ymax = self.get_rect_coords(self.window)
        for key, node in self.nodes.items():
            x, y = node[self.coordunits]
            if x > xmin and x < xmax and y > ymin and y < ymax:
                insetnodes.update({key: node})
                self.plotnode(self.axs[1], x, y)
                edges = node["nbrs"]
                for e in edges:
                    if e in self.idxlist:
                        nbr = self.nodes[e][self.coordunits]
                        self.plotLine(self.axs[1], x, y, nbr[0], nbr[1])

        self.axs[1].set_ylim(ymin, ymax)
        self.axs[1].set_xlim(xmin, xmax)
        #self.axs[1].set_aspect('equal', adjustable='box',anchor="NE")
        self.axs[1].set_xticks([])
        self.axs[1].set_yticks([])


#         pickle.dump(self., file('myplot.pickle', 'w'))

    def connect(self):
        'connect to all the events we need'
        self.cidpress = self.window.figure.canvas.mpl_connect(
            'button_press_event', self.on_press)
        self.cidrelease = self.window.figure.canvas.mpl_connect(
            'button_release_event', self.on_release)
        self.cidmotion = self.window.figure.canvas.mpl_connect(
            'motion_notify_event', self.on_motion)

    def on_press(self, event):
        'on button press we will see if the mouse is over us and store some data'
        if event.inaxes != self.window.axes: return

        contains, attrd = self.window.contains(event)
        self.window.set_x(event.xdata - self.window.get_width() * 0.5)
        self.window.set_y(event.ydata - self.window.get_height() * 0.5)
        if True:
            # Update attributes for motion
            print('event contains', self.window.xy)
            x0, y0 = self.window.xy
            self.press = x0, y0, event.xdata, event.ydata

    def on_motion(self, event):
        'on motion we will move the window if the mouse is over us'
        if self.press is None: return
        if event.inaxes != self.window.axes: return
        x0, y0, xpress, ypress = self.press
        dx = event.xdata - xpress
        dy = event.ydata - ypress
        #print('x0=%f, xpress=%f, event.xdata=%f, dx=%f, x0+dx=%f' %
        #      (x0, xpress, event.xdata, dx, x0+dx))

        self.window.set_x(x0 + dx)
        self.window.set_y(y0 + dy)
        self.window.figure.canvas.draw()

    def on_release(self, event):
        'on release we reset the press data'
        self.press = None
        self.updateinset()
        self.window.figure.canvas.draw()

    def disconnect(self):
        'disconnect all the stored connection ids'
        self.window.figure.canvas.mpl_disconnect(self.cidpress)
        self.window.figure.canvas.mpl_disconnect(self.cidrelease)
        self.window.figure.canvas.mpl_disconnect(self.cidmotion)
Exemple #37
0
class CustomToolbar(NavToolbar):

    toolitems = NavToolbar.toolitems + (
        (None, None, None, None),
        ("ROI", "Select ROI", "selection", "_on_custom_select"),
    )

    def __init__(self, plotCanvas):
        # create the default toolbar
        NavToolbar.__init__(self, plotCanvas)
        self.selector = RectSelector(
            self.canvas.figure.axes[0], self.onSelect, button=[1, 3], minspanx=5, minspany=5  # don't use middle button
        )
        self.selector.set_active(True)
        self.ax = self.canvas.figure.axes[0]
        self.roi = None
        self.fixedSize = False
        if wx.Platform == "__WXMAC__":
            self.to_draw = Rectangle(
                (0, 0), 0, 1, visible=False, facecolor="yellow", edgecolor="black", alpha=0.5, fill=True
            )
            self.ax.add_patch(self.to_draw)
            self.background = None

    def _init_toolbar(self):
        self._parent = self.canvas.GetParent()

        self.wx_ids = {}
        for text, tooltip_text, image_file, callback in self.toolitems:
            if text is None:
                self.AddSeparator()
                continue
            self.wx_ids[text] = wx.NewId()
            try:
                bitmap = _load_bitmap(image_file + ".png")
            except IOError:
                bitmap = wx.Bitmap(image_file + ".png")
            if text in ["Pan", "Zoom", "ROI"]:
                self.AddCheckTool(self.wx_ids[text], bitmap, shortHelp=text, longHelp=tooltip_text)
            else:
                self.AddSimpleTool(self.wx_ids[text], bitmap, text, tooltip_text)
            bind(self, wx.EVT_TOOL, getattr(self, callback), id=self.wx_ids[text])

        self.ToggleTool(self.wx_ids["ROI"], True)
        self.Realize()

    def _set_markers(self):
        self.canvas.parentFrame.set_markers()

    def _update_view(self):
        NavToolbar._update_view(self)
        self._set_markers()
        # MacOS needs a forced draw to update plot
        if wx.Platform == "__WXMAC__":
            self.canvas.draw()

    def draw(self):
        self._set_markers()
        NavToolbar.draw(self)
        # MacOS needs a forced draw to update plot
        if wx.Platform == "__WXMAC__":
            self.canvas.draw()

    def zoom(self, ev):
        if wx.Platform == "__WXMAC__":
            self.ToggleTool(self.wx_ids["Zoom"], self.GetToolState(self.wx_ids["Zoom"]))
        NavToolbar.zoom(self, ev)

    def pan(self, ev):
        if wx.Platform == "__WXMAC__":
            self.ToggleTool(self.wx_ids["Pan"], self.GetToolState(self.wx_ids["Pan"]))
        NavToolbar.pan(self, ev)

    def press_zoom(self, ev):
        if wx.Platform == "__WXMAC__":
            self.update_background()
            self.to_draw.set_visible(True)
        NavToolbar.press_zoom(self, ev)

    def release_zoom(self, ev):
        if wx.Platform == "__WXMAC__":
            self.to_draw.set_visible(False)
        NavToolbar.release_zoom(self, ev)

    def draw_rubberband(self, event, x0, y0, x1, y1):
        # XOR does not work on MacOS ...
        if wx.Platform != "__WXMAC__":
            NavToolbar.draw_rubberband(self, event, x0, y0, x1, y1)
        else:
            if self.background is not None:
                self.canvas.restore_region(self.background)
            c0, c1 = self.ax.transData.inverted().transform([[x0, y0], [x1, y1]])
            l, b = c0
            r, t = c1
            self.to_draw.set_bounds(l, b, r - l, t - b)
            self.ax.draw_artist(self.to_draw)
            self.canvas.blit(self.ax.bbox)

    def update_background(self):
        """force an update of the background"""
        self.background = self.canvas.copy_from_bbox(self.ax.bbox)

    # Turn on selection
    # TODO: Proper handling of states, actual functionality.
    def _on_custom_select(self, evt):
        #        for id in ['Zoom','Pan']:
        #            self.ToggleTool(self.wx_ids[id], False)
        #        print('Select ROI: %s' % (self.GetToolState(self.wx_ids['ROI'])))
        #        self.ToggleTool(self.wx_ids['ROI'],
        #                self.GetToolState(self.wx_ids['ROI']) )
        self.toggle_selector()

    #        print('Select ROI: %s' % (self.GetToolState(self.wx_ids['ROI'])))

    def onSelect(self, eclick, erelease):
        "eclick and erelease are matplotlib events at press and release"
        #        print(' startposition : (%f, %f)' % (eclick.xdata, eclick.ydata))
        #        print(' endposition   : (%f, %f)' % (erelease.xdata, erelease.ydata))
        #        print(' used button   : ', eclick.button)
        self.updateROI(
            min(eclick.xdata, erelease.xdata),
            min(eclick.ydata, erelease.ydata),
            abs(eclick.xdata - erelease.xdata),
            abs(eclick.ydata - erelease.ydata),
        )
        if self.canvas.parentFrame.fixedNumberCB.IsChecked():
            # We are working in the fixed-number mode
            # We need to find new roi for this center point
            # The handler will call the update ROI function for us.
            self.canvas.parentFrame.handleROIforN()

    def updateROI(self, x, y, w, h):
        if self.roi is None:
            # print('upd ROI:', x, y, w, h)
            self.roi = Rectangle((x, y), w, h, ls="solid", lw=2, color="r", fill=False, zorder=5)
            self.canvas.figure.axes[0].add_patch(self.roi)
        else:
            self.roi.set_bounds(x, y, w, h)
        self.updateCanvas()

    def toggle_selector(self):
        self.selector.set_active(not self.selector.active)

    def onFixedSize(self, ev):
        self.fixedSize = ev.IsChecked()
        self.updateCanvas()

    def onWidthChange(self, ev):
        if self.roi:
            x = self.roi.get_x()
            w = self.roi.get_width()
            nw = ev.GetValue()
            dw = {"C": (w - nw) / 2, "L": 0, "R": w - nw}[self.canvas.parentFrame.anchorRB.GetStringSelection()[0]]
            self.roi.set_x(x + dw)
            self.roi.set_width(nw)
            self.updateCanvas()

    def onHeightChange(self, ev):
        if self.roi:
            y = self.roi.get_y()
            h = self.roi.get_height()
            nh = ev.GetValue()
            dh = {"C": (h - nh) / 2, "B": 0, "T": h - nh}[self.canvas.parentFrame.anchorRB.GetStringSelection()[-1]]
            self.roi.set_y(y + dh)
            self.roi.set_height(nh)
            self.updateCanvas()

    def updateCanvas(self, redraw=True):
        if self.roi:
            self.canvas.parentFrame.showROI(
                self.roi.get_x(), self.roi.get_y(), self.roi.get_width(), self.roi.get_height()
            )
            self.canvas.parentFrame.setWH(self.roi.get_width(), self.roi.get_height())
            if self.fixedSize:
                self.selector.setSize(self.roi.get_width(), self.roi.get_height())
            else:
                self.selector.setSize()
        if redraw:
            self.draw()
Exemple #38
0
class LensGUI:
    def __init__(self,parent):
        self.root = Tk.Tk()

        self.parent = parent
        self.img = self.parent.img
        self.color = self.parent.color

        self.mover = None

        f1 = Figure((12.06,12.06))
        a1 = f1.add_axes([0,101./201,100./201,100./201])
        self.img1 = a1.imshow(self.img,origin='bottom',interpolation='nearest')
        a1.set_xticks([])
        a1.set_yticks([])
        xlim = a1.get_xlim()
        ylim = a1.get_ylim()

        a2 = f1.add_axes([101./201,101./201,100./201,100./201])
        self.img2 = a2.imshow(self.img,origin='bottom',interpolation='nearest')
        a2.set_xlim(xlim)
        a2.set_ylim(ylim)
        a2.set_xticks([])
        a2.set_yticks([])

        a3 = f1.add_axes([0.,0.,100./201,100./201])
        self.img3 = a3.imshow(self.img*0+1,origin='bottom',interpolation='nearest')
        a3.set_xlim(xlim)
        a3.set_ylim(ylim)
        a3.set_xticks([])
        a3.set_yticks([])

        a4 = f1.add_axes([101./201,0.,100./201,100./201])
        a4.imshow(self.parent.b*0)
        a4.cla()
        a4.set_xlim(xlim)
        a4.set_ylim(ylim)
        a4.set_xticks([])
        a4.set_yticks([])

        canvas = FigureCanvasTkAgg(f1,master=self.root)
        canvas.show()
        canvas.get_tk_widget().pack(side=Tk.TOP,fill=Tk.BOTH,expand=1)
        toolbar = NavigationToolbar2TkAgg(canvas,self.root )
        toolbar.update()
        canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
        bFrame = Tk.Frame(self.root)
        bFrame.pack(side=Tk.TOP,fill=Tk.BOTH,expand=1)

        self.f1 = f1
        self.a1 = a1
        self.a2 = a2
        self.a3 = a3
        self.a4 = a4
        self.bFrame = bFrame

        self.canvas = canvas
        self.toolbar = toolbar

        self.rubberBox = None

        self.addButtons()

    def addButtons(self):
        self.activeButton = None
        self.bAGtext = Tk.StringVar()
        self.bAGtext.set('Add Galaxy')
        self.buttonAG = Tk.Button(self.toolbar,textvariable=self.bAGtext,command=self.parent.addGal,width=10)
        self.buttonAG.pack(side=Tk.LEFT)

        self.bALtext = Tk.StringVar()
        self.bALtext.set('Add Lens')
        self.buttonAL = Tk.Button(self.toolbar,textvariable=self.bALtext,command=self.parent.addLens,width=10)
        self.buttonAL.pack(side=Tk.LEFT)

        self.bAStext = Tk.StringVar()
        self.bAStext.set('Add Source')
        self.buttonAS = Tk.Button(self.toolbar,textvariable=self.bAStext,command=self.parent.addSrc,width=10)
        self.buttonAS.pack(side=Tk.LEFT)
        self.buttonAS.configure(state='disabled')

        self.buttonFit = Tk.Button(self.toolbar,text='Fit Light',command=self.parent.fitLight,width=10)
        self.buttonFit.pack(side=Tk.LEFT)
        #self.buttonFit.configure(state='disabled')

        self.bOpttext = Tk.StringVar()
        self.bOpttext.set('Optimize')
        self.buttonOptimize = Tk.Button(self.toolbar,textvariable=self.bOpttext,command=self.parent.optimize,width=10)
        self.buttonOptimize.pack(side=Tk.LEFT)
        #self.buttonOptimize.configure(state='disabled')

        self.buttonSave = Tk.Button(self.bFrame,text='Save',command=self.parent.saveState,width=10)
        self.buttonSave.pack(side=Tk.LEFT)

        self.buttonLoad = Tk.Button(self.bFrame,text='Load',command=self.parent.loadState,width=10)
        self.buttonLoad.pack(side=Tk.LEFT)

        self.bAMtext = Tk.StringVar()
        self.bAMtext.set('Add Mask')
        self.buttonMask = Tk.Button(self.bFrame,textvariable=self.bAMtext,command=self.addMask,width=10)
        self.buttonMask.pack(side=Tk.LEFT)


    def deactivateButtons(self):
        if self.toolbar.mode!='':
            self.toolbar.zoom()
            self.toolbar.pan()
            self.toolbar.pan()
        if self.activeButton==self.buttonAG:
            self.bAGtext.set('Add Galaxy')
            self.canvas.mpl_disconnect(self.pressid)
        elif self.activeButton==self.buttonAL:
            self.bALtext.set('Add Lens')
            self.canvas.mpl_disconnect(self.pressid)
        elif self.activeButton==self.buttonAS:
            self.bAStext.set('Add Source')
            self.canvas.mpl_disconnect(self.pressid)
        elif self.activeButton==self.buttonMask:
            self.bAMtext.set('Add Mask')
            self.canvas.mpl_disconnect(self.pressid)
            self.canvas.mpl_disconnect(self.moveid)
            self.canvas.mpl_disconnect(self.releaseid)
        self.pressid = None
        self.releaseid = None
        self.activeButton = None


    def addMask(self,loaded=False):
        from matplotlib.patches import Rectangle
        if loaded and self.parent.mask is not None:
            import numpy
            y,x = numpy.where(self.parent.mask==1)
            x0,x1,y0,y1 = x.min(),x.max(),y.min(),y.max()
            self.rubberBox = Rectangle((x0,y0),x1-x0,y1-y0,fc='none',ec='w')
            self.a1.add_patch(self.rubberBox)
            self.canvas.draw()
            return
        if self.activeButton==self.buttonMask:
            self.deactivateButtons()
            return
        self.deactivateButtons()
        self.xmask = None
        def onPress(event):
            axes = event.inaxes
            if axes==self.a1:
                self.xmask = event.xdata
                self.ymask = event.ydata
            if self.rubberBox is not None:
                self.rubberBox.remove()
                self.rubberBox = None
        def onMove(event):
            if self.xmask is None:
                return
            axes = event.inaxes
            if axes==self.a1:
                x,y = event.xdata,event.ydata
                dx = x-self.xmask
                dy = y-self.ymask
                if self.rubberBox is None:
                    self.rubberBox = Rectangle((self.xmask,self.ymask),
                                                dx,dy,fc='none',ec='w')
                    self.a1.add_patch(self.rubberBox)
                else:
                    self.rubberBox.set_height(dy)
                    self.rubberBox.set_width(dx)
                self.canvas.draw()
        def onRelease(event):
            dy = int(self.rubberBox.get_height())
            dx = int(self.rubberBox.get_width())
            x0,y0 = int(self.xmask),int(self.ymask)
            x1,y1 = x0+dx,y0+dy
            self.parent.mask = self.parent.imgs[0]*0
            self.parent.mask[y0:y1,x0:x1] = 1
            self.parent.mask = self.parent.mask==1
            self.deactivateButtons()
        self.pressid = self.canvas.mpl_connect('button_press_event',onPress)
        self.moveid = self.canvas.mpl_connect('motion_notify_event',onMove)
        self.releaseid = self.canvas.mpl_connect('button_release_event',onRelease)
        self.bAMtext.set('Cancel')
        self.activeButton = self.buttonMask


    def showResid(self):
        if self.parent.models is None:
            self.a2.imshow(self.parent.img,origin='bottom',
                            interpolation='nearest')
            self.a3.cla()
            self.a3.set_xticks([])
            self.a3.set_yticks([])
            self.canvas.show()
            return
        models = self.parent.models
        imgs = self.parent.imgs
        nimgs = self.parent.nimgs
        if self.color is not None:
            if nimgs==2:
                b = imgs[0]-models[0]
                r = imgs[1]-models[1]
                g = (b+r)/2.
                resid = self.color.colorize(b,g,r)
                b = models[0]
                r = models[1]
                g = (b+r)/2.
                model = self.color.colorize(b,g,r,newI=True)
            else:
                b = imgs[0]-models[0]
                g = imgs[1]-models[1]
                r = imgs[2]-models[2]
                resid = self.color.colorize(b,g,r)
                b = models[0]
                g = models[1]
                r = models[2]
                model = self.color.colorize(b,g,r,newI=True)
        else:
            resid = imgs[0]-models[0]
            model = models[0]
            self.img3.set_clim([0.,model.max()])
        #self.a2.imshow(resid,origin='bottom',interpolation='nearest')
        #self.a3.imshow(model,origin='bottom',interpolation='nearest')
        self.img2.set_data(resid)
        self.img3.set_data(model)
        self.canvas.draw()

    def redrawSymbols(self):
        import objectMover
        if self.mover is not None:
            self.mover.remove()
        self.mover = objectMover.ObjMover(self.parent,self.a4,self.canvas)