数据集学习笔记(六):目标检测和图像分割标注软件介绍和使用,并转换成YOLO系列可使用的数据集格式

news2024/12/27 13:58:56

文章目录

  • 一、目标检测
    • 1.1 labelImg
    • 1.2 介绍
    • 1.3 安装
    • 1.4 使用
    • 1.5 转换
    • 1.6 验证
  • 二、图像分割
    • 2.1 labelme
    • 2.2 介绍
    • 2.3 安装
    • 2.4 使用
    • 2.5 转换
    • 2.6 验证

一、目标检测

1.1 labelImg

1.2 介绍

labelImg是一个开源的图像标注工具,用于创建图像标注数据集。它提供了一个简单易用的界面,允许用户通过绘制边界框或者创建多边形来标注图像中的对象。它支持多种常见的标注格式,如Pascal VOC、YOLO和COCO等。

使用labelImg,用户可以加载图像文件夹,逐个标注图像中的对象,并保存标注结果。该工具还提供了一些快捷键和功能,如缩放、移动和删除标注框,以及快速切换到下一张图像等。此外,labelImg还支持标注图像的困难程度、部分可见性和关键点等。

labelImg是一个跨平台的工具,可以在Windows、Linux和macOS等操作系统上运行。它基于Python和Qt开发,可以通过pip安装或从GitHub上获取源代码。这使得用户可以根据自己的需求进行定制和扩展。

总而言之,labelImg是一个功能强大、易于使用的图像标注工具,适用于创建各种类型的标注数据集,从而用于训练和评估计算机视觉模型。

1.3 安装

pip install labelImg

1.4 使用

  • 在cmd中输入labelImg,打开目标标注界面
    在这里插入图片描述
  • open dir选择图片的文件夹、Change Save Dir选择label保存的位置、在View下选择auto save mode可以不用每次都要点击保存、在File里面选择YOLO数据集的格式(点击pascalVOC切换)。
  • 通过w来选择标注区域,然后写上类别名
  • 键盘输入a是上一张,d是下一张
  • 然后按照这种格式将图片和label进行分开(train和valid同理)

在这里插入图片描述
在这里插入图片描述

1.5 转换

如果通过labelImg直接得到txt标签文本是不用进行转换就可以提供给YOLO进行训练的。
如果是保存的XML文本,则需要通过下面代码进行转换。

修改两个路径:xml文件地址和创建保存txt文件的地址

import os
import xml.etree.ElementTree as ET

# xml文件存放目录(修改成自己的文件名)
input_dir = r'E:\auto_label\annotation'

# 输出txt文件目录(自己创建的文件夹)
out_dir = r'E:\auto_label\labels'

class_list = []


# 获取目录所有xml文件
def file_name(input_dir):
    F = []
    for root, dirs, files in os.walk(input_dir):

        for file in files:
            # print file.decode('gbk')    #文件名中有中文字符时转码
            if os.path.splitext(file)[1] == '.xml':
                t = os.path.splitext(file)[0]
                F.append(t)  # 将所有的文件名添加到L列表中
    return F  # 返回L列表


# 获取所有分类
def get_class(filelist):
    for i in filelist:
        f_dir = input_dir + "\\" + i + ".xml"
        in_file = open(f_dir, encoding='UTF-8')
        filetree = ET.parse(in_file)
        in_file.close()
        root = filetree.getroot()
        for obj in root.iter('object'):
            cls = obj.find('name').text
            if cls not in class_list:
                class_list.append(cls)


def ConverCoordinate(imgshape, bbox):
    # 将xml像素坐标转换为txt归一化后的坐标
    xmin, xmax, ymin, ymax = bbox
    width = imgshape[0]
    height = imgshape[1]
    dw = 1. / width
    dh = 1. / height
    x = (xmin + xmax) / 2.0
    y = (ymin + ymax) / 2.0
    w = xmax - xmin
    h = ymax - ymin

    # 归一化
    x = x * dw
    y = y * dh
    w = w * dw
    h = h * dh

    return x, y, w, h


