导师CSDN:太阳花的小绿豆、哔哩哔哩:霹雳吧啦Wz
CSDN-Mask rcnn代码及详解链接: link
所有基础分类、检测、分割代码都可至霹雳吧啦Wz的GitHub获取 link
一、Mask_rcnn训练COCO数据集介绍:
1、mask_rcnn路径下data数据集构成如下:
其中,annotations为训练集的标注信息,train2017为训练图片,val2017为验证图片,分别如下所示:
对coco数据集不了解的朋友,可以点击链接: link
二、准备自己的数据集,然后进行labelme标注:
1、通过labelme.exe对自己准备的数据集进行标注,如下所示:
将标注的图片及对应json文件随意对应选取一部分用于训练,另一部分用于验证(可以通过代码随机挑选,也可以自己复制粘贴进行分离)
三、自行分离数据
将对应的训练集和验证集图片及json文件放至自己建立的文件夹下,切记不要错乱了。最后,还有标注文件的处理,第四点讲解。
四、labelme标注json文件转coco数据集标注json文件
提示:因为labelme标注生成的json文件信息与coco数据集标注json文件信息有所差异,Mask_rcnn训练以及推理需要coco数据集json格式。
如下图所示,将第三点中分离的train训练图以及对应的json文件放入如下文件夹内:
通过lableme2coco.py代码,将自己标注的数据集转成coco需要的格式,验证集也是如此,lableme2coco.py代码如下。
下面展示一些 内联代码片
。
// An highlighted block
import json
import glob
import PIL.Image
import PIL.ImageDraw
import os
import base64
import io
import numpy as np
import PIL.ExifTags
import PIL.Image
import PIL.ImageOps
import shutil
def img_b64_to_arr(img_b64):
f = io.BytesIO()
f.write(base64.b64decode(img_b64))
img_arr = np.array(PIL.Image.open(f))
return img_arr
def img_arr_to_b64(img_arr):
img_pil = PIL.Image.fromarray(img_arr)
f = io.BytesIO()
img_pil.save(f, format='PNG')
img_bin = f.getvalue()
if hasattr(base64, 'encodebytes'):
img_b64 = base64.encodebytes(img_bin)
else:
img_b64 = base64.encodestring(img_bin)
return img_b64
def img_data_to_png_data(img_data):
with io.BytesIO() as f:
f.write(img_data)
img = PIL.Image.open(f)
with io.BytesIO() as f:
img.save(f, 'PNG')
f.seek(0)
return f.read()
def apply_exif_orientation(image):
try:
exif = image._getexif()
except AttributeError:
exif = None
if exif is None:
return image
exif = {
PIL.ExifTags.TAGS[k]: v
for k, v in exif.items()
if k in PIL.ExifTags.TAGS
}
orientation = exif.get('Orientation', None)
if orientation == 1:
# do nothing
return image
elif orientation == 2:
# left-to-right mirror
return PIL.ImageOps.mirror(image)
elif orientation == 3:
# rotate 180
return image.transpose(PIL.Image.ROTATE_180)
elif orientation == 4:
# top-to-bottom mirror
return PIL.ImageOps.flip(image)
elif orientation == 5:
# top-to-left mirror
return PIL.ImageOps.mirror(image.transpose(PIL.Image.ROTATE_270))
elif orientation == 6:
# rotate 270
return image.transpose(PIL.Image.ROTATE_270)
elif orientation == 7:
# top-to-right mirror
return PIL.ImageOps.mirror(image.transpose(PIL.Image.ROTATE_90))
elif orientation == 8:
# rotate 90
return image.transpose(PIL.Image.ROTATE_90)
else:
return image
class labelme2coco(object):
def __init__(self,labelme_json=[],save_json_path='./new.json'):
"""
Args: labelme_json: paths of labelme json files
: save_json_path: saved path
"""
self.labelme_json=labelme_json
self.save_json_path=save_json_path
self.images=[]
self.categories=[]
self.annotations=[]
# self.data_coco = {}
self.label=[]
self.annID=1
self.height=0
self.width=0
self.save_json()
def data_transfer(self):
for num,json_file in enumerate(self.labelme_json):
with open(json_file,'r') as fp:
print("json_name=",json_file)
data = json.load(fp)
(prefix, res) = os.path.split(json_file)
(file_name, extension ) = os.path.splitext(res)
self.images.append(self.image(data,num,file_name))
for shapes in data['shapes']:
label=shapes['label']
if label not in self.label:
self.categories.append(self.categorie(label))
self.label.append(label)
points=shapes['points']
self.annotations.append(self.annotation(points,label,num))
self.annID+=1
def image(self,data,num,file_name):
image={}
# img = img_b64_to_arr(data['imageData'])
import cv2
img = cv2.imread(os.path.join('./image', f'{file_name}.jpg'))
height, width = img.shape[:2]
img = None
image['height']=height
image['width'] = width
image['id']= int(num+1)
image['file_name'] = file_name + '.jpg'
self.height=height
self.width=width
return image
def categorie(self,label):
categorie={}
categorie['supercategory'] = label
categorie['id']= int(len(self.label)+1)
categorie['name'] = label
return categorie
def annotation(self,points,label,num):
annotation={}
annotation['iscrowd'] = 0
annotation['image_id'] = int(num+1)
annotation['bbox'] = list(map(float,self.getbbox(points)))
point=[]
for p in points:
point.append(p[0])
point.append(p[1])
annotation['segmentation']=[point] # at least 6 points
annotation['category_id'] = self.getcatid(label)
annotation['id'] = int(self.annID)
#add area info
annotation['area'] = self.height * self.width # the area is not used for detection
return annotation
def getcatid(self,label):
for categorie in self.categories:
if label==categorie['name']:
return categorie['id']
return -1
def getbbox(self,points):
# img = np.zeros([self.height,self.width],np.uint8)
# cv2.polylines(img, [np.asarray(points)], True, 1, lineType=cv2.LINE_AA)
# cv2.fillPoly(img, [np.asarray(points)], 1)
polygons = points
mask = self.polygons_to_mask([self.height,self.width], polygons)
return self.mask2box(mask)
def mask2box(self, mask):
# np.where(mask==1)
index = np.argwhere(mask == 1)
rows = index[:, 0]
clos = index[:, 1]
left_top_r = np.min(rows) # y
left_top_c = np.min(clos) # x
right_bottom_r = np.max(rows)
right_bottom_c = np.max(clos)
return [left_top_c, left_top_r, right_bottom_c-left_top_c, right_bottom_r-left_top_r] # [x1,y1,w,h] for coco box format
def polygons_to_mask(self,img_shape, polygons):
mask = np.zeros(img_shape, dtype=np.uint8)
mask = PIL.Image.fromarray(mask)
xy = list(map(tuple, polygons))
PIL.ImageDraw.Draw(mask).polygon(xy=xy, outline=1, fill=1)
mask = np.array(mask, dtype=bool)
return mask
def data2coco(self):
data_coco={}
data_coco['images']=self.images
data_coco['categories']=self.categories
data_coco['annotations']=self.annotations
categoryName=open("categoryName.txt",'w')
for i in self.categories:
categoryName.write(i['name']+'\n')
return data_coco
def save_json(self):
self.data_transfer()
self.data_coco = self.data2coco()
json.dump(self.data_coco, open(self.save_json_path, 'w', encoding='utf-8'), indent=4, separators=(',', ': '), cls=MyEncoder)
# type check when save json files
class MyEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, np.integer):
return int(obj)
elif isinstance(obj, np.floating):
return float(obj)
elif isinstance(obj, np.ndarray):
return obj.tolist()
else:
return super(MyEncoder, self).default(obj)
def copyImage(): # 存放的图片文件夹路径
imgdir='./image/'
for file in os.listdir(imgdir):
if file.endswith('.jpg'):
shutil.copyfile(imgdir+file,'./data/coco2017/val_me/'+file)
def copyCategory():
shutil.copyfile('categoryName.txt',"F:\MyDeepLearning\deep-learning-for-image-processing-master\pytorch_object_detection\mask_rcnn\my_ImageData\data\coco2017")
if "__main__"==__name__:
labelme_json=glob.glob('./data/coco2017/json_lableme/*.json') # Lableme标注文件路径
if not os.path.exists("./data/coco2017/annotations/"): # 生成的coco标注文件路径
os.makedirs('./data/coco2017/annotations/')
if not os.path.exists('./data/coco2017/val_me/'): # 训练所需的图片
os.makedirs('./data/coco2017/val_me/')
copyImage()
labelme2coco(labelme_json,'./data/coco2017/annotations/val.json') # 生成的coco标注文件
# copyCategory() # 不晓得什么用途
提示:命名为lableme2coco.py,设置正确路径直接运行即可。
将最后得到的数据集,分别放入训练和预测推理的路径下,进行训练即可:
五、效果如下所示:
提示:train:训练,需要修改数据集路径以及检测目标类别数。predict:需要将训练得到的模型放至对应文件夹下。
提示:希望帮助到有需要的人,不喜勿喷,谢谢。非常感谢霹雳吧啦Wz导师的知识分享。