yolo目标检测数据采用矩形框进行标注,其标注格式为[cls_id xp yp wp hp],cls_id表示目标所属的类别序号。xp、yp表示目标中心点相对坐标,其中xp等于目标的绝对横坐标除以图像宽度,yp等于目标的绝对纵坐标除以图像高度。wp和hp表示目标的相对宽度和高度,其中wp等于目标的绝对宽度除以图像宽度,hp等于目标的绝对高度除以图像高度。每张图片的标注结果以txt文本文件存储,每一行[cls_id xp yp wp hp]表示一个目标。
cv_img=cv2.imdecode(np.fromfile(imagePath,dtype=np.uint8),flags=cv2.IMREAD_COLOR)
labelme矩形目标的标注格式为[x1 y1 x2 y2],表示目标的左上和右下的绝对坐标。
yolo转labelme程序
Java版本
转换方法:
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.domain.LabelMeObj;
import com.ruoyi.common.core.domain.LabelMeShape;
import org.bytedeco.opencv.opencv_core.Mat;
import java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import static org.bytedeco.opencv.global.opencv_imgcodecs.imread;
public class LabelUtil {
/**
* yolo转labelme格式
*
* @param imagePath
* @param yoloLabelPath
* @param labelMePath
*/
public static void yolo2labelMeConverter(String imagePath, String yoloLabelPath, String labelMePath) {
// 读取图像
try (Mat src = imread(imagePath)) {
int w = src.cols();
int h = src.rows();
// 读取注释文件
if (!new File(yoloLabelPath).exists()) {
return;
}
List<String> lines = FileUtil.readUtf8Lines(yoloLabelPath);
if (CollUtil.isNotEmpty(lines)) {
LabelMeObj labelMeObj = new LabelMeObj();
labelMeObj.setVersion("5.0.1");
labelMeObj.setFlags(new JSONObject());
labelMeObj.setImagePath(imagePath);
labelMeObj.setImageHeight(h);
labelMeObj.setImageWidth(w);
JSONArray jsonArray = new JSONArray();
for (String line : lines) {
if (StrUtil.isBlank(line)) {
continue;
}
LabelMeShape labelMeShape = new LabelMeShape();
List<String> split = StrUtil.split(line, StrUtil.SPACE);
double[][] points = new double[2][2];
// yolo注释数据
double x = Double.parseDouble(split.get(1));
double y = Double.parseDouble(split.get(2));
double w_ = Double.parseDouble(split.get(3));
double h_ = Double.parseDouble(split.get(4));
// 绝对数值转换
x = w * x;
y = h * y;
w_ = w * w_;
h_ = h * h_;
points[0][0] = new BigDecimal(x - w_ / 2).setScale(2, RoundingMode.HALF_UP).doubleValue();
points[0][1] = new BigDecimal(y - h_ / 2).setScale(2, RoundingMode.HALF_UP).doubleValue();
points[1][0] = new BigDecimal(x + w_ / 2).setScale(2, RoundingMode.HALF_UP).doubleValue();
points[1][1] = new BigDecimal(y + h_ / 2).setScale(2, RoundingMode.HALF_UP).doubleValue();
labelMeShape.setLabel(split.get(0));
labelMeShape.setPoints(JSONArray.of(points));
labelMeShape.setShape_type("rectangle");
labelMeShape.setFlags(new JSONObject());
jsonArray.add(labelMeShape);
}
labelMeObj.setShapes(jsonArray);
// 转换后注释写入文件
FileUtil.writeUtf8String(JSON.toJSONString(labelMeObj), labelMePath);
}
}
}
}
实体类:
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import lombok.Data;
/**
* @author lipei
*/
@Data
public class LabelMeObj {
private String version;
private JSONObject flags;
private String imageData;
private String imagePath;
private Integer imageHeight;
private Integer imageWidth;
private JSONArray shapes;
}
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import lombok.Data;
/**
* @author lipei
*/
@Data
public class LabelMeShape {
private String label;
private JSONArray points;
private String group_id;
private String shape_type;
private JSONObject flags;
}
原Python版本
# -*- coding: utf-8 -*-
"""
Created on Tue Mar 29 17:42:11 2022
@author: https://blog.youkuaiyun.com/suiyingy?type=blog
"""
import cv2
import os
import json
import shutil
import numpy as np
from pathlib import Path
id2cls = {0:'pig'}
def xyxy2labelme(labels, w, h, image_path, save_dir='res/'):
save_dir = str(Path(save_dir)) + '/'
if not os.path.exists(save_dir):
os.makedirs(save_dir)
label_dict = {}
label_dict['version'] = '5.0.1'
label_dict['flags'] = {}
label_dict['imageData'] = None
label_dict['imagePath'] = image_path
label_dict['imageHeight'] = h
label_dict['imageWidth'] = w
label_dict['shapes'] = []
for l in labels:
tmp = {}
tmp['label'] = id2cls[int(l[0])]
tmp['points'] =[[l[1], l[2]], [l[3], l[4]]]
tmp['group_id']= None
tmp['shape_type'] = 'rectangle'
tmp['flags'] = {}
label_dict['shapes'].append(tmp)
fn = save_dir+image_path.rsplit('.', 1)[0]+'.json'
with open(fn, 'w') as f:
json.dump(label_dict, f)
def yolo2labelme(yolo_image_dir, yolo_label_dir, save_dir='res/'):
yolo_image_dir = str(Path(yolo_image_dir)) + '/'
yolo_label_dir = str(Path(yolo_label_dir)) + '/'
save_dir = str(Path(save_dir)) + '/'
image_files = os.listdir(yolo_image_dir)
for iimgf, imgf in enumerate(image_files):
print(iimgf+1, '/', len(image_files), imgf)
fn = imgf.rsplit('.', 1)[0]
shutil.copy(yolo_image_dir + imgf, save_dir + imgf)
image = cv2.imread(yolo_image_dir + imgf)
h,w = image.shape[:2]
if not os.path.exists(yolo_label_dir + fn + '.txt'):
continue
labels = np.loadtxt(yolo_label_dir + fn + '.txt').reshape(-1, 5)
if len(labels) < 1:
continue
labels[:,1::2] = w * labels[:, 1::2]
labels[:,2::2] = h * labels[:, 2::2]
labels_xyxy = np.zeros(labels.shape)
labels_xyxy[:, 1] = np.clip(labels[:, 1] - labels[:, 3]/2, 0, w)
labels_xyxy[:, 2] = np.clip(labels[:, 2] - labels[:, 4]/2, 0, h)
labels_xyxy[:, 3] = np.clip(labels[:, 1] + labels[:, 3]/2, 0, w)
labels_xyxy[:, 4] = np.clip(labels[:, 2] + labels[:, 4]/2, 0, h)
xyxy2labelme(labels_xyxy, w, h, imgf, save_dir)
print('Completed!')
if __name__ == '__main__':
yolo_image_dir = r'H:\Data\pigs\images\train'
yolo_label_dir = r'H:\Data\pigs\labels\train'
save_dir = r'res/'
yolo2labelme(yolo_image_dir, yolo_label_dir, save_dir)
参考资料:https://blog.youkuaiyun.com/suiyingy/article/details/127217640