提示:这里可以添加本文要记录的大概内容:
maskrcnn首次将目标检测与语义分割任务结合起来,我们将目标检测划分为定位任务;将语义分割划分为逐像素的定位与分类任务;本文介绍了如何将像素级的图像标注转换为JSON标注文件并套用maskrcnn网络进行训练.
在创建文件过程中要注意annotation id与image id,每张影像中都会对应一个图像标注,但每个图像标注中会存在多个独立的标注标签。每个标注标签都有唯一的annotation id。
Coco Json数据中的关键数据:
{
"images": [image],
"annotations": [annotation],
"categories": [category]
}
image = {
"id": int,
"width": int,
"height": int,
"file_name": str,
}
annotation = {
"id": int,
"image_id": int,
"category_id": int,
"segmentation": RLE or [polygon],
"area": float,
"bbox": [x,y,width,height],
"iscrowd": 0 or 1,
}
categories = [{
"id": int,
"name": str,
"supercategory": str,
}]
代码如下(示例):
import json
import cv2 as cv
import os
import numpy as np
from tqdm import tqdm
#限定坐标值范围小于512
label_dir = r"\label"
def clamp(a,limit):
if a < limit:
return a
else:
return limit
#json数据是以字典形式组织的,marcnn训练集json中包含的主要信息有
#info:数据基本信息
#linceses:许可信息
#image:图像信息
#annotation:标注信息
JSON_data = {"info": {
"description": None,
"url": None,
"version": None,
"year": 2022,
"contributor": None,
"date_created": "2022-06-30 11:31:57.540212"
},
"licenses": [
{
"url": None,
"id": 0,
"name": None
}
],
"type": "instances",
"categories": [{
"id": 0,
"name": "water",
# "supercategory": "object"
}],
"images": [],
"annotations": []
}
# {
# "supercategory":None,
# "id": 1,
# "name": "water"
# }
img_datapth = r"E:\changdong\Water_data\Data\Water_result\Dataset_source\clipdata\image"
all_files = [f for f in os.listdir(img_datapth)]
anno_id = 0
bbox = []
for id , fn in enumerate(tqdm(all_files)):
label = cv.imread(os.path.join(label_dir,fn.replace(".tif",".png")),0)
# 读取影像,根据列表id获取相关信息
W,H= label.shape[:2]
image_info = {
"id": id,
"width": W,
"height": H,
"file_name": fn,
"license": 1,
"date_captured": "2021-01-01"
}
JSON_data["images"].append(image_info)
# img_inf = {}
# 相应的获取标注图像,每个标注对象轮廓,面积、bbox,记录每个对象id,img_id与图像对应
# category_id=1,iscrowd:
# 先获取轮廓,根据轮廓遍历添加
# gray = cv.cvtColor(label,cv.COLOR_BGR2GRAY)
annotation = {
"id": anno_id,
"image_id": id,
"category_id": 1, # 对应 "water" 类别的id
"bbox": bbox,
"area": 0,
"iscrowd": 0,
"segmentation": [] # 初始化空的分割信息
}
# 将图片二值化
_, binary = cv.threshold(label,127,255,cv.THRESH_BINARY)
# 在二值图上寻找轮廓
contours, _ = cv.findContours(binary,cv.RETR_TREE,cv.CHAIN_APPROX_SIMPLE)
for i, cont in enumerate(contours) :
# 这里的判断是为了剔除一些无效的轮廓
# if anno_id
# anno["id"] = anno_id
# anno["image_id"] = id
# anno["category_id"] = 1
# anno["segmentation"] = [cont.reshape(-1).tolist()]
# anno["area"] = cv.contourArea(cont)
x,y,w,h = cv.boundingRect(cont)
# # x1,y1,x2,y2 = x,y,clamp(x+w,W),clamp(y+h,H)
# anno["bbox"] = [x,y,w,h]
# anno["iscrowd"] = 0
anno = {
"id": anno_id,
"image_id": id,
"category_id": 0, # 对应 "water" 类别的id
"bbox": [x,y,w,h],
"area": cv.contourArea(cont),
"iscrowd": 0,
"segmentation": [cont.reshape(-1).tolist()] # 初始化空的分割信息
}
JSON_data["annotations"].append(anno)
# anno["id"] = 0
anno = {}
anno_id += 1
jsondata = json.dumps(JSON_data)
file = open('2023071714train.json', 'w')
file.write(jsondata)
file.close()
Json数据中无法存储arry结构,因此segmentation中需要将存储轮廓的arry转换成list格式
在训练前需要采用coco api对json数据进行解析。在制作实例分割数据集时,数据的面积必须计算不可省略,coco工具可能会根据面积来判定目标对象是否面积过小,从而忽略目标。
如存在问题欢迎及时反馈
20230814更新:
在根据二进制标签获取mask的polygon坐标时也需要注意,是否存在无效的ploygon.例如仅包含一个坐标点[[x1,y1]];对相应的情况要进行过滤
参考文档
MS COCO数据集介绍以及pycocotools简单使用