一、MaskRCNN模型
MaskRCNN模型为图像中的每个对象实例同时生成边界框和分割掩码。 它基于特征金字塔网络(FPN)和ResNet101主干网。
1. 源码
Github:https://github.com/matterport/Mask_RCNN
Mask R-CNN开源项目的设计非常易于扩展,只需做简单的修改就可以训练自己的数据集。
2. 依赖库配置
Python 3.4, TensorFlow 1.3, Keras 2.0.8 and other common packages listed in requirements.txt.
是基于Python 3,Keras和TensorFlow实现的MaskRCNN模型。
(1)linux系统或windows系统;
(2)python 3. 4: https://www.python.org
(3) anaconda :安装anaconda可以实现多个基本库的安装,比较方便;该软件下载较慢,可从官网或者清华镜像中下载;
(官网)https://www.anaconda.com/download/
(清华镜像)https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/
(4)cuda,cudnn
(cuda-ubuntu) https://developer.nvidia.com/cuda-90-download-archive?target_os=Linux&target_arch=x86_64&target_distro=Ubuntu&target_version=1604&target_type=runfilelocal(patch也需要下载,选择日期最新的)
(cudnn) https://developer.nvidia.com/rdp/form/cudnn-download-survey
需要先注册,再下载,配置。注意cuda,cudnn版本匹配,以及与GPU型号算力的匹配。
(5)requirements.txt库安装
numpy
scipy
Pillow
cython
matplotlib
scikit-image
tensorflow>=1.3.0
keras>=2.0.8
opencv-python
h5py
imgaug
IPython[all]
tensorflow:安装tensorflow之前要保证python3.4,anaconda,Cuda,Cudnn都已经安装好。
opencv:pip install opencv-python
**imgaug: **pip install imgaug 或者 pip3 install imageaug (https://github.com/aleju/imgaug)
3. pycocotools安装 ----COCO-pythonAPI
Linux: https://github.com/waleedka/coco
Ubuntu用户请执行以下代码:
git clone https://github.com/waleedka/coco.git
pip install git+ https://github.com/waleedka/coco.git#subdirectory=PythonAPI
这两句话的意思是,首先从git仓库中把所需要的api复制到电脑中,然后运行这个下载的下级目录里的PythonAPI。
## 安装coco pythonAPI的另一种方法:([https://blog.csdn.net/qq_41847324/article/details/86224628](https://blog.csdn.net/qq_41847324/article/details/86224628))
cd coco/PythonAPI
# 如果使用的是python2:
python setup.py build_ext install
# 如果使用的是python3:
python3 setup.py build_ext install
4. MaskRCNN安装
(1)从官网clone源码:
git clone https://github.com/matterport/Mask_RCNN.git #([GitHub - matterport/Mask_RCNN: Mask R-CNN for object detection and instance segmentation on Keras and TensorFlow](https://github.com/matterport/Mask_RCNN.git))
(2)cd 到Mask_RCNN目录下,
python setup.py install #(进行这一步操作后,可以在代码中import maskrcnn中的class或function)
(3)预训练权重
预训练权重是神经网络训练后得到的超参数,也就是说整个模型不需要再训练了,你可以直接加载官方的训练结果直接应用。下载链接:
https://github.com/matterport/Mask_RCNN/releases
找到mask_rcnn2.0下面的mask_rcnn_coco.h5点击下载。然后将这个h5文件复制或移动到MaskRCNN文件夹中就可以了,这个文件夹和你的环境名称一样这不是巧合,事实上他就是你activate的那个环境。一般都会在C:/user/用户名里面。提醒,请不要因为一会儿运行的demo在samples文件夹里就把这个h5文件存在samples里面,应该存在MaskRCNN的根目录里面,因为默认打开的路径是根目录里。
预训练权重文件放在目录“./Mask_RCNN/”内。
(4)运行maskrcnn demo
MaskRCNN中提供了很多demo,可以在jupyter notebook中逐步运行,即可得到相应的结果,来熟悉maskrcnn模型的流程。
"./Mask_RCNN/samples/coco/"是一个demo,可以在此基础上进行扩展修改,来基于自己的数据集进行模型训练。
二、COCO数据集
1. COCO数据集简介
COCO has five annotation types: forobject detection,keypoint detection,stuff segmentation,panoptic segmentation, andimage captioning. The annotations are stored usingJSON. Please note that theCOCO APIdescribed on thedownloadpage can be used to access and manipulate all anotations.
object detection: 目标检测;
keypoint detection: 关键点检测;
stuff segmentation: stuff没有固定形状的物体,例如天空、草地等,分割任务;
panoptic segmentation: 全景分割,图片中things,stuff等全被分割;
image captioning: “看图说话”,一个图片中的场景描述;
COCO数据集是一个大型的、丰富的物体检测,分割和字幕数据集。这个数据集以scene understanding为目标,主要从复杂的日常场景中截取,图像中的目标通过精确的segmentation进行位置的标定。图像包括91类目标,328,000影像和2,500,000个label。
COCO数据集有91类,虽然比ImageNet和SUN类别少,但是每一类的图像多,这有利于获得更多的每类中位于某种特定场景的能力,对比PASCAL VOC,其有更多类和图像。
2. COCO数据集下载
"./Mask_RCNN/samples/coco/coco.py" 中 “def auto_download(self, dataDir, dataType, dataYear):”可以实现train,val,(2014,2017)数据集的下载与解压。
3. COCO数据集格式
为了更好的使用数据集, COCO 对数据集的标注信息做了统一管理. 其中, 图像检测数据集的标注信息保存在 .json 文件中, 例如 2017_val 的标注数据就保存在 instances_val2017.json 文件中.
COCO 标注json文件的主要内容如下,详细描述见 “COCO 标注详解” https://blog.csdn.net/yeyang911/article/details/78675942
{
"info": info, # dict
"licenses": [license], # list ,内部是dict
"images": [image], # list ,内部是dict
"annotations": [annotation], # list ,内部是dict
"categories": # list ,内部是dict
}
实际案例:
可以看到, 标注文件中有我们最关心的 image 和 annotations 域, annotations 中保存的就是标注信息. 根据不同的应用场景, 标注信息又可分为: 目标的边界框 bbox 和图像分割区域 segmentation.
4. COCO PythonAPI
API 的作用就是为了提取标注文件中的信息, 使其分别用于各自的场景, 比如图像检测使用的边界框参数, 图像分割使用的 mask 参数, 人体姿态检测使用的关节点参数等.
接下来介绍如何用 COCO 提供的 Python API 来提取这些信息.
关于以下 API 的详细使用请参考 COCO 官网给出的 demo 脚本: coco/pycocoDemo.ipynb at master · dengdan/coco · GitHub https://github.com/dengdan/coco/blob/master/PythonAPI/pycocoDemo.ipynb
(1)安装已完成(前文的pycocotools安装)
(2)json文件解析
需要提前导入API的包,来处理coco数据集。COCO 是一个类, 因此, 使用构造函数创建一个 COCO 对象, 构造函数首先会加载 json 文件, 然后解析图片和标注信息的 id, 根据 id 来创建其关联关系.
from pycocotools.coco import COCO
import numpy as np
import skimage.io as io
import matplotlib.pyplot as plt
import pylab
pylab.rcParams['figure.figsize'] = (8.0, 10.0)
dataDir='/path/to/your/coco_data'
dataType='val2017'
annFile='{}/annotations/instances_{}.json'.format(dataDir,dataType)
# 初始化标注数据的 COCO api
coco=COCO(annFile)
COCO 对象创建完毕后会输出如下信息,表明json 脚本解析完毕, 并且将图片和对应的标注数据关联起来.
loading annotations into memory...
Done (t=0.81s)
creating index...
index created!
(3)显示 COCO 数据集中的具体类和超类
# display COCO categories and supercategories
cats = coco.loadCats(coco.getCatIds())
nms=[cat['name'] for cat in cats]
print('COCO categories: \n{}\n'.format(' '.join(nms)))
nms = set([cat['supercategory'] for cat in cats])
print('COCO supercategories: \n{}'.format(' '.join(nms)))
输出信息如下:
COCO categories:
person bicycle car motorcycle airplane bus train truck boat traffic light fire hydrant stop sign parking meter bench bird cat dog horse sheep cow elephant bear zebra giraffe backpack umbrella handbag tie suitcase frisbee skis snowboard sports ball kite baseball bat baseball glove skateboard surfboard tennis racket bottle wine glass cup fork knife spoon bowl banana apple sandwich orange broccoli carrot hot dog pizza donut cake chair couch potted plant bed dining table toilet tv laptop mouse remote keyboard cell phone microwave oven toaster sink refrigerator book clock vase scissors teddy bear hair drier toothbrush
COCO supercategories:
outdoor food indoor appliance sports person animal vehicle furniture accessory electronic kitchen
(4)加载并显示指定 id 的图片
# get all images containing given categories, select one at random
catIds = coco.getCatIds(catNms=['person','dog','skateboard']);
imgIds = coco.getImgIds(catIds=catIds );
imgIds = coco.getImgIds(imgIds = [324158])
// loadImgs() 返回的是只有一个元素的列表, 使用[0]来访问这个元素
// 列表中的这个元素又是字典类型, 关键字有: ["license", "file_name",
// "coco_url", "height", "width", "date_captured", "id"]
img = coco.loadImgs(imgIds[np.random.randint(0,len(imgIds))])[0]
# 加载并显示图片,可以使用两种方式: 1) 加载本地图片, 2) 在线加载远程图片
# 1) 使用本地路径, 对应关键字 "file_name"
# I = io.imread('%s/images/%s/%s'%(dataDir,dataType,img['file_name']))
# 2) 使用 url, 对应关键字 "coco_url"
I = io.imread(img['coco_url'])
plt.axis('off')
plt.imshow(I)
plt.show()
(5)加载并将 “segmentation” 标注信息显示在图片上
# 加载并显示标注信息
plt.imshow(I); plt.axis('off')
annIds = coco.getAnnIds(imgIds=img['id'], catIds=catIds, iscrowd=None)
anns = coco.loadAnns(annIds)
coco.showAnns(anns)
getAnnIds() 函数会根据 image id 来获取这张图对应的标注信息的 id, 然后 loadAnns() 函数会显示指定 id 的标注信息到图片上.
(6)可视化完成代码
# -*- coding:utf-8 -*-
from __future__ import print_function
from pycocotools.coco import COCO
import os, sys, zipfile
import urllib.request
import shutil
import numpy as np
import skimage.io as io
import matplotlib.pyplot as plt
import pylab
pylab.rcParams['figure.figsize'] = (8.0, 10.0)
annFile='./new_instances_val2017.json'
coco=COCO(annFile)
# display COCO categories and supercategories
cats = coco.loadCats(coco.getCatIds())
nms=[cat['name'] for cat in cats]
print('COCO categories: \n{}\n'.format(' '.join(nms)))
nms = set([cat['supercategory'] for cat in cats])
print('COCO supercategories: \n{}'.format(' '.join(nms)))
# imgIds = coco.getImgIds(imgIds = [324158])
imgIds = coco.getImgIds()
img = coco.loadImgs(imgIds[0])[0]
dataDir = '.'
dataType = 'val2017'
I = io.imread('%s/%s/%s'%(dataDir,dataType,img['file_name']))
plt.axis('off')
plt.imshow(I)
plt.show()
# load and display instance annotations
# 加载实例掩膜
# catIds = coco.getCatIds(catNms=['person','dog','skateboard']);
# catIds=coco.getCatIds()
catIds=[]
for ann in coco.dataset['annotations']:
if ann['image_id']==imgIds[0]:
catIds.append(ann['category_id'])
plt.imshow(I); plt.axis('off')
annIds = coco.getAnnIds(imgIds=img['id'], catIds=catIds, iscrowd=None)
anns = coco.loadAnns(annIds)
coco.showAnns(anns)
# initialize COCO api for person keypoints annotations
annFile = '{}/annotations/person_keypoints_{}.json'.format(dataDir,dataType)
coco_kps=COCO(annFile)
## load and display keypoints annotations
## 加载肢体关键点
#plt.imshow(I); plt.axis('off')
#ax = plt.gca()
#annIds = coco_kps.getAnnIds(imgIds=img['id'], catIds=catIds, iscrowd=None)
#anns = coco_kps.loadAnns(annIds)
#coco_kps.showAnns(anns)
## initialize COCO api for caption annotations
#annFile = '{}/annotations/captions_{}.json'.format(dataDir,dataType)
#coco_caps=COCO(annFile)
## load and display caption annotations
## 加载文本描述
#annIds = coco_caps.getAnnIds(imgIds=img['id']);
#anns = coco_caps.loadAnns(annIds)
#coco_caps.showAnns(anns)
plt.imshow(I); plt.axis('off'); plt.show()
标注信息对应的图片已经显示在当前的 “figure” 对象上了, 那么标注信息是如何找到这个 “figure” 对象的?
答案是: loadAnns() 函数内会调用 plt.gca() 函数来获取当前 “figure” 对象的轴, 如果存在的话直接返回, 不存在的话会新建一个"figure" 对象, 并将其轴返回.
COCO数据集中的其他类型,都可以依据以上类似的操作方式进行可视化,使用等。熟悉了 COCO Python API 之后, 就可以研究其中的数据分布情况. 然后在满足 COCO 原有数据分布的基础上将自己的数据集定制到 COCO 数据集中. https://blog.csdn.net/gzj2013/article/details/82385164
三、如何制备自己的数据集
1. 标注工具
labelme,VIA,arcgis?
2. labelme工具
(1)安装labelme
pip install pyqt #界面
pip install labelme
(2)使用工具
在终端直接输入labelme即可调用
labelme
出现labelme的界面,
一幅图片中有多个类型,或者一个类型有多个个体,要注意命名,coco数据集中包含主类和子类,一般命名规则,按照"父_子类_num"样式去命名,例如图片中所示,cat,dog是父类,bobcat,plushcat是子类。
标注好后,点击“save”可以把标注保存为json文件。
进入<文件名>.json所在目录下,在终端中执行:
labelme_json_to_dataset <文件名>.json
可得到一个文件夹,里面有五个文件,分别是:
*.png
info.yaml
label.png
label_names.txt
label_viz.png
其中 label.png 和 info.yaml 是我们需要用到的。
3. labelme json转换为coco json
转载自:https://blog.csdn.net/qq_35608277/article/details/79873456
利用自己的数据训练模型,会用到image\annotation\category,就能进行训练(没有area参数),如下转载的labelme2coco.py中,只转换了这三个,带有area参数的可去以上转载连接中。
labelme2COCO.py中利用一个class实现以下功能, 代码如下:
# -*- coding:utf-8 -*-
# !/usr/bin/env python
import argparse
import json
import matplotlib.pyplot as plt
import skimage.io as io
import cv2
from labelme import utils
import numpy as np
import glob
import PIL.Image
class labelme2coco(object):
def __init__(self,labelme_json=[],save_json_path='./new.json'):
'''
:param labelme_json: 所有labelme的json文件路径组成的列表
:param save_json_path: json保存位置
'''
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:
data = json.load(fp) # 加载json文件
self.images.append(self.image(data,num))
for shapes in data['shapes']:
label=shapes['label'].split('_')
if label[1] not in self.label:
self.categories.append(self.categorie(label))
self.label.append(label[1])
points=shapes['points']
self.annotations.append(self.annotation(points,label,num))
self.annID+=1
def image(self,data,num):
image={}
img = utils.img_b64_to_array(data['imageData']) # 解析原图片数据
# img=io.imread(data['imagePath']) # 通过图片路径打开图片
# img = cv2.imread(data['imagePath'], 0)
height, width = img.shape[:2]
img = None
image['height']=height
image['width'] = width
image['id']=num+1
image['file_name'] = data['imagePath'].split('/')[-1]
self.height=height
self.width=width
return image
def categorie(self,label):
categorie={}
categorie['supercategory'] = label[1]
categorie['id']=len(self.label)+1 # 0 默认为背景
categorie['name'] = label[1]
return categorie
def annotation(self,points,label,num):
annotation={}
annotation['segmentation']=[list(np.asarray(points).flatten())]
annotation['iscrowd'] = 0
annotation['image_id'] = num+1
# annotation['bbox'] = str(self.getbbox(points)) # 使用list保存json文件时报错(不知道为什么)
# list(map(int,a[1:-1].split(','))) a=annotation['bbox'] 使用该方式转成list
annotation['bbox'] = list(map(float,self.getbbox(points)))
annotation['category_id'] = self.getcatid(label)
annotation['id'] = self.annID
return annotation
def getcatid(self,label):
for categorie in self.categories:
if label[0]==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) # 画多边形 内部像素值为1
polygons = points
mask = self.polygons_to_mask([self.height,self.width], polygons)
return self.mask2box(mask)
def mask2box(self, mask):
'''从mask反算出其边框
mask:[h,w] 0、1组成的图片
1对应对象,只需计算1对应的行列号(左上角行列号,右下角行列号,就可以算出其边框)
'''
# 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_r,left_top_c),(right_bottom_r,right_bottom_c)]
# return [(left_top_c, left_top_r), (right_bottom_c, right_bottom_r)]
# return [left_top_c, left_top_r, right_bottom_c, right_bottom_r] # [x1,y1,x2,y2]
return [left_top_c, left_top_r, right_bottom_c-left_top_c, right_bottom_r-left_top_r] # [x1,y1,w,h] 对应COCO的bbox格式
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
return data_coco
def save_json(self):
self.data_transfer()
self.data_coco = self.data2coco()
# 保存json文件
json.dump(self.data_coco, open(self.save_json_path, 'w'), indent=4) # indent=4 更加美观显示
#labelme_json=glob.glob('./test_img/*.json')
labelme_json=glob.glob('./bird.json')
# labelme_json=['./1.json']
labelme2coco(labelme_json,'./new.json')
4. arcgis/qgis中的geojson格式转换为coco json格式
四、扩展maskrcnn-coco训练自己的数据集
1. 修改load mask等
参考:
https://blog.csdn.net/chenmoran0928/article/details/79999073
https://blog.csdn.net/gzj2013/article/details/82385164
https://blog.csdn.net/u011574296/article/details/79740633
mask rcnn训练自己的数据集: https://blog.csdn.net/qq_29462849/article/details/81037343
【Mask R-CNN】(七):制作并训练自己的数据集最详细教程: https://blog.csdn.net/heiheiya/article/details/81532914