コード例 #1
0
ファイル: image_viewer.py プロジェクト: ngageoint/sarpy_apps
class ImageViewer(WidgetPanel, WidgetWithMetadata):
    _widget_list = ("image_panel", "pyplot_panel")
    image_panel = widget_descriptors.ImagePanelDescriptor(
        "image_panel")  # type: ImagePanel
    pyplot_panel = widget_descriptors.PanelDescriptor(
        "pyplot_panel", PyplotImagePanel)  # type: PyplotImagePanel

    def __init__(self, primary):
        """

        Parameters
        ----------
        primary : tkinter.Toplevel|tkinter.Tk
        """

        self.root = primary
        self.primary_frame = basic_widgets.Frame(primary)
        WidgetPanel.__init__(self, self.primary_frame)
        WidgetWithMetadata.__init__(self, primary)
        self.variables = AppVariables()

        self.init_w_horizontal_layout()
        self.set_title()

        # define menus
        menubar = tkinter.Menu()
        # file menu
        filemenu = tkinter.Menu(menubar, tearoff=0)
        filemenu.add_command(label="Open Image",
                             command=self.callback_select_files)
        filemenu.add_command(label="Open Directory",
                             command=self.callback_select_directory)
        filemenu.add_separator()
        filemenu.add_command(label="Exit", command=self.exit)
        # menus for informational popups
        popups_menu = tkinter.Menu(menubar, tearoff=0)
        popups_menu.add_command(label="Metaicon", command=self.metaicon_popup)
        popups_menu.add_command(label="Metaviewer",
                                command=self.metaviewer_popup)
        # ensure menus cascade
        menubar.add_cascade(label="File", menu=filemenu)
        menubar.add_cascade(label="Metadata", menu=popups_menu)

        # handle packing
        self.primary_frame.pack(fill=tkinter.BOTH, expand=tkinter.YES)
        primary.config(menu=menubar)

        # hide extraneous tool elements
        self.image_panel.hide_tools('shape_drawing')
        self.image_panel.hide_shapes()

        # bind canvas events for proper functionality
        # this makes for bad performance on a larger image - do not activate
        # self.image_panel.canvas.bind('<<SelectionChanged>>', self.handle_selection_change)
        self.image_panel.canvas.bind('<<SelectionFinalized>>',
                                     self.handle_selection_change)
        self.image_panel.canvas.bind('<<RemapChanged>>',
                                     self.handle_remap_change)
        self.image_panel.canvas.bind('<<ImageIndexChanged>>',
                                     self.handle_image_index_changed)

    def set_title(self):
        """
        Sets the window title.
        """

        file_name = None if self.variables.image_reader is None else self.variables.image_reader.file_name
        if file_name is None:
            the_title = "Image Viewer"
        elif isinstance(file_name, (list, tuple)):
            the_title = "Image Viewer, Multiple Files"
        else:
            the_title = "Image Viewer for {}".format(
                os.path.split(file_name)[1])
        self.winfo_toplevel().title(the_title)

    def exit(self):
        self.root.destroy()

    # noinspection PyUnusedLocal
    def handle_selection_change(self, event):
        """
        Handle a change in the selection area.

        Parameters
        ----------
        event
        """

        if self.variables.image_reader is None:
            return

        full_image_width = self.image_panel.canvas.variables.state.canvas_width
        fill_image_height = self.image_panel.canvas.variables.state.canvas_height
        self.image_panel.canvas.zoom_to_canvas_selection(
            (0, 0, full_image_width, fill_image_height))
        self.display_canvas_rect_selection_in_pyplot_frame()

    # noinspection PyUnusedLocal
    def handle_remap_change(self, event):
        """
        Handle that the remap for the image canvas has changed.

        Parameters
        ----------
        event
        """
        if self.variables.image_reader is not None:
            self.display_canvas_rect_selection_in_pyplot_frame()

    #noinspection PyUnusedLocal
    def handle_image_index_changed(self, event):
        """
        Handle that the image index has changed.

        Parameters
        ----------
        event
        """

        self.my_populate_metaicon()

    def update_reader(self, the_reader):
        """
        Update the reader.

        Parameters
        ----------
        the_reader : ImageReader
        """

        # change the tool to view
        self.image_panel.canvas.set_current_tool_to_view()
        self.image_panel.canvas.set_current_tool_to_view()
        # update the reader
        self.variables.image_reader = the_reader
        self.image_panel.set_image_reader(the_reader)
        self.set_title()
        # refresh appropriate GUI elements
        self.pyplot_panel.make_blank()
        self.my_populate_metaicon()
        self.my_populate_metaviewer()

    def callback_select_files(self):
        fnames = askopenfilenames(initialdir=self.variables.browse_directory,
                                  filetypes=common_use_collection)
        if fnames is None or fnames in ['', ()]:
            return
        # update the default directory for browsing
        self.variables.browse_directory = os.path.split(fnames[0])[0]

        the_reader = None
        if len(fnames) > 1:
            the_reader = ComplexImageReader(fnames)
        if the_reader is None:
            try:
                the_reader = ComplexImageReader(fnames[0])
            except IOError:
                the_reader = None
        if the_reader is None:
            the_reader = DerivedImageReader(fnames[0])
        if the_reader is None:
            showinfo(
                'Opener not found',
                message='File {} was not successfully opened as a SICD type '
                'or SIDD type file.'.format(fnames))
            return
        self.update_reader(the_reader)

    def callback_select_directory(self):
        dirname = askdirectory(initialdir=self.variables.browse_directory,
                               mustexist=True)
        if dirname is None or dirname in [(), '']:
            return
        # update the default directory for browsing
        self.variables.browse_directory = os.path.split(dirname)[0]
        # TODO: handle non-complex data possibilities here?
        the_reader = ComplexImageReader(dirname)
        self.update_reader(the_reader)

    def display_canvas_rect_selection_in_pyplot_frame(self):
        def get_extent(coords):
            left = min(coords[1::2])
            right = max(coords[1::2])
            top = max(coords[0::2])
            bottom = min(coords[0::2])
            return left, right, top, bottom

        threshold = self.image_panel.canvas.variables.config.select_size_threshold

        select_id = self.image_panel.canvas.variables.select_rect.uid
        rect_coords = self.image_panel.canvas.get_shape_image_coords(select_id)
        extent = get_extent(rect_coords)

        if abs(extent[1] -
               extent[0]) < threshold or abs(extent[2] -
                                             extent[3]) < threshold:
            self.pyplot_panel.make_blank()
        else:
            image_data = self.image_panel.canvas.get_image_data_in_canvas_rect_by_id(
                select_id)
            if image_data is not None:
                self.pyplot_panel.update_image(image_data, extent=extent)
            else:
                self.pyplot_panel.make_blank()

    def my_populate_metaicon(self):
        """
        Populate the metaicon.
        """

        if self.image_panel.canvas.variables.canvas_image_object is None or \
                self.image_panel.canvas.variables.canvas_image_object.image_reader is None:
            image_reader = None
            the_index = 0
        else:
            image_reader = self.image_panel.canvas.variables.canvas_image_object.image_reader
            the_index = self.image_panel.canvas.get_image_index()
        self.populate_metaicon(image_reader, the_index)

    def my_populate_metaviewer(self):
        """
        Populate the metaviewer.
        """

        if self.image_panel.canvas.variables.canvas_image_object is None:
            image_reader = None
        else:
            image_reader = self.image_panel.canvas.variables.canvas_image_object.image_reader
        self.populate_metaviewer(image_reader)