def readxml(i):
    f_dir = input_dir + "\\" + i + ".xml"

    txtresult = ''

    outfile = open(f_dir, encoding='UTF-8')
    filetree = ET.parse(outfile)
    outfile.close()
    root = filetree.getroot()

    # 获取图片大小
    size = root.find('size')
    width = int(size.find('width').text)
    height = int(size.find('height').text)
    imgshape = (width, height)

    # 转化为yolov5的格式
    for obj in root.findall('object'):
        # 获取类别名
        obj_name = obj.find('name').text

        obj_id = class_list.index(obj_name)
        # 获取每个obj的bbox框的左上和右下坐标
        bbox = obj.find('bndbox')
        xmin = float(bbox.find('xmin').text)
        xmax = float(bbox.find('xmax').text)
        ymin = float(bbox.find('ymin').text)
        ymax = float(bbox.find('ymax').text)
        bbox_coor = (xmin, xmax, ymin, ymax)

        x, y, w, h = ConverCoordinate(imgshape, bbox_coor)
        txt = '{} {} {} {} {}\n'.format(obj_id, x, y, w, h)
        txtresult = txtresult + txt

    # print(txtresult)
    f = open(out_dir + "\\" + i + ".txt", 'a')
    f.write(txtresult)
    f.close()


# 获取文件夹下的所有文件
filelist = file_name(input_dir)

# 获取所有分类
get_class(filelist)

# 打印class
print(class_list)

# xml转txt
for i in filelist:
    readxml(i)

# 在out_dir下生成一个class文件
f = open(out_dir + "\\classes.txt", 'a')
classresult = ''
for i in class_list:
    classresult = classresult + i + "\n"
f.write(classresult)
f.close()

1.6 验证

import cv2
import os

# 读取txt文件信息
def read_list(txt_path):
    pos = []
    with open(txt_path, 'r') as file_to_read:
        while True:
            lines = file_to_read.readline()  # 整行读取数据
            if not lines:
                break
            # 将整行数据分割处理,如果分割符是空格,括号里就不用传入参数,如果是逗号, 则传入‘,'字符。
            p_tmp = [float(i) for i in lines.split(' ')]
            pos.append(p_tmp)  # 添加新读取的数据
            # Efield.append(E_tmp)
            pass
    return pos

# txt转换为box
def convert(size, box):
    xmin = (box[1] - box[3] / 2.) * size[1]
    xmax = (box[1] + box[3] / 2.) * size[1]
    ymin = (box[2] - box[4] / 2.) * size[0]
    ymax = (box[2] + box[4] / 2.) * size[0]
    box = (int(xmin), int(ymin), int(xmax), int(ymax))
    return box

def draw_box_in_single_image(image_path, txt_path):
    # 读取图像
    image = cv2.imread(image_path)
    pos = read_list(txt_path)

    for i in range(len(pos)):
        label = classes[int(str(int(pos[i][0])))]
        print('label is '+label)
        box = convert(image.shape, pos[i])
        image = cv2.rectangle(image,(box[0], box[1]),(box[2],box[3]),colores[int(str(int(pos[i][0])))],2)
        cv2.putText(image, label,(box[0],box[1]-2), 0, 1, colores[int(str(int(pos[i][0])))], thickness=2, lineType=cv2.LINE_AA)

    cv2.imshow("images", image)
    cv2.waitKey(0)

if __name__ == '__main__':

    img_folder = "D:\datasets\YOLO/images"
    img_list = os.listdir(img_folder)
    img_list.sort()

    label_folder = "D:\datasets\YOLO/labels"
    label_list = os.listdir(label_folder)
    label_list.sort()

    classes = {0: "cat", 1: "dog"}
    colores = [(0,0,255),(255,0,255)]

    for i in range(len(img_list)):
        image_path = img_folder + "\\" + img_list[i]
        txt_path = label_folder + "\\" + label_list[i]
        draw_box_in_single_image(image_path, txt_path)

在这里插入图片描述

二、图像分割

2.1 labelme

2.2 介绍

LabelMe是一个在线图像标注工具,旨在帮助用户对图像进行标注和注释。它提供了一个简单易用的界面,让用户可以方便地在图像上绘制边界框、标记点、线条等,并为每个标注对象添加文字描述。

LabelMe的主要特点包括

  • 灵活多样的标注工具:LabelMe提供了多种标注工具,包括矩形框、多边形、线条、点等,可以满足不同类型图像的标注需求。

  • 支持多种标注任务:LabelMe适用于各种标注任务,包括对象检测、语义分割、关键点标注等。

  • 数据的可视化和管理:LabelMe支持将标注结果可视化展示,用户可以在网页上查看和编辑标注结果。此外,LabelMe还提供了数据管理功能,可以方便地组织和管理大量的标注数据。

  • 数据的导入和导出:LabelMe支持将标注数据导入和导出为常见的数据格式,如XML、JSON等,方便与其他机器学习和计算机视觉工具集成。

