This commit is contained in:
Martin Baeuml
2014-03-19 22:00:51 +01:00
parent 1c0387a192
commit 5d207711de
8 changed files with 54 additions and 48 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
import sys
from os.path import dirname, realpath
sys.path.insert(1, dirname(dirname(dirname(realpath( __file__ )))))
sys.path.insert(1, dirname(dirname(dirname(realpath(__file__)))))
from PyQt4.QtGui import QApplication
from sloth.core.labeltool import LabelTool
from sloth import APP_NAME, ORGANIZATION_NAME, ORGANIZATION_DOMAIN
+5 -4
View File
@@ -1,5 +1,3 @@
import sys
import os
import sloth
import shutil
from pprint import pprint
@@ -7,8 +5,11 @@ from sloth.core.cli import BaseCommand, CommandError
from sloth.annotations.container import *
from optparse import make_option
import logging
logger = logging.getLogger(__name__)
class ConvertCommand(BaseCommand):
"""
Converts a label file from one file format to another.
@@ -152,7 +153,6 @@ class MergeFilesCommand(BaseCommand):
containerOut = self.labeltool._container_factory.create(output)
containerOut.save(an3, output)
def merge_annotations(self, an1, an2):
# I could also think of an implementation merging an1 and an2, and flattening the lists of lists
@@ -173,7 +173,6 @@ class MergeFilesCommand(BaseCommand):
assert(d1['frames'] != None)
assert(d2['frames'] != None)
frames1 = d1['frames']
frames2 = d2['frames']
@@ -222,10 +221,12 @@ def _make_writeable(filename):
# command dictionary str -> Command
_commands = {}
def register_command(name, command):
global _commands
_commands[name] = command
def get_commands():
global _commands
return _commands
+4 -1
View File
@@ -1,15 +1,18 @@
"""
Label tool exception classes.
Sloth exception classes.
"""
class ImproperlyConfigured(Exception):
"""There is an error in the configuration."""
pass
class NotImplementedException(Exception):
"""This function/method/class has not been implemented yet."""
pass
class InvalidArgumentException(Exception):
"""The argument is invalid."""
pass
+31 -33
View File
@@ -1,10 +1,8 @@
#!/usr/bin/python
"""
This is the core labeltool module.
"""
import sys, os
import os
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from sloth.annotations.model import *
@@ -16,13 +14,15 @@ from sloth import VERSION
from sloth.core.commands import get_commands
from sloth.gui import MainWindow
import logging
LOG = logging.getLogger(__name__)
try:
import okapy.videoio as okv
except:
except ImportError:
pass
class LabelTool(QObject):
"""
This is the main label tool object. It stores the state of the tool, i.e.
@@ -43,9 +43,9 @@ class LabelTool(QObject):
"Type '%s help <subcommand>' for help on a specific subcommand.\n\n"
# Signals
statusMessage = pyqtSignal(str)
annotationsLoaded = pyqtSignal()
pluginLoaded = pyqtSignal(QAction)
statusMessage = pyqtSignal(str)
annotationsLoaded = pyqtSignal()
pluginLoaded = pyqtSignal(QAction)
# This still emits a QModelIndex, because Qt cannot handle emiting
# a derived class instead of a base class, i.e. ImageFileModelItem
# instead of ModelItem
@@ -105,7 +105,8 @@ class LabelTool(QObject):
# Initialize logging
loglevel = (logging.CRITICAL, logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG)[int(options.verbosity)]
logging.basicConfig(level=loglevel, format='%(asctime)s %(levelname)-8s %(name)-30s %(message)s') #, datefmt='%H:%M:%S.%m')
logging.basicConfig(level=loglevel,
format='%(asctime)s %(levelname)-8s %(name)-30s %(message)s') #, datefmt='%H:%M:%S.%m')
# Disable PyQt log messages
logging.getLogger("PyQt4").setLevel(logging.WARNING)
@@ -170,7 +171,6 @@ class LabelTool(QObject):
else:
self.clearAnnotations()
def fetch_command(self, subcommand):
"""
Tries to fetch the given subcommand, printing a message with the
@@ -179,8 +179,8 @@ class LabelTool(QObject):
try:
app_name = get_commands()[subcommand]
except KeyError:
sys.stderr.write("Unknown command: %r\nType '%s help' for usage.\n" % \
(subcommand, self.prog_name))
sys.stderr.write("Unknown command: %r\nType '%s help' for usage.\n" %
(subcommand, self.prog_name))
sys.exit(1)
if isinstance(app_name, BaseCommand):
# If the command is already loaded, use it directly.
@@ -221,13 +221,13 @@ class LabelTool(QObject):
### Annoation file handling
###___________________________________________________________________________________________
def loadAnnotations(self, fname, handleErrors=True):
fname = str(fname) # convert from QString
fname = str(fname) # convert from QString
try:
self._container = self._container_factory.create(fname)
self._model = AnnotationModel(self._container.load(fname))
msg = "Successfully loaded %s (%d files, %d annotations)" % \
(fname, self._model.root().numFiles(), self._model.root().numAnnotations())
(fname, self._model.root().numFiles(), self._model.root().numAnnotations())
except Exception as e:
if handleErrors:
msg = "Error: Loading failed (%s)" % str(e)
@@ -247,7 +247,6 @@ class LabelTool(QObject):
try:
# create new container if the filename is different
if fname != self._container.filename():
# TODO: skip if it is the same class
self._container = self._container_factory.create(fname)
# Get annotations dict
@@ -256,7 +255,7 @@ class LabelTool(QObject):
self._container.save(ann, fname)
#self._model.writeback() # write back changes that are cached in the model itself, e.g. mask updates
msg = "Successfully saved %s (%d files, %d annotations)" % \
(fname, self._model.root().numFiles(), self._model.root().numAnnotations())
(fname, self._model.root().numFiles(), self._model.root().numAnnotations())
success = True
self._model.setDirty(False)
except Exception as e:
@@ -300,7 +299,7 @@ class LabelTool(QObject):
else:
next_image = next(self._model.iterator(ImageModelItem))
if next_image is not None:
next_image = next_image.getNextSibling(step-1)
next_image = next_image.getNextSibling(step - 1)
if next_image is not None:
self.setCurrentImage(next_image)
@@ -349,18 +348,18 @@ class LabelTool(QObject):
def addImageFile(self, fname):
fileitem = {
'filename': fname,
'class': 'image',
'annotations': [ ],
}
'filename': fname,
'class': 'image',
'annotations': [],
}
return self._model._root.appendFileItem(fileitem)
def addVideoFile(self, fname):
fileitem = {
'filename': fname,
'class': 'video',
'frames': [ ],
}
'filename': fname,
'class': 'video',
'frames': [],
}
# FIXME: OKAPI should provide a method to get all timestamps at once
# FIXME: Some dialog should be displayed, telling the user that the
@@ -376,17 +375,17 @@ class LabelTool(QObject):
LOG.debug("Adding %d frames" % len(timestamps))
fileitem['frames'] = [{'annotations': [], 'num': i,
'timestamp': ts, 'class': 'frame'}
for i, ts in enumerate(timestamps)]
for i, ts in enumerate(timestamps)]
else:
i = 0
while video.getNextFrame():
LOG.debug("Adding frame %d" % i)
ts = video.getTimestamp()
frame = { 'annotations': [],
'num': i,
'timestamp': ts,
'class': 'frame'
}
frame = {'annotations': [],
'num': i,
'timestamp': ts,
'class': 'frame'
}
fileitem['frames'].append(frame)
i += 1
@@ -429,7 +428,7 @@ class LabelTool(QObject):
def selectPreviousAnnotation(self):
if self._mainwindow is not None:
return self._mainwindow.scene.selectNextItem(reverse=True)
def selectAllAnnotations(self):
if self._mainwindow is not None:
return self._mainwindow.scene.selectAllItems()
@@ -449,5 +448,4 @@ class LabelTool(QObject):
if self._mainwindow is None:
return None
else:
return self._mainwindow.treeview
return self._mainwindow.treeview
+1
View File
@@ -1,6 +1,7 @@
from sloth.core import exceptions
from sloth.utils import importlib
def import_callable(module_path_name):
"""
Import the callable given by ``module_path_name``.
+4 -4
View File
@@ -1,5 +1,6 @@
from sloth.core.utils import import_callable
class Factory:
"""
A generic factory for both items and inserters.
@@ -34,8 +35,8 @@ class Factory:
"""
_type = str(_type)
if _type in self._items and not replace:
raise Exception("Type %s already has an item: %s" % \
(_type, str(self._items[_type])))
raise Exception("Type %s already has an item: %s" %
(_type, str(self._items[_type])))
else:
if type(item) == str:
item = import_callable(item)
@@ -53,7 +54,7 @@ class Factory:
"""
_type = str(_type)
if _type is None:
self._items = {}
self._items = {}
else:
if _type in self._items:
del self._items[_type]
@@ -82,4 +83,3 @@ class Factory:
if item is None:
return None
return item(*args, **kwargs)
+2 -2
View File
@@ -1,5 +1,4 @@
import logging
from PyQt4.QtGui import *
from PyQt4.Qt import *
@@ -99,7 +98,8 @@ class BaseItem(QAbstractGraphicsShapeItem):
self._valid = True
if len(self.cycleValuesOnKeypress) > 0:
logging.warning("cycleValueOnKeypress is deprecated and will be removed in the future. Set BaseItem.hotkeys instead with cycleValue()")
logging.warning("cycleValueOnKeypress is deprecated and will be removed in the future. " +
"Set BaseItem.hotkeys instead with cycleValue()")
self.changeColor()
+6 -3
View File
@@ -5,6 +5,8 @@ import random
import colorsys
gray_color_table = [qRgb(i, i, i) for i in range(256)]
def toQImage(im, copy=False):
if im is None:
return QImage()
@@ -17,12 +19,13 @@ def toQImage(im, copy=False):
elif len(im.shape) == 3:
if im.shape[2] == 3:
qim = QImage(im.data, im.shape[1], im.shape[0], im.strides[0], QImage.Format_RGB888);
qim = QImage(im.data, im.shape[1], im.shape[0], im.strides[0], QImage.Format_RGB888)
return qim.copy() if copy else qim
elif im.shape[2] == 4:
qim = QImage(im.data, im.shape[1], im.shape[0], im.strides[0], QImage.Format_ARGB32);
qim = QImage(im.data, im.shape[1], im.shape[0], im.strides[0], QImage.Format_ARGB32)
return qim.copy() if copy else qim
raise NotImplementedException('no conversion to QImage implemented for given image type (depth: %s, shape: %s)' % (im.dtype, im.shape))
raise NotImplementedException('no conversion to QImage implemented for given image type (depth: %s, shape: %s)' %
(im.dtype, im.shape))
def gen_colors(s=0.99, v=0.99, h=None, color_space='rgb', _golden_ratio_conjugate=0.618033988749895):