コード例 #2
0
class CanvasResize(WidgetPanel):
    _widget_list = ("image_panel", "button_panel")

    image_panel = widget_descriptors.ImagePanelDescriptor(
        "image_panel")  # type: ImagePanel
    button_panel = widget_descriptors.PanelDescriptor("button_panel",
                                                      Buttons)  # type: Buttons

    def __init__(self, primary):
        self._shape_ids = {}

        self.primary = primary

        primary_frame = tkinter.Frame(primary)
        WidgetPanel.__init__(self, primary_frame)

        self.init_w_horizontal_layout()

        image_npix_x = 2000
        image_npix_y = 1500

        self.image_panel.set_max_canvas_size(image_npix_x, image_npix_y)

        image_data = numpy.linspace(0, 255, image_npix_x * image_npix_y)
        image_data = numpy.reshape(image_data, (image_npix_y, image_npix_x))
        image_reader = NumpyImageReader(image_data)
        self.image_panel.set_image_reader(image_reader)

        self.drag_xlim_1 = image_npix_x * 0.1
        self.drag_xlim_2 = image_npix_x * 0.9
        self.drag_ylim_1 = image_npix_y * 0.1
        self.drag_ylim_2 = image_npix_y * 0.9

        self.image_panel.current_tool = ToolConstants.PAN

        self.image_panel.set_min_canvas_size(100, 100)

        primary_frame.pack(fill=tkinter.BOTH, expand=tkinter.YES)

        self.button_panel.draw_rect.config(command=self.callback_draw_rect)
        self.button_panel.draw_line.config(command=self.callback_draw_line)
        self.button_panel.draw_arrow.config(command=self.callback_draw_arrow)
        self.button_panel.draw_point.config(command=self.callback_draw_point)
        self.button_panel.draw_ellipse.config(
            command=self.callback_draw_ellipse)
        self.button_panel.draw_polygon.config(
            command=self.callback_draw_polygon)

        # handle the image creation event
        self.image_panel.canvas.bind('<<ShapeCreate>>', self.handle_new_shape)

    @property
    def point_id(self):
        """
        None|int: The point id.
        """

        return self._shape_ids.get(ShapeTypeConstants.POINT, None)

    @property
    def line_id(self):
        """
        None|int: The line id.
        """

        return self._shape_ids.get(ShapeTypeConstants.LINE, None)

    @property
    def arrow_id(self):
        """
        None|int: The arrow id.
        """

        return self._shape_ids.get(ShapeTypeConstants.ARROW, None)

    @property
    def rect_id(self):
        """
        None|int: The rectangle id.
        """

        return self._shape_ids.get(ShapeTypeConstants.RECT, None)

    @property
    def ellipse_id(self):
        """
        None|int: The ellipse id.
        """

        return self._shape_ids.get(ShapeTypeConstants.ELLIPSE, None)

    @property
    def polygon_id(self):
        """
        None|int: polygon id.
        """

        return self._shape_ids.get(ShapeTypeConstants.POLYGON, None)

    def callback_draw_point(self):
        self.image_panel.canvas.set_current_tool_to_draw_point(self.point_id)

    def callback_draw_line(self):
        self.image_panel.canvas.set_current_tool_to_draw_line(self.line_id)

    def callback_draw_arrow(self):
        self.image_panel.canvas.set_current_tool_to_draw_arrow(self.arrow_id)

    def callback_draw_rect(self):
        self.image_panel.canvas.set_current_tool_to_draw_rect(self.rect_id)

    def callback_draw_ellipse(self):
        self.image_panel.canvas.set_current_tool_to_draw_ellipse(
            self.ellipse_id)

    def callback_draw_polygon(self):
        self.image_panel.canvas.set_current_tool_to_draw_polygon(
            self.polygon_id)

    def handle_new_shape(self, event):
        """
        Handle the creation of a new shape.

        Parameters
        ----------
        event
        """

        # we'll be tracking the most recently created
        self._shape_ids[event.y] = event.x

    def exit(self):
        self.quit()
