制作语义分割数据集(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)