Skip to content

Commit e335d21

Browse files
committed
Merge branch 'master' into newpapermaster
2 parents b5d96e7 + ecf565e commit e335d21

File tree

15 files changed

+619
-45
lines changed

15 files changed

+619
-45
lines changed

DetectorNetwork/template.json

Lines changed: 408 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,23 @@ The annotations are saved as a [JSON](http://www.json.org/) file.
7070
```bash
7171
smarter_labelme # just open gui
7272
```
73+
74+
### Known Installation Issues.
75+
76+
Due to a version mismatch between OpenCV and system Qt libraries, on some system the following error might occur when attempting to run smarter-labelme:
77+
78+
```
79+
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in ".../site-packages/cv2/qt/plugins" even though it was found.
80+
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
81+
```
82+
83+
If this happens, you can run the following commands to remove the conflicting opencv qt libraries:
84+
85+
```
86+
python3 -m pip uninstall opencv-python
87+
python3 -m pip install --upgrade opencv-python-headless
88+
```
89+
7390
### Neural Network weights.
7491

7592
Smarter-labelme will automatically download pretrained network weights via torch.hub on the first start. They will be cashed in your local user directory and use approximately 200 Mb of space. You can use your own weights instead with the `--ssdmodel` and `--re3model` flags.

labelme/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# 1. MAJOR version when you make incompatible API changes;
1313
# 2. MINOR version when you add functionality in a backwards-compatible manner;
1414
# 3. PATCH version when you make backwards-compatible bug fixes.
15-
__version__ = '5.2.6'
15+
__version__ = '5.2.10'
1616

1717
QT4 = QT_VERSION[0] == '4'
1818
QT5 = QT_VERSION[0] == '5'

labelme/__main__.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,11 @@ def main():
118118
help='epsilon to find nearest vertex on canvas',
119119
default=argparse.SUPPRESS,
120120
)
121+
parser.add_argument(
122+
'--global-translation-track-size',
123+
help='Size in pixel for downsampled frame when estimating global camera translation and rotation. Set to zero to disable the feature. Default: 100',
124+
default=argparse.SUPPRESS,
125+
)
121126
parser.add_argument(
122127
'--ssdmodel',
123128
help='Filename for SSD multibox weights',
@@ -128,6 +133,28 @@ def main():
128133
help='Minimum resolution at which to auto annotate. Smaller values result in more memory usage and longer runtime but detect smaller objects. Default: 300',
129134
default=argparse.SUPPRESS,
130135
)
136+
parser.add_argument(
137+
'--ssd-threshold-autoannotation',
138+
help='Confidence threshold for auto annotation. Default: 0.15',
139+
default=argparse.SUPPRESS,
140+
)
141+
parser.add_argument(
142+
'--ssd-track-crop-factor',
143+
help='Region size around the tracked annotation in which to search for objects with SSD, relative to bounding box. Default: 3.0',
144+
default=argparse.SUPPRESS,
145+
)
146+
parser.add_argument(
147+
'--ssd-re3-correction-alpha',
148+
dest='ssd_re3_correction_alpha',
149+
help='Weighting factor for SSD detection coordinates when drift correcting Re³. Default: 0.8',
150+
default=argparse.SUPPRESS,
151+
)
152+
parser.add_argument(
153+
'--ssd-re3-min-iou',
154+
dest='ssd_re3_correction_min_iou',
155+
help='Minimum Jaccard-overlap (IOU) between tracked bounding box and highest confidence SSD detection to consider for Re³ drift correction. Default: 0.8',
156+
default=argparse.SUPPRESS,
157+
)
131158
parser.add_argument(
132159
'--re3model',
133160
help='Filename for RE3 multibox weights',
@@ -143,6 +170,20 @@ def main():
143170
help='Device to run Deep Neural Networks on - cpu or cuda',
144171
default=argparse.SUPPRESS,
145172
)
173+
parser.add_argument(
174+
'--autorun',
175+
dest='auto_run',
176+
action='store_true',
177+
help='Run in auto mode with tracking enabled, then exit',
178+
default=argparse.SUPPRESS,
179+
)
180+
parser.add_argument(
181+
'--freezekeyframes',
182+
dest='freeze_key_frames',
183+
action='store_true',
184+
help='When auto-tracking, do not change already annotated frames, instead re-init tracker dictionary',
185+
default=argparse.SUPPRESS,
186+
)
146187
args = parser.parse_args()
147188

148189
if args.version:

labelme/app.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from labelme.widgets import ToolBar
3030
from labelme.widgets import UniqueLabelQListWidget
3131
from labelme.widgets import ZoomWidget
32+
from labelme.widgets import StepsizeWidget
3233

3334
from labelme.trackerre3 import Tracker, trackerAutoAnnotate, trackerInit, trackerDetectFlags, trackerFindGlobalOffset
3435