コード例 #3
0
class LocalFrequencySupportTool(WidgetPanel, WidgetWithMetadata):
    _widget_list = ("image_panel", "frequency_panel")
    image_panel = widget_descriptors.ImagePanelDescriptor("image_panel")   # type: ImagePanel
    frequency_panel = widget_descriptors.ImagePanelDescriptor("frequency_panel")   # type: ImagePanel

    def __init__(self, primary):
        self.root = primary
        self.primary_frame = basic_widgets.Frame(primary)
        WidgetPanel.__init__(self, self.primary_frame)
        WidgetWithMetadata.__init__(self, primary)
        self.variables = AppVariables()

        self.init_w_horizontal_layout()
        self.set_title()

        # define menus
        menubar = tkinter.Menu()
        # file menu
        filemenu = tkinter.Menu(menubar, tearoff=0)
        filemenu.add_command(label="Open Image", command=self.callback_select_files)
        filemenu.add_command(label="Open Directory", command=self.callback_select_directory)
        filemenu.add_separator()
        filemenu.add_command(label="Exit", command=self.exit)
        # menus for informational popups
        popups_menu = tkinter.Menu(menubar, tearoff=0)
        popups_menu.add_command(label="Metaicon", command=self.metaicon_popup)
        popups_menu.add_command(label="Metaviewer", command=self.metaviewer_popup)
        # ensure menus cascade
        menubar.add_cascade(label="File", menu=filemenu)
        menubar.add_cascade(label="Metadata", menu=popups_menu)

        # handle packing
        self.primary_frame.pack(fill=tkinter.BOTH, expand=tkinter.YES)
        primary.config(menu=menubar)

        # hide extraneous tool elements
        self.image_panel.hide_tools('shape_drawing')
        self.image_panel.hide_shapes()
        self.frequency_panel.hide_tools(['shape_drawing', 'select'])
        self.frequency_panel.hide_shapes()
        self.frequency_panel.hide_select_index()

        # bind canvas events for proper functionality
        self.image_panel.canvas.bind('<<SelectionChanged>>', self.handle_selection_change)
        self.image_panel.canvas.bind('<<SelectionFinalized>>', self.handle_selection_change)
        self.image_panel.canvas.bind('<<ImageIndexChanged>>', self.handle_image_index_changed)

    def set_title(self):
        """
        Sets the window title.
        """

        file_name = None if self.variables.image_reader is None else self.variables.image_reader.file_name
        if file_name is None:
            the_title = "Frequency Support Tool"
        elif isinstance(file_name, (list, tuple)):
            the_title = "Frequency Support Tool, Multiple Files"
        else:
            the_title = "Frequency Support Tool for {}".format(os.path.split(file_name)[1])
        self.winfo_toplevel().title(the_title)

    def exit(self):
        self.root.destroy()

    def set_default_selection(self):
        """
        Sets the default selection on the currently selected image.
        """

        if self.variables.image_reader is None:
            return

        # get full image size
        full_rows = self.variables.image_reader.full_image_ny
        full_cols = self.variables.image_reader.full_image_nx
        default_size = 512
        middle = (
            max(0, int(0.5*(full_rows - default_size))),
            max(0, int(0.5*(full_cols - default_size))),
            min(full_rows, int(0.5*(full_rows + default_size))),
            min(full_cols, int(0.5*(full_cols + default_size))))
        self.image_panel.canvas.zoom_to_full_image_selection((0, 0, full_rows, full_cols))
        # set selection rectangle
        self.image_panel.canvas.set_current_tool_to_select()
        self.image_panel.canvas.modify_existing_shape_using_image_coords(
            self.image_panel.canvas.variables.select_rect.uid, middle)
        self.image_panel.canvas.show_shape(self.image_panel.canvas.variables.select_rect.uid)
        # we need to set some drawing state here...this is ugly, but not worth
        anchor = self.image_panel.canvas.get_shape_canvas_coords(self.image_panel.canvas.variables.select_rect.uid)[:2]
        self.image_panel.canvas.set_select_initial_state(anchor)

    # noinspection PyUnusedLocal
    def handle_selection_change(self, event):
        """
        Handle a change in the selection area.

        Parameters
        ----------
        event
        """

        if self.variables.image_reader is None:
            return

        full_image_width = self.image_panel.canvas.variables.state.canvas_width
        fill_image_height = self.image_panel.canvas.variables.state.canvas_height
        self.image_panel.canvas.zoom_to_canvas_selection((0, 0, full_image_width, fill_image_height))
        self.update_displayed_selection()

    #noinspection PyUnusedLocal
    def handle_image_index_changed(self, event):
        """
        Handle that the image index has changed.

        Parameters
        ----------
        event
        """

        self.my_populate_metaicon()
        self.set_default_selection()

    def update_reader(self, the_reader):
        """
        Update the reader.

        Parameters
        ----------
        the_reader : ImageReader
        """

        # change the tool to view
        self.image_panel.canvas.set_current_tool_to_view()
        self.image_panel.canvas.set_current_tool_to_view()
        # update the reader
        self.variables.image_reader = the_reader
        self.image_panel.set_image_reader(the_reader)
        self.set_title()
        # refresh appropriate GUI elements
        self.set_default_selection()
        self.my_populate_metaicon()
        self.my_populate_metaviewer()

    def callback_select_files(self):
        fnames = askopenfilenames(initialdir=self.variables.browse_directory, filetypes=common_use_collection)
        if fnames is None or fnames in ['', ()]:
            return
        # update the default directory for browsing
        self.variables.browse_directory = os.path.split(fnames[0])[0]

        the_reader = None
        if len(fnames) == 1:
            the_reader = ComplexImageReader(fnames[0])
        else:
            the_reader = ComplexImageReader(fnames)

        if the_reader is None:
            showinfo('Opener not found',
                     message='File {} was not successfully opened as a SICD type '
                             'file.'.format(fnames))
            return
        self.update_reader(the_reader)

    def callback_select_directory(self):
        dirname = askdirectory(initialdir=self.variables.browse_directory, mustexist=True)
        if dirname is None or dirname in [(), '']:
            return
        # update the default directory for browsing
        self.variables.browse_directory = os.path.split(dirname)[0]
        the_reader = ComplexImageReader(dirname)
        self.update_reader(the_reader)

    def _initialize_bandwidth_lines(self):
        if self.variables.row_line_low is None or \
                self.frequency_panel.canvas.get_vector_object(self.variables.row_line_low) is None:
            self.variables.row_deltak1 = self.frequency_panel.canvas.create_new_line(
                (0, 0, 0, 0), make_current=False, increment_color=False, fill='red')
            self.variables.row_deltak2 = self.frequency_panel.canvas.create_new_line(
                (0, 0, 0, 0), make_current=False, increment_color=False, fill='red')
            self.variables.col_deltak1 = self.frequency_panel.canvas.create_new_line(
                (0, 0, 0, 0), make_current=False, increment_color=False, fill='red')
            self.variables.col_deltak2 = self.frequency_panel.canvas.create_new_line(
                (0, 0, 0, 0), make_current=False, increment_color=False, fill='red')

            self.variables.row_line_low = self.frequency_panel.canvas.create_new_line(
                (0, 0, 0, 0), make_current=False, increment_color=False, fill='blue', dash=(3, ))
            self.variables.row_line_high = self.frequency_panel.canvas.create_new_line(
                (0, 0, 0, 0), make_current=False, increment_color=False, fill='blue', dash=(3, ))
            self.variables.col_line_low = self.frequency_panel.canvas.create_new_line(
                (0, 0, 0, 0), make_current=False, increment_color=False, fill='blue', dash=(3, ))
            self.variables.col_line_high = self.frequency_panel.canvas.create_new_line(
                (0, 0, 0, 0), make_current=False, increment_color=False, fill='blue', dash=(3, ))

        else:
            self.frequency_panel.canvas.modify_existing_shape_using_image_coords(
                self.variables.row_deltak1, (0, 0, 0, 0))
            self.frequency_panel.canvas.modify_existing_shape_using_image_coords(
                self.variables.row_deltak2, (0, 0, 0, 0))
            self.frequency_panel.canvas.modify_existing_shape_using_image_coords(
                self.variables.col_deltak1, (0, 0, 0, 0))
            self.frequency_panel.canvas.modify_existing_shape_using_image_coords(
                self.variables.col_deltak2, (0, 0, 0, 0))

            self.frequency_panel.canvas.modify_existing_shape_using_image_coords(
                self.variables.row_line_low, (0, 0, 0, 0))
            self.frequency_panel.canvas.modify_existing_shape_using_image_coords(
                self.variables.row_line_high, (0, 0, 0, 0))
            self.frequency_panel.canvas.modify_existing_shape_using_image_coords(
                self.variables.col_line_low, (0, 0, 0, 0))
            self.frequency_panel.canvas.modify_existing_shape_using_image_coords(
                self.variables.col_line_high, (0, 0, 0, 0))

    def update_displayed_selection(self):
        def get_extent(coords):
            return min(coords[0::2]), max(coords[0::2]), min(coords[1::2]), max(coords[1::2])

        def draw_row_delta_lines():
            deltak1 = (row_count - 1)*(0.5 + the_sicd.Grid.Row.SS*the_sicd.Grid.Row.DeltaK1) + 1
            deltak2 = (row_count - 1)*(0.5 + the_sicd.Grid.Row.SS*the_sicd.Grid.Row.DeltaK2) + 1

            self.frequency_panel.canvas.modify_existing_shape_using_image_coords(
                self.variables.row_deltak1, (deltak1, 0, deltak1, col_count))
            self.frequency_panel.canvas.modify_existing_shape_using_image_coords(
                self.variables.row_deltak2, (deltak2, 0, deltak2, col_count))

        def draw_col_delta_lines():
            deltak1 = (col_count - 1)*(0.5 + the_sicd.Grid.Col.SS*the_sicd.Grid.Col.DeltaK1) + 1
            deltak2 = (col_count - 1)*(0.5 + the_sicd.Grid.Col.SS*the_sicd.Grid.Col.DeltaK2) + 1

            self.frequency_panel.canvas.modify_existing_shape_using_image_coords(
                self.variables.col_deltak1, (0, deltak1, row_count, deltak1))
            self.frequency_panel.canvas.modify_existing_shape_using_image_coords(
                self.variables.col_deltak2, (0, deltak2, row_count, deltak2))

        def draw_row_bandwidth_lines():
            try:
                delta_kcoa_center = the_sicd.Grid.Row.DeltaKCOAPoly(row_phys, col_phys)
            except Exception:
                delta_kcoa_center = 0.0

            row_bw_low = (row_count - 1)*(
                    0.5 + the_sicd.Grid.Row.SS*(delta_kcoa_center - 0.5*the_sicd.Grid.Row.ImpRespBW)) + 1
            row_bw_high = (row_count - 1)*(
                    0.5 + the_sicd.Grid.Row.SS*(delta_kcoa_center + 0.5*the_sicd.Grid.Row.ImpRespBW)) + 1

            row_bw_low = (row_bw_low % row_count)
            row_bw_high = (row_bw_high % row_count)

            self.frequency_panel.canvas.modify_existing_shape_using_image_coords(
                self.variables.row_line_low, (row_bw_low, 0, row_bw_low, col_count))
            self.frequency_panel.canvas.modify_existing_shape_using_image_coords(
                self.variables.row_line_high, (row_bw_high, 0, row_bw_high, col_count))

        def draw_col_bandwidth_lines():
            try:
                delta_kcoa_center = the_sicd.Grid.Col.DeltaKCOAPoly(row_phys, col_phys)
            except Exception:
                delta_kcoa_center = 0.0

            col_bw_low = (col_count - 1) * (
                    0.5 + the_sicd.Grid.Col.SS*(delta_kcoa_center - 0.5*the_sicd.Grid.Col.ImpRespBW)) + 1
            col_bw_high = (col_count - 1) * (
                    0.5 + the_sicd.Grid.Col.SS*(delta_kcoa_center + 0.5*the_sicd.Grid.Col.ImpRespBW)) + 1

            col_bw_low = (col_bw_low % col_count)
            col_bw_high = (col_bw_high % col_count)

            self.frequency_panel.canvas.modify_existing_shape_using_image_coords(
                self.variables.col_line_low, (0, col_bw_low, row_count, col_bw_low))
            self.frequency_panel.canvas.modify_existing_shape_using_image_coords(
                self.variables.col_line_high, (0, col_bw_high, row_count, col_bw_high))

        threshold = self.image_panel.canvas.variables.config.select_size_threshold
        select_id = self.image_panel.canvas.variables.select_rect.uid
        rect_coords = self.image_panel.canvas.get_shape_image_coords(select_id)
        extent = get_extent(rect_coords)  # left, right, bottom, top
        row_count = extent[1] - extent[0]
        col_count = extent[3] - extent[2]

        the_sicd = self.variables.image_reader.get_sicd()
        row_phys, col_phys = get_physical_coordinates(
            the_sicd, 0.5*(extent[0]+extent[1]), 0.5*(extent[2]+extent[3]))

        if row_count < threshold or col_count < threshold:
            junk_data = numpy.zeros((100, 100), dtype='uint8')
            self.frequency_panel.set_image_reader(NumpyImageReader(junk_data))
            self._initialize_bandwidth_lines()
        else:
            image_data = self.variables.image_reader.base_reader[extent[0]:extent[1], extent[2]:extent[3]]
            if image_data is not None:
                self.frequency_panel.set_image_reader(
                    NumpyImageReader(remap.density(fftshift(fft2_sicd(image_data, the_sicd)))))
                self._initialize_bandwidth_lines()
                draw_row_delta_lines()
                draw_col_delta_lines()
                draw_row_bandwidth_lines()
                draw_col_bandwidth_lines()
            else:
                junk_data = numpy.zeros((100, 100), dtype='uint8')
                self.frequency_panel.set_image_reader(NumpyImageReader(junk_data))
                self._initialize_bandwidth_lines()

    def my_populate_metaicon(self):
        """
        Populate the metaicon.
        """

        if self.variables.image_reader is None:
            image_reader = None
            the_index = 0
        else:

            image_reader = self.variables.image_reader
            the_index = self.variables.image_reader.index
        self.populate_metaicon(image_reader, the_index)

    def my_populate_metaviewer(self):
        """
        Populate the metaviewer.
        """

        self.populate_metaviewer(self.variables.image_reader)
