def btn_confirm_accept_click(self, button):
        if self.edition_mode == ChartImageAnnotator.ModeConfirmOverwritePanels:
            # commit changes ....
            # ... create an empty annotation ...
            self.image_info = ImageInfo.CreateDefault(self.base_rgb_image)
            # copy the panel structure ...
            self.image_info.panel_tree = PanelTree.Copy(self.tempo_panel_tree)
            # ... get the empty annotation for each panel ...
            self.image_info.reset_panels_info()

            # go back to navigation mode ...
            self.set_editor_mode(ChartImageAnnotator.ModeNavigate)
            self.update_current_view(False)
            self.selected_panel = 0
            self.update_panel_info()

            self.unsaved_changes = True

        elif self.edition_mode == ChartImageAnnotator.ModeConfirmOverwriteClass:
            # commit changes ....
            # ... get selected class ...
            if "-" in self.lbx_class_panel_class.selected_option_value:
                # Chart type with orientation
                type_str, orientation_str = self.lbx_class_panel_class.selected_option_value.split(
                    "-")
                type_value = int(type_str)
                orientation = int(orientation_str)
            else:
                # No orientation
                type_value = int(
                    self.lbx_class_panel_class.selected_option_value)
                orientation = None

            if self.admin_mode:
                overwrite = input("Discard Chart Info (y/n)? ").lower() in [
                    "y", "yes", "1", "true"
                ]
            else:
                overwrite = True

            if overwrite:
                # ... create an empty panel annotation ...
                self.image_info.panels[self.selected_panel] = ChartInfo(
                    type_value, orientation)
            else:
                # ... admin request simple overwrite of values which might lead to inconsistencies ...
                self.image_info.panels[self.selected_panel].type = type_value
                self.image_info.panels[
                    self.selected_panel].orientation = orientation

            # go back to navigation mode ...
            self.set_editor_mode(ChartImageAnnotator.ModeNavigate)
            self.update_current_view(False)

        elif self.edition_mode == ChartImageAnnotator.ModeConfirmExit:
            # return with unsaved changes lost
            print("Unsaved changes on " + self.relative_path + " were lost")

            delta = self.get_reset_time_delta()
            self.time_stats.time_main += delta
            self.parent.update_annotation_times(self.time_stats)

            self.parent.refresh_page()
            self.return_screen = self.parent
