制作语义分割数据集(VOC格式)

环境:python3.8 labelme=5.0.1

1、使用labelme标注工具

直接在命令行安装或者在anaconda下面新建虚拟环境安装(避免污染环境,不用的时候可以直接delete该环境)

直接命令行(base)安装 

pip install labelme
labelme

创建虚拟环境安装,python版本选择3.8.x,打开Anaconda Prompt

conda create -n labelme python=3.8
conda activate labelme
pip install labelme
labelme

当前自动安装的版本为labelme-5.0.1

标注信息图如下

 

 

 

2:使用Labelme官方提供的脚本json_to_dataset.py把json转换为png形式,对于多分类的数据标注,需要在下面路径找到json_to_dataset.py修改:

虚拟环境下的路径为(具体情况具体分析):

C:\Users\siyu\miniconda3\envs\labelme\Lib\site-packages\labelme\cli

 运行脚本执行转换json操作,以下代码名为labelme_json_to_png.py

# -*- coding: utf-8 -*- 

import os
# json文件的存储路径
json_folder = r"E:/Dataset/3"

#  获取文件夹内的文件名
FileNameList = os.listdir(json_folder)
for i in range(len(FileNameList)):
    #  判断当前文件是否为json文件
    if(os.path.splitext(FileNameList[i])[1] == ".json"):
        json_file = json_folder + "\\" + FileNameList[i]
        #  用程序执行命令,将该json文件转为png
        os.system(r"python C:\Users\siyu\miniconda3\envs\labelme\Lib\site-packages\labelme\cli\json_to_dataset.py " + json_file)

 

运行上述代码

运行脚本

 生成的文件

3:把数据整理为images,segmentations对应的文件夹

 脚本如下:spilit_labelme_dataset.py

 1 # -*- coding: utf-8 -*-
 2 import os
 3 import numpy as np
 4 import json
 5 import shutil
 6 
 7 def find_dir_path(path, keyword_name, dir_list):
 8     files = os.listdir(path)
 9     for file_name in files:
10         file_path = os.path.join(path, file_name)
11         if os.path.isdir(file_path) and keyword_name not in file_path:
12             find_dir_path(file_path, keyword_name, dir_list)
13         elif os.path.isdir(file_path) and keyword_name in file_path:
14             dir_list.append(file_path)
15             
16 
17 all_result_path = []
18 src_path = r'E:\DataSet\3'
19 label_save_path = r'E:\DataSet\MyDataset\SegmentationClass'
20 image_save_path = r'E:\DataSet\MyDataset\JPEGImages'
21 find_dir_path(src_path, '_json', all_result_path)              # 找出所有带着关键词(_json)的所有目标文件夹
22 #print(all_result_path)   
23 
24 
25 for dir_path in all_result_path:
26     # print(dir_path)
27     file_name = dir_path.split('\\')[-1]
28     key_word = file_name[:-5]
29     # print(key_word)
30     label_file = dir_path + "\\" + "label.png"
31     new_label_save_path = label_save_path + "\\" + key_word + ".png"      # 复制生成的label.png到新的文件夹segmentations
32     # print(label_file,new_label_save_path)
33     shutil.copyfile(label_file, new_label_save_path)
34 
35     img_dir = os.path.dirname(dir_path)                         # 复制原图到新的文件夹images
36     img_file = img_dir + "\\" + key_word + ".jpg"
37     new_img_save_path = image_save_path + "\\" + key_word + ".jpg"
38     shutil.copyfile(img_file, new_img_save_path)

整理后如下图所示

 

 

 

 

 

 

4: 把png转换为label图

前面的用命令行转化的是8为掩码图像,不利于我们操作,因此转化为灰度图

 1 from PIL import Image
 2 import cv2
 3 import matplotlib.pyplot as plt
 4 import numpy as np
 5 
 6 root="E:/DataSet/MyDataset/SegmentationClass"
 7 fname="DJI_0001"
 8 
 9 # root="./dataset"
10 # fname="DJI_0001_0_0"
11 
12 # 使用PIL,就是windows的照片查看器
13 # im = Image.open('%s/%s.png' % (root, fname))
14 # print(im.load()[230,216])
15 # im.show()
16 
17 
18 im = Image.open('%s/%s.png' % (root, fname))
19 im.show()
20 im = np.array(im)
21 print(im.shape)
22 print("绿色:{0}".format(im[20][126]))
23 print("粉色:{0}".format(im[173][2972]))
24 print("红色:{0}".format(im[1097][661]))
25 print("蓝色:{0}".format(im[745][164]))

运行上述代码可以看到以及变成图像大小的矩阵

 

 在此给出一些查看图片以及具体位置像素的方法

1. 使用PIL库读取图片

# 使用PIL,就是windows的照片查看器
im = Image.open('%s/%s.png' % (root, fname))
print(im.load()[230,216]) #读取像素值
im.show()

2. 使用matplotlib读取并显示图片

# 带坐标和像素值!!好极了

import matplotlib.pyplot as plt

im = plt.imread('%s/%s.png' % (root, fname))
plt.imshow(im)
plt.show()

3. 使用opencv读取图片

import cv2

# opencv显示
img = cv2.imread('%s/%s.png' % (root, fname),) 
cv2.namedWindow('Image', cv2.WINDOW_NORMAL )#cv2.WINDOW_AUTOSIZE)
cv2.imshow('Image',img)
cv2.waitKey(0)

5: 划分验证集和测试集

