Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
不会修仙的道士
labelme
提交
5c980844
L
labelme
项目概览
不会修仙的道士
/
labelme
与 Fork 源项目一致
从无法访问的项目Fork
通知
4
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
L
labelme
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
5c980844
编写于
6月 13, 2020
作者:
K
Kentaro Wada
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Format code with black
上级
19433fca
变更
39
展开全部
隐藏空白更改
内联
并排
Showing
39 changed file
with
1297 addition
and
1059 deletion
+1297
-1059
.flake8
.flake8
+1
-1
.github/workflows/ci.yml
.github/workflows/ci.yml
+13
-6
examples/bbox_detection/labelme2voc.py
examples/bbox_detection/labelme2voc.py
+37
-35
examples/instance_segmentation/labelme2coco.py
examples/instance_segmentation/labelme2coco.py
+51
-55
examples/instance_segmentation/labelme2voc.py
examples/instance_segmentation/labelme2voc.py
+38
-35
examples/semantic_segmentation/labelme2voc.py
examples/semantic_segmentation/labelme2voc.py
+29
-28
examples/tutorial/load_label_png.py
examples/tutorial/load_label_png.py
+9
-9
labelme/__init__.py
labelme/__init__.py
+6
-6
labelme/__main__.py
labelme/__main__.py
+71
-69
labelme/app.py
labelme/app.py
+524
-380
labelme/cli/draw_json.py
labelme/cli/draw_json.py
+6
-6
labelme/cli/draw_label_png.py
labelme/cli/draw_label_png.py
+6
-5
labelme/cli/json_to_dataset.py
labelme/cli/json_to_dataset.py
+27
-23
labelme/cli/on_docker.py
labelme/cli/on_docker.py
+36
-38
labelme/config/__init__.py
labelme/config/__init__.py
+19
-19
labelme/label_file.py
labelme/label_file.py
+48
-47
labelme/logger.py
labelme/logger.py
+12
-15
labelme/shape.py
labelme/shape.py
+36
-20
labelme/testing.py
labelme/testing.py
+10
-10
labelme/utils/_io.py
labelme/utils/_io.py
+5
-5
labelme/utils/image.py
labelme/utils/image.py
+4
-4
labelme/utils/qt.py
labelme/utils/qt.py
+17
-8
labelme/utils/shape.py
labelme/utils/shape.py
+25
-24
labelme/widgets/brightness_contrast_dialog.py
labelme/widgets/brightness_contrast_dialog.py
+10
-10
labelme/widgets/canvas.py
labelme/widgets/canvas.py
+78
-48
labelme/widgets/color_dialog.py
labelme/widgets/color_dialog.py
+4
-3
labelme/widgets/escapable_qlist_widget.py
labelme/widgets/escapable_qlist_widget.py
+0
-1
labelme/widgets/label_dialog.py
labelme/widgets/label_dialog.py
+31
-24
labelme/widgets/tool_bar.py
labelme/widgets/tool_bar.py
+0
-1
labelme/widgets/unique_label_qlist_widget.py
labelme/widgets/unique_label_qlist_widget.py
+4
-4
labelme/widgets/zoom_widget.py
labelme/widgets/zoom_widget.py
+2
-3
pyproject.toml
pyproject.toml
+10
-0
setup.py
setup.py
+64
-54
tests/docs_tests/man_tests/test_labelme_1.py
tests/docs_tests/man_tests/test_labelme_1.py
+8
-8
tests/labelme_tests/test_app.py
tests/labelme_tests/test_app.py
+20
-20
tests/labelme_tests/utils_tests/test_image.py
tests/labelme_tests/utils_tests/test_image.py
+3
-3
tests/labelme_tests/utils_tests/test_shape.py
tests/labelme_tests/utils_tests/test_shape.py
+6
-5
tests/labelme_tests/utils_tests/util.py
tests/labelme_tests/utils_tests/util.py
+7
-7
tests/labelme_tests/widgets_tests/test_label_dialog.py
tests/labelme_tests/widgets_tests/test_label_dialog.py
+20
-20
未找到文件。
.flake8
浏览文件 @
5c980844
[flake8]
exclude = .anaconda3/*
ignore = W504
ignore =
E203, E741, W503,
W504
.github/workflows/ci.yml
浏览文件 @
5c980844
...
...
@@ -56,7 +56,7 @@ jobs:
env
:
PYTHON_VERSION
:
${{ matrix.PYTHON_VERSION }}
run
:
|
conda install -y python=$PYTHON_VERSION
conda install -
q -
y python=$PYTHON_VERSION
which python
python --version
pip --version
...
...
@@ -66,17 +66,17 @@ jobs:
run
:
|
if [ "${{ matrix.PYTEST_QT_API }}" = "pyside2" ]; then
if [ "${{ matrix.PYTHON_VERSION }}" = "2.7" ]; then
conda install -y 'pyside2!=5.12.4' -c conda-forge
conda install -
q -
y 'pyside2!=5.12.4' -c conda-forge
else
conda install -y pyside2 -c conda-forge
conda install -
q -
y pyside2 -c conda-forge
fi
elif [ "${{ matrix.PYTEST_QT_API }}" = "pyqt4v2" ]; then
conda install -y pyqt=4 -c conda-forge
conda install -
q -
y pyqt=4 -c conda-forge
else # pyqt5
conda install -y pyqt=5
conda install -
q -
y pyqt=5
fi
if [ "${{ matrix.os }}" != "windows-latest" ]; then
conda install -y help2man
conda install -
q -
y help2man
fi
pip install hacking pytest pytest-qt
...
...
@@ -91,6 +91,13 @@ jobs:
run
:
|
flake8 .
-
name
:
Black
shell
:
bash -l {0}
if
:
matrix.os != 'windows-latest' && matrix.python-version != '2.7'
run
:
|
pip install black
black --check .
-
name
:
Test with pytest
shell
:
bash -l {0}
if
:
matrix.os != 'windows-latest'
...
...
examples/bbox_detection/labelme2voc.py
浏览文件 @
5c980844
...
...
@@ -10,11 +10,12 @@ import sys
import
imgviz
import
labelme
try
:
import
lxml.builder
import
lxml.etree
except
ImportError
:
print
(
'Please install lxml:
\n\n
pip install lxml
\n
'
)
print
(
"Please install lxml:
\n\n
pip install lxml
\n
"
)
sys
.
exit
(
1
)
...
...
@@ -22,23 +23,23 @@ def main():
parser
=
argparse
.
ArgumentParser
(
formatter_class
=
argparse
.
ArgumentDefaultsHelpFormatter
)
parser
.
add_argument
(
'input_dir'
,
help
=
'input annotated directory'
)
parser
.
add_argument
(
'output_dir'
,
help
=
'output dataset directory'
)
parser
.
add_argument
(
'--labels'
,
help
=
'labels file'
,
required
=
True
)
parser
.
add_argument
(
"input_dir"
,
help
=
"input annotated directory"
)
parser
.
add_argument
(
"output_dir"
,
help
=
"output dataset directory"
)
parser
.
add_argument
(
"--labels"
,
help
=
"labels file"
,
required
=
True
)
parser
.
add_argument
(
'--noviz'
,
help
=
'no visualization'
,
action
=
'store_true'
"--noviz"
,
help
=
"no visualization"
,
action
=
"store_true"
)
args
=
parser
.
parse_args
()
if
osp
.
exists
(
args
.
output_dir
):
print
(
'Output directory already exists:'
,
args
.
output_dir
)
print
(
"Output directory already exists:"
,
args
.
output_dir
)
sys
.
exit
(
1
)
os
.
makedirs
(
args
.
output_dir
)
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
'JPEGImages'
))
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
'Annotations'
))
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
"JPEGImages"
))
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
"Annotations"
))
if
not
args
.
noviz
:
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
'AnnotationsVisualization'
))
print
(
'Creating dataset:'
,
args
.
output_dir
)
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
"AnnotationsVisualization"
))
print
(
"Creating dataset:"
,
args
.
output_dir
)
class_names
=
[]
class_name_to_id
=
{}
...
...
@@ -47,31 +48,30 @@ def main():
class_name
=
line
.
strip
()
class_name_to_id
[
class_name
]
=
class_id
if
class_id
==
-
1
:
assert
class_name
==
'__ignore__'
assert
class_name
==
"__ignore__"
continue
elif
class_id
==
0
:
assert
class_name
==
'_background_'
assert
class_name
==
"_background_"
class_names
.
append
(
class_name
)
class_names
=
tuple
(
class_names
)
print
(
'class_names:'
,
class_names
)
out_class_names_file
=
osp
.
join
(
args
.
output_dir
,
'class_names.txt'
)
with
open
(
out_class_names_file
,
'w'
)
as
f
:
f
.
writelines
(
'
\n
'
.
join
(
class_names
))
print
(
'Saved class_names:'
,
out_class_names_file
)
print
(
"class_names:"
,
class_names
)
out_class_names_file
=
osp
.
join
(
args
.
output_dir
,
"class_names.txt"
)
with
open
(
out_class_names_file
,
"w"
)
as
f
:
f
.
writelines
(
"
\n
"
.
join
(
class_names
))
print
(
"Saved class_names:"
,
out_class_names_file
)
for
filename
in
glob
.
glob
(
osp
.
join
(
args
.
input_dir
,
'*.json'
)):
print
(
'Generating dataset from:'
,
filename
)
for
filename
in
glob
.
glob
(
osp
.
join
(
args
.
input_dir
,
"*.json"
)):
print
(
"Generating dataset from:"
,
filename
)
label_file
=
labelme
.
LabelFile
(
filename
=
filename
)
base
=
osp
.
splitext
(
osp
.
basename
(
filename
))[
0
]
out_img_file
=
osp
.
join
(
args
.
output_dir
,
'JPEGImages'
,
base
+
'.jpg'
)
out_xml_file
=
osp
.
join
(
args
.
output_dir
,
'Annotations'
,
base
+
'.xml'
)
out_img_file
=
osp
.
join
(
args
.
output_dir
,
"JPEGImages"
,
base
+
".jpg"
)
out_xml_file
=
osp
.
join
(
args
.
output_dir
,
"Annotations"
,
base
+
".xml"
)
if
not
args
.
noviz
:
out_viz_file
=
osp
.
join
(
args
.
output_dir
,
'AnnotationsVisualization'
,
base
+
'.jpg'
)
args
.
output_dir
,
"AnnotationsVisualization"
,
base
+
".jpg"
)
img
=
labelme
.
utils
.
img_data_to_arr
(
label_file
.
imageData
)
imgviz
.
io
.
imsave
(
out_img_file
,
img
)
...
...
@@ -79,10 +79,10 @@ def main():
maker
=
lxml
.
builder
.
ElementMaker
()
xml
=
maker
.
annotation
(
maker
.
folder
(),
maker
.
filename
(
base
+
'.jpg'
),
maker
.
database
(),
# e.g., The VOC2007 Database
maker
.
filename
(
base
+
".jpg"
),
maker
.
database
(),
# e.g., The VOC2007 Database
maker
.
annotation
(),
# e.g., Pascal VOC2007
maker
.
image
(),
# e.g., flickr
maker
.
image
(),
# e.g., flickr
maker
.
size
(
maker
.
height
(
str
(
img
.
shape
[
0
])),
maker
.
width
(
str
(
img
.
shape
[
1
])),
...
...
@@ -94,15 +94,17 @@ def main():
bboxes
=
[]
labels
=
[]
for
shape
in
label_file
.
shapes
:
if
shape
[
'shape_type'
]
!=
'rectangle'
:
print
(
'Skipping shape: label={label}, shape_type={shape_type}'
.
format
(
**
shape
))
if
shape
[
"shape_type"
]
!=
"rectangle"
:
print
(
"Skipping shape: label={label}, "
"shape_type={shape_type}"
.
format
(
**
shape
)
)
continue
class_name
=
shape
[
'label'
]
class_name
=
shape
[
"label"
]
class_id
=
class_names
.
index
(
class_name
)
(
xmin
,
ymin
),
(
xmax
,
ymax
)
=
shape
[
'points'
]
(
xmin
,
ymin
),
(
xmax
,
ymax
)
=
shape
[
"points"
]
# swap if min is larger than max.
xmin
,
xmax
=
sorted
([
xmin
,
xmax
])
ymin
,
ymax
=
sorted
([
ymin
,
ymax
])
...
...
@@ -112,7 +114,7 @@ def main():
xml
.
append
(
maker
.
object
(
maker
.
name
(
shape
[
'label'
]),
maker
.
name
(
shape
[
"label"
]),
maker
.
pose
(),
maker
.
truncated
(),
maker
.
difficult
(),
...
...
@@ -136,9 +138,9 @@ def main():
)
imgviz
.
io
.
imsave
(
out_viz_file
,
viz
)
with
open
(
out_xml_file
,
'wb'
)
as
f
:
with
open
(
out_xml_file
,
"wb"
)
as
f
:
f
.
write
(
lxml
.
etree
.
tostring
(
xml
,
pretty_print
=
True
))
if
__name__
==
'__main__'
:
if
__name__
==
"__main__"
:
main
()
examples/instance_segmentation/labelme2coco.py
浏览文件 @
5c980844
...
...
@@ -18,7 +18,7 @@ import labelme
try
:
import
pycocotools.mask
except
ImportError
:
print
(
'Please install pycocotools:
\n\n
pip install pycocotools
\n
'
)
print
(
"Please install pycocotools:
\n\n
pip install pycocotools
\n
"
)
sys
.
exit
(
1
)
...
...
@@ -26,17 +26,17 @@ def main():
parser
=
argparse
.
ArgumentParser
(
formatter_class
=
argparse
.
ArgumentDefaultsHelpFormatter
)
parser
.
add_argument
(
'input_dir'
,
help
=
'input annotated directory'
)
parser
.
add_argument
(
'output_dir'
,
help
=
'output dataset directory'
)
parser
.
add_argument
(
'--labels'
,
help
=
'labels file'
,
required
=
True
)
parser
.
add_argument
(
"input_dir"
,
help
=
"input annotated directory"
)
parser
.
add_argument
(
"output_dir"
,
help
=
"output dataset directory"
)
parser
.
add_argument
(
"--labels"
,
help
=
"labels file"
,
required
=
True
)
args
=
parser
.
parse_args
()
if
osp
.
exists
(
args
.
output_dir
):
print
(
'Output directory already exists:'
,
args
.
output_dir
)
print
(
"Output directory already exists:"
,
args
.
output_dir
)
sys
.
exit
(
1
)
os
.
makedirs
(
args
.
output_dir
)
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
'JPEGImages'
))
print
(
'Creating dataset:'
,
args
.
output_dir
)
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
"JPEGImages"
))
print
(
"Creating dataset:"
,
args
.
output_dir
)
now
=
datetime
.
datetime
.
now
()
...
...
@@ -47,17 +47,13 @@ def main():
version
=
None
,
year
=
now
.
year
,
contributor
=
None
,
date_created
=
now
.
strftime
(
'%Y-%m-%d %H:%M:%S.%f'
),
date_created
=
now
.
strftime
(
"%Y-%m-%d %H:%M:%S.%f"
),
),
licenses
=
[
dict
(
url
=
None
,
id
=
0
,
name
=
None
,
)],
licenses
=
[
dict
(
url
=
None
,
id
=
0
,
name
=
None
,)],
images
=
[
# license, url, file_name, height, width, date_captured, id
],
type
=
'instances'
,
type
=
"instances"
,
annotations
=
[
# segmentation, area, iscrowd, image_id, bbox, category_id, id
],
...
...
@@ -71,46 +67,44 @@ def main():
class_id
=
i
-
1
# starts with -1
class_name
=
line
.
strip
()
if
class_id
==
-
1
:
assert
class_name
==
'__ignore__'
assert
class_name
==
"__ignore__"
continue
class_name_to_id
[
class_name
]
=
class_id
data
[
'categories'
].
append
(
dict
(
supercategory
=
None
,
id
=
class_id
,
name
=
class_name
,
))
out_ann_file
=
osp
.
join
(
args
.
output_dir
,
'annotations.json'
)
label_files
=
glob
.
glob
(
osp
.
join
(
args
.
input_dir
,
'*.json'
))
data
[
"categories"
].
append
(
dict
(
supercategory
=
None
,
id
=
class_id
,
name
=
class_name
,)
)
out_ann_file
=
osp
.
join
(
args
.
output_dir
,
"annotations.json"
)
label_files
=
glob
.
glob
(
osp
.
join
(
args
.
input_dir
,
"*.json"
))
for
image_id
,
filename
in
enumerate
(
label_files
):
print
(
'Generating dataset from:'
,
filename
)
print
(
"Generating dataset from:"
,
filename
)
label_file
=
labelme
.
LabelFile
(
filename
=
filename
)
base
=
osp
.
splitext
(
osp
.
basename
(
filename
))[
0
]
out_img_file
=
osp
.
join
(
args
.
output_dir
,
'JPEGImages'
,
base
+
'.jpg'
)
out_img_file
=
osp
.
join
(
args
.
output_dir
,
"JPEGImages"
,
base
+
".jpg"
)
img
=
labelme
.
utils
.
img_data_to_arr
(
label_file
.
imageData
)
PIL
.
Image
.
fromarray
(
img
).
convert
(
"RGB"
).
save
(
out_img_file
)
data
[
'images'
].
append
(
dict
(
license
=
0
,
url
=
None
,
file_name
=
osp
.
relpath
(
out_img_file
,
osp
.
dirname
(
out_ann_file
)),
height
=
img
.
shape
[
0
],
width
=
img
.
shape
[
1
],
date_captured
=
None
,
id
=
image_id
,
))
masks
=
{}
# for area
data
[
"images"
].
append
(
dict
(
license
=
0
,
url
=
None
,
file_name
=
osp
.
relpath
(
out_img_file
,
osp
.
dirname
(
out_ann_file
)),
height
=
img
.
shape
[
0
],
width
=
img
.
shape
[
1
],
date_captured
=
None
,
id
=
image_id
,
)
)
masks
=
{}
# for area
segmentations
=
collections
.
defaultdict
(
list
)
# for segmentation
for
shape
in
label_file
.
shapes
:
points
=
shape
[
'points'
]
label
=
shape
[
'label'
]
group_id
=
shape
.
get
(
'group_id'
)
shape_type
=
shape
.
get
(
'shape_type'
,
'polygon'
)
points
=
shape
[
"points"
]
label
=
shape
[
"label"
]
group_id
=
shape
.
get
(
"group_id"
)
shape_type
=
shape
.
get
(
"shape_type"
,
"polygon"
)
mask
=
labelme
.
utils
.
shape_to_mask
(
img
.
shape
[:
2
],
points
,
shape_type
)
...
...
@@ -125,7 +119,7 @@ def main():
else
:
masks
[
instance
]
=
mask
if
shape_type
==
'rectangle'
:
if
shape_type
==
"rectangle"
:
(
x1
,
y1
),
(
x2
,
y2
)
=
points
x1
,
x2
=
sorted
([
x1
,
x2
])
y1
,
y2
=
sorted
([
y1
,
y2
])
...
...
@@ -147,19 +141,21 @@ def main():
area
=
float
(
pycocotools
.
mask
.
area
(
mask
))
bbox
=
pycocotools
.
mask
.
toBbox
(
mask
).
flatten
().
tolist
()
data
[
'annotations'
].
append
(
dict
(
id
=
len
(
data
[
'annotations'
]),
image_id
=
image_id
,
category_id
=
cls_id
,
segmentation
=
segmentations
[
instance
],
area
=
area
,
bbox
=
bbox
,
iscrowd
=
0
,
))
with
open
(
out_ann_file
,
'w'
)
as
f
:
data
[
"annotations"
].
append
(
dict
(
id
=
len
(
data
[
"annotations"
]),
image_id
=
image_id
,
category_id
=
cls_id
,
segmentation
=
segmentations
[
instance
],
area
=
area
,
bbox
=
bbox
,
iscrowd
=
0
,
)
)
with
open
(
out_ann_file
,
"w"
)
as
f
:
json
.
dump
(
data
,
f
)
if
__name__
==
'__main__'
:
if
__name__
==
"__main__"
:
main
()
examples/instance_segmentation/labelme2voc.py
浏览文件 @
5c980844
...
...
@@ -18,32 +18,32 @@ def main():
parser
=
argparse
.
ArgumentParser
(
formatter_class
=
argparse
.
ArgumentDefaultsHelpFormatter
)
parser
.
add_argument
(
'input_dir'
,
help
=
'input annotated directory'
)
parser
.
add_argument
(
'output_dir'
,
help
=
'output dataset directory'
)
parser
.
add_argument
(
'--labels'
,
help
=
'labels file'
,
required
=
True
)
parser
.
add_argument
(
"input_dir"
,
help
=
"input annotated directory"
)
parser
.
add_argument
(
"output_dir"
,
help
=
"output dataset directory"
)
parser
.
add_argument
(
"--labels"
,
help
=
"labels file"
,
required
=
True
)
parser
.
add_argument
(
'--noviz'
,
help
=
'no visualization'
,
action
=
'store_true'
"--noviz"
,
help
=
"no visualization"
,
action
=
"store_true"
)
args
=
parser
.
parse_args
()
if
osp
.
exists
(
args
.
output_dir
):
print
(
'Output directory already exists:'
,
args
.
output_dir
)
print
(
"Output directory already exists:"
,
args
.
output_dir
)
sys
.
exit
(
1
)
os
.
makedirs
(
args
.
output_dir
)
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
'JPEGImages'
))
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
'SegmentationClass'
))
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
'SegmentationClassPNG'
))
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
"JPEGImages"
))
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
"SegmentationClass"
))
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
"SegmentationClassPNG"
))
if
not
args
.
noviz
:
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
'SegmentationClassVisualization'
)
osp
.
join
(
args
.
output_dir
,
"SegmentationClassVisualization"
)
)
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
'SegmentationObject'
))
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
'SegmentationObjectPNG'
))
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
"SegmentationObject"
))
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
"SegmentationObjectPNG"
))
if
not
args
.
noviz
:
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
'SegmentationObjectVisualization'
)
osp
.
join
(
args
.
output_dir
,
"SegmentationObjectVisualization"
)
)
print
(
'Creating dataset:'
,
args
.
output_dir
)
print
(
"Creating dataset:"
,
args
.
output_dir
)
class_names
=
[]
class_name_to_id
=
{}
...
...
@@ -52,45 +52,48 @@ def main():
class_name
=
line
.
strip
()
class_name_to_id
[
class_name
]
=
class_id
if
class_id
==
-
1
:
assert
class_name
==
'__ignore__'
assert
class_name
==
"__ignore__"
continue
elif
class_id
==
0
:
assert
class_name
==
'_background_'
assert
class_name
==
"_background_"
class_names
.
append
(
class_name
)
class_names
=
tuple
(
class_names
)
print
(
'class_names:'
,
class_names
)
out_class_names_file
=
osp
.
join
(
args
.
output_dir
,
'class_names.txt'
)
with
open
(
out_class_names_file
,
'w'
)
as
f
:
f
.
writelines
(
'
\n
'
.
join
(
class_names
))
print
(
'Saved class_names:'
,
out_class_names_file
)
print
(
"class_names:"
,
class_names
)
out_class_names_file
=
osp
.
join
(
args
.
output_dir
,
"class_names.txt"
)
with
open
(
out_class_names_file
,
"w"
)
as
f
:
f
.
writelines
(
"
\n
"
.
join
(
class_names
))
print
(
"Saved class_names:"
,
out_class_names_file
)
for
filename
in
glob
.
glob
(
osp
.
join
(
args
.
input_dir
,
'*.json'
)):
print
(
'Generating dataset from:'
,
filename
)
for
filename
in
glob
.
glob
(
osp
.
join
(
args
.
input_dir
,
"*.json"
)):
print
(
"Generating dataset from:"
,
filename
)
label_file
=
labelme
.
LabelFile
(
filename
=
filename
)
base
=
osp
.
splitext
(
osp
.
basename
(
filename
))[
0
]
out_img_file
=
osp
.
join
(
args
.
output_dir
,
'JPEGImages'
,
base
+
'.jpg'
)
out_img_file
=
osp
.
join
(
args
.
output_dir
,
"JPEGImages"
,
base
+
".jpg"
)
out_cls_file
=
osp
.
join
(
args
.
output_dir
,
'SegmentationClass'
,
base
+
'.npy'
)
args
.
output_dir
,
"SegmentationClass"
,
base
+
".npy"
)
out_clsp_file
=
osp
.
join
(
args
.
output_dir
,
'SegmentationClassPNG'
,
base
+
'.png'
)
args
.
output_dir
,
"SegmentationClassPNG"
,
base
+
".png"
)
if
not
args
.
noviz
:
out_clsv_file
=
osp
.
join
(
args
.
output_dir
,
'SegmentationClassVisualization'
,
base
+
'.jpg'
,
"SegmentationClassVisualization"
,
base
+
".jpg"
,
)
out_ins_file
=
osp
.
join
(
args
.
output_dir
,
'SegmentationObject'
,
base
+
'.npy'
)
args
.
output_dir
,
"SegmentationObject"
,
base
+
".npy"
)
out_insp_file
=
osp
.
join
(
args
.
output_dir
,
'SegmentationObjectPNG'
,
base
+
'.png'
)
args
.
output_dir
,
"SegmentationObjectPNG"
,
base
+
".png"
)
if
not
args
.
noviz
:
out_insv_file
=
osp
.
join
(
args
.
output_dir
,
'SegmentationObjectVisualization'
,
base
+
'.jpg'
,
"SegmentationObjectVisualization"
,
base
+
".jpg"
,
)
img
=
labelme
.
utils
.
img_data_to_arr
(
label_file
.
imageData
)
...
...
@@ -112,7 +115,7 @@ def main():
img
=
imgviz
.
rgb2gray
(
img
),
label_names
=
class_names
,
font_size
=
15
,
loc
=
'rb'
,
loc
=
"rb"
,
)
imgviz
.
io
.
imsave
(
out_clsv_file
,
clsv
)
...
...
@@ -127,10 +130,10 @@ def main():
img
=
imgviz
.
rgb2gray
(
img
),
label_names
=
instance_names
,
font_size
=
15
,
loc
=
'rb'
,
loc
=
"rb"
,
)
imgviz
.
io
.
imsave
(
out_insv_file
,
insv
)
if
__name__
==
'__main__'
:
if
__name__
==
"__main__"
:
main
()
examples/semantic_segmentation/labelme2voc.py
浏览文件 @
5c980844
...
...
@@ -18,26 +18,26 @@ def main():
parser
=
argparse
.
ArgumentParser
(
formatter_class
=
argparse
.
ArgumentDefaultsHelpFormatter
)
parser
.
add_argument
(
'input_dir'
,
help
=
'input annotated directory'
)
parser
.
add_argument
(
'output_dir'
,
help
=
'output dataset directory'
)
parser
.
add_argument
(
'--labels'
,
help
=
'labels file'
,
required
=
True
)
parser
.
add_argument
(
"input_dir"
,
help
=
"input annotated directory"
)
parser
.
add_argument
(
"output_dir"
,
help
=
"output dataset directory"
)
parser
.
add_argument
(
"--labels"
,
help
=
"labels file"
,
required
=
True
)
parser
.
add_argument
(
'--noviz'
,
help
=
'no visualization'
,
action
=
'store_true'
"--noviz"
,
help
=
"no visualization"
,
action
=
"store_true"
)
args
=
parser
.
parse_args
()
if
osp
.
exists
(
args
.
output_dir
):
print
(
'Output directory already exists:'
,
args
.
output_dir
)
print
(
"Output directory already exists:"
,
args
.
output_dir
)
sys
.
exit
(
1
)
os
.
makedirs
(
args
.
output_dir
)
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
'JPEGImages'
))
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
'SegmentationClass'
))
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
'SegmentationClassPNG'
))
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
"JPEGImages"
))
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
"SegmentationClass"
))
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
"SegmentationClassPNG"
))
if
not
args
.
noviz
:
os
.
makedirs
(
osp
.
join
(
args
.
output_dir
,
'SegmentationClassVisualization'
)
osp
.
join
(
args
.
output_dir
,
"SegmentationClassVisualization"
)
)
print
(
'Creating dataset:'
,
args
.
output_dir
)
print
(
"Creating dataset:"
,
args
.
output_dir
)
class_names
=
[]
class_name_to_id
=
{}
...
...
@@ -46,38 +46,39 @@ def main():
class_name
=
line
.
strip
()
class_name_to_id
[
class_name
]
=
class_id
if
class_id
==
-
1
:
assert
class_name
==
'__ignore__'
assert
class_name
==
"__ignore__"
continue
elif
class_id
==
0
:
assert
class_name
==
'_background_'
assert
class_name
==
"_background_"
class_names
.
append
(
class_name
)
class_names
=
tuple
(
class_names
)
print
(
'class_names:'
,
class_names
)
out_class_names_file
=
osp
.
join
(
args
.
output_dir
,
'class_names.txt'
)
with
open
(
out_class_names_file
,
'w'
)
as
f
:
f
.
writelines
(
'
\n
'
.
join
(
class_names
))
print
(
'Saved class_names:'
,
out_class_names_file
)
print
(
"class_names:"
,
class_names
)
out_class_names_file
=
osp
.
join
(
args
.
output_dir
,
"class_names.txt"
)
with
open
(
out_class_names_file
,
"w"
)
as
f
:
f
.
writelines
(
"
\n
"
.
join
(
class_names
))
print
(
"Saved class_names:"
,
out_class_names_file
)
for
filename
in
glob
.
glob
(
osp
.
join
(
args
.
input_dir
,
'*.json'
)):
print
(
'Generating dataset from:'
,
filename
)
for
filename
in
glob
.
glob
(
osp
.
join
(
args
.
input_dir
,
"*.json"
)):
print
(
"Generating dataset from:"
,
filename
)
label_file
=
labelme
.
LabelFile
(
filename
=
filename
)
base
=
osp
.
splitext
(
osp
.
basename
(
filename
))[
0
]
out_img_file
=
osp
.
join
(
args
.
output_dir
,
'JPEGImages'
,
base
+
'.jpg'
)
out_img_file
=
osp
.
join
(
args
.
output_dir
,
"JPEGImages"
,
base
+
".jpg"
)
out_lbl_file
=
osp
.
join
(
args
.
output_dir
,
'SegmentationClass'
,
base
+
'.npy'
)
args
.
output_dir
,
"SegmentationClass"
,
base
+
".npy"
)
out_png_file
=
osp
.
join
(
args
.
output_dir
,
'SegmentationClassPNG'
,
base
+
'.png'
)
args
.
output_dir
,
"SegmentationClassPNG"
,
base
+
".png"
)
if
not
args
.
noviz
:
out_viz_file
=
osp
.
join
(
args
.
output_dir
,
'SegmentationClassVisualization'
,
base
+
'.jpg'
,
"SegmentationClassVisualization"
,
base
+
".jpg"
,
)
with
open
(
out_img_file
,
'wb'
)
as
f
:
with
open
(
out_img_file
,
"wb"
)
as
f
:
f
.
write
(
label_file
.
imageData
)
img
=
labelme
.
utils
.
img_data_to_arr
(
label_file
.
imageData
)
...
...
@@ -96,10 +97,10 @@ def main():
img
=
imgviz
.
rgb2gray
(
img
),
font_size
=
15
,
label_names
=
class_names
,
loc
=
'rb'
,
loc
=
"rb"
,
)
imgviz
.
io
.
imsave
(
out_viz_file
,
viz
)
if
__name__
==
'__main__'
:
if
__name__
==
"__main__"
:
main
()
examples/tutorial/load_label_png.py
浏览文件 @
5c980844
...
...
@@ -12,26 +12,26 @@ here = osp.dirname(osp.abspath(__file__))
def
main
():
label_png
=
osp
.
join
(
here
,
'apc2016_obj3_json/label.png'
)
print
(
'Loading:'
,
label_png
)
label_png
=
osp
.
join
(
here
,
"apc2016_obj3_json/label.png"
)
print
(
"Loading:"
,
label_png
)
print
()
lbl
=
np
.
asarray
(
PIL
.
Image
.
open
(
label_png
))
labels
=
np
.
unique
(
lbl
)
label_names_txt
=
osp
.
join
(
here
,
'apc2016_obj3_json/label_names.txt'
)
label_names_txt
=
osp
.
join
(
here
,
"apc2016_obj3_json/label_names.txt"
)
label_names
=
[
name
.
strip
()
for
name
in
open
(
label_names_txt
)]
print
(
'# of labels:'
,
len
(
labels
))
print
(
'# of label_names:'
,
len
(
label_names
))
print
(
"# of labels:"
,
len
(
labels
))
print
(
"# of label_names:"
,
len
(
label_names
))
if
len
(
labels
)
!=
len
(
label_names
):
print
(
'Number of unique labels and label_names must be same.'
)
print
(
"Number of unique labels and label_names must be same."
)
quit
(
1
)
print
()
print
(
'label: label_name'
)
print
(
"label: label_name"
)
for
label
,
label_name
in
zip
(
labels
,
label_names
):
print
(
'%d: %s'
%
(
label
,
label_name
))
print
(
"%d: %s"
%
(
label
,
label_name
))
if
__name__
==
'__main__'
:
if
__name__
==
"__main__"
:
main
()
labelme/__init__.py
浏览文件 @
5c980844
...
...
@@ -6,20 +6,20 @@ import sys
from
qtpy
import
QT_VERSION
__appname__
=
'labelme'
__appname__
=
"labelme"
# Semantic Versioning 2.0.0: https://semver.org/
# 1. MAJOR version when you make incompatible API changes;
# 2. MINOR version when you add functionality in a backwards-compatible manner;
# 3. PATCH version when you make backwards-compatible bug fixes.
__version__
=
'4.4.0'
__version__
=
"4.4.0"
QT4
=
QT_VERSION
[
0
]
==
'4'
QT5
=
QT_VERSION
[
0
]
==
'5'
QT4
=
QT_VERSION
[
0
]
==
"4"
QT5
=
QT_VERSION
[
0
]
==
"5"
del
QT_VERSION
PY2
=
sys
.
version
[
0
]
==
'2'
PY3
=
sys
.
version
[
0
]
==
'3'
PY2
=
sys
.
version
[
0
]
==
"2"
PY3
=
sys
.
version
[
0
]
==
"3"
del
sys
from
labelme.label_file
import
LabelFile
...
...
labelme/__main__.py
浏览文件 @
5c980844
...
...
@@ -20,140 +20,142 @@ from labelme.utils import newIcon
def
main
():
parser
=
argparse
.
ArgumentParser
()
parser
.
add_argument
(
'--version'
,
'-V'
,
action
=
'store_true'
,
help
=
'show version'
"--version"
,
"-V"
,
action
=
"store_true"
,
help
=
"show version"
)
parser
.
add_argument
(
'--reset-config'
,
action
=
'store_true'
,
help
=
'reset qt config'
"--reset-config"
,
action
=
"store_true"
,
help
=
"reset qt config"
)
parser
.
add_argument
(
'--logger-level'
,
default
=
'info'
,
choices
=
[
'debug'
,
'info'
,
'warning'
,
'fatal'
,
'error'
],
help
=
'logger level'
,
"--logger-level"
,
default
=
"info"
,
choices
=
[
"debug"
,
"info"
,
"warning"
,
"fatal"
,
"error"
],
help
=
"logger level"
,
)
parser
.
add_argument
(
'filename'
,
nargs
=
'?'
,
help
=
'image or label filename'
)
parser
.
add_argument
(
"filename"
,
nargs
=
"?"
,
help
=
"image or label filename"
)
parser
.
add_argument
(
'--output'
,
'-O'
,
'-o'
,
help
=
'output file or directory (if it ends with .json it is '
'recognized as file, else as directory)'
"--output"
,
"-O"
,
"-o"
,
help
=
"output file or directory (if it ends with .json it is "
"recognized as file, else as directory)"
,
)
default_config_file
=
os
.
path
.
join
(
os
.
path
.
expanduser
(
'~'
),
'.labelmerc'
)
default_config_file
=
os
.
path
.
join
(
os
.
path
.
expanduser
(
"~"
),
".labelmerc"
)
parser
.
add_argument
(
'--config'
,
dest
=
'config'
,
help
=
'config file or yaml-format string (default: {})'
.
format
(
"--config"
,
dest
=
"config"
,
help
=
"config file or yaml-format string (default: {})"
.
format
(
default_config_file
),
default
=
default_config_file
,
)
# config for the gui
parser
.
add_argument
(
'--nodata'
,
dest
=
'store_data'
,
action
=
'store_false'
,
help
=
'stop storing image data to JSON file'
,
"--nodata"
,
dest
=
"store_data"
,
action
=
"store_false"
,
help
=
"stop storing image data to JSON file"
,
default
=
argparse
.
SUPPRESS
,
)
parser
.
add_argument
(
'--autosave'
,
dest
=
'auto_save'
,
action
=
'store_true'
,
help
=
'auto save'
,
"--autosave"
,
dest
=
"auto_save"
,
action
=
"store_true"
,
help
=
"auto save"
,
default
=
argparse
.
SUPPRESS
,
)
parser
.
add_argument
(
'--nosortlabels'
,
dest
=
'sort_labels'
,
action
=
'store_false'
,
help
=
'stop sorting labels'
,
"--nosortlabels"
,
dest
=
"sort_labels"
,
action
=
"store_false"
,
help
=
"stop sorting labels"
,
default
=
argparse
.
SUPPRESS
,
)
parser
.
add_argument
(
'--flags'
,
help
=
'comma separated list of flags OR file containing flags'
,
"--flags"
,
help
=
"comma separated list of flags OR file containing flags"
,
default
=
argparse
.
SUPPRESS
,
)
parser
.
add_argument
(
'--labelflags'
,
dest
=
'label_flags'
,
help
=
r
'yaml string of label specific flags OR file containing json '
r
'string of label specific flags (ex. {person-\d+: [male, tall], '
r
'dog-\d+: [black, brown, white], .*: [occluded]})'
,
# NOQA
"--labelflags"
,
dest
=
"label_flags"
,
help
=
r
"yaml string of label specific flags OR file containing json "
r
"string of label specific flags (ex. {person-\d+: [male, tall], "
r
"dog-\d+: [black, brown, white], .*: [occluded]})"
,
# NOQA
default
=
argparse
.
SUPPRESS
,
)
parser
.
add_argument
(
'--labels'
,
help
=
'comma separated list of labels OR file containing labels'
,
"--labels"
,
help
=
"comma separated list of labels OR file containing labels"
,
default
=
argparse
.
SUPPRESS
,
)
parser
.
add_argument
(
'--validatelabel'
,
dest
=
'validate_label'
,
choices
=
[
'exact'
],
help
=
'label validation types'
,
"--validatelabel"
,
dest
=
"validate_label"
,
choices
=
[
"exact"
],
help
=
"label validation types"
,
default
=
argparse
.
SUPPRESS
,
)
parser
.
add_argument
(
'--keep-prev'
,
action
=
'store_true'
,
help
=
'keep annotation of previous frame'
,
"--keep-prev"
,
action
=
"store_true"
,
help
=
"keep annotation of previous frame"
,
default
=
argparse
.
SUPPRESS
,
)
parser
.
add_argument
(
'--epsilon'
,
"--epsilon"
,
type
=
float
,
help
=
'epsilon to find nearest vertex on canvas'
,
help
=
"epsilon to find nearest vertex on canvas"
,
default
=
argparse
.
SUPPRESS
,
)
args
=
parser
.
parse_args
()
if
args
.
version
:
print
(
'{0} {1}'
.
format
(
__appname__
,
__version__
))
print
(
"{0} {1}"
.
format
(
__appname__
,
__version__
))
sys
.
exit
(
0
)
logger
.
setLevel
(
getattr
(
logging
,
args
.
logger_level
.
upper
()))
if
hasattr
(
args
,
'flags'
):
if
hasattr
(
args
,
"flags"
):
if
os
.
path
.
isfile
(
args
.
flags
):
with
codecs
.
open
(
args
.
flags
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
with
codecs
.
open
(
args
.
flags
,
"r"
,
encoding
=
"utf-8"
)
as
f
:
args
.
flags
=
[
line
.
strip
()
for
line
in
f
if
line
.
strip
()]
else
:
args
.
flags
=
[
line
for
line
in
args
.
flags
.
split
(
','
)
if
line
]
args
.
flags
=
[
line
for
line
in
args
.
flags
.
split
(
","
)
if
line
]
if
hasattr
(
args
,
'labels'
):
if
hasattr
(
args
,
"labels"
):
if
os
.
path
.
isfile
(
args
.
labels
):
with
codecs
.
open
(
args
.
labels
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
with
codecs
.
open
(
args
.
labels
,
"r"
,
encoding
=
"utf-8"
)
as
f
:
args
.
labels
=
[
line
.
strip
()
for
line
in
f
if
line
.
strip
()]
else
:
args
.
labels
=
[
line
for
line
in
args
.
labels
.
split
(
','
)
if
line
]
args
.
labels
=
[
line
for
line
in
args
.
labels
.
split
(
","
)
if
line
]
if
hasattr
(
args
,
'label_flags'
):
if
hasattr
(
args
,
"label_flags"
):
if
os
.
path
.
isfile
(
args
.
label_flags
):
with
codecs
.
open
(
args
.
label_flags
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
with
codecs
.
open
(
args
.
label_flags
,
"r"
,
encoding
=
"utf-8"
)
as
f
:
args
.
label_flags
=
yaml
.
safe_load
(
f
)
else
:
args
.
label_flags
=
yaml
.
safe_load
(
args
.
label_flags
)
config_from_args
=
args
.
__dict__
config_from_args
.
pop
(
'version'
)
reset_config
=
config_from_args
.
pop
(
'reset_config'
)
filename
=
config_from_args
.
pop
(
'filename'
)
output
=
config_from_args
.
pop
(
'output'
)
config_file_or_yaml
=
config_from_args
.
pop
(
'config'
)
config_from_args
.
pop
(
"version"
)
reset_config
=
config_from_args
.
pop
(
"reset_config"
)
filename
=
config_from_args
.
pop
(
"filename"
)
output
=
config_from_args
.
pop
(
"output"
)
config_file_or_yaml
=
config_from_args
.
pop
(
"config"
)
config
=
get_config
(
config_file_or_yaml
,
config_from_args
)
if
not
config
[
'labels'
]
and
config
[
'validate_label'
]:
logger
.
error
(
'--labels must be specified with --validatelabel or '
'validate_label: true in the config file '
'(ex. ~/.labelmerc).'
)
if
not
config
[
"labels"
]
and
config
[
"validate_label"
]:
logger
.
error
(
"--labels must be specified with --validatelabel or "
"validate_label: true in the config file "
"(ex. ~/.labelmerc)."
)
sys
.
exit
(
1
)
output_file
=
None
output_dir
=
None
if
output
is
not
None
:
if
output
.
endswith
(
'.json'
):
if
output
.
endswith
(
".json"
):
output_file
=
output
else
:
output_dir
=
output
...
...
@@ -161,11 +163,11 @@ def main():
translator
=
QtCore
.
QTranslator
()
translator
.
load
(
QtCore
.
QLocale
.
system
().
name
(),
osp
.
dirname
(
osp
.
abspath
(
__file__
))
+
'/translate'
osp
.
dirname
(
osp
.
abspath
(
__file__
))
+
"/translate"
,
)
app
=
QtWidgets
.
QApplication
(
sys
.
argv
)
app
.
setApplicationName
(
__appname__
)
app
.
setWindowIcon
(
newIcon
(
'icon'
))
app
.
setWindowIcon
(
newIcon
(
"icon"
))
app
.
installTranslator
(
translator
)
win
=
MainWindow
(
config
=
config
,
...
...
@@ -175,7 +177,7 @@ def main():
)
if
reset_config
:
logger
.
info
(
'Resetting Qt config: %s'
%
win
.
settings
.
fileName
())
logger
.
info
(
"Resetting Qt config: %s"
%
win
.
settings
.
fileName
())
win
.
settings
.
clear
()
sys
.
exit
(
0
)
...
...
@@ -185,5 +187,5 @@ def main():
# this main block is required to generate executable by pyinstaller
if
__name__
==
'__main__'
:
if
__name__
==
"__main__"
:
main
()
labelme/app.py
浏览文件 @
5c980844
此差异已折叠。
点击以展开。
labelme/cli/draw_json.py
浏览文件 @
5c980844
...
...
@@ -15,15 +15,15 @@ PY2 = sys.version_info[0] == 2
def
main
():
parser
=
argparse
.
ArgumentParser
()
parser
.
add_argument
(
'json_file'
)
parser
.
add_argument
(
"json_file"
)
args
=
parser
.
parse_args
()
label_file
=
LabelFile
(
args
.
json_file
)
img
=
utils
.
img_data_to_arr
(
label_file
.
imageData
)
label_name_to_value
=
{
'_background_'
:
0
}
for
shape
in
sorted
(
label_file
.
shapes
,
key
=
lambda
x
:
x
[
'label'
]):
label_name
=
shape
[
'label'
]
label_name_to_value
=
{
"_background_"
:
0
}
for
shape
in
sorted
(
label_file
.
shapes
,
key
=
lambda
x
:
x
[
"label"
]):
label_name
=
shape
[
"label"
]
if
label_name
in
label_name_to_value
:
label_value
=
label_name_to_value
[
label_name
]
else
:
...
...
@@ -41,7 +41,7 @@ def main():
img
=
imgviz
.
asgray
(
img
),
label_names
=
label_names
,
font_size
=
30
,
loc
=
'rb'
,
loc
=
"rb"
,
)
plt
.
subplot
(
121
)
...
...
@@ -51,5 +51,5 @@ def main():
plt
.
show
()
if
__name__
==
'__main__'
:
if
__name__
==
"__main__"
:
main
()
labelme/cli/draw_label_png.py
浏览文件 @
5c980844
...
...
@@ -10,19 +10,20 @@ from labelme.logger import logger
def
main
():
parser
=
argparse
.
ArgumentParser
(
formatter_class
=
argparse
.
ArgumentDefaultsHelpFormatter
)
parser
.
add_argument
(
'label_png'
,
help
=
'label PNG file'
)
formatter_class
=
argparse
.
ArgumentDefaultsHelpFormatter
)
parser
.
add_argument
(
"label_png"
,
help
=
"label PNG file"
)
args
=
parser
.
parse_args
()
lbl
=
np
.
asarray
(
PIL
.
Image
.
open
(
args
.
label_png
))
logger
.
info
(
'label shape: {}'
.
format
(
lbl
.
shape
))
logger
.
info
(
'unique label values: {}'
.
format
(
np
.
unique
(
lbl
)))
logger
.
info
(
"label shape: {}"
.
format
(
lbl
.
shape
))
logger
.
info
(
"unique label values: {}"
.
format
(
np
.
unique
(
lbl
)))
lbl_viz
=
imgviz
.
label2rgb
(
lbl
)
plt
.
imshow
(
lbl_viz
)
plt
.
show
()
if
__name__
==
'__main__'
:
if
__name__
==
"__main__"
:
main
()
labelme/cli/json_to_dataset.py
浏览文件 @
5c980844
...
...
@@ -12,20 +12,24 @@ from labelme import utils
def
main
():
logger
.
warning
(
'This script is aimed to demonstrate how to convert the '
'JSON file to a single image dataset.'
)
logger
.
warning
(
"It won't handle multiple JSON files to generate a "
"real-use dataset."
)
logger
.
warning
(
"This script is aimed to demonstrate how to convert the "
"JSON file to a single image dataset."
)
logger
.
warning
(
"It won't handle multiple JSON files to generate a "
"real-use dataset."
)
parser
=
argparse
.
ArgumentParser
()
parser
.
add_argument
(
'json_file'
)
parser
.
add_argument
(
'-o'
,
'--out'
,
default
=
None
)
parser
.
add_argument
(
"json_file"
)
parser
.
add_argument
(
"-o"
,
"--out"
,
default
=
None
)
args
=
parser
.
parse_args
()
json_file
=
args
.
json_file
if
args
.
out
is
None
:
out_dir
=
osp
.
basename
(
json_file
).
replace
(
'.'
,
'_'
)
out_dir
=
osp
.
basename
(
json_file
).
replace
(
"."
,
"_"
)
out_dir
=
osp
.
join
(
osp
.
dirname
(
json_file
),
out_dir
)
else
:
out_dir
=
args
.
out
...
...
@@ -33,25 +37,25 @@ def main():
os
.
mkdir
(
out_dir
)
data
=
json
.
load
(
open
(
json_file
))
imageData
=
data
.
get
(
'imageData'
)
imageData
=
data
.
get
(
"imageData"
)
if
not
imageData
:
imagePath
=
os
.
path
.
join
(
os
.
path
.
dirname
(
json_file
),
data
[
'imagePath'
])
with
open
(
imagePath
,
'rb'
)
as
f
:
imagePath
=
os
.
path
.
join
(
os
.
path
.
dirname
(
json_file
),
data
[
"imagePath"
])
with
open
(
imagePath
,
"rb"
)
as
f
:
imageData
=
f
.
read
()
imageData
=
base64
.
b64encode
(
imageData
).
decode
(
'utf-8'
)
imageData
=
base64
.
b64encode
(
imageData
).
decode
(
"utf-8"
)
img
=
utils
.
img_b64_to_arr
(
imageData
)
label_name_to_value
=
{
'_background_'
:
0
}
for
shape
in
sorted
(
data
[
'shapes'
],
key
=
lambda
x
:
x
[
'label'
]):
label_name
=
shape
[
'label'
]
label_name_to_value
=
{
"_background_"
:
0
}
for
shape
in
sorted
(
data
[
"shapes"
],
key
=
lambda
x
:
x
[
"label"
]):
label_name
=
shape
[
"label"
]
if
label_name
in
label_name_to_value
:
label_value
=
label_name_to_value
[
label_name
]
else
:
label_value
=
len
(
label_name_to_value
)
label_name_to_value
[
label_name
]
=
label_value
lbl
,
_
=
utils
.
shapes_to_label
(
img
.
shape
,
data
[
'shapes'
],
label_name_to_value
img
.
shape
,
data
[
"shapes"
],
label_name_to_value
)
label_names
=
[
None
]
*
(
max
(
label_name_to_value
.
values
())
+
1
)
...
...
@@ -59,19 +63,19 @@ def main():
label_names
[
value
]
=
name
lbl_viz
=
imgviz
.
label2rgb
(
label
=
lbl
,
img
=
imgviz
.
asgray
(
img
),
label_names
=
label_names
,
loc
=
'rb'
label
=
lbl
,
img
=
imgviz
.
asgray
(
img
),
label_names
=
label_names
,
loc
=
"rb"
)
PIL
.
Image
.
fromarray
(
img
).
save
(
osp
.
join
(
out_dir
,
'img.png'
))
utils
.
lblsave
(
osp
.
join
(
out_dir
,
'label.png'
),
lbl
)
PIL
.
Image
.
fromarray
(
lbl_viz
).
save
(
osp
.
join
(
out_dir
,
'label_viz.png'
))
PIL
.
Image
.
fromarray
(
img
).
save
(
osp
.
join
(
out_dir
,
"img.png"
))
utils
.
lblsave
(
osp
.
join
(
out_dir
,
"label.png"
),
lbl
)
PIL
.
Image
.
fromarray
(
lbl_viz
).
save
(
osp
.
join
(
out_dir
,
"label_viz.png"
))
with
open
(
osp
.
join
(
out_dir
,
'label_names.txt'
),
'w'
)
as
f
:
with
open
(
osp
.
join
(
out_dir
,
"label_names.txt"
),
"w"
)
as
f
:
for
lbl_name
in
label_names
:
f
.
write
(
lbl_name
+
'
\n
'
)
f
.
write
(
lbl_name
+
"
\n
"
)
logger
.
info
(
'Saved to: {}'
.
format
(
out_dir
))
logger
.
info
(
"Saved to: {}"
.
format
(
out_dir
))
if
__name__
==
'__main__'
:
if
__name__
==
"__main__"
:
main
()
labelme/cli/on_docker.py
浏览文件 @
5c980844
...
...
@@ -14,57 +14,55 @@ import sys
def
get_ip
():
dist
=
platform
.
platform
().
split
(
'-'
)[
0
]
if
dist
==
'Linux'
:
return
''
elif
dist
==
'Darwin'
:
cmd
=
'ifconfig en0'
dist
=
platform
.
platform
().
split
(
"-"
)[
0
]
if
dist
==
"Linux"
:
return
""
elif
dist
==
"Darwin"
:
cmd
=
"ifconfig en0"
output
=
subprocess
.
check_output
(
shlex
.
split
(
cmd
))
if
str
!=
bytes
:
# Python3
output
=
output
.
decode
(
'utf-8'
)
output
=
output
.
decode
(
"utf-8"
)
for
row
in
output
.
splitlines
():
cols
=
row
.
strip
().
split
(
' '
)
if
cols
[
0
]
==
'inet'
:
cols
=
row
.
strip
().
split
(
" "
)
if
cols
[
0
]
==
"inet"
:
ip
=
cols
[
1
]
return
ip
else
:
raise
RuntimeError
(
'No ip is found.'
)
raise
RuntimeError
(
"No ip is found."
)
else
:
raise
RuntimeError
(
'Unsupported platform.'
)
raise
RuntimeError
(
"Unsupported platform."
)
def
labelme_on_docker
(
in_file
,
out_file
):
ip
=
get_ip
()
cmd
=
'xhost + %s'
%
ip
cmd
=
"xhost + %s"
%
ip
subprocess
.
check_output
(
shlex
.
split
(
cmd
))
if
out_file
:
out_file
=
osp
.
abspath
(
out_file
)
if
osp
.
exists
(
out_file
):
raise
RuntimeError
(
'File exists: %s'
%
out_file
)
raise
RuntimeError
(
"File exists: %s"
%
out_file
)
else
:
open
(
osp
.
abspath
(
out_file
),
'w'
)
open
(
osp
.
abspath
(
out_file
),
"w"
)
cmd
=
'docker run -it --rm'
\
' -e DISPLAY={0}:0'
\
' -e QT_X11_NO_MITSHM=1'
\
' -v /tmp/.X11-unix:/tmp/.X11-unix'
\
' -v {1}:{2}'
\
' -w /home/developer'
in_file_a
=
osp
.
abspath
(
in_file
)
in_file_b
=
osp
.
join
(
'/home/developer'
,
osp
.
basename
(
in_file
))
cmd
=
cmd
.
format
(
ip
,
in_file_a
,
in_file_b
,
cmd
=
(
"docker run -it --rm"
" -e DISPLAY={0}:0"
" -e QT_X11_NO_MITSHM=1"
" -v /tmp/.X11-unix:/tmp/.X11-unix"
" -v {1}:{2}"
" -w /home/developer"
)
in_file_a
=
osp
.
abspath
(
in_file
)
in_file_b
=
osp
.
join
(
"/home/developer"
,
osp
.
basename
(
in_file
))
cmd
=
cmd
.
format
(
ip
,
in_file_a
,
in_file_b
,)
if
out_file
:
out_file_a
=
osp
.
abspath
(
out_file
)
out_file_b
=
osp
.
join
(
'/home/developer'
,
osp
.
basename
(
out_file
))
cmd
+=
' -v {0}:{1}'
.
format
(
out_file_a
,
out_file_b
)
cmd
+=
' wkentaro/labelme labelme {0}'
.
format
(
in_file_b
)
out_file_b
=
osp
.
join
(
"/home/developer"
,
osp
.
basename
(
out_file
))
cmd
+=
" -v {0}:{1}"
.
format
(
out_file_a
,
out_file_b
)
cmd
+=
" wkentaro/labelme labelme {0}"
.
format
(
in_file_b
)
if
out_file
:
cmd
+=
' -O {0}'
.
format
(
out_file_b
)
cmd
+=
" -O {0}"
.
format
(
out_file_b
)
subprocess
.
call
(
shlex
.
split
(
cmd
))
if
out_file
:
...
...
@@ -72,29 +70,29 @@ def labelme_on_docker(in_file, out_file):
json
.
load
(
open
(
out_file
))
return
out_file
except
Exception
:
if
open
(
out_file
).
read
()
==
''
:
if
open
(
out_file
).
read
()
==
""
:
os
.
remove
(
out_file
)
raise
RuntimeError
(
'Annotation is cancelled.'
)
raise
RuntimeError
(
"Annotation is cancelled."
)
def
main
():
parser
=
argparse
.
ArgumentParser
()
parser
.
add_argument
(
'in_file'
,
help
=
'Input file or directory.'
)
parser
.
add_argument
(
'-O'
,
'--output'
)
parser
.
add_argument
(
"in_file"
,
help
=
"Input file or directory."
)
parser
.
add_argument
(
"-O"
,
"--output"
)
args
=
parser
.
parse_args
()
if
not
distutils
.
spawn
.
find_executable
(
'docker'
):
print
(
'Please install docker'
,
file
=
sys
.
stderr
)
if
not
distutils
.
spawn
.
find_executable
(
"docker"
):
print
(
"Please install docker"
,
file
=
sys
.
stderr
)
sys
.
exit
(
1
)
try
:
out_file
=
labelme_on_docker
(
args
.
in_file
,
args
.
output
)
if
out_file
:
print
(
'Saved to: %s'
%
out_file
)
print
(
"Saved to: %s"
%
out_file
)
except
RuntimeError
as
e
:
sys
.
stderr
.
write
(
e
.
__str__
()
+
'
\n
'
)
sys
.
stderr
.
write
(
e
.
__str__
()
+
"
\n
"
)
sys
.
exit
(
1
)
if
__name__
==
'__main__'
:
if
__name__
==
"__main__"
:
main
()
labelme/config/__init__.py
浏览文件 @
5c980844
...
...
@@ -14,11 +14,9 @@ def update_dict(target_dict, new_dict, validate_item=None):
if
validate_item
:
validate_item
(
key
,
value
)
if
key
not
in
target_dict
:
logger
.
warn
(
'Skipping unexpected key in config: {}'
.
format
(
key
))
logger
.
warn
(
"Skipping unexpected key in config: {}"
.
format
(
key
))
continue
if
isinstance
(
target_dict
[
key
],
dict
)
and
\
isinstance
(
value
,
dict
):
if
isinstance
(
target_dict
[
key
],
dict
)
and
isinstance
(
value
,
dict
):
update_dict
(
target_dict
[
key
],
value
,
validate_item
=
validate_item
)
else
:
target_dict
[
key
]
=
value
...
...
@@ -28,33 +26,33 @@ def update_dict(target_dict, new_dict, validate_item=None):
def
get_default_config
():
config_file
=
osp
.
join
(
here
,
'default_config.yaml'
)
config_file
=
osp
.
join
(
here
,
"default_config.yaml"
)
with
open
(
config_file
)
as
f
:
config
=
yaml
.
safe_load
(
f
)
# save default config to ~/.labelmerc
user_config_file
=
osp
.
join
(
osp
.
expanduser
(
'~'
),
'.labelmerc'
)
user_config_file
=
osp
.
join
(
osp
.
expanduser
(
"~"
),
".labelmerc"
)
if
not
osp
.
exists
(
user_config_file
):
try
:
shutil
.
copy
(
config_file
,
user_config_file
)
except
Exception
:
logger
.
warn
(
'Failed to save config: {}'
.
format
(
user_config_file
))
logger
.
warn
(
"Failed to save config: {}"
.
format
(
user_config_file
))
return
config
def
validate_config_item
(
key
,
value
):
if
key
==
'validate_label'
and
value
not
in
[
None
,
'exact'
]:
if
key
==
"validate_label"
and
value
not
in
[
None
,
"exact"
]:
raise
ValueError
(
"Unexpected value for config key 'validate_label': {}"
.
format
(
value
)
"Unexpected value for config key 'validate_label': {}"
.
format
(
value
)
)
if
key
==
'shape_color'
and
value
not
in
[
None
,
'auto'
,
'manual'
]:
if
key
==
"shape_color"
and
value
not
in
[
None
,
"auto"
,
"manual"
]:
raise
ValueError
(
"Unexpected value for config key 'shape_color': {}"
.
format
(
value
)
"Unexpected value for config key 'shape_color': {}"
.
format
(
value
)
)
if
key
==
'labels'
and
value
is
not
None
and
len
(
value
)
!=
len
(
set
(
value
)):
if
key
==
"labels"
and
value
is
not
None
and
len
(
value
)
!=
len
(
set
(
value
)):
raise
ValueError
(
"Duplicates are detected for config key 'labels': {}"
.
format
(
value
)
)
...
...
@@ -70,15 +68,17 @@ def get_config(config_file_or_yaml=None, config_from_args=None):
if
not
isinstance
(
config_from_yaml
,
dict
):
with
open
(
config_from_yaml
)
as
f
:
logger
.
info
(
'Loading config file from: {}'
.
format
(
config_from_yaml
)
"Loading config file from: {}"
.
format
(
config_from_yaml
)
)
config_from_yaml
=
yaml
.
safe_load
(
f
)
update_dict
(
config
,
config_from_yaml
,
validate_item
=
validate_config_item
)
update_dict
(
config
,
config_from_yaml
,
validate_item
=
validate_config_item
)
# 3. command line argument or specified config file
if
config_from_args
is
not
None
:
update_dict
(
config
,
config_from_args
,
validate_item
=
validate_config_item
)
update_dict
(
config
,
config_from_args
,
validate_item
=
validate_config_item
)
return
config
labelme/label_file.py
浏览文件 @
5c980844
...
...
@@ -21,7 +21,7 @@ class LabelFileError(Exception):
class
LabelFile
(
object
):
suffix
=
'.json'
suffix
=
".json"
def
__init__
(
self
,
filename
=
None
):
self
.
shapes
=
[]
...
...
@@ -36,7 +36,7 @@ class LabelFile(object):
try
:
image_pil
=
PIL
.
Image
.
open
(
filename
)
except
IOError
:
logger
.
error
(
'Failed opening image file: {}'
.
format
(
filename
))
logger
.
error
(
"Failed opening image file: {}"
.
format
(
filename
))
return
# apply orientation to image according to exif
...
...
@@ -45,77 +45,78 @@ class LabelFile(object):
with
io
.
BytesIO
()
as
f
:
ext
=
osp
.
splitext
(
filename
)[
1
].
lower
()
if
PY2
and
QT4
:
format
=
'PNG'
elif
ext
in
[
'.jpg'
,
'.jpeg'
]:
format
=
'JPEG'
format
=
"PNG"
elif
ext
in
[
".jpg"
,
".jpeg"
]:
format
=
"JPEG"
else
:
format
=
'PNG'
format
=
"PNG"
image_pil
.
save
(
f
,
format
=
format
)
f
.
seek
(
0
)
return
f
.
read
()
def
load
(
self
,
filename
):
keys
=
[
'version'
,
'imageData'
,
'imagePath'
,
'shapes'
,
# polygonal annotations
'flags'
,
# image level flags
'imageHeight'
,
'imageWidth'
,
"version"
,
"imageData"
,
"imagePath"
,
"shapes"
,
# polygonal annotations
"flags"
,
# image level flags
"imageHeight"
,
"imageWidth"
,
]
shape_keys
=
[
'label'
,
'points'
,
'group_id'
,
'shape_type'
,
'flags'
,
"label"
,
"points"
,
"group_id"
,
"shape_type"
,
"flags"
,
]
try
:
with
open
(
filename
,
'rb'
if
PY2
else
'r'
)
as
f
:
with
open
(
filename
,
"rb"
if
PY2
else
"r"
)
as
f
:
data
=
json
.
load
(
f
)
version
=
data
.
get
(
'version'
)
version
=
data
.
get
(
"version"
)
if
version
is
None
:
logger
.
warn
(
'Loading JSON file ({}) of unknown version'
.
format
(
filename
)
"Loading JSON file ({}) of unknown version"
.
format
(
filename
)
)
elif
version
.
split
(
'.'
)[
0
]
!=
__version__
.
split
(
'.'
)[
0
]:
elif
version
.
split
(
"."
)[
0
]
!=
__version__
.
split
(
"."
)[
0
]:
logger
.
warn
(
'This JSON file ({}) may be incompatible with '
'current labelme. version in file: {}, '
'current version: {}'
.
format
(
"This JSON file ({}) may be incompatible with "
"current labelme. version in file: {}, "
"current version: {}"
.
format
(
filename
,
version
,
__version__
)
)
if
data
[
'imageData'
]
is
not
None
:
imageData
=
base64
.
b64decode
(
data
[
'imageData'
])
if
data
[
"imageData"
]
is
not
None
:
imageData
=
base64
.
b64decode
(
data
[
"imageData"
])
if
PY2
and
QT4
:
imageData
=
utils
.
img_data_to_png_data
(
imageData
)
else
:
# relative path from label file to relative path from cwd
imagePath
=
osp
.
join
(
osp
.
dirname
(
filename
),
data
[
'imagePath'
])
imagePath
=
osp
.
join
(
osp
.
dirname
(
filename
),
data
[
"imagePath"
])
imageData
=
self
.
load_image_file
(
imagePath
)
flags
=
data
.
get
(
'flags'
)
or
{}
imagePath
=
data
[
'imagePath'
]
flags
=
data
.
get
(
"flags"
)
or
{}
imagePath
=
data
[
"imagePath"
]
self
.
_check_image_height_and_width
(
base64
.
b64encode
(
imageData
).
decode
(
'utf-8'
),
data
.
get
(
'imageHeight'
),
data
.
get
(
'imageWidth'
),
base64
.
b64encode
(
imageData
).
decode
(
"utf-8"
),
data
.
get
(
"imageHeight"
),
data
.
get
(
"imageWidth"
),
)
shapes
=
[
dict
(
label
=
s
[
'label'
],
points
=
s
[
'points'
],
shape_type
=
s
.
get
(
'shape_type'
,
'polygon'
),
flags
=
s
.
get
(
'flags'
,
{}),
group_id
=
s
.
get
(
'group_id'
),
label
=
s
[
"label"
],
points
=
s
[
"points"
],
shape_type
=
s
.
get
(
"shape_type"
,
"polygon"
),
flags
=
s
.
get
(
"flags"
,
{}),
group_id
=
s
.
get
(
"group_id"
),
other_data
=
{
k
:
v
for
k
,
v
in
s
.
items
()
if
k
not
in
shape_keys
}
}
,
)
for
s
in
data
[
'shapes'
]
for
s
in
data
[
"shapes"
]
]
except
Exception
as
e
:
raise
LabelFileError
(
e
)
...
...
@@ -138,14 +139,14 @@ class LabelFile(object):
img_arr
=
utils
.
img_b64_to_arr
(
imageData
)
if
imageHeight
is
not
None
and
img_arr
.
shape
[
0
]
!=
imageHeight
:
logger
.
error
(
'imageHeight does not match with imageData or imagePath, '
'so getting imageHeight from actual image.'
"imageHeight does not match with imageData or imagePath, "
"so getting imageHeight from actual image."
)
imageHeight
=
img_arr
.
shape
[
0
]
if
imageWidth
is
not
None
and
img_arr
.
shape
[
1
]
!=
imageWidth
:
logger
.
error
(
'imageWidth does not match with imageData or imagePath, '
'so getting imageWidth from actual image.'
"imageWidth does not match with imageData or imagePath, "
"so getting imageWidth from actual image."
)
imageWidth
=
img_arr
.
shape
[
1
]
return
imageHeight
,
imageWidth
...
...
@@ -162,7 +163,7 @@ class LabelFile(object):
flags
=
None
,
):
if
imageData
is
not
None
:
imageData
=
base64
.
b64encode
(
imageData
).
decode
(
'utf-8'
)
imageData
=
base64
.
b64encode
(
imageData
).
decode
(
"utf-8"
)
imageHeight
,
imageWidth
=
self
.
_check_image_height_and_width
(
imageData
,
imageHeight
,
imageWidth
)
...
...
@@ -183,7 +184,7 @@ class LabelFile(object):
assert
key
not
in
data
data
[
key
]
=
value
try
:
with
open
(
filename
,
'wb'
if
PY2
else
'w'
)
as
f
:
with
open
(
filename
,
"wb"
if
PY2
else
"w"
)
as
f
:
json
.
dump
(
data
,
f
,
ensure_ascii
=
False
,
indent
=
2
)
self
.
filename
=
filename
except
Exception
as
e
:
...
...
labelme/logger.py
浏览文件 @
5c980844
...
...
@@ -7,16 +7,15 @@ from . import __appname__
COLORS
=
{
'WARNING'
:
'yellow'
,
'INFO'
:
'white'
,
'DEBUG'
:
'blue'
,
'CRITICAL'
:
'red'
,
'ERROR'
:
'red'
,
"WARNING"
:
"yellow"
,
"INFO"
:
"white"
,
"DEBUG"
:
"blue"
,
"CRITICAL"
:
"red"
,
"ERROR"
:
"red"
,
}
class
ColoredFormatter
(
logging
.
Formatter
):
def
__init__
(
self
,
fmt
,
use_color
=
True
):
logging
.
Formatter
.
__init__
(
self
,
fmt
)
self
.
use_color
=
use_color
...
...
@@ -27,27 +26,25 @@ class ColoredFormatter(logging.Formatter):
def
colored
(
text
):
return
termcolor
.
colored
(
text
,
color
=
COLORS
[
levelname
],
attrs
=
{
'bold'
:
True
},
text
,
color
=
COLORS
[
levelname
],
attrs
=
{
"bold"
:
True
},
)
record
.
levelname2
=
colored
(
'{:<7}'
.
format
(
record
.
levelname
))
record
.
levelname2
=
colored
(
"{:<7}"
.
format
(
record
.
levelname
))
record
.
message2
=
colored
(
record
.
msg
)
asctime2
=
datetime
.
datetime
.
fromtimestamp
(
record
.
created
)
record
.
asctime2
=
termcolor
.
colored
(
asctime2
,
color
=
'green'
)
record
.
asctime2
=
termcolor
.
colored
(
asctime2
,
color
=
"green"
)
record
.
module2
=
termcolor
.
colored
(
record
.
module
,
color
=
'cyan'
)
record
.
funcName2
=
termcolor
.
colored
(
record
.
funcName
,
color
=
'cyan'
)
record
.
lineno2
=
termcolor
.
colored
(
record
.
lineno
,
color
=
'cyan'
)
record
.
module2
=
termcolor
.
colored
(
record
.
module
,
color
=
"cyan"
)
record
.
funcName2
=
termcolor
.
colored
(
record
.
funcName
,
color
=
"cyan"
)
record
.
lineno2
=
termcolor
.
colored
(
record
.
lineno
,
color
=
"cyan"
)
return
logging
.
Formatter
.
format
(
self
,
record
)
class
ColoredLogger
(
logging
.
Logger
):
FORMAT
=
(
'[%(levelname2)s] %(module2)s:%(funcName2)s:%(lineno2)s - %(message2)s'
"[%(levelname2)s] %(module2)s:%(funcName2)s:%(lineno2)s - %(message2)s"
)
def
__init__
(
self
,
name
):
...
...
labelme/shape.py
浏览文件 @
5c980844
...
...
@@ -12,11 +12,11 @@ import labelme.utils
R
,
G
,
B
=
SHAPE_COLOR
=
0
,
255
,
0
# green
DEFAULT_LINE_COLOR
=
QtGui
.
QColor
(
R
,
G
,
B
,
128
)
# bf hovering
DEFAULT_FILL_COLOR
=
QtGui
.
QColor
(
R
,
G
,
B
,
128
)
# hovering
DEFAULT_SELECT_LINE_COLOR
=
QtGui
.
QColor
(
255
,
255
,
255
)
# selected
DEFAULT_SELECT_FILL_COLOR
=
QtGui
.
QColor
(
R
,
G
,
B
,
155
)
# selected
DEFAULT_VERTEX_FILL_COLOR
=
QtGui
.
QColor
(
R
,
G
,
B
,
255
)
# hovering
DEFAULT_LINE_COLOR
=
QtGui
.
QColor
(
R
,
G
,
B
,
128
)
# bf hovering
DEFAULT_FILL_COLOR
=
QtGui
.
QColor
(
R
,
G
,
B
,
128
)
# hovering
DEFAULT_SELECT_LINE_COLOR
=
QtGui
.
QColor
(
255
,
255
,
255
)
# selected
DEFAULT_SELECT_FILL_COLOR
=
QtGui
.
QColor
(
R
,
G
,
B
,
155
)
# selected
DEFAULT_VERTEX_FILL_COLOR
=
QtGui
.
QColor
(
R
,
G
,
B
,
255
)
# hovering
DEFAULT_HVERTEX_FILL_COLOR
=
QtGui
.
QColor
(
255
,
255
,
255
,
255
)
# hovering
...
...
@@ -37,8 +37,14 @@ class Shape(object):
point_size
=
8
scale
=
1.0
def
__init__
(
self
,
label
=
None
,
line_color
=
None
,
shape_type
=
None
,
flags
=
None
,
group_id
=
None
):
def
__init__
(
self
,
label
=
None
,
line_color
=
None
,
shape_type
=
None
,
flags
=
None
,
group_id
=
None
,
):
self
.
label
=
label
self
.
group_id
=
group_id
self
.
points
=
[]
...
...
@@ -72,10 +78,16 @@ class Shape(object):
@
shape_type
.
setter
def
shape_type
(
self
,
value
):
if
value
is
None
:
value
=
'polygon'
if
value
not
in
[
'polygon'
,
'rectangle'
,
'point'
,
'line'
,
'circle'
,
'linestrip'
]:
raise
ValueError
(
'Unexpected shape_type: {}'
.
format
(
value
))
value
=
"polygon"
if
value
not
in
[
"polygon"
,
"rectangle"
,
"point"
,
"line"
,
"circle"
,
"linestrip"
,
]:
raise
ValueError
(
"Unexpected shape_type: {}"
.
format
(
value
))
self
.
_shape_type
=
value
def
close
(
self
):
...
...
@@ -88,7 +100,7 @@ class Shape(object):
self
.
points
.
append
(
point
)
def
canAddPoint
(
self
):
return
self
.
shape_type
in
[
'polygon'
,
'linestrip'
]
return
self
.
shape_type
in
[
"polygon"
,
"linestrip"
]
def
popPoint
(
self
):
if
self
.
points
:
...
...
@@ -114,8 +126,9 @@ class Shape(object):
def
paint
(
self
,
painter
):
if
self
.
points
:
color
=
self
.
select_line_color
\
if
self
.
selected
else
self
.
line_color
color
=
(
self
.
select_line_color
if
self
.
selected
else
self
.
line_color
)
pen
=
QtGui
.
QPen
(
color
)
# Try using integer sizes for smoother drawing(?)
pen
.
setWidth
(
max
(
1
,
int
(
round
(
2.0
/
self
.
scale
))))
...
...
@@ -124,7 +137,7 @@ class Shape(object):
line_path
=
QtGui
.
QPainterPath
()
vrtx_path
=
QtGui
.
QPainterPath
()
if
self
.
shape_type
==
'rectangle'
:
if
self
.
shape_type
==
"rectangle"
:
assert
len
(
self
.
points
)
in
[
1
,
2
]
if
len
(
self
.
points
)
==
2
:
rectangle
=
self
.
getRectFromLine
(
*
self
.
points
)
...
...
@@ -160,8 +173,11 @@ class Shape(object):
painter
.
drawPath
(
vrtx_path
)
painter
.
fillPath
(
vrtx_path
,
self
.
_vertex_fill_color
)
if
self
.
fill
:
color
=
self
.
select_fill_color
\
if
self
.
selected
else
self
.
fill_color
color
=
(
self
.
select_fill_color
if
self
.
selected
else
self
.
fill_color
)
painter
.
fillPath
(
line_path
,
color
)
def
drawVertex
(
self
,
path
,
i
):
...
...
@@ -183,7 +199,7 @@ class Shape(object):
assert
False
,
"unsupported vertex shape"
def
nearestVertex
(
self
,
point
,
epsilon
):
min_distance
=
float
(
'inf'
)
min_distance
=
float
(
"inf"
)
min_i
=
None
for
i
,
p
in
enumerate
(
self
.
points
):
dist
=
labelme
.
utils
.
distance
(
p
-
point
)
...
...
@@ -193,7 +209,7 @@ class Shape(object):
return
min_i
def
nearestEdge
(
self
,
point
,
epsilon
):
min_distance
=
float
(
'inf'
)
min_distance
=
float
(
"inf"
)
post_i
=
None
for
i
in
range
(
len
(
self
.
points
)):
line
=
[
self
.
points
[
i
-
1
],
self
.
points
[
i
]]
...
...
@@ -217,7 +233,7 @@ class Shape(object):
return
rectangle
def
makePath
(
self
):
if
self
.
shape_type
==
'rectangle'
:
if
self
.
shape_type
==
"rectangle"
:
path
=
QtGui
.
QPainterPath
()
if
len
(
self
.
points
)
==
2
:
rectangle
=
self
.
getRectFromLine
(
*
self
.
points
)
...
...
labelme/testing.py
浏览文件 @
5c980844
...
...
@@ -10,24 +10,24 @@ def assert_labelfile_sanity(filename):
data
=
json
.
load
(
open
(
filename
))
assert
'imagePath'
in
data
imageData
=
data
.
get
(
'imageData'
,
None
)
assert
"imagePath"
in
data
imageData
=
data
.
get
(
"imageData"
,
None
)
if
imageData
is
None
:
parent_dir
=
osp
.
dirname
(
filename
)
img_file
=
osp
.
join
(
parent_dir
,
data
[
'imagePath'
])
img_file
=
osp
.
join
(
parent_dir
,
data
[
"imagePath"
])
assert
osp
.
exists
(
img_file
)
img
=
imgviz
.
io
.
imread
(
img_file
)
else
:
img
=
labelme
.
utils
.
img_b64_to_arr
(
imageData
)
H
,
W
=
img
.
shape
[:
2
]
assert
H
==
data
[
'imageHeight'
]
assert
W
==
data
[
'imageWidth'
]
assert
H
==
data
[
"imageHeight"
]
assert
W
==
data
[
"imageWidth"
]
assert
'shapes'
in
data
for
shape
in
data
[
'shapes'
]:
assert
'label'
in
shape
assert
'points'
in
shape
for
x
,
y
in
shape
[
'points'
]:
assert
"shapes"
in
data
for
shape
in
data
[
"shapes"
]:
assert
"label"
in
shape
assert
"points"
in
shape
for
x
,
y
in
shape
[
"points"
]:
assert
0
<=
x
<=
W
assert
0
<=
y
<=
H
labelme/utils/_io.py
浏览文件 @
5c980844
...
...
@@ -7,17 +7,17 @@ import PIL.Image
def
lblsave
(
filename
,
lbl
):
import
imgviz
if
osp
.
splitext
(
filename
)[
1
]
!=
'.png'
:
filename
+=
'.png'
if
osp
.
splitext
(
filename
)[
1
]
!=
".png"
:
filename
+=
".png"
# Assume label ranses [-1, 254] for int32,
# and [0, 255] for uint8 as VOC.
if
lbl
.
min
()
>=
-
1
and
lbl
.
max
()
<
255
:
lbl_pil
=
PIL
.
Image
.
fromarray
(
lbl
.
astype
(
np
.
uint8
),
mode
=
'P'
)
lbl_pil
=
PIL
.
Image
.
fromarray
(
lbl
.
astype
(
np
.
uint8
),
mode
=
"P"
)
colormap
=
imgviz
.
label_colormap
()
lbl_pil
.
putpalette
(
colormap
.
flatten
())
lbl_pil
.
save
(
filename
)
else
:
raise
ValueError
(
'[%s] Cannot save the pixel-wise class label as PNG. '
'Please consider using the .npy format.'
%
filename
"[%s] Cannot save the pixel-wise class label as PNG. "
"Please consider using the .npy format."
%
filename
)
labelme/utils/image.py
浏览文件 @
5c980844
...
...
@@ -23,9 +23,9 @@ def img_b64_to_arr(img_b64):
def
img_arr_to_b64
(
img_arr
):
img_pil
=
PIL
.
Image
.
fromarray
(
img_arr
)
f
=
io
.
BytesIO
()
img_pil
.
save
(
f
,
format
=
'PNG'
)
img_pil
.
save
(
f
,
format
=
"PNG"
)
img_bin
=
f
.
getvalue
()
if
hasattr
(
base64
,
'encodebytes'
):
if
hasattr
(
base64
,
"encodebytes"
):
img_b64
=
base64
.
encodebytes
(
img_bin
)
else
:
img_b64
=
base64
.
encodestring
(
img_bin
)
...
...
@@ -38,7 +38,7 @@ def img_data_to_png_data(img_data):
img
=
PIL
.
Image
.
open
(
f
)
with
io
.
BytesIO
()
as
f
:
img
.
save
(
f
,
'PNG'
)
img
.
save
(
f
,
"PNG"
)
f
.
seek
(
0
)
return
f
.
read
()
...
...
@@ -58,7 +58,7 @@ def apply_exif_orientation(image):
if
k
in
PIL
.
ExifTags
.
TAGS
}
orientation
=
exif
.
get
(
'Orientation'
,
None
)
orientation
=
exif
.
get
(
"Orientation"
,
None
)
if
orientation
==
1
:
# do nothing
...
...
labelme/utils/qt.py
浏览文件 @
5c980844
...
...
@@ -12,8 +12,8 @@ here = osp.dirname(osp.abspath(__file__))
def
newIcon
(
icon
):
icons_dir
=
osp
.
join
(
here
,
'../icons'
)
return
QtGui
.
QIcon
(
osp
.
join
(
':/'
,
icons_dir
,
'%s.png'
%
icon
))
icons_dir
=
osp
.
join
(
here
,
"../icons"
)
return
QtGui
.
QIcon
(
osp
.
join
(
":/"
,
icons_dir
,
"%s.png"
%
icon
))
def
newButton
(
text
,
icon
=
None
,
slot
=
None
):
...
...
@@ -25,12 +25,21 @@ def newButton(text, icon=None, slot=None):
return
b
def
newAction
(
parent
,
text
,
slot
=
None
,
shortcut
=
None
,
icon
=
None
,
tip
=
None
,
checkable
=
False
,
enabled
=
True
,
checked
=
False
):
def
newAction
(
parent
,
text
,
slot
=
None
,
shortcut
=
None
,
icon
=
None
,
tip
=
None
,
checkable
=
False
,
enabled
=
True
,
checked
=
False
,
):
"""Create a new action and assign callbacks, shortcuts, etc."""
a
=
QtWidgets
.
QAction
(
text
,
parent
)
if
icon
is
not
None
:
a
.
setIconText
(
text
.
replace
(
' '
,
'
\n
'
))
a
.
setIconText
(
text
.
replace
(
" "
,
"
\n
"
))
a
.
setIcon
(
newIcon
(
icon
))
if
shortcut
is
not
None
:
if
isinstance
(
shortcut
,
(
list
,
tuple
)):
...
...
@@ -60,7 +69,7 @@ def addActions(widget, actions):
def
labelValidator
():
return
QtGui
.
QRegExpValidator
(
QtCore
.
QRegExp
(
r
'^[^ \t].+'
),
None
)
return
QtGui
.
QRegExpValidator
(
QtCore
.
QRegExp
(
r
"^[^ \t].+"
),
None
)
class
struct
(
object
):
...
...
@@ -85,5 +94,5 @@ def distancetoline(point, line):
def
fmtShortcut
(
text
):
mod
,
key
=
text
.
split
(
'+'
,
1
)
return
'<b>%s</b>+<b>%s</b>'
%
(
mod
,
key
)
mod
,
key
=
text
.
split
(
"+"
,
1
)
return
"<b>%s</b>+<b>%s</b>"
%
(
mod
,
key
)
labelme/utils/shape.py
浏览文件 @
5c980844
...
...
@@ -16,32 +16,33 @@ def polygons_to_mask(img_shape, polygons, shape_type=None):
return
shape_to_mask
(
img_shape
,
points
=
polygons
,
shape_type
=
shape_type
)
def
shape_to_mask
(
img_shape
,
points
,
shape_type
=
None
,
line_width
=
10
,
point_size
=
5
):
def
shape_to_mask
(
img_shape
,
points
,
shape_type
=
None
,
line_width
=
10
,
point_size
=
5
):
mask
=
np
.
zeros
(
img_shape
[:
2
],
dtype
=
np
.
uint8
)
mask
=
PIL
.
Image
.
fromarray
(
mask
)
draw
=
PIL
.
ImageDraw
.
Draw
(
mask
)
xy
=
[
tuple
(
point
)
for
point
in
points
]
if
shape_type
==
'circle'
:
assert
len
(
xy
)
==
2
,
'Shape of shape_type=circle must have 2 points'
if
shape_type
==
"circle"
:
assert
len
(
xy
)
==
2
,
"Shape of shape_type=circle must have 2 points"
(
cx
,
cy
),
(
px
,
py
)
=
xy
d
=
math
.
sqrt
((
cx
-
px
)
**
2
+
(
cy
-
py
)
**
2
)
draw
.
ellipse
([
cx
-
d
,
cy
-
d
,
cx
+
d
,
cy
+
d
],
outline
=
1
,
fill
=
1
)
elif
shape_type
==
'rectangle'
:
assert
len
(
xy
)
==
2
,
'Shape of shape_type=rectangle must have 2 points'
elif
shape_type
==
"rectangle"
:
assert
len
(
xy
)
==
2
,
"Shape of shape_type=rectangle must have 2 points"
draw
.
rectangle
(
xy
,
outline
=
1
,
fill
=
1
)
elif
shape_type
==
'line'
:
assert
len
(
xy
)
==
2
,
'Shape of shape_type=line must have 2 points'
elif
shape_type
==
"line"
:
assert
len
(
xy
)
==
2
,
"Shape of shape_type=line must have 2 points"
draw
.
line
(
xy
=
xy
,
fill
=
1
,
width
=
line_width
)
elif
shape_type
==
'linestrip'
:
elif
shape_type
==
"linestrip"
:
draw
.
line
(
xy
=
xy
,
fill
=
1
,
width
=
line_width
)
elif
shape_type
==
'point'
:
assert
len
(
xy
)
==
1
,
'Shape of shape_type=point must have 1 points'
elif
shape_type
==
"point"
:
assert
len
(
xy
)
==
1
,
"Shape of shape_type=point must have 1 points"
cx
,
cy
=
xy
[
0
]
r
=
point_size
draw
.
ellipse
([
cx
-
r
,
cy
-
r
,
cx
+
r
,
cy
+
r
],
outline
=
1
,
fill
=
1
)
else
:
assert
len
(
xy
)
>
2
,
'Polygon must have points more than 2'
assert
len
(
xy
)
>
2
,
"Polygon must have points more than 2"
draw
.
polygon
(
xy
=
xy
,
outline
=
1
,
fill
=
1
)
mask
=
np
.
array
(
mask
,
dtype
=
bool
)
return
mask
...
...
@@ -52,12 +53,12 @@ def shapes_to_label(img_shape, shapes, label_name_to_value):
ins
=
np
.
zeros_like
(
cls
)
instances
=
[]
for
shape
in
shapes
:
points
=
shape
[
'points'
]
label
=
shape
[
'label'
]
group_id
=
shape
.
get
(
'group_id'
)
points
=
shape
[
"points"
]
label
=
shape
[
"label"
]
group_id
=
shape
.
get
(
"group_id"
)
if
group_id
is
None
:
group_id
=
uuid
.
uuid1
()
shape_type
=
shape
.
get
(
'shape_type'
,
None
)
shape_type
=
shape
.
get
(
"shape_type"
,
None
)
cls_name
=
label
instance
=
(
cls_name
,
group_id
)
...
...
@@ -75,12 +76,14 @@ def shapes_to_label(img_shape, shapes, label_name_to_value):
def
labelme_shapes_to_label
(
img_shape
,
shapes
):
logger
.
warn
(
'labelme_shapes_to_label is deprecated, so please use '
'shapes_to_label.'
)
logger
.
warn
(
"labelme_shapes_to_label is deprecated, so please use "
"shapes_to_label."
)
label_name_to_value
=
{
'_background_'
:
0
}
label_name_to_value
=
{
"_background_"
:
0
}
for
shape
in
shapes
:
label_name
=
shape
[
'label'
]
label_name
=
shape
[
"label"
]
if
label_name
in
label_name_to_value
:
label_value
=
label_name_to_value
[
label_name
]
else
:
...
...
@@ -94,13 +97,11 @@ def labelme_shapes_to_label(img_shape, shapes):
def
masks_to_bboxes
(
masks
):
if
masks
.
ndim
!=
3
:
raise
ValueError
(
'masks.ndim must be 3, but it is {}'
.
format
(
masks
.
ndim
)
"masks.ndim must be 3, but it is {}"
.
format
(
masks
.
ndim
)
)
if
masks
.
dtype
!=
bool
:
raise
ValueError
(
'masks.dtype must be bool type, but it is {}'
.
format
(
masks
.
dtype
)
"masks.dtype must be bool type, but it is {}"
.
format
(
masks
.
dtype
)
)
bboxes
=
[]
for
mask
in
masks
:
...
...
labelme/widgets/brightness_contrast_dialog.py
浏览文件 @
5c980844
...
...
@@ -10,31 +10,31 @@ class BrightnessContrastDialog(QtWidgets.QDialog):
def
__init__
(
self
,
filename
,
callback
,
parent
=
None
):
super
(
BrightnessContrastDialog
,
self
).
__init__
(
parent
)
self
.
setModal
(
True
)
self
.
setWindowTitle
(
'Brightness/Contrast'
)
self
.
setWindowTitle
(
"Brightness/Contrast"
)
self
.
slider_brightness
=
self
.
_create_slider
()
self
.
slider_contrast
=
self
.
_create_slider
()
formLayout
=
QtWidgets
.
QFormLayout
()
formLayout
.
addRow
(
self
.
tr
(
'Brightness'
),
self
.
slider_brightness
)
formLayout
.
addRow
(
self
.
tr
(
'Contrast'
),
self
.
slider_contrast
)
formLayout
.
addRow
(
self
.
tr
(
"Brightness"
),
self
.
slider_brightness
)
formLayout
.
addRow
(
self
.
tr
(
"Contrast"
),
self
.
slider_contrast
)
self
.
setLayout
(
formLayout
)
self
.
img
=
Image
.
open
(
filename
).
convert
(
'RGBA'
)
self
.
img
=
Image
.
open
(
filename
).
convert
(
"RGBA"
)
self
.
callback
=
callback
def
onNewValue
(
self
,
value
):
brightness
=
self
.
slider_brightness
.
value
()
/
100.
contrast
=
self
.
slider_contrast
.
value
()
/
100.
brightness
=
self
.
slider_brightness
.
value
()
/
100.
0
contrast
=
self
.
slider_contrast
.
value
()
/
100.
0
img
=
self
.
img
img
=
ImageEnhance
.
Brightness
(
img
).
enhance
(
brightness
)
img
=
ImageEnhance
.
Contrast
(
img
).
enhance
(
contrast
)
bytes
=
img
.
tobytes
(
'raw'
,
'RGBA'
)
qimage
=
QtGui
.
QImage
(
bytes
,
img
.
size
[
0
],
img
.
size
[
1
],
QtGui
.
QImage
.
Format_RGB32
).
rgbSwapped
()
bytes
=
img
.
tobytes
(
"raw"
,
"RGBA"
)
qimage
=
QtGui
.
QImage
(
bytes
,
img
.
size
[
0
],
img
.
size
[
1
],
QtGui
.
QImage
.
Format_RGB32
).
rgbSwapped
()
self
.
callback
(
qimage
)
def
_create_slider
(
self
):
...
...
labelme/widgets/canvas.py
浏览文件 @
5c980844
...
...
@@ -32,17 +32,18 @@ class Canvas(QtWidgets.QWidget):
CREATE
,
EDIT
=
0
,
1
# polygon, rectangle, line, or point
_createMode
=
'polygon'
_createMode
=
"polygon"
_fill_drawing
=
False
def
__init__
(
self
,
*
args
,
**
kwargs
):
self
.
epsilon
=
kwargs
.
pop
(
'epsilon'
,
10.0
)
self
.
double_click
=
kwargs
.
pop
(
'double_click'
,
'close'
)
if
self
.
double_click
not
in
[
None
,
'close'
]:
self
.
epsilon
=
kwargs
.
pop
(
"epsilon"
,
10.0
)
self
.
double_click
=
kwargs
.
pop
(
"double_click"
,
"close"
)
if
self
.
double_click
not
in
[
None
,
"close"
]:
raise
ValueError
(
'Unexpected value for double_click event: {}'
.
format
(
self
.
double_click
)
"Unexpected value for double_click event: {}"
.
format
(
self
.
double_click
)
)
super
(
Canvas
,
self
).
__init__
(
*
args
,
**
kwargs
)
# Initialise local state.
...
...
@@ -95,9 +96,15 @@ class Canvas(QtWidgets.QWidget):
@
createMode
.
setter
def
createMode
(
self
,
value
):
if
value
not
in
[
'polygon'
,
'rectangle'
,
'circle'
,
'line'
,
'point'
,
'linestrip'
]:
raise
ValueError
(
'Unsupported createMode: %s'
%
value
)
if
value
not
in
[
"polygon"
,
"rectangle"
,
"circle"
,
"line"
,
"point"
,
"linestrip"
,
]:
raise
ValueError
(
"Unsupported createMode: %s"
%
value
)
self
.
_createMode
=
value
def
storeShapes
(
self
):
...
...
@@ -187,26 +194,29 @@ class Canvas(QtWidgets.QWidget):
# Don't allow the user to draw outside the pixmap.
# Project the point to the pixmap's edges.
pos
=
self
.
intersectionPoint
(
self
.
current
[
-
1
],
pos
)
elif
len
(
self
.
current
)
>
1
and
self
.
createMode
==
'polygon'
and
\
self
.
closeEnough
(
pos
,
self
.
current
[
0
]):
elif
(
len
(
self
.
current
)
>
1
and
self
.
createMode
==
"polygon"
and
self
.
closeEnough
(
pos
,
self
.
current
[
0
])
):
# Attract line to starting point and
# colorise to alert the user.
pos
=
self
.
current
[
0
]
self
.
overrideCursor
(
CURSOR_POINT
)
self
.
current
.
highlightVertex
(
0
,
Shape
.
NEAR_VERTEX
)
if
self
.
createMode
in
[
'polygon'
,
'linestrip'
]:
if
self
.
createMode
in
[
"polygon"
,
"linestrip"
]:
self
.
line
[
0
]
=
self
.
current
[
-
1
]
self
.
line
[
1
]
=
pos
elif
self
.
createMode
==
'rectangle'
:
elif
self
.
createMode
==
"rectangle"
:
self
.
line
.
points
=
[
self
.
current
[
0
],
pos
]
self
.
line
.
close
()
elif
self
.
createMode
==
'circle'
:
elif
self
.
createMode
==
"circle"
:
self
.
line
.
points
=
[
self
.
current
[
0
],
pos
]
self
.
line
.
shape_type
=
"circle"
elif
self
.
createMode
==
'line'
:
elif
self
.
createMode
==
"line"
:
self
.
line
.
points
=
[
self
.
current
[
0
],
pos
]
self
.
line
.
close
()
elif
self
.
createMode
==
'point'
:
elif
self
.
createMode
==
"point"
:
self
.
line
.
points
=
[
self
.
current
[
0
]]
self
.
line
.
close
()
self
.
repaint
()
...
...
@@ -220,8 +230,9 @@ class Canvas(QtWidgets.QWidget):
self
.
boundedMoveShapes
(
self
.
selectedShapesCopy
,
pos
)
self
.
repaint
()
elif
self
.
selectedShapes
:
self
.
selectedShapesCopy
=
\
[
s
.
copy
()
for
s
in
self
.
selectedShapes
]
self
.
selectedShapesCopy
=
[
s
.
copy
()
for
s
in
self
.
selectedShapes
]
self
.
repaint
()
return
...
...
@@ -268,7 +279,8 @@ class Canvas(QtWidgets.QWidget):
self
.
prevhShape
=
self
.
hShape
=
shape
self
.
prevhEdge
=
self
.
hEdge
=
index_edge
self
.
setToolTip
(
self
.
tr
(
"Click & drag to move shape '%s'"
)
%
shape
.
label
)
self
.
tr
(
"Click & drag to move shape '%s'"
)
%
shape
.
label
)
self
.
setStatusTip
(
self
.
toolTip
())
self
.
overrideCursor
(
CURSOR_GRAB
)
self
.
update
()
...
...
@@ -313,16 +325,16 @@ class Canvas(QtWidgets.QWidget):
if
self
.
drawing
():
if
self
.
current
:
# Add point to existing shape.
if
self
.
createMode
==
'polygon'
:
if
self
.
createMode
==
"polygon"
:
self
.
current
.
addPoint
(
self
.
line
[
1
])
self
.
line
[
0
]
=
self
.
current
[
-
1
]
if
self
.
current
.
isClosed
():
self
.
finalise
()
elif
self
.
createMode
in
[
'rectangle'
,
'circle'
,
'line'
]:
elif
self
.
createMode
in
[
"rectangle"
,
"circle"
,
"line"
]:
assert
len
(
self
.
current
.
points
)
==
1
self
.
current
.
points
=
self
.
line
.
points
self
.
finalise
()
elif
self
.
createMode
==
'linestrip'
:
elif
self
.
createMode
==
"linestrip"
:
self
.
current
.
addPoint
(
self
.
line
[
1
])
self
.
line
[
0
]
=
self
.
current
[
-
1
]
if
int
(
ev
.
modifiers
())
==
QtCore
.
Qt
.
ControlModifier
:
...
...
@@ -331,22 +343,22 @@ class Canvas(QtWidgets.QWidget):
# Create new shape.
self
.
current
=
Shape
(
shape_type
=
self
.
createMode
)
self
.
current
.
addPoint
(
pos
)
if
self
.
createMode
==
'point'
:
if
self
.
createMode
==
"point"
:
self
.
finalise
()
else
:
if
self
.
createMode
==
'circle'
:
self
.
current
.
shape_type
=
'circle'
if
self
.
createMode
==
"circle"
:
self
.
current
.
shape_type
=
"circle"
self
.
line
.
points
=
[
pos
,
pos
]
self
.
setHiding
()
self
.
drawingPolygon
.
emit
(
True
)
self
.
update
()
else
:
group_mode
=
(
int
(
ev
.
modifiers
())
==
QtCore
.
Qt
.
ControlModifier
)
group_mode
=
int
(
ev
.
modifiers
())
==
QtCore
.
Qt
.
ControlModifier
self
.
selectShapePoint
(
pos
,
multiple_selection_mode
=
group_mode
)
self
.
prevPoint
=
pos
self
.
repaint
()
elif
ev
.
button
()
==
QtCore
.
Qt
.
RightButton
and
self
.
editing
():
group_mode
=
(
int
(
ev
.
modifiers
())
==
QtCore
.
Qt
.
ControlModifier
)
group_mode
=
int
(
ev
.
modifiers
())
==
QtCore
.
Qt
.
ControlModifier
self
.
selectShapePoint
(
pos
,
multiple_selection_mode
=
group_mode
)
self
.
prevPoint
=
pos
self
.
repaint
()
...
...
@@ -355,8 +367,10 @@ class Canvas(QtWidgets.QWidget):
if
ev
.
button
()
==
QtCore
.
Qt
.
RightButton
:
menu
=
self
.
menus
[
len
(
self
.
selectedShapesCopy
)
>
0
]
self
.
restoreCursor
()
if
not
menu
.
exec_
(
self
.
mapToGlobal
(
ev
.
pos
()))
\
and
self
.
selectedShapesCopy
:
if
(
not
menu
.
exec_
(
self
.
mapToGlobal
(
ev
.
pos
()))
and
self
.
selectedShapesCopy
):
# Cancel the move by deleting the shadow copy.
self
.
selectedShapesCopy
=
[]
self
.
repaint
()
...
...
@@ -365,8 +379,10 @@ class Canvas(QtWidgets.QWidget):
if
self
.
movingShape
and
self
.
hShape
:
index
=
self
.
shapes
.
index
(
self
.
hShape
)
if
(
self
.
shapesBackups
[
-
1
][
index
].
points
!=
self
.
shapes
[
index
].
points
):
if
(
self
.
shapesBackups
[
-
1
][
index
].
points
!=
self
.
shapes
[
index
].
points
):
self
.
storeShapes
()
self
.
shapeMoved
.
emit
()
...
...
@@ -405,8 +421,11 @@ class Canvas(QtWidgets.QWidget):
def
mouseDoubleClickEvent
(
self
,
ev
):
# We need at least 4 points here, since the mousePress handler
# adds an extra one before this handler is called.
if
(
self
.
double_click
==
'close'
and
self
.
canCloseShape
()
and
len
(
self
.
current
)
>
3
):
if
(
self
.
double_click
==
"close"
and
self
.
canCloseShape
()
and
len
(
self
.
current
)
>
3
):
self
.
current
.
popPoint
()
self
.
finalise
()
...
...
@@ -428,7 +447,8 @@ class Canvas(QtWidgets.QWidget):
if
multiple_selection_mode
:
if
shape
not
in
self
.
selectedShapes
:
self
.
selectionChanged
.
emit
(
self
.
selectedShapes
+
[
shape
])
self
.
selectedShapes
+
[
shape
]
)
else
:
self
.
selectionChanged
.
emit
([
shape
])
return
...
...
@@ -457,8 +477,10 @@ class Canvas(QtWidgets.QWidget):
pos
-=
QtCore
.
QPoint
(
min
(
0
,
o1
.
x
()),
min
(
0
,
o1
.
y
()))
o2
=
pos
+
self
.
offsets
[
1
]
if
self
.
outOfPixmap
(
o2
):
pos
+=
QtCore
.
QPoint
(
min
(
0
,
self
.
pixmap
.
width
()
-
o2
.
x
()),
min
(
0
,
self
.
pixmap
.
height
()
-
o2
.
y
()))
pos
+=
QtCore
.
QPoint
(
min
(
0
,
self
.
pixmap
.
width
()
-
o2
.
x
()),
min
(
0
,
self
.
pixmap
.
height
()
-
o2
.
y
()),
)
# XXX: The next line tracks the new position of the cursor
# relative to the shape, but also results in making it
# a bit "shaky" when nearing the border and allows it to
...
...
@@ -522,8 +544,9 @@ class Canvas(QtWidgets.QWidget):
p
.
drawPixmap
(
0
,
0
,
self
.
pixmap
)
Shape
.
scale
=
self
.
scale
for
shape
in
self
.
shapes
:
if
(
shape
.
selected
or
not
self
.
_hideBackround
)
and
\
self
.
isVisible
(
shape
):
if
(
shape
.
selected
or
not
self
.
_hideBackround
)
and
self
.
isVisible
(
shape
):
shape
.
fill
=
shape
.
selected
or
shape
==
self
.
hShape
shape
.
paint
(
p
)
if
self
.
current
:
...
...
@@ -533,8 +556,12 @@ class Canvas(QtWidgets.QWidget):
for
s
in
self
.
selectedShapesCopy
:
s
.
paint
(
p
)
if
(
self
.
fillDrawing
()
and
self
.
createMode
==
'polygon'
and
self
.
current
is
not
None
and
len
(
self
.
current
.
points
)
>=
2
):
if
(
self
.
fillDrawing
()
and
self
.
createMode
==
"polygon"
and
self
.
current
is
not
None
and
len
(
self
.
current
.
points
)
>=
2
):
drawing_shape
=
self
.
current
.
copy
()
drawing_shape
.
addPoint
(
self
.
line
[
1
])
drawing_shape
.
fill
=
True
...
...
@@ -582,10 +609,12 @@ class Canvas(QtWidgets.QWidget):
# and find the one intersecting the current line segment.
# http://paulbourke.net/geometry/lineline2d/
size
=
self
.
pixmap
.
size
()
points
=
[(
0
,
0
),
(
size
.
width
()
-
1
,
0
),
(
size
.
width
()
-
1
,
size
.
height
()
-
1
),
(
0
,
size
.
height
()
-
1
)]
points
=
[
(
0
,
0
),
(
size
.
width
()
-
1
,
0
),
(
size
.
width
()
-
1
,
size
.
height
()
-
1
),
(
0
,
size
.
height
()
-
1
),
]
# x1, y1 should be in the pixmap, x2, y2 should be out of the pixmap
x1
=
min
(
max
(
p1
.
x
(),
0
),
size
.
width
()
-
1
)
y1
=
min
(
max
(
p1
.
y
(),
0
),
size
.
height
()
-
1
)
...
...
@@ -663,7 +692,8 @@ class Canvas(QtWidgets.QWidget):
ev
.
delta
(),
QtCore
.
Qt
.
Horizontal
if
(
QtCore
.
Qt
.
ShiftModifier
==
int
(
mods
))
else
QtCore
.
Qt
.
Vertical
)
else
QtCore
.
Qt
.
Vertical
,
)
else
:
self
.
scrollRequest
.
emit
(
ev
.
delta
(),
QtCore
.
Qt
.
Horizontal
)
ev
.
accept
()
...
...
@@ -689,11 +719,11 @@ class Canvas(QtWidgets.QWidget):
assert
self
.
shapes
self
.
current
=
self
.
shapes
.
pop
()
self
.
current
.
setOpen
()
if
self
.
createMode
in
[
'polygon'
,
'linestrip'
]:
if
self
.
createMode
in
[
"polygon"
,
"linestrip"
]:
self
.
line
.
points
=
[
self
.
current
[
-
1
],
self
.
current
[
0
]]
elif
self
.
createMode
in
[
'rectangle'
,
'line'
,
'circle'
]:
elif
self
.
createMode
in
[
"rectangle"
,
"line"
,
"circle"
]:
self
.
current
.
points
=
self
.
current
.
points
[
0
:
1
]
elif
self
.
createMode
==
'point'
:
elif
self
.
createMode
==
"point"
:
self
.
current
=
None
self
.
drawingPolygon
.
emit
(
True
)
...
...
labelme/widgets/color_dialog.py
浏览文件 @
5c980844
...
...
@@ -2,7 +2,6 @@ from qtpy import QtWidgets
class
ColorDialog
(
QtWidgets
.
QColorDialog
):
def
__init__
(
self
,
parent
=
None
):
super
(
ColorDialog
,
self
).
__init__
(
parent
)
self
.
setOption
(
QtWidgets
.
QColorDialog
.
ShowAlphaChannel
)
...
...
@@ -25,6 +24,8 @@ class ColorDialog(QtWidgets.QColorDialog):
return
self
.
currentColor
()
if
self
.
exec_
()
else
None
def
checkRestore
(
self
,
button
):
if
self
.
bb
.
buttonRole
(
button
)
&
\
QtWidgets
.
QDialogButtonBox
.
ResetRole
and
self
.
default
:
if
(
self
.
bb
.
buttonRole
(
button
)
&
QtWidgets
.
QDialogButtonBox
.
ResetRole
and
self
.
default
):
self
.
setCurrentColor
(
self
.
default
)
labelme/widgets/escapable_qlist_widget.py
浏览文件 @
5c980844
...
...
@@ -3,7 +3,6 @@ from qtpy import QtWidgets
class
EscapableQListWidget
(
QtWidgets
.
QListWidget
):
def
keyPressEvent
(
self
,
event
):
super
(
EscapableQListWidget
,
self
).
keyPressEvent
(
event
)
if
event
.
key
()
==
Qt
.
Key_Escape
:
...
...
labelme/widgets/label_dialog.py
浏览文件 @
5c980844
...
...
@@ -9,7 +9,7 @@ from labelme.logger import logger
import
labelme.utils
QT5
=
QT_VERSION
[
0
]
==
'5'
QT5
=
QT_VERSION
[
0
]
==
"5"
# TODO(unknown):
...
...
@@ -17,7 +17,6 @@ QT5 = QT_VERSION[0] == '5'
class
LabelQLineEdit
(
QtWidgets
.
QLineEdit
):
def
setListWidget
(
self
,
list_widget
):
self
.
list_widget
=
list_widget
...
...
@@ -29,12 +28,19 @@ class LabelQLineEdit(QtWidgets.QLineEdit):
class
LabelDialog
(
QtWidgets
.
QDialog
):
def
__init__
(
self
,
text
=
"Enter object label"
,
parent
=
None
,
labels
=
None
,
sort_labels
=
True
,
show_text_field
=
True
,
completion
=
'startswith'
,
fit_to_content
=
None
,
flags
=
None
):
def
__init__
(
self
,
text
=
"Enter object label"
,
parent
=
None
,
labels
=
None
,
sort_labels
=
True
,
show_text_field
=
True
,
completion
=
"startswith"
,
fit_to_content
=
None
,
flags
=
None
,
):
if
fit_to_content
is
None
:
fit_to_content
=
{
'row'
:
False
,
'column'
:
True
}
fit_to_content
=
{
"row"
:
False
,
"column"
:
True
}
self
.
_fit_to_content
=
fit_to_content
super
(
LabelDialog
,
self
).
__init__
(
parent
)
...
...
@@ -45,9 +51,9 @@ class LabelDialog(QtWidgets.QDialog):
if
flags
:
self
.
edit
.
textChanged
.
connect
(
self
.
updateFlags
)
self
.
edit_group_id
=
QtWidgets
.
QLineEdit
()
self
.
edit_group_id
.
setPlaceholderText
(
'Group ID'
)
self
.
edit_group_id
.
setPlaceholderText
(
"Group ID"
)
self
.
edit_group_id
.
setValidator
(
QtGui
.
QRegExpValidator
(
QtCore
.
QRegExp
(
r
'\d*'
),
None
)
QtGui
.
QRegExpValidator
(
QtCore
.
QRegExp
(
r
"\d*"
),
None
)
)
layout
=
QtWidgets
.
QVBoxLayout
()
if
show_text_field
:
...
...
@@ -61,18 +67,18 @@ class LabelDialog(QtWidgets.QDialog):
QtCore
.
Qt
.
Horizontal
,
self
,
)
bb
.
button
(
bb
.
Ok
).
setIcon
(
labelme
.
utils
.
newIcon
(
'done'
))
bb
.
button
(
bb
.
Cancel
).
setIcon
(
labelme
.
utils
.
newIcon
(
'undo'
))
bb
.
button
(
bb
.
Ok
).
setIcon
(
labelme
.
utils
.
newIcon
(
"done"
))
bb
.
button
(
bb
.
Cancel
).
setIcon
(
labelme
.
utils
.
newIcon
(
"undo"
))
bb
.
accepted
.
connect
(
self
.
validate
)
bb
.
rejected
.
connect
(
self
.
reject
)
layout
.
addWidget
(
bb
)
# label_list
self
.
labelList
=
QtWidgets
.
QListWidget
()
if
self
.
_fit_to_content
[
'row'
]:
if
self
.
_fit_to_content
[
"row"
]:
self
.
labelList
.
setHorizontalScrollBarPolicy
(
QtCore
.
Qt
.
ScrollBarAlwaysOff
)
if
self
.
_fit_to_content
[
'column'
]:
if
self
.
_fit_to_content
[
"column"
]:
self
.
labelList
.
setVerticalScrollBarPolicy
(
QtCore
.
Qt
.
ScrollBarAlwaysOff
)
...
...
@@ -83,7 +89,8 @@ class LabelDialog(QtWidgets.QDialog):
self
.
labelList
.
sortItems
()
else
:
self
.
labelList
.
setDragDropMode
(
QtWidgets
.
QAbstractItemView
.
InternalMove
)
QtWidgets
.
QAbstractItemView
.
InternalMove
)
self
.
labelList
.
currentItemChanged
.
connect
(
self
.
labelSelected
)
self
.
labelList
.
itemDoubleClicked
.
connect
(
self
.
labelDoubleClicked
)
self
.
edit
.
setListWidget
(
self
.
labelList
)
...
...
@@ -99,21 +106,21 @@ class LabelDialog(QtWidgets.QDialog):
self
.
setLayout
(
layout
)
# completion
completer
=
QtWidgets
.
QCompleter
()
if
not
QT5
and
completion
!=
'startswith'
:
if
not
QT5
and
completion
!=
"startswith"
:
logger
.
warn
(
"completion other than 'startswith' is only "
"supported with Qt5. Using 'startswith'"
)
completion
=
'startswith'
if
completion
==
'startswith'
:
completion
=
"startswith"
if
completion
==
"startswith"
:
completer
.
setCompletionMode
(
QtWidgets
.
QCompleter
.
InlineCompletion
)
# Default settings.
# completer.setFilterMode(QtCore.Qt.MatchStartsWith)
elif
completion
==
'contains'
:
elif
completion
==
"contains"
:
completer
.
setCompletionMode
(
QtWidgets
.
QCompleter
.
PopupCompletion
)
completer
.
setFilterMode
(
QtCore
.
Qt
.
MatchContains
)
else
:
raise
ValueError
(
'Unsupported completion: {}'
.
format
(
completion
))
raise
ValueError
(
"Unsupported completion: {}"
.
format
(
completion
))
completer
.
setModel
(
self
.
labelList
.
model
())
self
.
edit
.
setCompleter
(
completer
)
...
...
@@ -129,7 +136,7 @@ class LabelDialog(QtWidgets.QDialog):
def
validate
(
self
):
text
=
self
.
edit
.
text
()
if
hasattr
(
text
,
'strip'
):
if
hasattr
(
text
,
"strip"
):
text
=
text
.
strip
()
else
:
text
=
text
.
trimmed
()
...
...
@@ -141,7 +148,7 @@ class LabelDialog(QtWidgets.QDialog):
def
postProcess
(
self
):
text
=
self
.
edit
.
text
()
if
hasattr
(
text
,
'strip'
):
if
hasattr
(
text
,
"strip"
):
text
=
text
.
strip
()
else
:
text
=
text
.
trimmed
()
...
...
@@ -164,7 +171,7 @@ class LabelDialog(QtWidgets.QDialog):
self
.
flagsLayout
.
removeWidget
(
item
)
item
.
setParent
(
None
)
def
resetFlags
(
self
,
label
=
''
):
def
resetFlags
(
self
,
label
=
""
):
flags
=
{}
for
pattern
,
keys
in
self
.
_flags
.
items
():
if
re
.
match
(
pattern
,
label
):
...
...
@@ -194,11 +201,11 @@ class LabelDialog(QtWidgets.QDialog):
return
None
def
popUp
(
self
,
text
=
None
,
move
=
True
,
flags
=
None
,
group_id
=
None
):
if
self
.
_fit_to_content
[
'row'
]:
if
self
.
_fit_to_content
[
"row"
]:
self
.
labelList
.
setMinimumHeight
(
self
.
labelList
.
sizeHintForRow
(
0
)
*
self
.
labelList
.
count
()
+
2
)
if
self
.
_fit_to_content
[
'column'
]:
if
self
.
_fit_to_content
[
"column"
]:
self
.
labelList
.
setMinimumWidth
(
self
.
labelList
.
sizeHintForColumn
(
0
)
+
2
)
...
...
labelme/widgets/tool_bar.py
浏览文件 @
5c980844
...
...
@@ -3,7 +3,6 @@ from qtpy import QtWidgets
class
ToolBar
(
QtWidgets
.
QToolBar
):
def
__init__
(
self
,
title
):
super
(
ToolBar
,
self
).
__init__
(
title
)
layout
=
self
.
layout
()
...
...
labelme/widgets/unique_label_qlist_widget.py
浏览文件 @
5c980844
...
...
@@ -7,7 +7,6 @@ from .escapable_qlist_widget import EscapableQListWidget
class
UniqueLabelQListWidget
(
EscapableQListWidget
):
def
mousePressEvent
(
self
,
event
):
super
(
UniqueLabelQListWidget
,
self
).
mousePressEvent
(
event
)
if
not
self
.
indexAt
(
event
.
pos
()).
isValid
():
...
...
@@ -29,11 +28,12 @@ class UniqueLabelQListWidget(EscapableQListWidget):
def
setItemLabel
(
self
,
item
,
label
,
color
=
None
):
qlabel
=
QtWidgets
.
QLabel
()
if
color
is
None
:
qlabel
.
setText
(
'{}'
.
format
(
label
))
qlabel
.
setText
(
"{}"
.
format
(
label
))
else
:
qlabel
.
setText
(
'{} <font color="#{:02x}{:02x}{:02x}">●</font>'
.
format
(
label
,
*
color
)
'{} <font color="#{:02x}{:02x}{:02x}">●</font>'
.
format
(
label
,
*
color
)
)
qlabel
.
setAlignment
(
Qt
.
AlignBottom
)
...
...
labelme/widgets/zoom_widget.py
浏览文件 @
5c980844
...
...
@@ -4,14 +4,13 @@ from qtpy import QtWidgets
class
ZoomWidget
(
QtWidgets
.
QSpinBox
):
def
__init__
(
self
,
value
=
100
):
super
(
ZoomWidget
,
self
).
__init__
()
self
.
setButtonSymbols
(
QtWidgets
.
QAbstractSpinBox
.
NoButtons
)
self
.
setRange
(
1
,
1000
)
self
.
setSuffix
(
' %'
)
self
.
setSuffix
(
" %"
)
self
.
setValue
(
value
)
self
.
setToolTip
(
'Zoom Level'
)
self
.
setToolTip
(
"Zoom Level"
)
self
.
setStatusTip
(
self
.
toolTip
())
self
.
setAlignment
(
QtCore
.
Qt
.
AlignCenter
)
...
...
pyproject.toml
0 → 100644
浏览文件 @
5c980844
[tool.black]
line-length
=
79
exclude
=
'''
(
^/\..*
| ^/docs/
| ^/build/
| ^/github2pypi/
)
'''
setup.py
浏览文件 @
5c980844
...
...
@@ -5,15 +5,21 @@ import re
from
setuptools
import
find_packages
from
setuptools
import
setup
import
shlex
import
site
import
subprocess
import
sys
# XXX: with pyproject.toml and without --no-use-pep517,
# sitepackages are not inserted to sys.path by default.
sys
.
path
.
extend
(
site
.
getsitepackages
())
def
get_version
():
filename
=
'labelme/__init__.py'
filename
=
"labelme/__init__.py"
with
open
(
filename
)
as
f
:
match
=
re
.
search
(
r
'''^__version__ = ['"]([^'"]*)['"]'''
,
f
.
read
(),
re
.
M
r
"""^__version__ = ['"]([^'"]*)['"]"""
,
f
.
read
(),
re
.
M
)
if
not
match
:
raise
RuntimeError
(
"{} doesn't contain __version__"
.
format
(
filename
))
...
...
@@ -27,13 +33,13 @@ def get_install_requires():
assert
PY3
or
PY2
install_requires
=
[
'imgviz>=0.11.0'
,
'matplotlib'
,
'numpy'
,
'Pillow>=2.8.0'
,
'PyYAML'
,
'qtpy'
,
'termcolor'
,
"imgviz>=0.11.0"
,
"matplotlib"
,
"numpy"
,
"Pillow>=2.8.0"
,
"PyYAML"
,
"qtpy"
,
"termcolor"
,
]
# Find python binding for qt with priority:
...
...
@@ -43,45 +49,49 @@ def get_install_requires():
try
:
import
PyQt5
# NOQA
QT_BINDING
=
'pyqt5'
QT_BINDING
=
"pyqt5"
except
ImportError
:
pass
if
QT_BINDING
is
None
:
try
:
import
PySide2
# NOQA
QT_BINDING
=
'pyside2'
QT_BINDING
=
"pyside2"
except
ImportError
:
pass
if
QT_BINDING
is
None
:
try
:
import
PyQt4
# NOQA
QT_BINDING
=
'pyqt4'
QT_BINDING
=
"pyqt4"
except
ImportError
:
if
PY2
:
print
(
'Please install PyQt5, PySide2 or PyQt4 for Python2.
\n
'
'Note that PyQt5 can be installed via pip for Python3.'
,
"Please install PyQt5, PySide2 or PyQt4 for Python2.
\n
"
"Note that PyQt5 can be installed via pip for Python3."
,
file
=
sys
.
stderr
,
)
sys
.
exit
(
1
)
assert
PY3
# PyQt5 can be installed via pip for Python3
install_requires
.
append
(
'PyQt5'
)
QT_BINDING
=
'pyqt5'
install_requires
.
append
(
"PyQt5"
)
QT_BINDING
=
"pyqt5"
del
QT_BINDING
return
install_requires
def
get_long_description
():
with
open
(
'README.md'
)
as
f
:
with
open
(
"README.md"
)
as
f
:
long_description
=
f
.
read
()
try
:
import
github2pypi
return
github2pypi
.
replace_url
(
slug
=
'wkentaro/labelme'
,
content
=
long_description
slug
=
"wkentaro/labelme"
,
content
=
long_description
)
except
Exception
:
return
long_description
...
...
@@ -90,63 +100,63 @@ def get_long_description():
def
main
():
version
=
get_version
()
if
sys
.
argv
[
1
]
==
'release'
:
if
not
distutils
.
spawn
.
find_executable
(
'twine'
):
if
sys
.
argv
[
1
]
==
"release"
:
if
not
distutils
.
spawn
.
find_executable
(
"twine"
):
print
(
'Please install twine:
\n\n\t
pip install twine
\n
'
,
"Please install twine:
\n\n\t
pip install twine
\n
"
,
file
=
sys
.
stderr
,
)
sys
.
exit
(
1
)
commands
=
[
'python tests/docs_tests/man_tests/test_labelme_1.py'
,
'git tag v{:s}'
.
format
(
version
),
'git push origin master --tag'
,
'python setup.py sdist'
,
'twine upload dist/labelme-{:s}.tar.gz'
.
format
(
version
),
"python tests/docs_tests/man_tests/test_labelme_1.py"
,
"git tag v{:s}"
.
format
(
version
),
"git push origin master --tag"
,
"python setup.py sdist"
,
"twine upload dist/labelme-{:s}.tar.gz"
.
format
(
version
),
]
for
cmd
in
commands
:
subprocess
.
check_call
(
shlex
.
split
(
cmd
))
sys
.
exit
(
0
)
setup
(
name
=
'labelme'
,
name
=
"labelme"
,
version
=
version
,
packages
=
find_packages
(
exclude
=
[
'github2pypi'
]),
description
=
'Image Polygonal Annotation with Python'
,
packages
=
find_packages
(
exclude
=
[
"github2pypi"
]),
description
=
"Image Polygonal Annotation with Python"
,
long_description
=
get_long_description
(),
long_description_content_type
=
'text/markdown'
,
author
=
'Kentaro Wada'
,
author_email
=
'www.kentaro.wada@gmail.com'
,
url
=
'https://github.com/wkentaro/labelme'
,
long_description_content_type
=
"text/markdown"
,
author
=
"Kentaro Wada"
,
author_email
=
"www.kentaro.wada@gmail.com"
,
url
=
"https://github.com/wkentaro/labelme"
,
install_requires
=
get_install_requires
(),
license
=
'GPLv3'
,
keywords
=
'Image Annotation, Machine Learning'
,
license
=
"GPLv3"
,
keywords
=
"Image Annotation, Machine Learning"
,
classifiers
=
[
'Development Status :: 5 - Production/Stable'
,
'Intended Audience :: Developers'
,
'Natural Language :: English'
,
'Programming Language :: Python'
,
'Programming Language :: Python :: 2.7'
,
'Programming Language :: Python :: 3.5'
,
'Programming Language :: Python :: 3.6'
,
'Programming Language :: Python :: 3.7'
,
'Programming Language :: Python :: Implementation :: CPython'
,
'Programming Language :: Python :: Implementation :: PyPy'
,
"Development Status :: 5 - Production/Stable"
,
"Intended Audience :: Developers"
,
"Natural Language :: English"
,
"Programming Language :: Python"
,
"Programming Language :: Python :: 2.7"
,
"Programming Language :: Python :: 3.5"
,
"Programming Language :: Python :: 3.6"
,
"Programming Language :: Python :: 3.7"
,
"Programming Language :: Python :: Implementation :: CPython"
,
"Programming Language :: Python :: Implementation :: PyPy"
,
],
package_data
=
{
'labelme'
:
[
'icons/*'
,
'config/*.yaml'
]},
package_data
=
{
"labelme"
:
[
"icons/*"
,
"config/*.yaml"
]},
entry_points
=
{
'console_scripts'
:
[
'labelme=labelme.__main__:main'
,
'labelme_draw_json=labelme.cli.draw_json:main'
,
'labelme_draw_label_png=labelme.cli.draw_label_png:main'
,
'labelme_json_to_dataset=labelme.cli.json_to_dataset:main'
,
'labelme_on_docker=labelme.cli.on_docker:main'
,
"console_scripts"
:
[
"labelme=labelme.__main__:main"
,
"labelme_draw_json=labelme.cli.draw_json:main"
,
"labelme_draw_label_png=labelme.cli.draw_label_png:main"
,
"labelme_json_to_dataset=labelme.cli.json_to_dataset:main"
,
"labelme_on_docker=labelme.cli.on_docker:main"
,
],
},
data_files
=
[(
'share/man/man1'
,
[
'docs/man/labelme.1'
])],
data_files
=
[(
"share/man/man1"
,
[
"docs/man/labelme.1"
])],
)
if
__name__
==
'__main__'
:
if
__name__
==
"__main__"
:
main
()
tests/docs_tests/man_tests/test_labelme_1.py
浏览文件 @
5c980844
...
...
@@ -11,17 +11,17 @@ import sys
here
=
osp
.
dirname
(
osp
.
abspath
(
__file__
))
cmd
=
'help2man labelme'
cmd
=
"help2man labelme"
man_expected
=
subprocess
.
check_output
(
shlex
.
split
(
cmd
)).
decode
().
splitlines
()
man_file
=
osp
.
realpath
(
osp
.
join
(
here
,
'../../../docs/man/labelme.1'
))
man_file
=
osp
.
realpath
(
osp
.
join
(
here
,
"../../../docs/man/labelme.1"
))
with
open
(
man_file
)
as
f
:
man_actual
=
f
.
read
().
splitlines
()
patterns_exclude
=
[
r
'^\.TH .*'
,
r
'^.*/\.labelmerc\)$'
,
r
'^\.\\.*'
,
r
"^\.TH .*"
,
r
"^.*/\.labelmerc\)$"
,
r
"^\.\\.*"
,
]
PASS
=
1
...
...
@@ -31,13 +31,13 @@ for line_expected, line_actual in zip(man_expected, man_actual):
break
else
:
if
line_expected
!=
line_actual
:
print
(
repr
(
'> {}'
.
format
(
line_expected
)),
file
=
sys
.
stderr
)
print
(
repr
(
'< {}'
.
format
(
line_actual
)),
file
=
sys
.
stderr
)
print
(
repr
(
"> {}"
.
format
(
line_expected
)),
file
=
sys
.
stderr
)
print
(
repr
(
"< {}"
.
format
(
line_actual
)),
file
=
sys
.
stderr
)
PASS
=
0
if
not
PASS
:
print
(
'Please run:
\n\n\t
help2man labelme > {}
\n
'
.
format
(
man_file
),
"Please run:
\n\n\t
help2man labelme > {}
\n
"
.
format
(
man_file
),
file
=
sys
.
stderr
,
)
assert
PASS
tests/labelme_tests/test_app.py
浏览文件 @
5c980844
...
...
@@ -8,14 +8,14 @@ import labelme.testing
here
=
osp
.
dirname
(
osp
.
abspath
(
__file__
))
data_dir
=
osp
.
join
(
here
,
'data'
)
data_dir
=
osp
.
join
(
here
,
"data"
)
def
_win_show_and_wait_imageData
(
qtbot
,
win
):
win
.
show
()
def
check_imageData
():
assert
hasattr
(
win
,
'imageData'
)
assert
hasattr
(
win
,
"imageData"
)
assert
win
.
imageData
is
not
None
qtbot
.
waitUntil
(
check_imageData
)
# wait for loadFile
...
...
@@ -29,7 +29,7 @@ def test_MainWindow_open(qtbot):
def
test_MainWindow_open_img
(
qtbot
):
img_file
=
osp
.
join
(
data_dir
,
'raw/2011_000003.jpg'
)
img_file
=
osp
.
join
(
data_dir
,
"raw/2011_000003.jpg"
)
win
=
labelme
.
app
.
MainWindow
(
filename
=
img_file
)
qtbot
.
addWidget
(
win
)
_win_show_and_wait_imageData
(
qtbot
,
win
)
...
...
@@ -38,8 +38,8 @@ def test_MainWindow_open_img(qtbot):
def
test_MainWindow_open_json
(
qtbot
):
json_files
=
[
osp
.
join
(
data_dir
,
'annotated_with_data/apc2016_obj3.json'
),
osp
.
join
(
data_dir
,
'annotated/2011_000003.json'
),
osp
.
join
(
data_dir
,
"annotated_with_data/apc2016_obj3.json"
),
osp
.
join
(
data_dir
,
"annotated/2011_000003.json"
),
]
for
json_file
in
json_files
:
labelme
.
testing
.
assert_labelfile_sanity
(
json_file
)
...
...
@@ -51,7 +51,7 @@ def test_MainWindow_open_json(qtbot):
def
test_MainWindow_open_dir
(
qtbot
):
directory
=
osp
.
join
(
data_dir
,
'raw'
)
directory
=
osp
.
join
(
data_dir
,
"raw"
)
win
=
labelme
.
app
.
MainWindow
(
filename
=
directory
)
qtbot
.
addWidget
(
win
)
_win_show_and_wait_imageData
(
qtbot
,
win
)
...
...
@@ -70,33 +70,33 @@ def test_MainWindow_openPrevImg(qtbot):
def
test_MainWindow_annotate_jpg
(
qtbot
):
tmp_dir
=
tempfile
.
mkdtemp
()
input_file
=
osp
.
join
(
data_dir
,
'raw/2011_000003.jpg'
)
out_file
=
osp
.
join
(
tmp_dir
,
'2011_000003.json'
)
input_file
=
osp
.
join
(
data_dir
,
"raw/2011_000003.jpg"
)
out_file
=
osp
.
join
(
tmp_dir
,
"2011_000003.json"
)
config
=
labelme
.
config
.
get_default_config
()
win
=
labelme
.
app
.
MainWindow
(
config
=
config
,
filename
=
input_file
,
output_file
=
out_file
,
config
=
config
,
filename
=
input_file
,
output_file
=
out_file
,
)
qtbot
.
addWidget
(
win
)
_win_show_and_wait_imageData
(
qtbot
,
win
)
label
=
'whole'
label
=
"whole"
points
=
[
(
100
,
100
),
(
100
,
238
),
(
400
,
238
),
(
400
,
100
),
]
shapes
=
[
dict
(
label
=
label
,
group_id
=
None
,
points
=
points
,
shape_type
=
'polygon'
,
flags
=
{},
other_data
=
{}
)]
shapes
=
[
dict
(
label
=
label
,
group_id
=
None
,
points
=
points
,
shape_type
=
"polygon"
,
flags
=
{},
other_data
=
{},
)
]
win
.
loadLabels
(
shapes
)
win
.
saveFile
()
...
...
tests/labelme_tests/utils_tests/test_image.py
浏览文件 @
5c980844
...
...
@@ -16,7 +16,7 @@ def test_img_b64_to_arr():
def
test_img_arr_to_b64
():
img_file
=
osp
.
join
(
data_dir
,
'annotated_with_data/apc2016_obj3.jpg'
)
img_file
=
osp
.
join
(
data_dir
,
"annotated_with_data/apc2016_obj3.jpg"
)
img_arr
=
np
.
asarray
(
PIL
.
Image
.
open
(
img_file
))
img_b64
=
image_module
.
img_arr_to_b64
(
img_arr
)
img_arr2
=
image_module
.
img_b64_to_arr
(
img_b64
)
...
...
@@ -24,8 +24,8 @@ def test_img_arr_to_b64():
def
test_img_data_to_png_data
():
img_file
=
osp
.
join
(
data_dir
,
'annotated_with_data/apc2016_obj3.jpg'
)
with
open
(
img_file
,
'rb'
)
as
f
:
img_file
=
osp
.
join
(
data_dir
,
"annotated_with_data/apc2016_obj3.jpg"
)
with
open
(
img_file
,
"rb"
)
as
f
:
img_data
=
f
.
read
()
png_data
=
image_module
.
img_data_to_png_data
(
img_data
)
assert
isinstance
(
png_data
,
bytes
)
tests/labelme_tests/utils_tests/test_shape.py
浏览文件 @
5c980844
...
...
@@ -6,18 +6,19 @@ from labelme.utils import shape as shape_module
def
test_shapes_to_label
():
img
,
data
=
get_img_and_data
()
label_name_to_value
=
{}
for
shape
in
data
[
'shapes'
]:
label_name
=
shape
[
'label'
]
for
shape
in
data
[
"shapes"
]:
label_name
=
shape
[
"label"
]
label_value
=
len
(
label_name_to_value
)
label_name_to_value
[
label_name
]
=
label_value
cls
,
_
=
shape_module
.
shapes_to_label
(
img
.
shape
,
data
[
'shapes'
],
label_name_to_value
)
img
.
shape
,
data
[
"shapes"
],
label_name_to_value
)
assert
cls
.
shape
==
img
.
shape
[:
2
]
def
test_shape_to_mask
():
img
,
data
=
get_img_and_data
()
for
shape
in
data
[
'shapes'
]:
points
=
shape
[
'points'
]
for
shape
in
data
[
"shapes"
]:
points
=
shape
[
"points"
]
mask
=
shape_module
.
shape_to_mask
(
img
.
shape
[:
2
],
points
)
assert
mask
.
shape
==
img
.
shape
[:
2
]
tests/labelme_tests/utils_tests/util.py
浏览文件 @
5c980844
...
...
@@ -6,13 +6,13 @@ from labelme.utils import shape as shape_module
here
=
osp
.
dirname
(
osp
.
abspath
(
__file__
))
data_dir
=
osp
.
join
(
here
,
'../data'
)
data_dir
=
osp
.
join
(
here
,
"../data"
)
def
get_img_and_data
():
json_file
=
osp
.
join
(
data_dir
,
'annotated_with_data/apc2016_obj3.json'
)
json_file
=
osp
.
join
(
data_dir
,
"annotated_with_data/apc2016_obj3.json"
)
data
=
json
.
load
(
open
(
json_file
))
img_b64
=
data
[
'imageData'
]
img_b64
=
data
[
"imageData"
]
img
=
image_module
.
img_b64_to_arr
(
img_b64
)
return
img
,
data
...
...
@@ -20,9 +20,9 @@ def get_img_and_data():
def
get_img_and_lbl
():
img
,
data
=
get_img_and_data
()
label_name_to_value
=
{
'__background__'
:
0
}
for
shape
in
data
[
'shapes'
]:
label_name
=
shape
[
'label'
]
label_name_to_value
=
{
"__background__"
:
0
}
for
shape
in
data
[
"shapes"
]:
label_name
=
shape
[
"label"
]
label_value
=
len
(
label_name_to_value
)
label_name_to_value
[
label_name
]
=
label_value
...
...
@@ -32,6 +32,6 @@ def get_img_and_lbl():
label_names
[
label_value
]
=
label_name
lbl
,
_
=
shape_module
.
shapes_to_label
(
img
.
shape
,
data
[
'shapes'
],
label_name_to_value
img
.
shape
,
data
[
"shapes"
],
label_name_to_value
)
return
img
,
lbl
,
label_names
tests/labelme_tests/widgets_tests/test_label_dialog.py
浏览文件 @
5c980844
...
...
@@ -7,21 +7,17 @@ from labelme.widgets import LabelQLineEdit
def
test_LabelQLineEdit
(
qtbot
):
list_widget
=
QtWidgets
.
QListWidget
()
list_widget
.
addItems
([
'cat'
,
'dog'
,
'person'
,
])
list_widget
.
addItems
([
"cat"
,
"dog"
,
"person"
])
widget
=
LabelQLineEdit
()
widget
.
setListWidget
(
list_widget
)
qtbot
.
addWidget
(
widget
)
# key press to navigate in label list
item
=
widget
.
list_widget
.
findItems
(
'cat'
,
QtCore
.
Qt
.
MatchExactly
)[
0
]
item
=
widget
.
list_widget
.
findItems
(
"cat"
,
QtCore
.
Qt
.
MatchExactly
)[
0
]
widget
.
list_widget
.
setCurrentItem
(
item
)
assert
widget
.
list_widget
.
currentItem
().
text
()
==
'cat'
assert
widget
.
list_widget
.
currentItem
().
text
()
==
"cat"
qtbot
.
keyPress
(
widget
,
QtCore
.
Qt
.
Key_Down
)
assert
widget
.
list_widget
.
currentItem
().
text
()
==
'dog'
assert
widget
.
list_widget
.
currentItem
().
text
()
==
"dog"
# key press to enter label
qtbot
.
keyPress
(
widget
,
QtCore
.
Qt
.
Key_P
)
...
...
@@ -30,37 +26,39 @@ def test_LabelQLineEdit(qtbot):
qtbot
.
keyPress
(
widget
,
QtCore
.
Qt
.
Key_S
)
qtbot
.
keyPress
(
widget
,
QtCore
.
Qt
.
Key_O
)
qtbot
.
keyPress
(
widget
,
QtCore
.
Qt
.
Key_N
)
assert
widget
.
text
()
==
'person'
assert
widget
.
text
()
==
"person"
def
test_LabelDialog_addLabelHistory
(
qtbot
):
labels
=
[
'cat'
,
'dog'
,
'person'
]
labels
=
[
"cat"
,
"dog"
,
"person"
]
widget
=
LabelDialog
(
labels
=
labels
,
sort_labels
=
True
)
qtbot
.
addWidget
(
widget
)
widget
.
addLabelHistory
(
'bicycle'
)
widget
.
addLabelHistory
(
"bicycle"
)
assert
widget
.
labelList
.
count
()
==
4
widget
.
addLabelHistory
(
'bicycle'
)
widget
.
addLabelHistory
(
"bicycle"
)
assert
widget
.
labelList
.
count
()
==
4
item
=
widget
.
labelList
.
item
(
0
)
assert
item
.
text
()
==
'bicycle'
assert
item
.
text
()
==
"bicycle"
def
test_LabelDialog_popUp
(
qtbot
):
labels
=
[
'cat'
,
'dog'
,
'person'
]
labels
=
[
"cat"
,
"dog"
,
"person"
]
widget
=
LabelDialog
(
labels
=
labels
,
sort_labels
=
True
)
qtbot
.
addWidget
(
widget
)
# popUp(text='cat')
def
interact
():
qtbot
.
keyClick
(
widget
.
edit
,
QtCore
.
Qt
.
Key_P
)
# enter 'p' for 'person' # NOQA
qtbot
.
keyClick
(
widget
.
edit
,
QtCore
.
Qt
.
Key_P
)
# enter 'p' for 'person' # NOQA
qtbot
.
keyClick
(
widget
.
edit
,
QtCore
.
Qt
.
Key_Enter
)
# NOQA
qtbot
.
keyClick
(
widget
.
edit
,
QtCore
.
Qt
.
Key_Enter
)
# NOQA
QtCore
.
QTimer
.
singleShot
(
500
,
interact
)
label
,
flags
,
group_id
=
widget
.
popUp
(
'cat'
)
assert
label
==
'person'
label
,
flags
,
group_id
=
widget
.
popUp
(
"cat"
)
assert
label
==
"person"
assert
flags
==
{}
assert
group_id
is
None
...
...
@@ -72,19 +70,21 @@ def test_LabelDialog_popUp(qtbot):
QtCore
.
QTimer
.
singleShot
(
500
,
interact
)
label
,
flags
,
group_id
=
widget
.
popUp
()
assert
label
==
'person'
assert
label
==
"person"
assert
flags
==
{}
assert
group_id
is
None
# popUp() + key_Up
def
interact
():
qtbot
.
keyClick
(
widget
.
edit
,
QtCore
.
Qt
.
Key_Up
)
# 'person' -> 'dog' # NOQA
qtbot
.
keyClick
(
widget
.
edit
,
QtCore
.
Qt
.
Key_Up
)
# 'person' -> 'dog' # NOQA
qtbot
.
keyClick
(
widget
.
edit
,
QtCore
.
Qt
.
Key_Enter
)
# NOQA
qtbot
.
keyClick
(
widget
.
edit
,
QtCore
.
Qt
.
Key_Enter
)
# NOQA
QtCore
.
QTimer
.
singleShot
(
500
,
interact
)
label
,
flags
,
group_id
=
widget
.
popUp
()
assert
label
==
'dog'
assert
label
==
"dog"
assert
flags
==
{}
assert
group_id
is
None
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录