总的来说,LabelMe是一个功能强大且易于使用的在线图像标注工具,适用于各种图像标注任务,并提供了方便的数据管理和导入导出功能。

2.3 安装

pip install labelme -i https://pypi.tuna.tsinghua.edu.cn/simple/

2.4 使用

参考链接:点击
在这里插入图片描述
打完标签后,会在我们图片的目录下相应的生成JSON标签文件,首先我们先验证一下我们打的标签和图片是否对应,如果没问题那么我们才转换成YOLO可训练的标签文件。参考代码如下:

import os, cv2, json
import numpy as np

base_path = '../dataset/labelme_dataset'
path_list = [i.split('.')[0] for i in os.listdir(base_path) if 'json' in i]
print(path_list)
for path in path_list:
    image = cv2.imread(f'{base_path}/{path}.jpg')
    h, w, c = image.shape
    label = np.zeros((h, w), dtype=np.uint8)
    with open(f'{base_path}/{path}.json') as f:
        mask = json.load(f)['shapes']
    for i in mask:
        i = np.array([np.array(j) for j in i['points']])
        label = cv2.fillPoly(label, [np.array(i, dtype=np.int32)], color=255)
    image = cv2.bitwise_and(image, image, mask=label)
    cv2.imshow('Pic', image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

在这里插入图片描述

2.5 转换

既然打的标签文件是没问题的,那么我们开始转换成YOLO可用的TXT文件,转换代码如下:

import os, cv2, json
import numpy as np

classes = ['square', 'triangle'] # 修改成对应的类别

base_path = '../dataset/labelme_dataset' # 指定json和图片的位置
path_list = [i.split('.')[0] for i in os.listdir(base_path)]
for path in path_list:
    image = cv2.imread(f'{base_path}/{path}.jpg')
    h, w, c = image.shape
    with open(f'{base_path}/{path}.json') as f:
        masks = json.load(f)['shapes']
    with open(f'{base_path}/{path}.txt', 'w+') as f:
        for idx, mask_data in enumerate(masks):
            mask_label = mask_data['label']
            if '_' in mask_label:
                mask_label = mask_label.split('_')[0]
            mask = np.array([np.array(i) for i in mask_data['points']], dtype=np.float)
            mask[:, 0] /= w
            mask[:, 1] /= h
            mask = mask.reshape((-1))
            if idx != 0:
                f.write('\n')
            f.write(f'{classes.index(mask_label)} {" ".join(list(map(lambda x:f"{x:.6f}", mask)))}')

通过这个代码可以在当前目录生成对应文件名的TXT标签文件,然后我们需要将其划分为训练集、验证集和测试集,可通过下面的代码:

import os, shutil, random
import numpy as np

postfix = 'jpg' # 里面都是jpg图片
base_path = '../dataset/labelme_dataset' # 原图片和TXT文件
dataset_path = '../dataset/custom_dataset' # 保存的目标位置
val_size, test_size = 0.1, 0.2

os.makedirs(dataset_path, exist_ok=True)
os.makedirs(f'{dataset_path}/images', exist_ok=True)
os.makedirs(f'{dataset_path}/images/train', exist_ok=True)
os.makedirs(f'{dataset_path}/images/val', exist_ok=True)
os.makedirs(f'{dataset_path}/images/test', exist_ok=True)
os.makedirs(f'{dataset_path}/labels/train', exist_ok=True)
os.makedirs(f'{dataset_path}/labels/val', exist_ok=True)
os.makedirs(f'{dataset_path}/labels/test', exist_ok=True)

path_list = np.array([i.split('.')[0] for i in os.listdir(base_path) if 'txt' in i])
random.shuffle(path_list)
train_id = path_list[:int(len(path_list) * (1 - val_size - test_size))]
val_id = path_list[int(len(path_list) * (1 - val_size - test_size)):int(len(path_list) * (1 - test_size))]
test_id = path_list[int(len(path_list) * (1 - test_size)):]

for i in train_id:
    shutil.copy(f'{base_path}/{i}.{postfix}', f'{dataset_path}/images/train/{i}.{postfix}')
    shutil.copy(f'{base_path}/{i}.txt', f'{dataset_path}/labels/train/{i}.txt')

for i in val_id:
    shutil.copy(f'{base_path}/{i}.{postfix}', f'{dataset_path}/images/val/{i}.{postfix}')
    shutil.copy(f'{base_path}/{i}.txt', f'{dataset_path}/labels/val/{i}.txt')

for i in test_id:
    shutil.copy(f'{base_path}/{i}.{postfix}', f'{dataset_path}/images/test/{i}.{postfix}')
    shutil.copy(f'{base_path}/{i}.txt', f'{dataset_path}/labels/test/{i}.txt')

2.6 验证

通过结合TXT标签文件以及图片来进行可视化,以验证其是否正确。

import os, cv2
import numpy as np

img_base_path = '../dataset/custom_dataset/images/train'
lab_base_path = '../dataset/custom_dataset/labels/train'

label_path_list = [i.split('.')[0] for i in os.listdir(img_base_path)]
for path in label_path_list:
    image = cv2.imread(f'{img_base_path}/{path}.jpg')
    h, w, c = image.shape
    label = np.zeros((h, w), dtype=np.uint8)
    with open(f'{lab_base_path}/{path}.txt') as f:
        mask = np.array(list(map(lambda x:np.array(x.strip().split()), f.readlines())))
    for i in mask:
        i = np.array(i, dtype=np.float32)[1:].reshape((-1, 2))
        i[:, 0] *= w
        i[:, 1] *= h
        label = cv2.fillPoly(label, [np.array(i, dtype=np.int32)], color=255)
    image = cv2.bitwise_and(image, image, mask=label)
    cv2.imshow('Pic', image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/949935.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023-08-30 LeetCode每日一题(到家的最少跳跃次数)

2023-08-30每日一题 一、题目编号 1654. 到家的最少跳跃次数二、题目链接 点击跳转到题目位置 三、题目描述 有一只跳蚤的家在数轴上的位置 x 处。请你帮助它从位置 0 出发,到达它的家。 跳蚤跳跃的规则如下: 它可以 往前 跳恰好 a 个位置&#x…

OpenCVSharp入门学习①-获取本地摄像头数据

1. nuget包安装opencvsharp4和opencvsharp4.extensiongs和opencvsharp4.runtime.win 如果不安装opencvsharp4.runtime.win的话会报 System.TypeInitializationException:““OpenCvSharp.Internal.NativeMethods”的类型初始值设定项引发异常。”DllNotFoundException: 无法加…

vue v-for 例子

vue v-for 例子 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </head&…

AssemblyManager 程序集管理器

AssemblyManager 程序集管理器 程序执行中使用反射对框架的搭建有着强大的影响&#xff0c;如何管理程序集方便使用反射获取类型操作对象是本文章的重点 1.AssemblyInfo 对于一个程序集这里使用一个AssemblyInfo对象进行管理 Assembly &#xff1a;对应的程序集AssemblyTyp…

Java多线程与并发编程

课程地址&#xff1a; https://www.itlaoqi.com/chapter.html?sid98&cid1425 源码文档&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1WMvM3j6qhyjIeAT87kIcxg 提取码&#xff1a;5g56 Java多线程与并发编程 1-并发背后的故事什么是并发 2-你必须知道线程的概念程…

Cadence网表导出常见错误

前言 好不容易绘制出来原理图&#xff0c;结果导出报了很多条错误&#xff0c;由于哥们还是小白&#xff0c;所以很多事情还不懂&#xff0c;有错误的地方希望大佬们能够指出&#xff0c;主要还是以我遇到的为主。 生成网表时候的常见错误 36002-封装名缺失 36003-多part器…

pdf怎么调整大小kb?一分钟学会pdf压缩

PDF是一种常见的文件格式&#xff0c;有时候我们需要将PDF文件的大小进行压缩&#xff0c;以便于传输或存储&#xff0c;那么怎么调整PDF文件的大小呢&#xff1f;接下来就给大家分享几个简单又实用的方法&#xff0c;帮助我们轻松解决PDF文件过大的问题。 方法一&#xff1a;嗨…

【高等数学重点题型篇】——一元函数微分学的应用

本文仅用于个人学习记录&#xff0c;使用的教材为汤家凤老师的《高等数学辅导讲义》。本文无任何盈利或者赚取个人声望的目的&#xff0c;如有侵权&#xff0c;请联系删除&#xff01; 文章目录 一、证明f ( n ) \ ^{(n)} (n)(ξ) 0二、待证结论中只有一个中值ξ&#xff0c;不…

【编译原理】课程一:编译原理入门

目录 1.为什么要学习编译原理 2.什么是编译原理 3.编译与计算机程序设计语言的关系 3.1.程序设计语言的转换方式 3.2.编译的转换过程 3.3.编译器在语言处理系统中的位置 3.4.编译系统的结构 3.4.1.词法分析(扫描) 3.4.2.语法分析(parsing) 3.4.1.1.语法分析的定义 3…

四轴飞行器的电池研究(MatlabSimulink仿真)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Python教程(11)——Python中的字典dict的用法介绍

dict的用法介绍 创建字典访问字典修改字典删除字典字典的相关函数 列表虽然好&#xff0c;但是如果需要快速的数据查找&#xff0c;就必须进行需要遍历&#xff0c;也就是最坏情况需要遍历完一遍才能找到需要的那个数据&#xff0c;时间复杂度是O(n)&#xff0c;显然这个速度是…

Canvas实现3D效果

3D 球 效果图 代码 var canvas document.getElementById("cas"),ctx canvas.getContext("2d"),vpx canvas.width / 2,vpy canvas.height / 2,Radius 150,balls [],angleX Math.PI / 1000,angleY Math.PI / 1000,factor 0.0001 //旋转因子var An…

解决方案 | 法大大电子签为保险行业加个“双保险”

近年来&#xff0c;人们自我保障意识的不断增强&#xff0c;带动了保险行业的蓬勃发展&#xff1b;数字化进程的加快&#xff0c;也让保险签署更加便捷高效。但与此同时&#xff0c;对于保险企业的安全合规化要求也在不断提升&#xff0c;电子签作为企业数字化转型的重要抓手&a…

vue3集成bpmn.js

1 安装依赖 npm install bpmn-js npm install bpmn-js-properties-panel npm install camunda-bpmn-moddle 注意依赖会有冲突&#xff0c;最好按照下列版本来安装&#xff1a; "bpmn-js": "^7.3.1", "bpmn-js-properties-panel": "^0.37.…

量子计算机使模拟化学反应减慢了1000亿倍!

悉尼大学(University of Sydney)的科学家们首次利用量子计算机设计并直接观测了化学反应中的一个关键过程&#xff0c;将其速度减慢了1000亿倍。 “Direct observation of geometric-phase interference in dynamics around a conical intersection” 主要作者Vanessa Olaya Ag…

免费可商用的高清视频素材库分享~

找视频素材绝对不能错过这个6个网站&#xff0c;免费可商用&#xff0c;视频剪辑、自媒体必备&#xff0c;赶紧收藏~ 1、菜鸟图库 https://www.sucai999.com/video.html?vNTYwNDUx 菜鸟图库不仅是一个设计网站&#xff0c;它还有非常丰富的视频和音频素材&#xff0c;视频素材…

[JDK8下的HashMap类应用及源码分析] 数据结构、哈希碰撞、链表变红黑树

系列文章目录 [Java基础] StringBuffer 和 StringBuilder 类应用及源码分析 [Java基础] 数组应用及源码分析 [Java基础] String&#xff0c;分析内存地址&#xff0c;源码 [JDK8环境下的HashMap类应用及源码分析] 第一篇 空构造函数初始化 [JDK8环境下的HashMap类应用及源码分…

Java 复习笔记 - 方法篇

文章目录 一&#xff0c;方法的定义二&#xff0c;最简单的方法定义和调用三&#xff0c;带参数的方法定义和调用四&#xff0c;带返回值方法的定义和调用五&#xff0c;小结六&#xff0c;方法的重载七&#xff0c;方法简单练习1&#xff0c;数组遍历2&#xff0c;数组最大值3…

【深入解读Redis系列】Redis系列(五):切片集群详解

首发博客地址 https://blog.zysicyj.top/ 系列文章地址[1] 如果 Redis 内存很大怎么办&#xff1f; 假设一台 32G 内存的服务器部署了一个 Redis&#xff0c;内存占用了 25G&#xff0c;会发生什么&#xff1f; 此时最明显的表现是 Redis 的响应变慢&#xff0c;甚至非常慢。 这…

Spring框架中如何处理事务管理

文章目录 **1. 声明式事务管理&#xff1a;****定义事务管理器&#xff1a;****配置事务通知&#xff1a;****将事务通知应用到方法&#xff1a;** **2. 编程式事务管理&#xff1a;****通过编程方式启动事务&#xff1a;** **3. 配置事务属性&#xff1a;** &#x1f388;个人…