@@ -82,6 +83,7 @@ def __init__(
8283
# Whether we need to save or not.
8384
self.dirty = False
8485
self.image_skip = int(self._config['image_skip'])
86+
self.autoMode = False
8587

8688
self._noSelectionSlot = False
8789

@@ -164,6 +166,7 @@ def __init__(
164166
self.file_dock.setWidget(fileListWidget)
165167

166168
self.zoomWidget = ZoomWidget()
169+
self.stepsizeWidget = StepsizeWidget(value=self.image_skip)
167170

168171
self.canvas = self.labelList.canvas = Canvas(
169172
epsilon=self._config['epsilon'],
@@ -381,6 +384,12 @@ def __init__(
381384
self.tr('Automatically annotate all object instances visible'),
382385
enabled=False)
383386

387+
startStopAutoMode = action(self.tr('StartStopAutoMode'), self.startStopAutoMode,
388+
shortcuts['startStopAutoMode'], 'icon',
389+
self.tr('Automatically annotate the whole video'),
390+
enabled=False,
391+
checkable=True)
392+
384393
undo = action(self.tr('Undo'), self.undoShapeEdit,
385394
shortcuts['undo'], 'undo',
386395
self.tr('Undo last add and edit of shape'),
@@ -415,6 +424,15 @@ def __init__(
415424
)
416425
self.zoomWidget.setEnabled(False)
417426

427+
stepsize = QtWidgets.QWidgetAction(self)
428+
stepsize.setDefaultWidget(self.stepsizeWidget)
429+
self.stepsizeWidget.setWhatsThis(
430+
self.tr(
431+
'Skip size for iteration through Image.'
432+
)
433+
)
434+
self.stepsizeWidget.setEnabled(True)
435+
418436
zoomIn = action(self.tr('Zoom &In'),
419437
functools.partial(self.addZoom, 1.1),
420438
shortcuts['zoom_in'], 'zoom-in',
@@ -504,6 +522,8 @@ def __init__(
504522
createLineStripMode=createLineStripMode,
505523
zoom=zoom, zoomIn=zoomIn, zoomOut=zoomOut, zoomOrg=zoomOrg,
506524
fitWindow=fitWindow, fitWidth=fitWidth,
525+
startStopAutoMode=startStopAutoMode,
526+
stepsize=stepsize,
507527
zoomActions=zoomActions,
508528
openNextImg=openNextImg, openPrevImg=openPrevImg, openseg=openseg,
509529
increase_blend=increase_blend, decrease_blend=decrease_blend,
@@ -553,6 +573,7 @@ def __init__(
553573
createLineStripMode,
554574
editMode,
555575
autoAnnotate,
576+
startStopAutoMode,
556577
),
557578
onShapesPresent=(saveAs, hideAll, showAll),
558579
)
@@ -652,6 +673,8 @@ def __init__(
652673
zoomOut,
653674
fitWindow,
654675
fitWidth,
676+
startStopAutoMode,
677+
stepsize,
655678
)
656679

657680
self.statusBar().showMessage(self.tr('%s started.') % __appname__)
@@ -725,12 +748,16 @@ def __init__(
725748

726749
# Callbacks:
727750
self.zoomWidget.valueChanged.connect(self.paintCanvas)
751+
self.stepsizeWidget.valueChanged.connect(self.stepsizeChanged)
728752

729753
self.populateModeActions()
730754

731755
# self.firstStart = True
732756
# if self.firstStart:
733757
# QWhatsThis.enterWhatsThisMode()
758+
if self._config['auto_run']:
759+
logger.info('Auto Run Engaged')
760+
self.queueEvent(functools.partial(self.autoRun))
734761

735762
def menu(self, title, actions=None):
736763
menu = self.menuBar().addMenu(title)
@@ -799,6 +826,7 @@ def setClean(self):
799826
self.actions.createPointMode.setEnabled(True)
800827
self.actions.createLineStripMode.setEnabled(True)
801828
self.actions.autoAnnotate.setEnabled(True)
829+
self.actions.startStopAutoMode.setEnabled(True)
802830
title = __appname__
803831
if self.filename is not None:
804832
title = '{} - {}'.format(title, self.filename)
@@ -1508,6 +1536,17 @@ def loadFile(self, filename=None, reset=True):
15081536
flags.update(self.labelFile.flags)
15091537
self.loadFlags(flags)
15101538

1539+
if self.autoMode and self.tracker_dict and self._config['freeze_key_frames'] and len(self.canvas.shapes)>0:
1540+
#this frame has annotated labels - we treat it as a key frame and do not change it
1541+
self.stop_tracker()
1542+
if self.autoMode and self._config['freeze_key_frames'] and len(self.canvas.shapes)>0:
1543+
logger.info('Auto Run encountered keyframe %s'%self.filename)
1544+
selected_shapes=[]
1545+
for shape in self.canvas.shapes:
1546+
selected_shapes.append(shape)
1547+
self.canvas.selectShapes(selected_shapes)
1548+
self.start_tracker()
1549+
15111550
if self.tracker_dict:
15121551
otrack_shapes=[]
15131552
for shape in prev_shapes:
@@ -2098,3 +2137,44 @@ def autoAnnotate(self):
20982137
self.loadShapes(track_shapes, replace=False)
20992138
self.setDirty()
21002139

2140+
def startStopAutoMode(self):
2141+
if self.autoMode:
2142+
self.actions.startStopAutoMode.setChecked(False)
2143+
self.autoMode = False
2144+
logger.info('Auto Run Stopped')
2145+
else:
2146+
if not self.mayContinue():
2147+
return
2148+
self.actions.startStopAutoMode.setChecked(True)
2149+
self.autoMode = True
2150+
logger.info('Auto Run Started')
2151+
self.queueEvent(functools.partial(self.autoStep))
2152+
2153+
def stepsizeChanged(self):
2154+
self.image_skip=int(self.stepsizeWidget.value())
2155+
2156+
def autoStep(self):
2157+
if self.autoMode:
2158+
if len(self.imageList) <= 0 or self.filename == self.imageList[-1]:
2159+
self.autoMode = False
2160+
self.actions.startStopAutoMode.setChecked(False)
2161+
if self._config['auto_run']:
2162+
self.queueEvent(functools.partial(self.autoRunFin))
2163+
2164+
else:
2165+
logger.info('Auto Run: %s'%self.filename)
2166+
self._openNextImg(skip=self.image_skip)
2167+
self.queueEvent(functools.partial(self.autoStep))
2168+
2169+
def autoRun(self):
2170+
selected_shapes=[]
2171+
for shape in self.canvas.shapes:
2172+
selected_shapes.append(shape)
2173+
if len(selected_shapes):
2174+
self.canvas.selectShapes(selected_shapes)
2175+
self.actions.toggle_tracker.toggle()
2176+
self.start_tracker()
2177+
self.startStopAutoMode()
2178+
2179+
def autoRunFin(self):
2180+
self.close()

labelme/cli/convert_fps.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def main():
1414
parser.add_argument('dest_annotation_folder')
1515
parser.add_argument('--source_framerate','-sf',required=True,type=float,help="Framerate of the source annotations")
1616
parser.add_argument('--dest_framerate','-df',default=30000./1001,type=float,help="Resample to this framerate")
17-
parser.add_argument('--dest_template',default='frame_%05d',help="Frame file name template for resulting annotations")
17+
parser.add_argument('--dest_template',default='frame_%06d',help="Frame file name template for resulting annotations")
1818
parser.add_argument('--dest_image_type',default='.jpg',help="Image file name extension written in resulting annotation")
1919
args = parser.parse_args()
2020
if not os.path.isdir(args.source_annotation_folder):

labelme/cli/draw_overlay.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,12 @@ def main():
2727

2828
if data['imageData']:
2929
imageData = data['imageData']
30+
img = utils.img_b64_to_arr(imageData)
3031
else:
3132
imagePath = os.path.join(os.path.dirname(json_file), data['imagePath'])
3233
with open(imagePath, 'rb') as f:
3334
imageData = f.read()
34-
imageData = base64.b64encode(imageData).decode('utf-8')
35-
img = utils.img_b64_to_arr(imageData)
36-
35+
img = utils.img_data_to_arr(imageData)
3736
label_name_to_value = {'': 0}
3837
label_texts={0:''}
3938
for shape in sorted(data['shapes'], key=lambda x: x['label']):

labelme/config/default_config.yaml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
auto_run: false
12
auto_save: true
23
canvas:
34
double_click: null
@@ -21,7 +22,9 @@ flag_dock:
2122
show: true
2223
flagmodel: null
2324
flags: null
24-
image_skip: 15
25+
freeze_key_frames: false
26+
global_translation_track_size: 100
27+
image_skip: 1
2528
keep_prev: false
2629
keep_prev_scale: true
2730
label_colors: null
@@ -79,6 +82,7 @@ shortcuts:
7982
save: Ctrl+S
8083
save_as: Ctrl+Shift+S
8184
save_to: null
85+
startStopAutoMode: Ctrl+Space
8286
toggle_keep_prev_mode: null
8387
toggle_tracker:
8488
- Ctrl+T
@@ -94,7 +98,11 @@ shortcuts:
9498
show_label_text_field: true
9599
sort_labels: true
96100
ssd_min_resolution: 300
101+
ssd_re3_correction_alpha: 0.8
102+
ssd_re3_correction_min_iou: 0.8
103+
ssd_threshold_autoannotation: 0.15
104+
ssd_track_crop_factor: 3.0
97105
ssdmodel: null
98106
store_data: false
99107
validate_label: null
100-
version: 5.2.6
108+
version: 5.2.10

labelme/shape.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ def transform(self, T):
250250
tpoints=[]
251251
for p in self.points:
252252
tp = np.dot(T , [p.x(),p.y(), 1])
253-
qp = QtCore.QPoint(tp[0],tp[1])
253+
qp = QtCore.QPointF(tp[0],tp[1])
254254
tpoints.append(qp)
255255

256256
self.points = tpoints
@@ -302,4 +302,4 @@ def __getitem__(self, key):
302302
return self.points[key]
303303

304304
def __setitem__(self, key, value):
305-
self.points[key] = value
305+
self.points[key] = value

0 commit comments

Comments
 (0)