Merge pull request #64 from des0ps/feature/verified_flag
Implement verification feature
This commit is contained in:
commit
29f62ad64f
@ -83,6 +83,7 @@ You can edit the [data/predefined_classes.txt](https://github.com/tzutalin/label
|
||||
| Ctrl + r | Change the default annotation target dir |
|
||||
| Ctrl + s | Save |
|
||||
| Ctrl + d | Copy the current label and rect box |
|
||||
| Space | Flag the current image as verified |
|
||||
| w | Create a rect box |
|
||||
| d | Next image |
|
||||
| a | Previous image |
|
||||
|
||||
34
labelImg.py
Executable file → Normal file
34
labelImg.py
Executable file → Normal file
@ -212,6 +212,9 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||
openPrevImg = action('&Prev Image', self.openPrevImg,
|
||||
'a', 'prev', u'Open Prev')
|
||||
|
||||
verify = action('&Verify Image', self.verifyImg,
|
||||
'space', 'verify', u'Verify Image')
|
||||
|
||||
save = action('&Save', self.saveFile,
|
||||
'Ctrl+S', 'save', u'Save labels to file', enabled=False)
|
||||
saveAs = action('&Save As', self.saveFileAs,
|
||||
@ -353,7 +356,7 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||
|
||||
self.tools = self.toolbar('Tools')
|
||||
self.actions.beginner = (
|
||||
open, opendir, openNextImg, openPrevImg, save, None, create, copy, delete, None,
|
||||
open, opendir, openNextImg, openPrevImg, verify, save, None, create, copy, delete, None,
|
||||
zoomIn, zoom, zoomOut, fitWindow, fitWidth)
|
||||
|
||||
self.actions.advanced = (
|
||||
@ -658,7 +661,9 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||
|
||||
def saveLabels(self, annotationFilePath):
|
||||
annotationFilePath = u(annotationFilePath)
|
||||
lf = LabelFile()
|
||||
if self.labelFile is None:
|
||||
self.labelFile = LabelFile()
|
||||
self.labelFile.verified = self.canvas.verified
|
||||
|
||||
def format_shape(s):
|
||||
return dict(label=s.label,
|
||||
@ -674,12 +679,11 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||
if self.usingPascalVocFormat is True:
|
||||
print ('Img: ' + self.filePath +
|
||||
' -> Its xml: ' + annotationFilePath)
|
||||
lf.savePascalVocFormat(annotationFilePath, shapes, self.filePath, self.imageData,
|
||||
self.labelFile.savePascalVocFormat(annotationFilePath, shapes, self.filePath, self.imageData,
|
||||
self.lineColor.getRgb(), self.fillColor.getRgb())
|
||||
else:
|
||||
lf.save(annotationFilePath, shapes, self.filePath, self.imageData,
|
||||
self.labelFile.save(annotationFilePath, shapes, self.filePath, self.imageData,
|
||||
self.lineColor.getRgb(), self.fillColor.getRgb())
|
||||
self.labelFile = lf
|
||||
return True
|
||||
except LabelFileError as e:
|
||||
self.errorMessage(u'Error saving label data',
|
||||
@ -829,7 +833,9 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||
xmlPath = os.path.join(self.defaultSaveDir, basename)
|
||||
self.loadPascalXMLByFilename(xmlPath)
|
||||
|
||||
self.canvas.setFocus()
|
||||
self.setWindowTitle('{} - {}'.format(__appname__, filePath))
|
||||
|
||||
self.canvas.setFocus(True)
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -970,6 +976,21 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||
item = QListWidgetItem(imgPath)
|
||||
self.fileListWidget.addItem(item)
|
||||
|
||||
def verifyImg(self, _value=False):
|
||||
# Proceding next image without dialog if having any label
|
||||
if self.filePath is not None:
|
||||
try:
|
||||
self.labelFile.toggleVerify()
|
||||
except AttributeError:
|
||||
# If the labelling file does not exist yet, create if and
|
||||
# re-save it with the verified attribute.
|
||||
self.saveFile()
|
||||
self.labelFile.toggleVerify()
|
||||
|
||||
self.canvas.verified = self.labelFile.verified
|
||||
self.paintCanvas()
|
||||
self.saveFile()
|
||||
|
||||
def openPrevImg(self, _value=False):
|
||||
if not self.mayContinue():
|
||||
return
|
||||
@ -1156,6 +1177,7 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||
tVocParseReader = PascalVocReader(xmlPath)
|
||||
shapes = tVocParseReader.getShapes()
|
||||
self.loadLabels(shapes)
|
||||
self.canvas.verified = tVocParseReader.verified
|
||||
|
||||
|
||||
class Settings(object):
|
||||
|
||||
@ -59,6 +59,7 @@ class Canvas(QWidget):
|
||||
# Set widget options.
|
||||
self.setMouseTracking(True)
|
||||
self.setFocusPolicy(Qt.WheelFocus)
|
||||
self.verified = False
|
||||
|
||||
def enterEvent(self, ev):
|
||||
self.overrideCursor(self._cursor)
|
||||
@ -419,6 +420,16 @@ class Canvas(QWidget):
|
||||
p.setBrush(brush)
|
||||
p.drawRect(leftTop.x(), leftTop.y(), rectWidth, rectHeight)
|
||||
|
||||
self.setAutoFillBackground(True)
|
||||
if self.verified:
|
||||
pal = self.palette()
|
||||
pal.setColor(self.backgroundRole(), QColor(184, 239, 38, 128))
|
||||
self.setPalette(pal)
|
||||
else:
|
||||
pal = self.palette()
|
||||
pal.setColor(self.backgroundRole(), QColor(232, 232, 232, 255))
|
||||
self.setPalette(pal)
|
||||
|
||||
p.end()
|
||||
|
||||
def transformPos(self, point):
|
||||
|
||||
@ -24,8 +24,7 @@ class LabelFile(object):
|
||||
self.shapes = ()
|
||||
self.imagePath = None
|
||||
self.imageData = None
|
||||
if filename is not None:
|
||||
self.load(filename)
|
||||
self.verified = False
|
||||
|
||||
def savePascalVocFormat(self, filename, shapes, imagePath, imageData,
|
||||
lineColor=None, fillColor=None, databaseSrc=None):
|
||||
@ -41,6 +40,8 @@ class LabelFile(object):
|
||||
1 if image.isGrayscale() else 3]
|
||||
writer = PascalVocWriter(imgFolderName, imgFileNameWithoutExt,
|
||||
imageShape, localImgPath=imagePath)
|
||||
writer.verified = self.verified
|
||||
|
||||
for shape in shapes:
|
||||
points = shape['points']
|
||||
label = shape['label']
|
||||
@ -50,6 +51,9 @@ class LabelFile(object):
|
||||
writer.save(targetFile=filename)
|
||||
return
|
||||
|
||||
def toggleVerify(self):
|
||||
self.verified = not self.verified
|
||||
|
||||
@staticmethod
|
||||
def isLabelFile(filename):
|
||||
fileSuffix = os.path.splitext(filename)[1].lower()
|
||||
@ -72,10 +76,10 @@ class LabelFile(object):
|
||||
# Martin Kersner, 2015/11/12
|
||||
# 0-valued coordinates of BB caused an error while
|
||||
# training faster-rcnn object detector.
|
||||
if (xmin < 1):
|
||||
if xmin < 1:
|
||||
xmin = 1
|
||||
|
||||
if (ymin < 1):
|
||||
if ymin < 1:
|
||||
ymin = 1
|
||||
|
||||
return (int(xmin), int(ymin), int(xmax), int(ymax))
|
||||
|
||||
@ -19,6 +19,7 @@ class PascalVocWriter:
|
||||
self.imgSize = imgSize
|
||||
self.boxlist = []
|
||||
self.localImgPath = localImgPath
|
||||
self.verified = False
|
||||
|
||||
def prettify(self, elem):
|
||||
"""
|
||||
@ -39,6 +40,8 @@ class PascalVocWriter:
|
||||
return None
|
||||
|
||||
top = Element('annotation')
|
||||
top.set('verified', 'yes' if self.verified else 'no')
|
||||
|
||||
folder = SubElement(top, 'folder')
|
||||
folder.text = self.foldername
|
||||
|
||||
@ -119,6 +122,7 @@ class PascalVocReader:
|
||||
# [labbel, [(x1,y1), (x2,y2), (x3,y3), (x4,y4)], color, color]
|
||||
self.shapes = []
|
||||
self.filepath = filepath
|
||||
self.verified = False
|
||||
self.parseXML()
|
||||
|
||||
def getShapes(self):
|
||||
@ -137,6 +141,12 @@ class PascalVocReader:
|
||||
parser = etree.XMLParser(encoding='utf-8')
|
||||
xmltree = ElementTree.parse(self.filepath, parser=parser).getroot()
|
||||
filename = xmltree.find('filename').text
|
||||
try:
|
||||
verified = xmltree.attrib['verified']
|
||||
if verified == 'yes':
|
||||
self.verified = True
|
||||
except KeyError:
|
||||
self.verified = False
|
||||
|
||||
for object_iter in xmltree.findall('object'):
|
||||
bndbox = object_iter.find("bndbox")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user