2019-08-23-MaskRCNN模型

一、MaskRCNN模型

MaskRCNN模型为图像中的每个对象实例同时生成边界框和分割掩码。 它基于特征金字塔网络(FPN)和ResNet101主干网。

1. 源码

Github:https://github.com/matterport/Mask_RCNN

Mask R-CNN开源项目的设计非常易于扩展,只需做简单的修改就可以训练自己的数据集。

中文:https://github.com/wucng/TensorExpand/tree/master/TensorExpand/Object%20detection/Mask%20RCNN/matterport-Mask_RCNN

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
image

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/”内。

image

(4)运行maskrcnn demo

MaskRCNN中提供了很多demo,可以在jupyter notebook中逐步运行,即可得到相应的结果,来熟悉maskrcnn模型的流程。

"./Mask_RCNN/samples/coco/"是一个demo,可以在此基础上进行扩展修改,来基于自己的数据集进行模型训练。

二、COCO数据集

1. COCO数据集简介

官网:cocodataset.org

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

可以看到, 标注文件中有我们最关心的 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)可视化完成代码

转载自:https://blog.csdn.net/wc781708249/article/details/79603522#%E4%BB%BF%E7%85%A7coco-json%E6%96%87%E4%BB%B6

# -*- 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的界面,


image.png
image.png

一幅图片中有多个类型,或者一个类型有多个个体,要注意命名,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 是我们需要用到的。


image.png

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容