def set_label_schema(self, label_schema): """ Sets the label schema value. Parameters ---------- label_schema : None|str|LabelSchema """ if label_schema is None: self.variables.label_file_name = None self.variables.label_schema = LabelSchema() elif isinstance(label_schema, str): the_file = label_schema label_schema = LabelSchema.from_file(the_file) self.variables.label_file_name = the_file self.variables.label_schema = label_schema browse_dir = os.path.split(os.path.abspath(the_file))[0] self.variables.browse_directory = browse_dir elif isinstance(label_schema, LabelSchema): self.variables.label_file_name = None self.variables.label_schema = label_schema else: raise TypeError( 'input must be the path for a label schema file or a LabelSchema instance' ) self.variables.unsaved_edits = False self.variables.current_id = None self._update_schema_display()
def set_file_name(self, file_name): self._file_name = file_name if os.path.exists(file_name): self.label_schema = LabelSchema.from_file(file_name) else: self.label_schema = LabelSchema() # TODO: set our entries as appropriate if self._new_file: pass else: pass
def convert_afrl_to_native(research: ResearchType, include_chip: bool = False) -> FileLabelCollection: """ Converts an AFRL structure to a label structure for simple viewing. Parameters ---------- research : ResearchType include_chip : bool Include the chip definition in the geometry structure? Returns ------- FileLabelCollection """ def _convert_object_to_json(t_object: TheObjectType) -> LabelFeature: # extract the "properties" geometry, geometry_properties = t_object.get_image_geometry_object_for_sicd( include_chip=include_chip) feature = LabelFeature(geometry=geometry, properties=LabelProperties( name=t_object.SystemName, geometry_properties=geometry_properties)) feature.add_annotation_metadata( LabelMetadata(label_id=t_object.ObjectLabel)) return feature if not isinstance(research, ResearchType): raise TypeError('Expected ResearchType, got type `{}`'.format( type(research))) if research.DetailObjectInfo is None or \ research.DetailObjectInfo.Objects is None or \ len(research.DetailObjectInfo.Objects) == 0: raise ValueError('Nothing to be done') # create our adhoc containers label_schema = LabelSchema(version='AdHoc') annotation_collection = LabelCollection() for the_object in research.DetailObjectInfo.Objects: new_key = the_object.ObjectLabel if new_key not in label_schema.labels: label_schema.add_entry(new_key, new_key) annotation_collection.add_feature(_convert_object_to_json(the_object)) # finalize the collection return FileLabelCollection( label_schema, annotations=annotation_collection, image_file_name=research.DetailImageInfo.DataFilename)
def open_schema(self): """ Open and edit a schema file. Returns ------- None """ if self._file_name is not None and self._unsaved_edits: result = askyesnocancel( title="Unsaved Edits", message= "There are unsaved edits. Save before opening a new file?") if result is True: self.save() elif result is None: return schema_file = askopenfilename( initialdir=self.browse_directory, filetypes=[file_filters.json_files, file_filters.all_files]) if schema_file == '' or schema_file == (): # closed or cancelled return self.browse_directory = os.path.split(schema_file)[0] self._file_name = schema_file self._new_file = False self._unsaved_edits = False self.label_schema = LabelSchema.from_file(schema_file) self.schema_viewer.fill_from_label_schema(self.label_schema) self._populate_fields_schema()
def new_schema(self): """ Create a new schema. Returns ------- None """ schema_file = asksaveasfilename( initialdir=self.browse_directory, filetypes=[file_filters.json_files, file_filters.all_files]) if schema_file == '' or schema_file == (): # closed or cancelled return self.browse_directory = os.path.split(schema_file)[0] self._file_name = schema_file self._new_file = True self._unsaved_edits = True self.label_schema = LabelSchema() self.schema_viewer.fill_from_label_schema(self.label_schema) self._populate_fields_schema()
def create_new_annotation_file(self): if not self._verify_image_selected(): return # prompt for any unsaved changes response = self._prompt_unsaved() if not response: return label_schema_file = self._prompt_for_label_schema() if label_schema_file is None: label_schema = get_default_schema() else: label_schema = LabelSchema.from_file(label_schema_file) annotations = self._NEW_FILE_ANNOTATION_TYPE(label_schema) self.set_annotations(annotations)
def _validate_schema(schema): """ Utility function for verifying that an input argument is or points to a LabelSchema. Parameters ---------- schema : str|LabelSchema Returns ------- LabelSchema """ if isinstance(schema, string_types): schema = LabelSchema.from_file(schema) if not isinstance(schema, LabelSchema): raise TypeError( 'label_schema must be either a path to am appropriate .json file or a ' 'LabelSchema object. Got type {}'.format(type(schema))) return schema
def __init__(self, label_schema, start_item=None): """ Parameters ---------- label_schema : str|LabelSchema start_item : None|str The initial item selected """ # validate label schema input if isinstance(label_schema, str): label_schema = LabelSchema.from_file(label_schema) if not isinstance(label_schema, LabelSchema): raise TypeError( 'label_schema must be either a path to am appropriate .json file or a ' 'LabelSchema object. Got type {}'.format(type(label_schema))) # initialize the selected value option self._selected_value = '' self.root = tkinter.Toplevel() self.root.geometry('250x400') self.root.wm_title('Select Label Schema Entry') self.viewer = SchemaViewer(self.root, label_schema=label_schema) self.viewer.frame.pack(side=tkinter.TOP, expand=tkinter.TRUE, fill=tkinter.BOTH) self.set_selected_value(start_item) self.submit_button = Button(self.root, text='Submit', command=self.set_value) self.submit_button.pack(side=tkinter.BOTTOM, expand=tkinter.TRUE) self.root.grab_set() self.root.wait_window()
def callback_new_schema(self): if not self._check_save_state(): return self.set_label_schema(LabelSchema())
def __init__(self, root): """ Parameters ---------- root : tkinter.Toplevel|tkinter.Tk """ self.root = root self.browse_directory = os.path.expanduser('~') self._file_name = None self.label_schema = LabelSchema() # type: LabelSchema self._new_file = None self._unsaved_edits = None self.primary = basic_widgets.Frame(root) WidgetPanel.__init__(self, self.primary) self.init_w_rows() # self.init_w_basic_widget_list(7, [2, 2, 2, 2, 2, 2, 1]) # modify packing so that the viewer gets the extra space self.version_label.master.pack(expand=tkinter.FALSE, fill=tkinter.X) self.version_date_label.master.pack(expand=tkinter.FALSE, fill=tkinter.X) self.classification_label.master.pack(expand=tkinter.FALSE, fill=tkinter.X) self.confidence_label.master.pack(expand=tkinter.FALSE, fill=tkinter.X) self.geometries_label.master.pack(expand=tkinter.FALSE, fill=tkinter.X) self.edit_button.master.pack(expand=tkinter.FALSE, fill=tkinter.X) self.move_up_button.master.pack(expand=tkinter.FALSE, fill=tkinter.X) self.schema_viewer.master.pack(expand=tkinter.TRUE, side=tkinter.BOTTOM) # setup the appearance of labels self.version_label.config(relief=tkinter.RIDGE, justify=tkinter.LEFT, padding=5) self.version_date_label.config(relief=tkinter.RIDGE, justify=tkinter.LEFT, padding=5) self.classification_label.config(relief=tkinter.RIDGE, justify=tkinter.LEFT, padding=5) self.confidence_label.config(relief=tkinter.RIDGE, justify=tkinter.LEFT, padding=5) self.geometries_label.config(relief=tkinter.RIDGE, justify=tkinter.LEFT, padding=5) # setup the GUI callbacks and appearance of labels self.version_entry.config(state='disabled', validate='focusout', validatecommand=self._version_entry_validate) self.version_date_entry.config(state='disabled') self.classification_entry.config( state='disabled', validate='focusout', validatecommand=self._classification_validate) self.confidence_entry.config(state='disabled', validate='focusout', validatecommand=self._confidence_validate) self.geometries_entry.config(state='disabled') self.edit_button.config(command=self.edit_entry) self.new_button.config(command=self.new_entry) self.delete_button.config(command=self.delete_entry) self.move_up_button.config(command=self.move_up) self.move_down_button.config(command=self.move_down) # set up the menu bar menu = tkinter.Menu() filemenu = tkinter.Menu(menu, tearoff=0) filemenu.add_command(label="New Schema", command=self.new_schema) filemenu.add_command(label="Open Schema", command=self.open_schema) filemenu.add_command(label="Save", command=self.save) filemenu.add_separator() filemenu.add_command(label="Exit", command=self.exit) menu.add_cascade(label="File", menu=filemenu) self.primary.pack(expand=tkinter.YES, fill=tkinter.BOTH) root.config(menu=menu)
class SchemaEditor(WidgetPanel): _widget_list = (('version_label', 'version_entry'), ('version_date_label', 'version_date_entry'), ('classification_label', 'classification_entry'), ('confidence_label', 'confidence_entry'), ('geometries_label', 'geometries_entry'), ('new_button', 'edit_button', 'delete_button'), ('move_up_button', 'move_down_button'), ('schema_viewer', )) version_label = LabelDescriptor( 'version_label', default_text='Version:', docstring='The version label') # type: basic_widgets.Label version_entry = EntryDescriptor( 'version_entry', default_text='', docstring='The version value') # type: basic_widgets.Entry version_date_label = LabelDescriptor( 'version_date_label', default_text='Version Date:', docstring='The version_date label') # type: basic_widgets.Label version_date_entry = EntryDescriptor( 'version_date_entry', default_text='', docstring='The version_date value') # type: basic_widgets.Entry classification_label = LabelDescriptor( 'classification_label', default_text='Classification:', docstring='The classification label') # type: basic_widgets.Label classification_entry = EntryDescriptor( 'classification_entry', default_text='', docstring='The classification value') # type: basic_widgets.Entry confidence_label = LabelDescriptor( 'confidence_label', default_text='Confidence Values:', docstring='The confidence label') # type: basic_widgets.Label confidence_entry = EntryDescriptor( 'confidence_entry', default_text='', docstring='The confidence value') # type: basic_widgets.Entry geometries_label = LabelDescriptor( 'geometries_label', default_text='Geometries:', docstring='The geometries label') # type: basic_widgets.Label geometries_entry = EntryDescriptor( 'geometries_entry', default_text='', docstring='The geometries value') # type: basic_widgets.Entry new_button = ButtonDescriptor( 'new_button', default_text='New Entry', docstring='The new entry button') # type: basic_widgets.Button edit_button = ButtonDescriptor( 'edit_button', default_text='Edit Entry', docstring='The edit button') # type: basic_widgets.Button delete_button = ButtonDescriptor( 'delete_button', default_text='Delete Entry', docstring='The delete entry button') # type: basic_widgets.Button move_up_button = ButtonDescriptor( 'move_up_button', default_text='Move Entry Up', docstring='The move up entry button') # type: basic_widgets.Button move_down_button = ButtonDescriptor( 'move_down_button', default_text='Move Entry Down', docstring='The move down entry button') # type: basic_widgets.Button schema_viewer = TypedDescriptor( 'schema_viewer', SchemaViewer, docstring='The viewer widget for the label schema.' ) # type: SchemaViewer def __init__(self, root): """ Parameters ---------- root : tkinter.Toplevel|tkinter.Tk """ self.root = root self.browse_directory = os.path.expanduser('~') self._file_name = None self.label_schema = LabelSchema() # type: LabelSchema self._new_file = None self._unsaved_edits = None self.primary = basic_widgets.Frame(root) WidgetPanel.__init__(self, self.primary) self.init_w_rows() # self.init_w_basic_widget_list(7, [2, 2, 2, 2, 2, 2, 1]) # modify packing so that the viewer gets the extra space self.version_label.master.pack(expand=tkinter.FALSE, fill=tkinter.X) self.version_date_label.master.pack(expand=tkinter.FALSE, fill=tkinter.X) self.classification_label.master.pack(expand=tkinter.FALSE, fill=tkinter.X) self.confidence_label.master.pack(expand=tkinter.FALSE, fill=tkinter.X) self.geometries_label.master.pack(expand=tkinter.FALSE, fill=tkinter.X) self.edit_button.master.pack(expand=tkinter.FALSE, fill=tkinter.X) self.move_up_button.master.pack(expand=tkinter.FALSE, fill=tkinter.X) self.schema_viewer.master.pack(expand=tkinter.TRUE, side=tkinter.BOTTOM) # setup the appearance of labels self.version_label.config(relief=tkinter.RIDGE, justify=tkinter.LEFT, padding=5) self.version_date_label.config(relief=tkinter.RIDGE, justify=tkinter.LEFT, padding=5) self.classification_label.config(relief=tkinter.RIDGE, justify=tkinter.LEFT, padding=5) self.confidence_label.config(relief=tkinter.RIDGE, justify=tkinter.LEFT, padding=5) self.geometries_label.config(relief=tkinter.RIDGE, justify=tkinter.LEFT, padding=5) # setup the GUI callbacks and appearance of labels self.version_entry.config(state='disabled', validate='focusout', validatecommand=self._version_entry_validate) self.version_date_entry.config(state='disabled') self.classification_entry.config( state='disabled', validate='focusout', validatecommand=self._classification_validate) self.confidence_entry.config(state='disabled', validate='focusout', validatecommand=self._confidence_validate) self.geometries_entry.config(state='disabled') self.edit_button.config(command=self.edit_entry) self.new_button.config(command=self.new_entry) self.delete_button.config(command=self.delete_entry) self.move_up_button.config(command=self.move_up) self.move_down_button.config(command=self.move_down) # set up the menu bar menu = tkinter.Menu() filemenu = tkinter.Menu(menu, tearoff=0) filemenu.add_command(label="New Schema", command=self.new_schema) filemenu.add_command(label="Open Schema", command=self.open_schema) filemenu.add_command(label="Save", command=self.save) filemenu.add_separator() filemenu.add_command(label="Exit", command=self.exit) menu.add_cascade(label="File", menu=filemenu) self.primary.pack(expand=tkinter.YES, fill=tkinter.BOTH) root.config(menu=menu) def set_file_name(self, file_name): self._file_name = file_name if os.path.exists(file_name): self.label_schema = LabelSchema.from_file(file_name) else: self.label_schema = LabelSchema() # TODO: set our entries as appropriate if self._new_file: pass else: pass # main schema element edit callbacks - piggyback on validation methods def _version_entry_validate(self): the_value = self.version_entry.get().strip() if the_value != '' and self.label_schema.version != the_value: self._unsaved_edits = True self.label_schema._version = the_value self.label_schema.update_version_date(value=None) self.version_date_entry.set_text(self.label_schema.version_date) return True def _classification_validate(self): the_value = self.classification_entry.get().strip() if self.label_schema.classification != the_value: self._unsaved_edits = True self.label_schema._classification = the_value return True def _confidence_validate(self): the_value = self.confidence_entry.get().strip() print('the confidence value', the_value) if the_value == '': the_values = None else: temp_values = the_value.split() # noinspection PyBroadException try: the_values = [int(entry) for entry in temp_values] except: the_values = temp_values if self.label_schema.confidence_values != the_values: self._unsaved_edits = True self.label_schema.confidence_values = the_values return True def _populate_fields_schema(self): """ Populate the GUI values from the schema. Returns ------- None """ self.version_entry.config(state='normal') self.version_entry.set_text(self.label_schema.version) self.version_date_entry.set_text(self.label_schema.version_date) self.classification_entry.config(state='normal') self.classification_entry.set_text(self.label_schema.classification) self.confidence_entry.config(state='normal') if self.label_schema.confidence_values is None: self.confidence_entry.set_text('') else: self.confidence_entry.set_text(' '.join( '{}'.format(entry) for entry in self.label_schema.confidence_values)) self.confidence_entry.config(state='normal') if self.label_schema.permitted_geometries is None: self.geometries_entry.set_text('') else: self.geometries_entry.set_text(' '.join( self.label_schema.permitted_geometries)) def edit_entry(self): """ Edit the selected element. Returns ------- None """ if self._file_name is None: showinfo('No Schema Selected', message='Choose schema location from File menu') return selected = self.schema_viewer.treeview.focus() if selected == '': showinfo('No Element Selected', message='Choose element from Viewer') return popup = LabelEntryWidget(self.label_schema, edit_id=selected) if popup.id_changed is not None: self.schema_viewer.rerender_entry(popup.id_changed) self._unsaved_edits = True popup.destroy() def new_entry(self): """ Create a new label schema entry. Returns ------- None """ if self._file_name is None: showinfo('No Schema Selected', message='Choose schema location from File menu') return popup = LabelEntryWidget(self.label_schema, edit_id=None) if popup.id_changed is not None: self.schema_viewer.rerender_entry(popup.id_changed) self._unsaved_edits = True popup.destroy() def delete_entry(self): """ Delete the selected entry. Returns ------- None """ if self._file_name is None: showinfo('No Schema Selected', message='Choose schema location from File menu') return selected = self.schema_viewer.treeview.focus() if selected == '': showinfo('No Element Selected', message='Choose element from Viewer') return # does the selected entry have any children? children = self.label_schema.subtypes.get(selected, None) if children is not None and len(children) > 0: response = askyesnocancel( 'Delete Children?', message='Selected entry has children. Delete all children?') if response is not True: return self.schema_viewer.delete_entry(selected) self._unsaved_edits = True def move_up(self): """ Move the selected entry up one spot. Returns ------- None """ if self._file_name is None: showinfo('No Schema Selected', message='Choose schema location from File menu') return selected = self.schema_viewer.treeview.focus() if selected == '': showinfo('No Element Selected', message='Choose element from Viewer') return result = self.label_schema.reorder_child_element(selected, spaces=-1) if result: self.schema_viewer.rerender_entry(selected) self._unsaved_edits = True def move_down(self): """ Move the selected entry down one spot. Returns ------- None """ if self._file_name is None: showinfo('No Schema Selected', message='Choose schema location from File menu') return selected = self.schema_viewer.treeview.focus() if selected == '': showinfo('No Element Selected', message='Choose element from Viewer') return result = self.label_schema.reorder_child_element(selected, spaces=1) if result: self.schema_viewer.rerender_entry(selected) self._unsaved_edits = True def new_schema(self): """ Create a new schema. Returns ------- None """ schema_file = asksaveasfilename( initialdir=self.browse_directory, filetypes=[file_filters.json_files, file_filters.all_files]) if schema_file == '' or schema_file == (): # closed or cancelled return self.browse_directory = os.path.split(schema_file)[0] self._file_name = schema_file self._new_file = True self._unsaved_edits = True self.label_schema = LabelSchema() self.schema_viewer.fill_from_label_schema(self.label_schema) self._populate_fields_schema() def open_schema(self): """ Open and edit a schema file. Returns ------- None """ if self._file_name is not None and self._unsaved_edits: result = askyesnocancel( title="Unsaved Edits", message= "There are unsaved edits. Save before opening a new file?") if result is True: self.save() elif result is None: return schema_file = askopenfilename( initialdir=self.browse_directory, filetypes=[file_filters.json_files, file_filters.all_files]) if schema_file == '' or schema_file == (): # closed or cancelled return self.browse_directory = os.path.split(schema_file)[0] self._file_name = schema_file self._new_file = False self._unsaved_edits = False self.label_schema = LabelSchema.from_file(schema_file) self.schema_viewer.fill_from_label_schema(self.label_schema) self._populate_fields_schema() def save(self): """ Save any current progress. Returns ------- None """ if self._file_name is None: showinfo('No Schema Selected', message='Choose schema location from File menu') return if self._unsaved_edits: self.label_schema.to_file(self._file_name) self._unsaved_edits = False def exit(self): """ Exit the application. Returns ------- None """ if self._file_name is not None and self._unsaved_edits: save_state = askyesno('Save Progress', message='There are unsaved edits. Save?') if save_state is True: self.save() self.root.destroy()
def get_default_schema(): return LabelSchema(labels={'0': 'unknown'})