def split_dir_annotations(in_img_dir, in_annot_dir, out_img_dir, out_annot_dir,
                          rel_path):
    input_dir = in_annot_dir + rel_path
    elements = os.listdir(input_dir)

    panels_per_type = {}
    for element in elements:
        element_path = input_dir + element

        if os.path.isdir(element_path):
            sub_dir_stats = split_dir_annotations(in_img_dir, in_annot_dir,
                                                  out_img_dir, out_annot_dir,
                                                  element_path + "/")

            # add stats
            for chart_type in sub_dir_stats:
                if chart_type in panels_per_type:
                    # already collected this type ...
                    panels_per_type[chart_type] += sub_dir_stats[chart_type]
                else:
                    # first of this type
                    panels_per_type[chart_type] = sub_dir_stats[chart_type]
        else:
            print("Processing: " + element_path)

            # load the corresponding image
            base, ext = os.path.splitext(element)
            img_path = in_img_dir + rel_path + base + ".jpg"
            current_img = cv2.imread(img_path)

            # load the annotation
            image_info = ImageInfo.FromXML(element_path, current_img)

            # For each panel ....
            for panel_idx, panel in enumerate(image_info.panels):
                type_str, orientation_str = panel.get_description()
                chart_type = type_str + "_" + orientation_str

                if chart_type in panels_per_type:
                    panels_per_type[chart_type] += 1
                else:
                    panels_per_type[chart_type] = 1

                # if the panel is non-chart, then skip
                if panel.type == ChartInfo.TypeNonChart:
                    continue

                # crop the panel from main image
                panel_img = image_info.get_panel_image(panel_idx)

                # Save panel image to output image directory
                os.makedirs(out_img_dir + "/" + chart_type + rel_path,
                            exist_ok=True)
                out_img_panel_path = out_img_dir + "/" + chart_type + rel_path + base + "_panel_" + str(
                    panel_idx + 1) + ".jpg"
                cv2.imwrite(out_img_panel_path, panel_img)

                # Create a new annotation structure ... only for that panel
                panel_annotation = ImageInfo.CreateDefault(panel_img)
                panel_annotation.panels[0] = panel

                # Save panel annotation to output image directory
                os.makedirs(out_annot_dir + "/" + chart_type + rel_path,
                            exist_ok=True)
                out_panel_annotation = out_annot_dir + "/" + chart_type + rel_path + base + "_panel_" + str(
                    panel_idx + 1) + ".xml"
                tempo_xml = panel_annotation.to_XML()
                with open(out_panel_annotation, "w") as out_annot_file:
                    out_annot_file.write(tempo_xml)

    return panels_per_type
    def __init__(self, size, chart_dir, annotation_dir, relative_path,
                 parent_menu, admin_mode):
        BaseImageAnnotator.__init__(self,
                                    "Chart Ground Truth Annotation Interface",
                                    size)

        self.general_background = (20, 85, 50)
        self.text_color = (255, 255, 255)

        self.parent = parent_menu
        self.chart_dir = chart_dir
        self.annotation_dir = annotation_dir
        self.relative_path = relative_path
        self.admin_mode = admin_mode

        self.time_stats = TimeStats()
        self.in_menu_time_start = time.time()
        self.wait_mode = ChartImageAnnotator.WaitModeNone

        # find output path ...
        relative_dir, img_filename = os.path.split(self.relative_path)
        img_base, ext = os.path.splitext(img_filename)
        # output dir
        self.output_dir = self.annotation_dir + relative_dir
        self.annotation_filename = self.output_dir + "/" + img_base + ".xml"

        # first ... load image ....
        self.base_rgb_image = cv2.imread(self.chart_dir + self.relative_path)
        self.base_rgb_image = cv2.cvtColor(self.base_rgb_image,
                                           cv2.COLOR_BGR2RGB)
        # ... and cache the gray-scale version
        self.base_gray_image = np.zeros(self.base_rgb_image.shape,
                                        self.base_rgb_image.dtype)
        self.base_gray_image[:, :, 0] = cv2.cvtColor(self.base_rgb_image,
                                                     cv2.COLOR_RGB2GRAY)
        self.base_gray_image[:, :, 1] = self.base_gray_image[:, :, 0].copy()
        self.base_gray_image[:, :, 2] = self.base_gray_image[:, :, 0].copy()

        # load annotations for this image .... (if any)
        if os.path.exists(self.annotation_filename):
            # annotation found!
            self.image_info = ImageInfo.FromXML(self.annotation_filename,
                                                self.base_rgb_image)
        else:
            # create an empty annotation
            self.image_info = ImageInfo.CreateDefault(self.base_rgb_image)

        self.split_panel_operation = None
        self.tempo_panel_tree = None
        self.selected_panel = 0
        self.unsaved_changes = False

        self.elements.back_color = self.general_background

        self.label_title = None
        self.container_confirm_buttons = None
        self.lbl_confirm_message = None
        self.btn_confirm_cancel = None
        self.btn_confirm_accept = None

        self.container_panels_buttons = None
        self.lbl_panels_title = None
        self.btn_label_panels = None
        self.btn_panels_verify = None
        self.lbl_panels_current = None
        self.btn_panels_prev = None
        self.btn_panels_next = None

        self.container_annotation_buttons = None
        self.lbl_edit_title = None
        self.btn_edit_class = None
        self.btn_edit_text = None
        self.btn_edit_legend = None
        self.btn_edit_axis = None
        self.btn_edit_data = None

        self.btn_verify_class = None
        self.btn_verify_text = None
        self.btn_verify_legend = None
        self.btn_verify_axis = None
        self.btn_verify_data = None

        self.container_split_panels = None
        self.lbl_split_panel_title = None
        self.btn_split_panel_horizontal = None
        self.btn_split_panel_vertical = None
        self.btn_merge_panel = None
        self.btn_split_return = None

        self.container_classify_panels = None
        self.lbl_class_panel_title = None
        self.lbx_class_panel_class = None
        self.btn_class_panel_continue = None

        self.btn_save = None
        self.btn_auto_check = None
        self.btn_return = None

        # generate the interface!
        self.create_controllers()

        # get the view ...
        self.update_current_view(True)