コード例 #4
0
class CanvasResize(WidgetPanel):
    _widget_list = ("image_panel", "button_panel")

    image_panel = widget_descriptors.ImagePanelDescriptor("image_panel")         # type: ImagePanel
    button_panel = widget_descriptors.PanelDescriptor("button_panel", Buttons)  # type: Buttons

    def __init__(self, primary):
        self.rect_id = None
        self.line_id = None
        self.arrow_id = None
        self.point_id = None
        self.polygon_id = None
        self.n_shapes = 0

        self.primary = primary

        primary_frame = tkinter.Frame(primary)
        WidgetPanel.__init__(self, primary_frame)

        self.init_w_horizontal_layout()

        self.image_panel.image_frame.set_canvas_size(800, 600)
        self.image_panel.resizeable = True

        image_npix_x = 1200
        image_npix_y = 500

        image_data = numpy.random.random((image_npix_y, image_npix_x))
        image_data = image_data * 255
        image_reader = NumpyImageReader(image_data)
        self.image_panel.set_image_reader(image_reader)

        self.drag_xlim_1 = image_npix_x * 0.25
        self.drag_xlim_2 = image_npix_x * 0.75
        self.drag_ylim_1 = image_npix_y * 0.1
        self.drag_ylim_2 = image_npix_y * 0.9

        self.image_panel.current_tool = ToolConstants.PAN_TOOL

        self.image_panel.axes_canvas.image_x_min_val = 500
        self.image_panel.axes_canvas.image_x_max_val = 1200

        self.image_panel.axes_canvas.image_y_min_val = 5000
        self.image_panel.axes_canvas.image_y_max_val = 2000

        primary_frame.pack(fill=tkinter.BOTH, expand=tkinter.YES)
        self.image_panel.canvas.set_canvas_size(800, 800)

        self.button_panel.draw_rect.on_left_mouse_click(self.callback_draw_rect)
        self.button_panel.draw_line.on_left_mouse_click(self.callback_draw_line)
        self.button_panel.draw_arrow.on_left_mouse_click(self.callback_draw_arrow)
        self.button_panel.draw_point.on_left_mouse_click(self.callback_draw_point)
        self.button_panel.draw_polygon.on_left_mouse_click(self.callback_draw_polygon)
        self.button_panel.edit_shape.on_left_mouse_click(self.callback_edit_shape)
        self.image_panel.canvas.on_left_mouse_release(self.callback_on_left_mouse_release)

    def callback_draw_rect(self, event):
        self.image_panel.canvas.set_current_tool_to_draw_rect(self.rect_id)

    def callback_draw_line(self, event):
        self.image_panel.canvas.set_current_tool_to_draw_line_by_dragging(self.line_id)

    def callback_draw_arrow(self, event):
        self.image_panel.canvas.set_current_tool_to_draw_arrow_by_dragging(self.arrow_id)

    def callback_draw_point(self, event):
        self.image_panel.canvas.set_current_tool_to_draw_point(self.point_id)

    def callback_draw_polygon(self, event):
        self.image_panel.canvas.set_current_tool_to_draw_polygon_by_clicking(self.polygon_id)

    def callback_edit_shape(self, event):
        self.image_panel.canvas.set_current_tool_to_edit_shape()

    def callback_on_left_mouse_release(self, event):
        self.image_panel.canvas.callback_handle_left_mouse_release(event)
        n_shapes = len(self.image_panel.canvas.get_non_tool_shape_ids())
        if n_shapes > self.n_shapes:
            if self.image_panel.current_tool == ToolConstants.DRAW_RECT_BY_DRAGGING:
                self.rect_id = self.image_panel.canvas.variables.current_shape_id
            elif self.image_panel.current_tool == ToolConstants.DRAW_LINE_BY_DRAGGING:
                self.line_id = self.image_panel.canvas.variables.current_shape_id
            elif self.image_panel.current_tool == ToolConstants.DRAW_ARROW_BY_DRAGGING:
                self.arrow_id = self.image_panel.canvas.variables.current_shape_id
            elif self.image_panel.current_tool == ToolConstants.DRAW_POINT_BY_CLICKING:
                self.point_id = self.image_panel.canvas.variables.current_shape_id
            elif self.image_panel.current_tool == ToolConstants.DRAW_POLYGON_BY_CLICKING:
                self.polygon_id = self.image_panel.canvas.variables.current_shape_id
            self.image_panel.canvas.get_vector_object(
                self.image_panel.canvas.variables.current_shape_id).image_drag_limits = (self.drag_ylim_1,
                                                                                         self.drag_xlim_1,
                                                                                         self.drag_ylim_2,
                                                                                         self.drag_xlim_2)

    def exit(self):
        self.quit()
