labelimgplusplus 2.0.0a0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
libs/utils.py ADDED
@@ -0,0 +1,119 @@
1
+ from math import sqrt
2
+ from libs.ustr import ustr
3
+ import hashlib
4
+ import re
5
+ import sys
6
+
7
+ try:
8
+ from PyQt5.QtGui import *
9
+ from PyQt5.QtCore import *
10
+ from PyQt5.QtWidgets import *
11
+ QT5 = True
12
+ except ImportError:
13
+ from PyQt4.QtGui import *
14
+ from PyQt4.QtCore import *
15
+ QT5 = False
16
+
17
+
18
+ def new_icon(icon):
19
+ return QIcon(':/' + icon)
20
+
21
+
22
+ def new_button(text, icon=None, slot=None):
23
+ b = QPushButton(text)
24
+ if icon is not None:
25
+ b.setIcon(new_icon(icon))
26
+ if slot is not None:
27
+ b.clicked.connect(slot)
28
+ return b
29
+
30
+
31
+ def new_action(parent, text, slot=None, shortcut=None, icon=None,
32
+ tip=None, checkable=False, enabled=True):
33
+ """Create a new action and assign callbacks, shortcuts, etc."""
34
+ a = QAction(text, parent)
35
+ if icon is not None:
36
+ a.setIcon(new_icon(icon))
37
+ if shortcut is not None:
38
+ if isinstance(shortcut, (list, tuple)):
39
+ a.setShortcuts(shortcut)
40
+ else:
41
+ a.setShortcut(shortcut)
42
+ if tip is not None:
43
+ a.setToolTip(tip)
44
+ a.setStatusTip(tip)
45
+ if slot is not None:
46
+ a.triggered.connect(slot)
47
+ if checkable:
48
+ a.setCheckable(True)
49
+ a.setEnabled(enabled)
50
+ return a
51
+
52
+
53
+ def add_actions(widget, actions):
54
+ for action in actions:
55
+ if action is None:
56
+ widget.addSeparator()
57
+ elif isinstance(action, QMenu):
58
+ widget.addMenu(action)
59
+ elif isinstance(action, QWidget):
60
+ widget.addWidget(action)
61
+ else:
62
+ widget.addAction(action)
63
+
64
+
65
+ def label_validator():
66
+ return QRegExpValidator(QRegExp(r'^[^ \t].+'), None)
67
+
68
+
69
+ class Struct(object):
70
+
71
+ def __init__(self, **kwargs):
72
+ self.__dict__.update(kwargs)
73
+
74
+
75
+ def distance(p):
76
+ return sqrt(p.x() * p.x() + p.y() * p.y())
77
+
78
+
79
+ def format_shortcut(text):
80
+ mod, key = text.split('+', 1)
81
+ return '<b>%s</b>+<b>%s</b>' % (mod, key)
82
+
83
+
84
+ def generate_color_by_text(text):
85
+ s = ustr(text)
86
+ hash_code = int(hashlib.sha256(s.encode('utf-8')).hexdigest(), 16)
87
+ r = int((hash_code / 255) % 255)
88
+ g = int((hash_code / 65025) % 255)
89
+ b = int((hash_code / 16581375) % 255)
90
+ return QColor(r, g, b, 100)
91
+
92
+
93
+ def have_qstring():
94
+ """p3/qt5 get rid of QString wrapper as py3 has native unicode str type"""
95
+ return not (sys.version_info.major >= 3 or QT_VERSION_STR.startswith('5.'))
96
+
97
+
98
+ def util_qt_strlistclass():
99
+ return QStringList if have_qstring() else list
100
+
101
+
102
+ def natural_sort(list, key=lambda s:s):
103
+ """
104
+ Sort the list into natural alphanumeric order.
105
+ """
106
+ def get_alphanum_key_func(key):
107
+ convert = lambda text: int(text) if text.isdigit() else text
108
+ return lambda s: [convert(c) for c in re.split('([0-9]+)', key(s))]
109
+ sort_key = get_alphanum_key_func(key)
110
+ list.sort(key=sort_key)
111
+
112
+
113
+ # QT4 has a trimmed method, in QT5 this is called strip
114
+ if QT5:
115
+ def trimmed(text):
116
+ return text.strip()
117
+ else:
118
+ def trimmed(text):
119
+ return text.trimmed()
libs/yolo_io.py ADDED
@@ -0,0 +1,143 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf8 -*-
3
+ import codecs
4
+ import os
5
+
6
+ from libs.constants import DEFAULT_ENCODING
7
+
8
+ TXT_EXT = '.txt'
9
+ ENCODE_METHOD = DEFAULT_ENCODING
10
+
11
+ class YOLOWriter:
12
+
13
+ def __init__(self, folder_name, filename, img_size, database_src='Unknown', local_img_path=None):
14
+ self.folder_name = folder_name
15
+ self.filename = filename
16
+ self.database_src = database_src
17
+ self.img_size = img_size
18
+ self.box_list = []
19
+ self.local_img_path = local_img_path
20
+ self.verified = False
21
+
22
+ def add_bnd_box(self, x_min, y_min, x_max, y_max, name, difficult):
23
+ bnd_box = {'xmin': x_min, 'ymin': y_min, 'xmax': x_max, 'ymax': y_max}
24
+ bnd_box['name'] = name
25
+ bnd_box['difficult'] = difficult
26
+ self.box_list.append(bnd_box)
27
+
28
+ def bnd_box_to_yolo_line(self, box, class_list=[]):
29
+ x_min = box['xmin']
30
+ x_max = box['xmax']
31
+ y_min = box['ymin']
32
+ y_max = box['ymax']
33
+
34
+ x_center = float((x_min + x_max)) / 2 / self.img_size[1]
35
+ y_center = float((y_min + y_max)) / 2 / self.img_size[0]
36
+
37
+ w = float((x_max - x_min)) / self.img_size[1]
38
+ h = float((y_max - y_min)) / self.img_size[0]
39
+
40
+ # PR387
41
+ box_name = box['name']
42
+ if box_name not in class_list:
43
+ class_list.append(box_name)
44
+
45
+ class_index = class_list.index(box_name)
46
+
47
+ return class_index, x_center, y_center, w, h
48
+
49
+ def save(self, class_list=[], target_file=None):
50
+
51
+ out_file = None # Update yolo .txt
52
+ out_class_file = None # Update class list .txt
53
+
54
+ if target_file is None:
55
+ out_file = open(
56
+ self.filename + TXT_EXT, 'w', encoding=ENCODE_METHOD)
57
+ classes_file = os.path.join(os.path.dirname(os.path.abspath(self.filename)), "classes.txt")
58
+ out_class_file = open(classes_file, 'w')
59
+
60
+ else:
61
+ out_file = codecs.open(target_file, 'w', encoding=ENCODE_METHOD)
62
+ classes_file = os.path.join(os.path.dirname(os.path.abspath(target_file)), "classes.txt")
63
+ out_class_file = open(classes_file, 'w')
64
+
65
+
66
+ for box in self.box_list:
67
+ class_index, x_center, y_center, w, h = self.bnd_box_to_yolo_line(box, class_list)
68
+ # print (classIndex, x_center, y_center, w, h)
69
+ out_file.write("%d %.6f %.6f %.6f %.6f\n" % (class_index, x_center, y_center, w, h))
70
+
71
+ # print (classList)
72
+ # print (out_class_file)
73
+ for c in class_list:
74
+ out_class_file.write(c+'\n')
75
+
76
+ out_class_file.close()
77
+ out_file.close()
78
+
79
+
80
+
81
+ class YoloReader:
82
+
83
+ def __init__(self, file_path, image, class_list_path=None):
84
+ # shapes type:
85
+ # [labbel, [(x1,y1), (x2,y2), (x3,y3), (x4,y4)], color, color, difficult]
86
+ self.shapes = []
87
+ self.file_path = file_path
88
+
89
+ if class_list_path is None:
90
+ dir_path = os.path.dirname(os.path.realpath(self.file_path))
91
+ self.class_list_path = os.path.join(dir_path, "classes.txt")
92
+ else:
93
+ self.class_list_path = class_list_path
94
+
95
+ # print (file_path, self.class_list_path)
96
+
97
+ classes_file = open(self.class_list_path, 'r')
98
+ self.classes = classes_file.read().strip('\n').split('\n')
99
+
100
+ # print (self.classes)
101
+
102
+ img_size = [image.height(), image.width(),
103
+ 1 if image.isGrayscale() else 3]
104
+
105
+ self.img_size = img_size
106
+
107
+ self.verified = False
108
+ # try:
109
+ self.parse_yolo_format()
110
+ # except:
111
+ # pass
112
+
113
+ def get_shapes(self):
114
+ return self.shapes
115
+
116
+ def add_shape(self, label, x_min, y_min, x_max, y_max, difficult):
117
+
118
+ points = [(x_min, y_min), (x_max, y_min), (x_max, y_max), (x_min, y_max)]
119
+ self.shapes.append((label, points, None, None, difficult))
120
+
121
+ def yolo_line_to_shape(self, class_index, x_center, y_center, w, h):
122
+ label = self.classes[int(class_index)]
123
+
124
+ x_min = max(float(x_center) - float(w) / 2, 0)
125
+ x_max = min(float(x_center) + float(w) / 2, 1)
126
+ y_min = max(float(y_center) - float(h) / 2, 0)
127
+ y_max = min(float(y_center) + float(h) / 2, 1)
128
+
129
+ x_min = round(self.img_size[1] * x_min)
130
+ x_max = round(self.img_size[1] * x_max)
131
+ y_min = round(self.img_size[0] * y_min)
132
+ y_max = round(self.img_size[0] * y_max)
133
+
134
+ return label, x_min, y_min, x_max, y_max
135
+
136
+ def parse_yolo_format(self):
137
+ bnd_box_file = open(self.file_path, 'r')
138
+ for bndBox in bnd_box_file:
139
+ class_index, x_center, y_center, w, h = bndBox.strip().split(' ')
140
+ label, x_min, y_min, x_max, y_max = self.yolo_line_to_shape(class_index, x_center, y_center, w, h)
141
+
142
+ # Caveat: difficult flag is discarded when saved as yolo format.
143
+ self.add_shape(label, x_min, y_min, x_max, y_max, False)
libs/zoomWidget.py ADDED
@@ -0,0 +1,26 @@
1
+ try:
2
+ from PyQt5.QtGui import *
3
+ from PyQt5.QtCore import *
4
+ from PyQt5.QtWidgets import *
5
+ except ImportError:
6
+ from PyQt4.QtGui import *
7
+ from PyQt4.QtCore import *
8
+
9
+
10
+ class ZoomWidget(QSpinBox):
11
+
12
+ def __init__(self, value=100):
13
+ super(ZoomWidget, self).__init__()
14
+ self.setButtonSymbols(QAbstractSpinBox.NoButtons)
15
+ self.setRange(1, 500)
16
+ self.setSuffix(' %')
17
+ self.setValue(value)
18
+ self.setToolTip(u'Zoom Level')
19
+ self.setStatusTip(self.toolTip())
20
+ self.setAlignment(Qt.AlignCenter)
21
+
22
+ def minimumSizeHint(self):
23
+ height = super(ZoomWidget, self).minimumSizeHint().height()
24
+ fm = QFontMetrics(self.font())
25
+ width = fm.width(str(self.maximum()))
26
+ return QSize(width, height)