From 3f0aa1c99a6c5cb44d81ad55db55d46418dd59d5 Mon Sep 17 00:00:00 2001 From: Martin Baeuml Date: Fri, 6 May 2011 16:26:57 +0200 Subject: [PATCH] implement new config system --- annotationscene.py | 11 +++++--- bboxitem.py | 59 ++++++++++++++++++++++++++++++++++++++++++ buttonarea.py | 22 +++++++++------- conf/__init__.py | 23 ++++++++++++++++ conf/default_config.py | 20 ++++++++++++++ example_config.py | 40 +++++++++++++++------------- labeltool.py | 44 +++++++++++++++++++------------ loaders/__init__.py | 0 std_config.py | 52 ++++++++++++++++++++++++++++++++----- 9 files changed, 216 insertions(+), 55 deletions(-) create mode 100644 bboxitem.py create mode 100644 conf/__init__.py create mode 100644 conf/default_config.py create mode 100644 loaders/__init__.py diff --git a/annotationscene.py b/annotationscene.py index 7a96019..6adff2e 100644 --- a/annotationscene.py +++ b/annotationscene.py @@ -1,6 +1,6 @@ from PyQt4.QtGui import * from PyQt4.QtCore import * -from sceneitems import * +from items import * from annotationmodel import TypeRole, ImageRole import math import okapy @@ -10,7 +10,7 @@ class AnnotationScene(QGraphicsScene): # TODO signal itemadded - def __init__(self, parent=None): + def __init__(self, items=None, inserters=None, parent=None): super(AnnotationScene, self).__init__(parent) self.model_ = None @@ -20,6 +20,9 @@ class AnnotationScene(QGraphicsScene): self.message_ = "" self.last_key_ = None + self.itemfactory_ = Factory(items) + self.inserterfactory_ = Factory(inserters) + self.setBackgroundBrush(Qt.darkGray) self.setMode(None) @@ -93,7 +96,7 @@ class AnnotationScene(QGraphicsScene): for row in range(first, last+1): child = self.root_.child(row, 0) # get index _type = str(child.data(TypeRole).toPyObject()) # get type from index - item = ItemFactory.createItem(_type, child) # create graphics item from factory + item = self.itemfactory_.create(_type, child) # create graphics item from factory if item is not None: self.addItem(item) @@ -108,7 +111,7 @@ class AnnotationScene(QGraphicsScene): self.inserter_ = None return - inserter = ItemFactory.createItemInserter(self.mode_['type'], self) + inserter = self.inserterfactory_.create(self.mode_['type'], self) if inserter is None: raise InvalidArgumentException("Invalid mode") diff --git a/bboxitem.py b/bboxitem.py new file mode 100644 index 0000000..b5bd15a --- /dev/null +++ b/bboxitem.py @@ -0,0 +1,59 @@ +from items import ItemInserter, AnnotationGraphicsItem +from PyQt4.QtGui import * +from PyQt4.Qt import * + +class BodyBoundingboxItemInserter(ItemInserter): + def __init__(self, scene, mode=None): + ItemInserter.__init__(self, scene, mode) + self.point_items_ = [] + self.points_ = [] + + def mousePressEvent(self, event, index): + pos = event.scenePos() + self.points_.append((pos.x(), pos.y())) + item = QGraphicsEllipseItem(pos.x()-2, pos.y()-2, 4, 4) + item.setPen(Qt.red) + self.point_items_.append(item) + self.scene().addItem(item) + + event.accept() + if self.complete(index): + self.clear() + + def complete(self, index): + if len(self.points_) == 4: + ann = {'type': 'bodybbox', + 'x1': self.points_[0][0], 'y1': self.points_[0][1], + 'x2': self.points_[1][0], 'y2': self.points_[1][1], + 'x3': self.points_[2][0], 'y3': self.points_[2][1], + 'x4': self.points_[3][0], 'y4': self.points_[3][1]} + index.model().addAnnotation(index, ann) + return True + return False + + def clear(self): + for item in self.point_items_: + self.scene().removeItem(item) + self.point_items_ = [] + self.points_ = [] + +class BodyBoundingboxItem(AnnotationGraphicsItem): + def __init__(self, index, parent=None): + AnnotationGraphicsItem.__init__(self, index, parent) + + self.data_ = self.index().data(DataRole).toPyObject() + self.points_ = [(self.data_['x1'], self.data_['y1']), + (self.data_['x2'], self.data_['y2']), + (self.data_['x3'], self.data_['y3']), + (self.data_['x4'], self.data_['y4'])] + + def boundingRect(self): + return QRectF(QPointF(0, 0), QSizeF(20, 20)) + + def paint(self, painter, option, widget = None): + pen = self.pen() + if self.isSelected(): + pen.setStyle(Qt.DashLine) + painter.setPen(pen) + painter.drawRect(self.boundingRect()) + diff --git a/buttonarea.py b/buttonarea.py index 5b18019..ddc812a 100644 --- a/buttonarea.py +++ b/buttonarea.py @@ -64,7 +64,7 @@ class ButtonListWidget(QWidget): class ButtonArea(QWidget): stateChanged = pyqtSignal(object) - def __init__(self, parent=None): + def __init__(self, labels=None, hotkeys=None, parent=None): QWidget.__init__(self, parent) self.label_names = [] @@ -84,6 +84,14 @@ class ButtonArea(QWidget): self.setLayout(self.hlayout) 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) + self.init_button_lists() + def stateHasChanged(self, state): print "stateChanged(object)", state @@ -171,16 +179,12 @@ class ButtonArea(QWidget): self.show_only_label_properties("") self.stateChanged.emit(self.get_current_state()) - - def load(self, config_filepath): - execfile(config_filepath) - self.init_button_lists() - def main(): - app = QApplication(sys.argv) + from conf import config + config.update("example_config") - ba = ButtonArea() - ba.load("example_config.py") + app = QApplication(sys.argv) + ba = ButtonArea(config.LABELS, config.HOTKEYS) ba.show() return app.exec_() diff --git a/conf/__init__.py b/conf/__init__.py new file mode 100644 index 0000000..cfc3db9 --- /dev/null +++ b/conf/__init__.py @@ -0,0 +1,23 @@ +from conf import default_config +import importlib + +class Config: + def __init__(self): + # init the configuration with the default config + for setting in dir(default_config): + if setting == setting.upper(): + setattr(self, setting, getattr(default_config, setting)) + + def update(self, module_path): + try: + mod = importlib.import_module(module_path) + except ImportError, e: + raise ImportError("Could not import configuration '%s' (Is it on sys.path?): %s" % (module_path, e)) + + for setting in dir(mod): + if setting == setting.upper(): + setting_value = getattr(mod, setting) + setattr(self, setting, setting_value) + +config = Config() + diff --git a/conf/default_config.py b/conf/default_config.py new file mode 100644 index 0000000..09b7dea --- /dev/null +++ b/conf/default_config.py @@ -0,0 +1,20 @@ +LABELS = ( +) + +HOTKEYS = ( +) + +ITEMS = ( + ("rect", "items.RectItem", "items.RectItemInserter"), + ("point", "items.PointItem", "items.PointItemInserter") +) + +INSERTERS = ( +) + +LOADERS = ( +) + +PLUGINS = ( +) + diff --git a/example_config.py b/example_config.py index 610c3c3..7ed1907 100644 --- a/example_config.py +++ b/example_config.py @@ -4,22 +4,26 @@ obj_type_choice2 = ["Peach", "Table", "Window"] ID_choice = ["Martin", "Mika", "Alexander", "Lukas", "Tobias"] ID_choice2 = ["Boris", "Manel", "Rainer", "Hua", "Hazim"] -self.add_label("Head", {"type": "rect", - "class": "head", - "id": ID_choice}) -self.add_label("Left Eye", {"type": "point", - "class": "left_eye", - "id": ID_choice, - "obj_type": obj_type_choice}) -self.add_label("Right Eye", {"type": "point", - "class": "right_eye", - "id": ID_choice2, - "obj_type": obj_type_choice2}) -self.add_label("Left Hand", {"type": "rect", - "class": "left_hand", - "obj_type": obj_type_choice}) -self.add_label("Right Hand", {"type": "rect", - "class": "right_hand"}) +LABELS = ( + ("Head", {"type": "rect", + "class": "head", + "id": ID_choice}), + ("Left Eye", {"type": "point", + "class": "left_eye", + "id": ID_choice, + "obj_type": obj_type_choice}), + ("Right Eye", {"type": "point", + "class": "right_eye", + "id": ID_choice2, + "obj_type": obj_type_choice2}), + ("Left Hand", {"type": "rect", + "class": "left_hand", + "obj_type": obj_type_choice}), + ("Right Hand", {"type": "rect", + "class": "right_hand"}), +) -self.add_hotkey("", "Head", "h") -self.add_hotkey("id", "Martin", "CTRL+m") +HOTKEYS = ( + ("", "Head", "h"), + ("id", "Martin", "CTRL+m"), +) diff --git a/labeltool.py b/labeltool.py index 8a95289..8b29dbf 100755 --- a/labeltool.py +++ b/labeltool.py @@ -1,6 +1,6 @@ #!/usr/bin/python import sys, os -import functools +import functools, importlib from PyQt4.QtGui import * from PyQt4.QtCore import * import PyQt4.uic as uic @@ -9,18 +9,28 @@ from buttonarea import * from annotationmodel import * from annotationscene import * from frameviewer import * +from loaders import * +from optparse import OptionParser import annotations - +from conf import config APP_NAME = """labeltool""" ORGANIZATION_NAME = """CVHCI Research Group""" ORGANIZATION_DOMAIN = """cvhci.anthropomatik.kit.edu""" __version__ = """0.1""" - class MainWindow(QMainWindow): def __init__(self, argv, parent=None): super(MainWindow, self).__init__(parent) + + # parse command line options + options, args = self.parseCommandLineOptions(argv) + if options.config != "": + # load config + config.update(options.config) + + self.loaders_ = [] + self.anno_container = annotations.AnnotationContainer() self.current_index_ = None @@ -30,26 +40,33 @@ class MainWindow(QMainWindow): self.updateStatus() self.updateViews() - if len(argv) > 0: - self.loadInitialFile(argv[0]) + if len(args) > 0: + self.loadInitialFile(args[0]) else: self.loadInitialFile() + def parseCommandLineOptions(self, argv): + usage = "Usage: %prog [-c config.py] [annotation_file]" + version = "%prog " + __version__ + + parser = OptionParser(usage=usage, version=version) + parser.add_option("-c", "--config", action="store", type="string", default="", help="Configuration file.") + + return parser.parse_args(argv) + ### ### GUI/Application setup ###___________________________________________________________________________________________ def setupGui(self): self.ui = uic.loadUi("labeltool.ui", self) - self.scene = AnnotationScene(self) + self.scene = AnnotationScene(items=config.ITEMS, inserters=config.INSERTERS) self.view = GraphicsView(self) self.view.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.view.setScene(self.scene) self.setCentralWidget(self.view) - self.buttonarea = ButtonArea() - # TODO make this configurable/settable via command line option - self.buttonarea.load("std_config.py") + self.buttonarea = ButtonArea(config.LABELS, config.HOTKEYS) self.ui.dockAnnotationButtons.setWidget(self.buttonarea) self.buttonarea.stateChanged.connect(self.scene.setMode) @@ -58,14 +75,6 @@ class MainWindow(QMainWindow): self.treeview.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Preferred) self.ui.dockInformation.setWidget(self.treeview) - ## create action group for tools - self.toolActions = QActionGroup(self) - for action in (self.ui.actionSelection, - self.ui.actionPoint, - self.ui.actionRectangle, - self.ui.actionMask): - self.toolActions.addAction(action) - self.ui.show() ## connect action signals @@ -106,6 +115,7 @@ class MainWindow(QMainWindow): filename = QVariant() settings.setValue("LastFile", filename) + ### ### Annoation file handling ###___________________________________________________________________________________________ diff --git a/loaders/__init__.py b/loaders/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/std_config.py b/std_config.py index 357e01c..054532e 100644 --- a/std_config.py +++ b/std_config.py @@ -1,10 +1,48 @@ +from items import AnnotationGraphicsRectItem as RectItem +from items import RectItemInserter +from bboxitem import * + RATIOS = ["0.5", "1", "2"] -self.add_label("Rect", {"type": "rect"}) -self.add_label("FixedRatioRect", {"type": "ratiorect", "_ratio": RATIOS}) -self.add_label("Point", {"type": "point"}) -self.add_label("Polygon", {"type": "polygon"}) +LABELS = ( + ("Rect", {"type" : "rect"}), + ("FixedRatioRect", {"type": "ratiorect", "_ratio": RATIOS}), + ("Point", {"type": "point"}), + ("Polygon", {"type": "polygon"}), + ("BodyBBox", {"type": "bodybbox"}), +) + +HOTKEYS = ( + ("", "Rect", "r"), + ("", "Point", "p"), + ("", "Polygon", "o"), + ("", "BodyBBox", "b") +) + +ITEMS = ( + ("rect", RectItem), + ("bodybbox", BodyBoundingboxItem), +) + +INSERTERS = ( + ("rect", RectItemInserter), + ("bodybbox", BodyBoundingboxItemInserter), +) + +LOADERS = ( +) + +PLUGINS = ( +) + +#labeltool.buttonarea.add_label("Rect", {"type": "rect"}) +#labeltool.buttonarea.add_label("FixedRatioRect", {"type": "ratiorect", "_ratio": RATIOS}) +#labeltool.buttonarea.add_label("Point", {"type": "point"}) +#labeltool.buttonarea.add_label("Polygon", {"type": "polygon"}) +#labeltool.buttonarea.add_label("BodyBBox", {"type": "bodybbox"}) +# +#Labeltool.buttonarea.add_hotkey("", "Rect", "r") +#Labeltool.buttonarea.add_hotkey("", "Point", "p") +#Labeltool.buttonarea.add_hotkey("", "Polygon", "o") +#Labeltool.buttonarea.add_hotkey("", "BodyBBox", "b") -self.add_hotkey("", "Rect", "r") -self.add_hotkey("", "Point", "p") -self.add_hotkey("", "Polygon", "o")