コード例 #5
0
class FullFrequencySupportTool(WidgetPanel, WidgetWithMetadata):
    _widget_list = ("row_centered_image_panel", "column_centered_image_panel")
    row_centered_image_panel = widget_descriptors.ImagePanelDescriptor(
        "row_centered_image_panel")  # type: ImagePanel
    column_centered_image_panel = widget_descriptors.ImagePanelDescriptor(
        "column_centered_image_panel")  # type: ImagePanel

    def __init__(self, primary):
        self.root = primary
        self.primary_frame = basic_widgets.Frame(primary)
        self.variables = AppVariables()
        WidgetPanel.__init__(self, self.primary_frame)
        WidgetWithMetadata.__init__(self, primary)

        self.init_w_horizontal_layout()
        self.set_title()

        # define menus
        menubar = tkinter.Menu()
        # file menu
        filemenu = tkinter.Menu(menubar, tearoff=0)
        filemenu.add_command(label="Open Image",
                             command=self.callback_select_files)
        filemenu.add_command(label="Open Directory",
                             command=self.callback_select_directory)
        filemenu.add_separator()
        filemenu.add_command(label="Exit", command=self.exit)
        # menus for informational popups
        popups_menu = tkinter.Menu(menubar, tearoff=0)
        popups_menu.add_command(label="Weight Plots",
                                command=self.create_weights_plot)
        popups_menu.add_command(label="Metaicon", command=self.metaicon_popup)
        popups_menu.add_command(label="Metaviewer",
                                command=self.metaviewer_popup)
        # ensure menus cascade
        menubar.add_cascade(label="File", menu=filemenu)
        menubar.add_cascade(label="Metadata", menu=popups_menu)

        # handle packing
        self.primary_frame.pack(fill=tkinter.BOTH, expand=tkinter.YES)
        primary.config(menu=menubar)

        # hide extraneous tool elements
        self.row_centered_image_panel.hide_tools(['shape_drawing', 'select'])
        self.row_centered_image_panel.hide_shapes()
        self.row_centered_image_panel.hide_select_index()

        self.column_centered_image_panel.hide_tools(
            ['shape_drawing', 'select'])
        self.column_centered_image_panel.hide_shapes()
        self.column_centered_image_panel.hide_select_index()

        # TODO: allow changing the image index somewhere?
        #   bind the handle_image_index_changed method

    def set_title(self):
        """
        Sets the window title.
        """

        file_name = None if self.variables.image_reader is None else self.variables.image_reader.file_name
        if file_name is None:
            the_title = "Full Frequency Support Tool"
        elif isinstance(file_name, (list, tuple)):
            the_title = "Full Frequency Support Tool, Multiple Files"
        else:
            the_title = "Full Frequency Support Tool for {}".format(
                os.path.split(file_name)[1])
        self.winfo_toplevel().title(the_title)

    def exit(self):
        self._delete_files()
        self.root.destroy()

    def _delete_files(self):
        """
        This is a helper function for cleaning up our state.
        """

        if not hasattr(self, 'variables') or self.variables is None:
            return

        self.variables.row_fourier_reader = None
        self.variables.column_fourier_reader = None
        if self.variables.row_fourier_file is not None \
                and os.path.exists(self.variables.row_fourier_file):
            os.remove(self.variables.row_fourier_file)
            logger.debug('Removing temp file % s' %
                         self.variables.row_fourier_file)

        if self.variables.column_fourier_file is not None and \
                os.path.exists(self.variables.column_fourier_file):
            os.remove(self.variables.column_fourier_file)
            logger.debug('Removing temp file % s' %
                         self.variables.column_fourier_file)

        self.variables.row_fourier_file = None
        self.variables.column_fourier_file = None

    def _clear_display(self):
        """
        Clear the row and column Fourier transform displays
        """

        self._delete_files()
        junk_data = numpy.zeros((100, 100), dtype='uint8')
        self.row_centered_image_panel.set_image_reader(
            NumpyImageReader(junk_data))
        self.column_centered_image_panel.set_image_reader(
            NumpyImageReader(junk_data))

    def _calculate_fourier_data(self):
        def set_row_data():
            # calculate the fourier transform with deskew in the row direction
            row_file, row_memmap, row_mean_value = create_deskewed_transform(
                self.variables.image_reader, dimension=0)
            self.variables.row_fourier_file = row_file
            self.variables.row_fourier_reader = ComplexImageReader(
                FlatSICDReader(self.variables.image_reader.get_sicd(),
                               row_memmap))
            self.row_centered_image_panel.set_image_reader(
                self.variables.row_fourier_reader)

            draw_deltak_lines(self.row_centered_image_panel.canvas)

            # rescale the row_mean_value so that the smoothed max value is essentially 1
            if row_mean_value.size < 200:
                the_max = numpy.amax(row_mean_value)
            else:
                the_size = int(numpy.ceil(row_mean_value.size / 200.))
                smoothed = numpy.convolve(row_mean_value,
                                          numpy.full((the_size, ),
                                                     1. / the_size,
                                                     dtype='float64'),
                                          mode='valid')
                the_max = numpy.amax(smoothed)
            row_mean_value /= the_max
            self.variables.scaled_row_mean = row_mean_value
            # construct the proper weights and prepare information for weight plotting
            self.variables.derived_row_weights = the_sicd.Grid.Row.define_weight_function(
                populate=False)

        def set_col_data():
            # calculate the fourier transform with deskew in the column direction
            col_file, col_memmap, col_mean_value = create_deskewed_transform(
                self.variables.image_reader, dimension=1)
            self.variables.column_fourier_file = col_file
            self.variables.column_fourier_reader = ComplexImageReader(
                FlatSICDReader(self.variables.image_reader.get_sicd(),
                               col_memmap))
            self.column_centered_image_panel.set_image_reader(
                self.variables.column_fourier_reader)

            draw_deltak_lines(self.column_centered_image_panel.canvas)

            # rescale the row_mean_value so that the smoothed max value is essentially 1
            if col_mean_value.size < 200:
                the_max = numpy.amax(col_mean_value)
            else:
                the_size = int(numpy.ceil(col_mean_value.size / 200.))
                smoothed = numpy.convolve(col_mean_value,
                                          numpy.full((the_size, ),
                                                     1. / the_size,
                                                     dtype='float64'),
                                          mode='valid')
                the_max = numpy.amax(smoothed)
            col_mean_value /= the_max
            self.variables.scaled_column_mean = col_mean_value
            # construct the proper weights and prepare information for weight plotting
            self.variables.derived_column_weights = the_sicd.Grid.Col.define_weight_function(
                populate=False)

        def draw_deltak_lines(canvas):
            # calculate the row deltak1/deltak2 values
            deltak1 = (row_count - 1) * (
                0.5 + the_sicd.Grid.Row.SS * the_sicd.Grid.Row.DeltaK1) + 1
            deltak2 = (row_count - 1) * (
                0.5 + the_sicd.Grid.Row.SS * the_sicd.Grid.Row.DeltaK2) + 1
            # draw the deltak1/deltak2 lines
            deltak1_id = canvas.create_new_line((0, 0, 0, 0),
                                                make_current=False,
                                                increment_color=False,
                                                fill='red')
            canvas.modify_existing_shape_using_image_coords(
                deltak1_id, (deltak1, 0, deltak1, col_count))
            deltak2_id = canvas.create_new_line((0, 0, 0, 0),
                                                make_current=False,
                                                increment_color=False,
                                                fill='red')
            canvas.modify_existing_shape_using_image_coords(
                deltak2_id, (deltak2, 0, deltak2, col_count))

            # calculate the column deltak1/deltak2 values
            deltak1 = (col_count - 1) * (
                0.5 + the_sicd.Grid.Col.SS * the_sicd.Grid.Col.DeltaK1) + 1
            deltak2 = (col_count - 1) * (
                0.5 + the_sicd.Grid.Col.SS * the_sicd.Grid.Col.DeltaK2) + 1
            # draw the deltak1/deltak2 lines
            deltak1_id = canvas.create_new_line((0, 0, 0, 0),
                                                make_current=False,
                                                increment_color=False,
                                                fill='red')
            canvas.modify_existing_shape_using_image_coords(
                deltak1_id, (0, deltak1, row_count, deltak1))
            deltak2_id = canvas.create_new_line((0, 0, 0, 0),
                                                make_current=False,
                                                increment_color=False,
                                                fill='red')
            canvas.modify_existing_shape_using_image_coords(
                deltak2_id, (0, deltak2, row_count, deltak2))

        # delete any previous state variables and clear displays
        self._clear_display()
        self.variables.scaled_row_mean = None
        self.variables.derived_row_weights = None
        self.variables.scaled_column_mean = None
        self.variables.derived_column_weights = None
        if self.variables.image_reader is None:
            return

        self.update_idletasks()
        the_sicd = self.variables.image_reader.get_sicd()
        row_count = the_sicd.ImageData.NumRows
        col_count = the_sicd.ImageData.NumCols

        set_row_data()
        self.update_idletasks()
        set_col_data()

    def create_weights_plot(self):
        """
        Create a matplotlib (using the user default backend) of the weight
        information.
        """

        if self.variables.image_reader is None or \
                self.variables.scaled_row_mean is None or \
                self.variables.scaled_column_mean is None:
            return  # nothing to be done currently

        the_sicd = self.variables.image_reader.get_sicd()
        fig, axs = pyplot.subplots(nrows=2, ncols=1)

        the_title = 'Weight information for file {}'.format(
            os.path.split(self.variables.image_reader.file_name)[1])
        fig.suptitle(the_title)

        # plot the row information
        axs[0].set_ylabel('Row Information')
        axs[0].set_xlabel('Krow (cycles/meter)')
        axs[0].plot(numpy.linspace(-0.5 / the_sicd.Grid.Row.SS,
                                   0.5 / the_sicd.Grid.Row.SS,
                                   self.variables.scaled_row_mean.size),
                    self.variables.scaled_row_mean,
                    'b',
                    lw=1,
                    label='Observed Data')
        if self.variables.derived_row_weights is not None:
            axs[0].plot(
                numpy.linspace(-0.5 * the_sicd.Grid.Row.ImpRespBW,
                               0.5 * the_sicd.Grid.Row.ImpRespBW,
                               self.variables.derived_row_weights.size),
                self.variables.derived_row_weights,
                'g--',
                lw=3,
                label='Row Derived Weights')
        if the_sicd.Grid.Row.WgtFunct is not None:
            axs[0].plot(numpy.linspace(-0.5 * the_sicd.Grid.Row.ImpRespBW,
                                       0.5 * the_sicd.Grid.Row.ImpRespBW,
                                       the_sicd.Grid.Row.WgtFunct.size),
                        the_sicd.Grid.Row.WgtFunct,
                        'r:',
                        lw=3,
                        label='Row.WgtFunct')
        axs[0].set_xlim(
            min(-0.5 / the_sicd.Grid.Row.SS,
                -0.5 * the_sicd.Grid.Row.ImpRespBW),
            max(0.5 / the_sicd.Grid.Row.SS, 0.5 * the_sicd.Grid.Row.ImpRespBW))
        axs[0].legend(loc='upper right')

        axs[1].set_ylabel('Column Information')
        axs[1].set_xlabel('Kcol (cycles/meter)')
        axs[1].plot(numpy.linspace(-0.5 / the_sicd.Grid.Col.SS,
                                   0.5 / the_sicd.Grid.Col.SS,
                                   self.variables.scaled_column_mean.size),
                    self.variables.scaled_column_mean,
                    'b',
                    lw=1,
                    label='Observed Data')
        if self.variables.derived_column_weights is not None:
            axs[1].plot(numpy.linspace(
                -0.5 * the_sicd.Grid.Col.ImpRespBW,
                0.5 * the_sicd.Grid.Col.ImpRespBW,
                self.variables.derived_column_weights.size),
                        self.variables.derived_column_weights,
                        'g--',
                        lw=3,
                        label='Col Derived Weights')
        if the_sicd.Grid.Col.WgtFunct is not None:
            axs[1].plot(numpy.linspace(-0.5 * the_sicd.Grid.Col.ImpRespBW,
                                       0.5 * the_sicd.Grid.Col.ImpRespBW,
                                       the_sicd.Grid.Col.WgtFunct.size),
                        the_sicd.Grid.Col.WgtFunct,
                        'r:',
                        lw=3,
                        label='Col.WgtFunct')
        axs[1].set_xlim(
            min(-0.5 / the_sicd.Grid.Col.SS,
                -0.5 * the_sicd.Grid.Col.ImpRespBW),
            max(0.5 / the_sicd.Grid.Col.SS, 0.5 * the_sicd.Grid.Col.ImpRespBW))
        axs[1].legend(loc='upper right')

        # create a toplevel, and put our figure inside it
        root = tkinter.Toplevel(self.root)

        root.wm_title("Embedding in Tk")

        canvas = FigureCanvasTkAgg(fig, master=root)  # A tk.DrawingArea.
        canvas.draw()
        canvas.get_tk_widget().pack(side=tkinter.TOP,
                                    fill=tkinter.BOTH,
                                    expand=1)

        toolbar = NavigationToolbar2Tk(canvas, root)
        toolbar.update()
        canvas.get_tk_widget().pack(side=tkinter.TOP,
                                    fill=tkinter.BOTH,
                                    expand=1)

        # grab the focus, so this is blocking
        root.grab_set()
        root.wait_window()

    def handle_image_index_changed(self):
        """
        Handle that the image index has changed.
        """

        self.my_populate_metaicon()
        self._calculate_fourier_data()

    def update_reader(self, the_reader):
        """
        Update the reader.

        Parameters
        ----------
        the_reader : ImageReader
        """

        # change the tool to view
        self.row_centered_image_panel.canvas.set_current_tool_to_view()
        self.row_centered_image_panel.canvas.set_current_tool_to_view()
        # update the reader
        self.variables.image_reader = the_reader
        self.variables.image_index = 0
        self.set_title()
        # refresh appropriate GUI elements
        self._calculate_fourier_data()
        self.my_populate_metaicon()
        self.my_populate_metaviewer()

    def callback_select_files(self):
        fnames = askopenfilenames(initialdir=self.variables.browse_directory,
                                  filetypes=common_use_collection)
        if fnames is None or fnames in ['', ()]:
            return
        # update the default directory for browsing
        self.variables.browse_directory = os.path.split(fnames[0])[0]

        the_reader = None
        if len(fnames) == 1:
            the_reader = ComplexImageReader(fnames[0])
        else:
            the_reader = ComplexImageReader(fnames)

        if the_reader is None:
            showinfo(
                'Opener not found',
                message='File {} was not successfully opened as a SICD type '
                'file.'.format(fnames))
            return
        self.update_reader(the_reader)

    def callback_select_directory(self):
        dirname = askdirectory(initialdir=self.variables.browse_directory,
                               mustexist=True)
        if dirname is None or dirname in [(), '']:
            return
        # update the default directory for browsing
        self.variables.browse_directory = os.path.split(dirname)[0]
        the_reader = ComplexImageReader(dirname)
        self.update_reader(the_reader)

    def my_populate_metaicon(self):
        """
        Populate the metaicon.
        """

        self.populate_metaicon(self.variables.image_reader,
                               self.variables.image_reader.index)

    def my_populate_metaviewer(self):
        """
        Populate the metaviewer.
        """

        self.populate_metaviewer(self.variables.image_reader)

    def __del__(self):
        self._delete_files()