划分验证集与测试集的脚本voc.annotation.py

import os
import random

#-------------------------------------------------------#
#   想要增加测试集修改trainval_percent 
#   修改train_percent用于改变验证集的比例 9:1
#   
#   当前该库将测试集当作验证集使用,不单独划分测试集
#-------------------------------------------------------#
trainval_percent    = 0.9
train_percent       = 0.9
#-------------------------------------------------------#
#   指向VOC数据集所在的文件夹
#   默认指向根目录下的VOC数据集
#-------------------------------------------------------#
dataset_path  = './MyDataset/'

if __name__ == "__main__":
    random.seed(0)
    print("Generate txt in ImageSets.")
    segfilepath     = os.path.join(dataset_path, 'SegmentationClass')
    saveBasePath    = os.path.join(dataset_path, 'ImageSets/Segmentation')
    
    if not os.path.exists(saveBasePath):
            os.makedirs(saveBasePath)


    temp_seg = os.listdir(segfilepath)
    total_seg = []
    for seg in temp_seg:
        if seg.endswith(".png"):
            total_seg.append(seg)

    num     = len(total_seg)  
    list    = range(num)  
    tv      = int(num*trainval_percent)  
    tr      = int(tv*train_percent)  
    trainval= random.sample(list,tv)  
    train   = random.sample(trainval,tr)  
    
    print("train and val size",tv)
    print("traub suze",tr)
    ftrainval   = open(os.path.join(saveBasePath,'trainval.txt'), 'w')  
    ftest       = open(os.path.join(saveBasePath,'test.txt'), 'w')  
    ftrain      = open(os.path.join(saveBasePath,'train.txt'), 'w')  
    fval        = open(os.path.join(saveBasePath,'val.txt'), 'w')  
    
    for i  in list:  
        name=total_seg[i][:-4]+'\n'  
        if i in trainval:  
            ftrainval.write(name)  
            if i in train:  
                ftrain.write(name)  
            else:  
                fval.write(name)  
        else:  
            ftest.write(name)  
    
    ftrainval.close()  
    ftrain.close()  
    fval.close()  
    ftest.close()
    print("Generate txt in ImageSets done.")

6: 将图片划分为更小的图片(可选项)

import cv2
import os
import numpy as np
from PIL import Image


def mkdir(path):
    folder=os.path.exists(path)
    if not folder:
        os.makedirs(path)


#原始图片的h,w
def cutImg(img,cutSize,fileName):
    '''
    img 是图像矩阵,cutSize是裁剪大小(正方形),fileName
    '''
    sumWidth = img.shape[1]  #图片宽、高
    sumHeight = img.shape[0]
    if not os.path.exists(SAVE_DIR):
        os.makedirs(SAVE_DIR)
    rnumber=int(sumWidth/cutSize)
    cnumber=int(sumHeight/cutSize)

    print("裁剪所得{0}列图片,{1}行图片.".format(rnumber,cnumber))
    for i in range(rnumber):
            for j in range(cnumber):
                # imgs=img[j*cutSize:(j+1)*cutSize,i*cutSize:(i+1)*cutSize] #裁剪png时使用
                imgs=img[j*cutSize:(j+1)*cutSize,i*cutSize:(i+1)*cutSize,:] #裁剪jpg时使用,三通道
                a=[j,i,imgs.shape]
                # 裁剪png时使用
                # cv2.imwrite(SAVE_DIR+os.path.splitext(fileName)[0]+'_'+str(j)+'_'+str(i)+os.path.splitext(fileName)[1],img[j*cutSize:(j+1)*cutSize,i*cutSize:(i+1)*cutSize])
                # 裁剪jpg时使用,三通道
                cv2.imwrite(SAVE_DIR+os.path.splitext(fileName)[0]+'_'+str(j)+'_'+str(i)+os.path.splitext(fileName)[1],img[j*cutSize:(j+1)*cutSize,i*cutSize:(i+1)*cutSize,:])
                print(imgs.shape)
                print(a)
    print("裁剪完成,得到{0}张图片.".format(rnumber*cnumber))
    print("文件保存在{0}".format(SAVE_DIR))


# 返回原图和标签的URL
def imgPath(fileName):
    suffix = os.path.splitext(fileName)[1]
    if suffix == ".jpg":
        return os.path.splitext(fileName)[0]


"""调用裁剪函数示例"""
IMG_DIR='E:/DataSet/MyDataset/JPEGImages/'
GT_DIR='E:/DataSet/MyDataset/SegmentationClass/'
CUTSIZE= 512 #裁剪为正方形
SAVE_DIR= './dataset/'


# IMG_PATH=[]
# GT_PATH=[]

FILE_NAME=[]
IMAGE_GT = []

for fileName in os.listdir(IMG_DIR):
    FILE_NAME.append(imgPath(fileName))
    

for i in FILE_NAME:
    IMAGE_GT.append([IMG_DIR+i+'.jpg',GT_DIR+i+'.png'])

for i in IMAGE_GT:
    jpg = Image.open(i[0])
    jpgName = i[0].split('/')[-1]
    jpg = np.array(jpg)

    """裁剪标签图片"""
    # png = Image.open(i[1])
    # pngName = i[1].split('/')[-1]
    # png = np.array(png)

    cutImg(jpg,CUTSIZE,jpgName)

 

 
posted @ 2024-05-08 10:40  雨天尊  阅读(1430)  评论(0编辑  收藏  举报