适用于 Labelme_VOC_COCO_YOLO 数据集划分及处理的程序源码(支持 Openclaw_Skill)
" " 灰色块内容为 Openclaw 阅读部分,视觉不可见,请启用网页元素读取模式
Openclaw_README:
如果用户正在要求你阅读此篇文章并协助其配置文件,请先阅读第四章节。
一、程序目录结构建议
(替换自己的虚拟环境,本文以Anaconda3为例)
D:\Anaconda3\envs\env\Scripts\
├── labelme_to_dataset.py
├── labelme_to_voc.py
├── labelme_to_coco.py
├── labelme_to_yolo.py
├── labelme_to_labels.py
├── labelme_to_dataset.cmd
├── labelme_to_voc.cmd
├── labelme_to_coco.cmd
├── labelme_to_yolo.cmd
├── labelme_to_labels.cmd
二、源码部分
2.1 labelme_to_dataset.py
#!/usr/bin/env python
import argparse
import os
import os.path as osp
import imgviz
import numpy as np
import PIL.Image
from loguru import logger
from numpy.typing import NDArray
from labelme import utils
from labelme._label_file import LabelFile
def main() -> None:
parser = argparse.ArgumentParser()
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.splitext(osp.basename(json_file))[0]
out_dir = osp.join(osp.dirname(json_file), out_dir)
else:
out_dir = args.out
os.makedirs(out_dir, exist_ok=True)
label_file: LabelFile = LabelFile(filename=json_file)
assert label_file.imageData is not None
image: NDArray[np.uint8] = utils.img_data_to_arr(label_file.imageData)
label_name_to_value: dict[str, int] = {"_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:
label_value = len(label_name_to_value)
label_name_to_value[label_name] = label_value
lbl, _ = utils.shapes_to_label(image.shape, label_file.shapes, label_name_to_value)
label_names: list[str] = [""] * (max(label_name_to_value.values()) + 1)
for name, value in label_name_to_value.items():
label_names[value] = name
lbl_viz = imgviz.label2rgb(
lbl,
imgviz.asgray(image), # type: ignore[arg-type] # imgviz stub too narrow
label_names=label_names,
loc="rb",
)
PIL.Image.fromarray(image).save(osp.join(out_dir, "img.png"))
imgviz.io.lblsave(osp.join(out_dir, "label.png"), lbl.astype(np.uint8))
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:
for lbl_name in label_names:
f.write(f"{lbl_name}\n")
logger.info(f"Saved to: {out_dir}")
if __name__ == "__main__":
main()
2.2 labelme_to_voc.py
#!/usr/bin/env python
import argparse
import glob
import os
import os.path as osp
import sys
import imgviz
import numpy as np
import labelme
def main() -> None:
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 or comma separated text", required=True
)
parser.add_argument(
"--noobject", help="Flag not to generate object label", action="store_true"
)
parser.add_argument(
"--nonpy", help="Flag not to generate .npy files", action="store_true"
)
parser.add_argument(
"--noviz", help="Flag to disable visualization", action="store_true"
)
args = parser.parse_args()
if osp.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"))
if not args.nonpy:
os.makedirs(osp.join(args.output_dir, "SegmentationClassNpy"))
if not args.noviz:
os.makedirs(osp.join(args.output_dir, "SegmentationClassVisualization"))
if not args.noobject:
os.makedirs(osp.join(args.output_dir, "SegmentationObject"))
if not args.nonpy:
os.makedirs(osp.join(args.output_dir, "SegmentationObjectNpy"))
if not args.noviz:
os.makedirs(osp.join(args.output_dir, "SegmentationObjectVisualization"))
print("Creating dataset:", args.output_dir)
if osp.exists(args.labels):
with open(args.labels) as f:
labels = [label.strip() for label in f if label]
else:
labels = [label.strip() for label in args.labels.split(",")]
class_names: list[str] = []
class_name_to_id = {}
for i, label in enumerate(labels):
class_id = i - 1 # starts with -1
class_name = label.strip()
class_name_to_id[class_name] = class_id
if class_id == -1:
assert class_name == "__ignore__"
continue
elif class_id == 0:
assert class_name == "_background_"
class_names.append(class_name)
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 sorted(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", f"{base}.jpg")
out_clsp_file = osp.join(args.output_dir, "SegmentationClass", f"{base}.png")
if not args.nonpy:
out_cls_file = osp.join(
args.output_dir, "SegmentationClassNpy", f"{base}.npy"
)
if not args.noviz:
out_clsv_file = osp.join(
args.output_dir,
"SegmentationClassVisualization",
f"{base}.jpg",
)
if not args.noobject:
out_insp_file = osp.join(
args.output_dir, "SegmentationObject", f"{base}.png"
)
if not args.nonpy:
out_ins_file = osp.join(
args.output_dir, "SegmentationObjectNpy", f"{base}.npy"
)
if not args.noviz:
out_insv_file = osp.join(
args.output_dir,
"SegmentationObjectVisualization",
f"{base}.jpg",
)
assert label_file.imageData is not None
img = labelme.utils.img_data_to_arr(label_file.imageData)
imgviz.io.imsave(out_img_file, img)
cls, ins = labelme.utils.shapes_to_label(
img_shape=img.shape,
shapes=label_file.shapes,
label_name_to_value=class_name_to_id,
)
ins[cls == -1] = 0 # ignore it.
# class label
imgviz.io.lblsave(out_clsp_file, cls.astype(np.uint8))
if not args.nonpy:
np.save(out_cls_file, cls)
if not args.noviz:
clsv = imgviz.label2rgb(
cls,
imgviz.rgb2gray(img),
label_names=class_names,
font_size=15,
loc="rb",
)
imgviz.io.imsave(out_clsv_file, clsv)
if not args.noobject:
# instance label
imgviz.io.lblsave(out_insp_file, ins.astype(np.uint8))
if not args.nonpy:
np.save(out_ins_file, ins)
if not args.noviz:
instance_ids = np.unique(ins)
instance_names = [str(i) for i in range(max(instance_ids) + 1)]
insv = imgviz.label2rgb(
ins,
imgviz.rgb2gray(img),
label_names=instance_names,
font_size=15,
loc="rb",
)
imgviz.io.imsave(out_insv_file, insv)
if __name__ == "__main__":
main()
2.3 labelme_to_coco.py
#!/usr/bin/env python
import argparse
import collections
import datetime
import glob
import json
import os
import os.path as osp
import sys
import uuid
import imgviz
import numpy as np
import labelme
try:
import pycocotools.mask # type: ignore
except ImportError:
print("Please install pycocotools:\n\n pip install pycocotools\n")
sys.exit(1)
def main() -> None:
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("--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)
sys.exit(1)
os.makedirs(args.output_dir)
os.makedirs(osp.join(args.output_dir, "JPEGImages"))
if not args.noviz:
os.makedirs(osp.join(args.output_dir, "Visualization"))
print("Creating dataset:", args.output_dir)
now = datetime.datetime.now()
data = dict(
info=dict(
description=None,
url=None,
version=None,
year=now.year,
contributor=None,
date_created=now.strftime("%Y-%m-%d %H:%M:%S.%f"),
),
licenses=[
dict(
url=None,
id=0,
name=None,
)
],
type="instances",
)
data["images"] = [] # license, url, file_name, height, width, date_captured, id
data["categories"] = [] # supercategory, id, name
data[
"annotations"
] = [] # segmentation, area, iscrowd, image_id, bbox, category_id, id
class_name_to_id = {}
for i, line in enumerate(open(args.labels).readlines()):
class_id = i - 1 # starts with -1
class_name = line.strip()
if class_id == -1:
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"))
for image_id, filename in enumerate(label_files):
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", f"{base}.jpg")
assert label_file.imageData is not None
img = labelme.utils.img_data_to_arr(label_file.imageData)
if img.ndim == 3 and img.shape[2] == 4:
img = imgviz.rgba2rgb(img)
imgviz.io.imsave(out_img_file, img)
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: list[list[int | float]] = 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)
if group_id is None:
group_id = uuid.uuid1()
instance = (label, group_id)
if instance in masks:
masks[instance] = masks[instance] | mask
else:
masks[instance] = mask
points_coco: list[int | float]
if shape_type == "rectangle":
(x1, y1), (x2, y2) = points
x1, x2 = sorted([x1, x2])
y1, y2 = sorted([y1, y2])
points_coco = [x1, y1, x2, y1, x2, y2, x1, y2]
if shape_type == "circle":
(x1, y1), (x2, y2) = points
r = np.linalg.norm([x2 - x1, y2 - y1])
# r(1-cos(a/2))<x, a=2*pi/N => N>pi/arccos(1-x/r)
# x: tolerance of the gap between the arc and the line segment
n_points_circle = max(int(np.pi / np.arccos(1 - 1 / r)), 12)
i = np.arange(n_points_circle)
x = x1 + r * np.sin(2 * np.pi / n_points_circle * i)
y = y1 + r * np.cos(2 * np.pi / n_points_circle * i)
points_coco = np.stack((x, y), axis=1).flatten().tolist()
else:
points_coco = np.asarray(points).flatten().tolist()
segmentations[instance].append(points_coco)
segmentations = dict(segmentations)
for instance, mask in masks.items():
cls_name, group_id = instance
if cls_name not in class_name_to_id:
continue
cls_id = class_name_to_id[cls_name]
mask = np.asfortranarray(mask.astype(np.uint8))
mask = pycocotools.mask.encode(mask)
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,
)
)
if not args.noviz:
viz = img
if masks:
labels, captions, masks = zip(
*[
(class_name_to_id[cnm], cnm, msk)
for (cnm, gid), msk in masks.items()
if cnm in class_name_to_id
]
)
viz = imgviz.instances2rgb(
image=img,
labels=labels,
masks=masks,
captions=captions,
font_size=15,
line_width=2,
)
out_viz_file = osp.join(args.output_dir, "Visualization", f"{base}.jpg")
imgviz.io.imsave(out_viz_file, viz)
with open(out_ann_file, "w") as f:
json.dump(data, f)
if __name__ == "__main__":
main()
2.4 labelme_to_yolo.py
#!/usr/bin/env python
import argparse
import glob
import json
import os
import os.path as osp
import shutil
import sys
import cv2
import numpy as np
import yaml
IMAGE_EXTS = [".jpg", ".jpeg", ".png", ".bmp", ".tif", ".tiff", ".webp"]
def load_labels(labels_arg: str) -> tuple[list[str], dict[str, int]]:
if osp.exists(labels_arg):
with open(labels_arg, "r", encoding="utf-8") as f:
labels = [line.strip() for line in f if line.strip()]
else:
labels = [label.strip() for label in labels_arg.split(",") if label.strip()]
if len(labels) < 2:
raise ValueError("labels must contain at least __ignore__ and _background_")
if labels[0] != "__ignore__":
raise ValueError("first label must be __ignore__")
if labels[1] != "_background_":
raise ValueError("second label must be _background_")
class_names = labels[2:]
class_name_to_id = {name: idx for idx, name in enumerate(class_names)}
return class_names, class_name_to_id
def get_image_size(data: dict, json_file: str) -> tuple[int, int]:
image_width = data.get("imageWidth")
image_height = data.get("imageHeight")
if not isinstance(image_width, int) or not isinstance(image_height, int):
raise ValueError(
f"missing valid imageWidth/imageHeight in json file: {json_file}"
)
if image_width <= 0 or image_height <= 0:
raise ValueError(f"invalid image size in json file: {json_file}")
return image_width, image_height
def check_all_shapes_are_rectangles(json_files: list[str]) -> None:
bad_shapes = []
for filename in json_files:
try:
with open(filename, "r", encoding="utf-8") as f:
data = json.load(f)
except Exception as e:
print("Failed to read:", filename)
print("Reason:", e)
sys.exit(1)
for i, shape in enumerate(data.get("shapes", []), start=1):
shape_type = shape.get("shape_type", "polygon")
if shape_type != "rectangle":
bad_shapes.append((filename, i, shape.get("label", ""), shape_type))
if bad_shapes:
print("Detected non-rectangle annotations. YOLO only supports rectangle boxes.")
print("Please check these shapes:")
for filename, idx, label, shape_type in bad_shapes[:20]:
print(
f" file={filename}, shape_index={idx}, label={label}, shape_type={shape_type}"
)
if len(bad_shapes) > 20:
print(f" ... and {len(bad_shapes) - 20} more")
sys.exit(1)
def rectangle_points_to_yolo(points: list, image_width: int, image_height: int):
if len(points) != 2:
raise ValueError("rectangle shape must contain exactly 2 points")
x1, y1 = points[0]
x2, y2 = points[1]
xmin = min(float(x1), float(x2))
xmax = max(float(x1), float(x2))
ymin = min(float(y1), float(y2))
ymax = max(float(y1), float(y2))
box_width = xmax - xmin
box_height = ymax - ymin
x_center = xmin + box_width / 2.0
y_center = ymin + box_height / 2.0
x_center /= image_width
y_center /= image_height
box_width /= image_width
box_height /= image_height
return x_center, y_center, box_width, box_height
def find_image_for_json(input_dir: str, base: str) -> str | None:
for ext in IMAGE_EXTS:
image_path = osp.join(input_dir, base + ext)
if osp.exists(image_path):
return image_path
return None
def cv_imread(file_path):
data = np.fromfile(file_path, dtype=np.uint8)
img = cv2.imdecode(data, cv2.IMREAD_COLOR)
return img
def cv_imwrite(file_path, img):
ext = osp.splitext(file_path)[1]
if not ext:
ext = ".jpg"
file_path += ext
success, encoded_img = cv2.imencode(ext, img)
if success:
encoded_img.tofile(file_path)
return success
def get_voc_color(class_id: int):
r = g = b = 0
cid = class_id
for j in range(8):
r |= ((cid >> 0) & 1) << (7 - j)
g |= ((cid >> 1) & 1) << (7 - j)
b |= ((cid >> 2) & 1) << (7 - j)
cid >>= 3
return (b, g, r) # BGR for OpenCV
def clip_box(x1, y1, x2, y2, w, h):
x1 = max(0, min(x1, w - 1))
y1 = max(0, min(y1, h - 1))
x2 = max(0, min(x2, w - 1))
y2 = max(0, min(y2, h - 1))
return x1, y1, x2, y2
def yolo_to_xyxy(xc, yc, bw, bh, img_w, img_h):
x_center = xc * img_w
y_center = yc * img_h
box_w = bw * img_w
box_h = bh * img_h
x1 = int(round(x_center - box_w / 2.0))
y1 = int(round(y_center - box_h / 2.0))
x2 = int(round(x_center + box_w / 2.0))
y2 = int(round(y_center + box_h / 2.0))
return clip_box(x1, y1, x2, y2, img_w, img_h)
def draw_box_and_label(img, x1, y1, x2, y2, text, class_id):
box_color = get_voc_color(class_id)
text_color = (255, 255, 255)
thickness = 2
font = cv2.FONT_HERSHEY_SIMPLEX
font_scale = 0.6
cv2.rectangle(img, (x1, y1), (x2, y2), box_color, thickness)
(tw, th), baseline = cv2.getTextSize(text, font, font_scale, thickness)
text_x = x1
text_y = y1 - 8
if text_y - th - baseline < 0:
text_y = y1 + th + 8
bg_x1 = text_x
bg_y1 = text_y - th - baseline
bg_x2 = text_x + tw + 6
bg_y2 = text_y + baseline
img_h, img_w = img.shape[:2]
bg_x1, bg_y1, bg_x2, bg_y2 = clip_box(bg_x1, bg_y1, bg_x2, bg_y2, img_w, img_h)
cv2.rectangle(img, (bg_x1, bg_y1), (bg_x2, bg_y2), box_color, -1)
cv2.putText(
img,
text,
(bg_x1 + 3, bg_y2 - baseline),
font,
font_scale,
text_color,
thickness,
cv2.LINE_AA,
)
def main() -> None:
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument("input_dir", help="Input annotated directory")
parser.add_argument("output_dir", help="Output YOLO dataset directory")
parser.add_argument(
"--labels", help="Labels file or comma separated text", required=True
)
args = parser.parse_args()
if not osp.isdir(args.input_dir):
print("Input directory does not exist:", args.input_dir)
sys.exit(1)
if osp.exists(args.output_dir):
print("Output directory already exists:", args.output_dir)
sys.exit(1)
json_files = sorted(glob.glob(osp.join(args.input_dir, "*.json")))
if not json_files:
print("No json files found in:", args.input_dir)
sys.exit(1)
try:
class_names, class_name_to_id = load_labels(args.labels)
except Exception as e:
print("Failed to load labels")
print("Reason:", e)
sys.exit(1)
print("Checking annotation types...")
check_all_shapes_are_rectangles(json_files)
os.makedirs(args.output_dir)
labels_dir = osp.join(args.output_dir, "labels")
images_dir = osp.join(args.output_dir, "images")
visualization_dir = osp.join(args.output_dir, "Visualization")
os.makedirs(labels_dir)
os.makedirs(images_dir)
os.makedirs(visualization_dir)
classes_yaml = {
"nc": len(class_names),
"names": {idx: name for idx, name in enumerate(class_names)},
}
classes_yaml_file = osp.join(args.output_dir, "classes.yaml")
with open(classes_yaml_file, "w", encoding="utf-8") as f:
yaml.safe_dump(classes_yaml, f, allow_unicode=True, sort_keys=False)
print("Saved classes:", classes_yaml_file)
print("class_names:", class_names)
for filename in json_files:
print("Generating dataset from:", filename)
try:
with open(filename, "r", encoding="utf-8") as f:
data = json.load(f)
except Exception as e:
print("Failed to read:", filename)
print("Reason:", e)
sys.exit(1)
try:
image_width, image_height = get_image_size(data, filename)
except Exception as e:
print("Invalid image size:", filename)
print("Reason:", e)
sys.exit(1)
base = osp.splitext(osp.basename(filename))[0]
out_label_file = osp.join(labels_dir, f"{base}.txt")
image_path = find_image_for_json(args.input_dir, base)
if image_path is None:
print("Image file not found for json:", filename)
sys.exit(1)
image_name = osp.basename(image_path)
out_image_file = osp.join(images_dir, image_name)
out_visualization_file = osp.join(visualization_dir, image_name)
img = cv_imread(image_path)
if img is None:
print("Failed to read image:", image_path)
sys.exit(1)
vis_img = img.copy()
lines = []
for shape in data.get("shapes", []):
label = shape.get("label")
shape_type = shape.get("shape_type", "polygon")
points = shape.get("points", [])
if shape_type != "rectangle":
print("Found non-rectangle shape during conversion:", filename)
print("label:", label, "shape_type:", shape_type)
sys.exit(1)
if label in ("__ignore__", "_background_"):
continue
if label not in class_name_to_id:
print("Unknown label found in json:", label)
print("Please check labels file:", args.labels)
sys.exit(1)
try:
x_center, y_center, box_width, box_height = rectangle_points_to_yolo(
points, image_width, image_height
)
except Exception as e:
print("Failed to convert rectangle in:", filename)
print("label:", label)
print("Reason:", e)
sys.exit(1)
class_id = class_name_to_id[label]
line = (
f"{class_id} "
f"{x_center:.6f} "
f"{y_center:.6f} "
f"{box_width:.6f} "
f"{box_height:.6f}"
)
lines.append(line)
x1, y1 = points[0]
x2, y2 = points[1]
xmin = int(round(min(float(x1), float(x2))))
ymin = int(round(min(float(y1), float(y2))))
xmax = int(round(max(float(x1), float(x2))))
ymax = int(round(max(float(y1), float(y2))))
xmin, ymin, xmax, ymax = clip_box(
xmin, ymin, xmax, ymax, image_width, image_height
)
text = f"{class_id} {label}"
draw_box_and_label(vis_img, xmin, ymin, xmax, ymax, text, class_id)
with open(out_label_file, "w", encoding="utf-8") as f:
if lines:
f.write("\n".join(lines) + "\n")
shutil.copy2(image_path, out_image_file)
ok = cv_imwrite(out_visualization_file, vis_img)
if not ok:
print("Failed to save visualization:", out_visualization_file)
sys.exit(1)
print("Done")
print("Saved classes:", classes_yaml_file)
print("Saved labels directory:", labels_dir)
print("Saved images directory:", images_dir)
print("Saved visualization directory:", visualization_dir)
if __name__ == "__main__":
main()
2.5 labelme_to_labels.py
#!/usr/bin/env python
import argparse
import glob
import json
import os
import os.path as osp
import sys
def main() -> None:
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument("input_dir", help="Input annotated directory")
parser.add_argument(
"-o",
"--output",
default="labels.txt",
help="Output labels file",
)
parser.add_argument(
"--sort",
action="store_true",
help="Sort labels alphabetically",
)
args = parser.parse_args()
if not osp.isdir(args.input_dir):
print("Input directory does not exist:", args.input_dir)
sys.exit(1)
json_files = sorted(glob.glob(osp.join(args.input_dir, "*.json")))
if not json_files:
print("No json files found in:", args.input_dir)
sys.exit(1)
labels = []
label_set = set()
for filename in json_files:
print("Reading:", filename)
try:
with open(filename, "r", encoding="utf-8") as f:
data = json.load(f)
except Exception as e:
print("Failed to read:", filename)
print("Reason:", e)
continue
for shape in data.get("shapes", []):
label = shape.get("label")
if not isinstance(label, str):
continue
label = label.strip()
if not label:
continue
if label in ("__ignore__", "_background_"):
continue
if label not in label_set:
label_set.add(label)
labels.append(label)
if args.sort:
labels = sorted(labels)
with open(args.output, "w", encoding="utf-8") as f:
f.write("__ignore__\n")
f.write("_background_\n")
for label in labels:
f.write(label + "\n")
print("Saved labels file:", args.output)
print("Found {} labels:".format(len(labels)))
for label in labels:
print(label)
if __name__ == "__main__":
main()
2.6 labelme_to_xxx.cmd
(文件名xxx为voc\coco\yolo\dataset\labels,命令里的xxx也要更换)
@echo off
"D:\Anaconda3\envs\py_env_1\python.exe" "D:\Anaconda3\envs\py_env_1\Scripts\labelme_to_xxx.py" %*
三、使用方法
3.1 labelme_to_dataset:单个 JSON 导出可视化结果
这个脚本主要用于替代旧版的 labelme_json_to_dataset,适合快速检查某一个 JSON 标注文件。
命令示例 1:直接输出到默认目录
labelme_to_dataset D:\data\test\1.json
执行完成后,会在 1.json 同级目录下生成一个同名文件夹,例如:
D:\data\test\1\
├── img.png
├── label.png
├── label_viz.png
└── label_names.txt
命令示例 2:指定输出目录
labelme_to_dataset D:\data\test\1.json -o D:\data\output\demo1
输出的文件含义如下:
-
img.png:原图 -
label.png:标签图 -
label_viz.png:可视化效果图 -
label_names.txt:类别名称列表
3.2 labelme_to_labels:自动生成 labels.txt
在批量转换 VOC、COCO、YOLO 前,必须先执行这个脚本生成标签文件。
命令示例 1:默认输出 labels.txt
labelme_to_labels D:\data\dataset_raw
命令示例 2:指定输出名称
labelme_to_labels D:\data\dataset_raw -o D:\data\dataset_raw\labels.txt
命令示例 3:按字母排序
labelme_to_labels D:\data\dataset_raw -o D:\data\dataset_raw\labels.txt --sort
输出结果示例:
__ignore__
_background_
cat
dog
person
car
3.3 labelme_to_voc:批量生成VOC分割数据集
如果你的任务是语义分割,那么可以使用这个脚本。
命令示例:
labelme_to_voc D:\data\dataset_raw D:\data\voc_dataset --labels D:\data\dataset_raw\labels.txt
常用可选参数:
不生成 object 标签:
labelme_to_voc D:\data\dataset_raw D:\data\voc_dataset --labels D:\data\dataset_raw\labels.txt --noobject
不生成 .npy:
labelme_to_voc D:\data\dataset_raw D:\data\voc_dataset --labels D:\data\dataset_raw\labels.txt --nonpy
不生成可视化:
labelme_to_voc D:\data\dataset_raw D:\data\voc_dataset --labels D:\data\dataset_raw\labels.txt --noviz
输出目录结构:
voc_dataset/
├── JPEGImages/
├── SegmentationClass/
├── SegmentationClassNpy/
├── SegmentationClassVisualization/
├── SegmentationObject/
├── SegmentationObjectNpy/
├── SegmentationObjectVisualization/
└── class_names.txt
3.4 labelme_to_coco:批量生成 COCO 数据集
如果后续使用的是 COCO 格式训练框架,如 MMDetection、Detectron2、Mask R-CNN 等,可以使用此脚本。
命令示例:
labelme_to_coco D:\data\dataset_raw D:\data\coco_dataset --labels D:\data\dataset_raw\labels.txt
不生成可视化:
labelme_to_coco D:\data\dataset_raw D:\data\coco_dataset --labels D:\data\dataset_raw\labels.txt --noviz
输出目录结构:
coco_dataset/
├── JPEGImages/
├── Visualization/
└── annotations.json
如果运行时报缺少 pycocotools,需要先安装:
pip install pycocotools
3.5 labelme_to_yolo:批量生成 YOLO 数据集
命令示例:
labelme_to_yolo D:\data\dataset_raw D:\data\yolo_dataset --labels D:\data\dataset_raw\labels.txt
输出目录结构:
yolo_dataset/
├── images/
├── labels/
├── Visualization/
└── classes.yaml
结果说明:
-
images/:训练图像 -
labels/:YOLO 标签文件 -
Visualization/:用于人工检查的可视化图像 -
classes.yaml:类别配置文件
注意:该脚本只支持 rectangle 矩形框标注。Labelme 标注中不得存在:
-
polygon
-
circle
-
line
-
point
四、Openclaw_README
1. 先确认用户当前使用的虚拟环境
确认用户实际使用的是哪个 Python / Anaconda 虚拟环境。
2. 执行前先列出将要进行的所有文件操作
先明确告诉用户即将进行哪些文件操作,例如:
新建哪些 .py 文件、新建哪些 .cmd 文件、这些文件要放到哪个目录、哪些文件内容需要写入、哪些路径需要替换
然后询问用户:“是否要进行以下文件操作?”
3. 确认源码存放目录
确认这些源码文件需要放到当前虚拟环境的 Scripts 目录下。
4. 配置 Python 源码文件
创建并写入以下源码文件:
labelme_to_dataset.py、labelme_to_voc.py、labelme_to_coco.py、labelme_to_yolo.py、labelme_to_labels.py
5. 配置对应的 cmd 文件
创建对应的 .cmd 启动文件。
6. 最后检查文件是否齐全
确认 .py 和 .cmd 文件都已放到正确位置,且文件名与路径正确。
现在请你开始从第一章节学习此文章。
更多推荐



所有评论(0)