コード例 #6
0
ファイル: canvas_demo.py プロジェクト: ngageoint/sarpy_apps
class CanvasDemo(WidgetPanel):
    _widget_list = ("button_panel", "canvas_demo_image_panel", "pyplot_panel")
    button_panel = widget_descriptors.PanelDescriptor(
        "button_panel", CanvasDemoButtonPanel)  # type: CanvasDemoButtonPanel
    pyplot_panel = widget_descriptors.PyplotImagePanelDescriptor(
        "pyplot_panel")  # type: PyplotImagePanel
    canvas_demo_image_panel = widget_descriptors.ImagePanelDescriptor(
        "canvas_demo_image_panel")  # type: ImagePanel

    def __init__(self, primary):
        primary_frame = basic_widgets.Frame(primary)
        WidgetPanel.__init__(self, primary_frame)
        self.variables = AppVariables()

        self.init_w_horizontal_layout()
        primary_frame.pack(fill=tkinter.BOTH, expand=tkinter.YES)
        self.button_panel.pack(fill=tkinter.X, expand=tkinter.NO)
        self.pyplot_panel.pack(expand=tkinter.YES)
        self.canvas_demo_image_panel.pack(expand=tkinter.YES)

        # bind events to callbacks here
        self.button_panel.fname_select.config(
            command=self.callback_initialize_canvas_image)
        self.button_panel.rect_select.config(
            command=self.callback_set_to_select)

        self.button_panel.draw_line.config(command=self.callback_draw_line)
        self.button_panel.draw_arrow.config(command=self.callback_draw_arrow)
        self.button_panel.draw_rect.config(command=self.callback_draw_rect)
        self.button_panel.draw_polygon.config(
            command=self.callback_draw_polygon)
        self.button_panel.draw_point.config(command=self.callback_draw_point)
        self.button_panel.edit.config(command=self.callback_edit)
        self.button_panel.color_selector.config(
            command=self.callback_activate_color_selector)
        self.button_panel.remap_dropdown.on_selection(self.callback_remap)

        self.canvas_demo_image_panel.canvas.on_left_mouse_click(
            self.callback_handle_canvas_left_mouse_click)
        self.canvas_demo_image_panel.canvas.on_left_mouse_release(
            self.callback_handle_canvas_left_mouse_release)

    def callback_save_kml(self):
        kml_save_fname = asksaveasfilename(
            initialdir=os.path.expanduser("~/Downloads"))

        kml_util = KmlUtil()

        for shape_id in self.canvas_demo_image_panel.canvas.variables.shape_ids:
            image_coords = self.canvas_demo_image_panel.canvas.get_shape_image_coords(
                shape_id)
            shape_type = self.canvas_demo_image_panel.canvas.get_shape_type(
                shape_id)
            if image_coords:
                sicd_meta = self.canvas_demo_image_panel.canvas.variables.canvas_image_object.reader_object.sicdmeta
                image_points = numpy.zeros((int(len(image_coords) / 2), 2))
                image_points[:, 0] = image_coords[0::2]
                image_points[:, 1] = image_coords[1::2]

                ground_points_ecf = point_projection.image_to_ground(
                    image_points, sicd_meta)
                ground_points_latlon = geocoords.ecf_to_geodetic(
                    ground_points_ecf)

                world_y_coordinates = ground_points_latlon[:, 0]
                world_x_coordinates = ground_points_latlon[:, 1]

                xy_point_list = [
                    (x, y)
                    for x, y in zip(world_x_coordinates, world_y_coordinates)
                ]

                if shape_id == self.canvas_demo_image_panel.canvas.variables.zoom_rect.uid:
                    pass
                elif shape_type == self.canvas_demo_image_panel.canvas.variables.select_rect.uid:
                    pass
                elif shape_type == ShapeTypeConstants.POINT:
                    kml_util.add_point(str(shape_id), xy_point_list[0])
                elif shape_type == ShapeTypeConstants.LINE:
                    kml_util.add_linestring(str(shape_id), xy_point_list)
                elif shape_type == ShapeTypeConstants.POLYGON:
                    kml_util.add_polygon(str(shape_id), xy_point_list)
                elif shape_type == ShapeTypeConstants.RECT:
                    kml_util.add_polygon(str(shape_id), xy_point_list)
        kml_util.write_to_file(kml_save_fname)

    def callback_handle_canvas_left_mouse_click(self, event):
        self.canvas_demo_image_panel.canvas.callback_handle_left_mouse_click(
            event)
        current_shape = self.canvas_demo_image_panel.canvas.current_shape_id
        if current_shape:
            self.variables.shapes_in_selector.append(current_shape)
            self.variables.shapes_in_selector = sorted(
                list(set(self.variables.shapes_in_selector)))

    def callback_handle_canvas_left_mouse_release(self, event):
        self.canvas_demo_image_panel.canvas.callback_handle_left_mouse_release(
            event)
        if self.canvas_demo_image_panel.canvas.variables.select_rect.uid == self.canvas_demo_image_panel.canvas.current_shape_id:
            self.update_selection()

    def callback_edit(self):
        self.canvas_demo_image_panel.canvas.set_current_tool_to_edit_shape(
            select_closest_first=True)

    def callback_activate_color_selector(self):
        self.canvas_demo_image_panel.canvas.activate_color_selector()

    def callback_draw_line(self):
        self.canvas_demo_image_panel.canvas.set_current_tool_to_draw_line()

    def callback_draw_arrow(self):
        self.canvas_demo_image_panel.canvas.set_current_tool_to_draw_arrow()

    def callback_draw_rect(self):
        self.canvas_demo_image_panel.canvas.set_current_tool_to_draw_rect()

    def callback_draw_polygon(self):
        self.canvas_demo_image_panel.canvas.set_current_tool_to_draw_polygon()

    def callback_draw_point(self):
        self.canvas_demo_image_panel.canvas.set_current_tool_to_draw_point()

    def callback_set_to_select(self):
        self.canvas_demo_image_panel.canvas.set_current_tool_to_select()

    # define custom callbacks here
    def callback_remap(self):
        self.update_selection()

    def update_selection(self):
        remap_dict = {entry[0]: entry[1] for entry in remap.get_remap_list()}
        selection = self.button_panel.remap_dropdown.get()
        self.variables.image_reader.set_remap_type(remap_dict[selection])
        image_data = self.canvas_demo_image_panel.canvas.get_image_data_in_canvas_rect_by_id(
            self.canvas_demo_image_panel.canvas.variables.select_rect.uid)
        self.pyplot_panel.update_image(image_data)
        self.canvas_demo_image_panel.canvas.update_current_image()

    def callback_initialize_canvas_image(self):
        image_file_extensions = ['*.nitf', '*.NITF', '*.ntf', '*.NTF']
        ftypes = [
            ('NITF files', image_file_extensions),
            ('All files', '*'),
        ]
        new_fname = askopenfilename(initialdir=self.variables.browse_directory,
                                    filetypes=ftypes)
        if new_fname:
            self.variables.browse_directory = os.path.split(new_fname)[0]
            self.variables.image_reader = ComplexImageReader(new_fname)
            self.canvas_demo_image_panel.set_image_reader(
                self.variables.image_reader)