diff --git a/sloth/conf/default_config.py b/sloth/conf/default_config.py index 9501c32..120943e 100644 --- a/sloth/conf/default_config.py +++ b/sloth/conf/default_config.py @@ -1,30 +1,80 @@ +# This is sloth's default configuration. +# +# The configuration file is a simple python module with module-level +# variables. This module contains the default values for sloth's +# configuration variables. +# +# In all cases in the configuration where a python callable (such as a +# function, class constructor, etc.) is expected, it is equally possible +# to specify a module path (as string) pointing to such a python callable. +# It will then be automatically imported. + +# LABLES +# +# List/tuple of dictionaries that defines the label types +# that are handled by sloth. For each label, there should +# be one dictionary that contains the following keys: +# +# - 'item' : Visualization item for this label. This can be +# any python callable or a module path string +# implementing the visualization item interface. +# +# - 'inserter' : (optional) Item inserter for this label. +# If the user selects to insert a new label of this type +# the inserter is responsible to actually +# capture the users mouse actions and insert +# a new label into the annotation model. +# +# - 'hotkey' : (optional) A keyboard shortcut starting +# the insertion of a new label of this type. +# +# - 'attributes' : (optional) A dictionary that defines the +# keys and possible values of this label +# type. LABELS = ( - ('Rect', {'type': 'rect'}), - ('Point', {'type': 'point'}), + { + 'attributes': { + 'type': 'rect', + }, + 'inserter': 'sloth.items.RectItemInserter', + 'item': 'sloth.items.RectItem', + 'hotkey': 'r', + 'text': 'Rectangle', + }, + { + 'attributes': { + 'type': 'point', + }, + 'inserter': 'sloth.items.PointItemInserter', + 'item': 'sloth.items.PointItem', + 'hotkey': 'p', + 'text': 'Point', + }, ) +# HOTKEYS +# +# Defines the keyboard shortcuts. Each hotkey is defined by a tuple +# with at least 2 entries, where the first entry is the hotkey (sequence), +# and the second entry is the function that is called. The function +# should expect a single parameter, the labeltool object. The optional +# third entry -- if present -- is expected to be a string describing the +# action. HOTKEYS = ( - ('PgDown', lambda lt: lt.gotoNext(), 'Next image/frame'), - ('PgUp', lambda lt: lt.gotoPrevious(), 'Previous image/frame'), - ('Tab', lambda lt: lt.selectNextAnnotation(), 'Select next annotation'), - ('Shift+Tab', lambda lt: lt.selectPreviousAnnotation(), 'Select previous annotation'), - ('ESC', lambda lt: lt.exitInsertMode(), 'Exit insert mode'), + ('PgDown', lambda lt: lt.gotoNext(), 'Next image/frame'), + ('PgUp', lambda lt: lt.gotoPrevious(), 'Previous image/frame'), + ('Tab', lambda lt: lt.selectNextAnnotation(), 'Select next annotation'), + ('Shift+Tab', lambda lt: lt.selectPreviousAnnotation(), 'Select previous annotation'), + ('ESC', lambda lt: lt.exitInsertMode(), 'Exit insert mode'), ) -# Defines the mapping from the annotation type to the visualization item. The -# values need to be either python callables, or a module path string that -# points to a python callable. The callable is responsible for creating and -# returning the corresponding visualization item. -ITEMS = { - 'rect': 'sloth.items.RectItem', - 'point': 'sloth.items.PointItem', -} - -INSERTERS = { - 'rect': 'sloth.items.RectItemInserter', - 'point': 'sloth.items.PointItemInserter', -} - +# CONTAINERS +# +# A list/tuple of two-tuples defining the mapping between filename pattern and +# annotation container classes. The filename pattern can contain wildcards +# such as * and ?. The corresponding container is expected to either a python +# class implementing the sloth container interface, or a module path pointing +# to such a class. CONTAINERS = ( ('*.json', 'sloth.annotations.container.JsonContainer'), ('*.yaml', 'sloth.annotations.container.YamlContainer'), @@ -32,6 +82,11 @@ CONTAINERS = ( ('*.sloth-init', 'sloth.annotations.container.FileNameListContainer'), ) +# PLUGINS +# +# A list/tuple of classes implementing the sloth plugin interface. The +# classes can either be given directly or their module path be specified +# as string. PLUGINS = ( ) diff --git a/sloth/conf/template/config_template.py b/sloth/conf/template/config_template.py index 2f6253e..679c548 100644 --- a/sloth/conf/template/config_template.py +++ b/sloth/conf/template/config_template.py @@ -1,29 +1,78 @@ -# Import defaults. -# You can either overwrite or modify the defaults to your liking. -from sloth.conf.default_config import * +# Sloth configuration. +# +# The configuration file is a simple python module with module-level +# variables. This module contains the default values for sloth's +# configuration variables. +# +# In all cases in the configuration where a python callable (such as a +# function, class constructor, etc.) is expected, it is equally possible +# to specify a module path (as string) pointing to such a python callable. +# It will then be automatically imported. +# LABLES +# +# List/tuple of dictionaries that defines the label types +# that are handled by sloth. For each label, there should +# be one dictionary that contains the following keys: +# +# - 'item' : Visualization item for this label. This can be +# any python callable or a module path string +# implementing the visualization item interface. +# +# - 'inserter' : (optional) Item inserter for this label. +# If the user selects to insert a new label of this type +# the inserter is responsible to actually +# capture the users mouse actions and insert +# a new label into the annotation model. +# +# - 'hotkey' : (optional) A keyboard shortcut starting +# the insertion of a new label of this type. +# +# - 'attributes' : (optional) A dictionary that defines the +# keys and possible values of this label +# type. LABELS = ( - ('Rect', {'type': 'rect'}), - ('Point', {'type': 'point'}), + { + 'attributes': { + 'type': 'rect', + }, + 'inserter': 'sloth.items.RectItemInserter', + 'item': 'sloth.items.RectItem', + 'hotkey': 'r', + }, + { + 'attributes': { + 'type': 'point', + }, + 'inserter': 'sloth.items.PointItemInserter', + 'item': 'sloth.items.PointItem', + 'hotkey': 'p', + }, ) +# HOTKEYS +# +# Defines the keyboard shortcuts. Each hotkey is defined by a tuple +# with at least 2 entries, where the first entry is the hotkey (sequence), +# and the second entry is the function that is called. The function +# should expect a single parameter, the labeltool object. The optional +# third entry -- if present -- is expected to be a string describing the +# action. HOTKEYS = ( + ('PgDown', lambda lt: lt.gotoNext(), 'Next image/frame'), + ('PgUp', lambda lt: lt.gotoPrevious(), 'Previous image/frame'), + ('Tab', lambda lt: lt.selectNextAnnotation(), 'Select next annotation'), + ('Shift+Tab', lambda lt: lt.selectPreviousAnnotation(), 'Select previous annotation'), + ('ESC', lambda lt: lt.exitInsertMode(), 'Exit insert mode'), ) -# Defines the mapping from the annotation type to the visualization item. The -# values need to be either python callables, or a module path string that -# points to a python callable. The callable is responsible for creating and -# returning the corresponding visualization item. -ITEMS = { - 'rect': 'sloth.items.RectItem', - 'point': 'sloth.items.PointItem', -} - -INSERTERS = { - 'rect': 'sloth.items.RectItemInserter', - 'point': 'sloth.items.PointItemInserter', -} - +# CONTAINERS +# +# A list/tuple of two-tuples defining the mapping between filename pattern and +# annotation container classes. The filename pattern can contain wildcards +# such as * and ?. The corresponding container is expected to either a python +# class implementing the sloth container interface, or a module path pointing +# to such a class. CONTAINERS = ( ('*.json', 'sloth.annotations.container.JsonContainer'), ('*.yaml', 'sloth.annotations.container.YamlContainer'), @@ -31,6 +80,11 @@ CONTAINERS = ( ('*.sloth-init', 'sloth.annotations.container.FileNameListContainer'), ) +# PLUGINS +# +# A list/tuple of classes implementing the sloth plugin interface. The +# classes can either be given directly or their module path be specified +# as string. PLUGINS = ( ) diff --git a/sloth/gui/buttonarea.py b/sloth/gui/buttonarea.py index 632ad04..9f5a717 100644 --- a/sloth/gui/buttonarea.py +++ b/sloth/gui/buttonarea.py @@ -71,7 +71,7 @@ class ButtonListWidget(QGroupBox): class ButtonArea(QWidget): stateChanged = pyqtSignal(object) - def __init__(self, labels=None, hotkeys=None, parent=None): + def __init__(self, labels=None, parent=None): QWidget.__init__(self, parent) self.label_names = [] @@ -91,11 +91,12 @@ class ButtonArea(QWidget): self.stateChanged.connect(self.stateHasChanged) if labels is not None: - for name, prop in labels: - self.add_label(name, prop) - if hotkeys is not None: - for choice, name, hotkey in hotkeys: - self.add_hotkey(choice, name, hotkey) + for label in labels: + # Description is given in key 'text'. + # If empty, use the type attribute. + name = label.get('name', '') or label.get('attributes', {}).get('type', '') + self.add_label(name, label.get('attributes', {})) + self.init_button_lists() self.vlayout.addStretch(1) self.setLayout(self.vlayout) diff --git a/sloth/gui/labeltool.py b/sloth/gui/labeltool.py index ad3931c..c576059 100755 --- a/sloth/gui/labeltool.py +++ b/sloth/gui/labeltool.py @@ -88,7 +88,16 @@ class MainWindow(QMainWindow): def setupGui(self): self.ui = uic.loadUi(os.path.join(GUIDIR, "labeltool.ui"), self) - self.scene = AnnotationScene(self.labeltool, items=config.ITEMS, inserters=config.INSERTERS) + # get inserters and items from labels + # FIXME for handling the new-style config correctly + inserters = dict([(label['attributes']['type'], label['inserter']) + for label in config.LABELS + if 'type' in label.get('attributes', {}) and 'inserter' in label]) + items = dict([(label['attributes']['type'], label['item']) + for label in config.LABELS + if 'type' in label.get('attributes', {}) and 'item' in label]) + + self.scene = AnnotationScene(self.labeltool, items=items, inserters=inserters) self.view = GraphicsView(self) self.view.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.view.setScene(self.scene) @@ -105,7 +114,7 @@ class MainWindow(QMainWindow): self.initShortcuts(config.HOTKEYS) - self.buttonarea = ButtonArea(config.LABELS, ()) + self.buttonarea = ButtonArea(config.LABELS) self.ui.dockAnnotationButtons.setWidget(self.buttonarea) self.buttonarea.stateChanged.connect(self.scene.setMode)