Mask Rcnn 爬坑小结
一
Mask Rcnn 主要内容
Mask R-CNN ICCV2017 best paper
https://arxiv.org/pdf/1703.06870
Mask R-CNN= Faster R-CNN + FCN, 大致可以这么理解!
本文主要讲 Faster R-CNN 拓展到图像分割上,提出了 Mask R-CNN 简单快捷的解决 Instance segmentation,什么是 Instance segmentation,就是将一幅图像中所有物体框出来,并将物体进行像素级别的分割提取。如下图示例:
结合参考国内某些视觉公司的分割方案,考虑是否可以和我现在做的机器人6D抓取结合起来,于是开始阅读大神攻略及尝试Mask-Rcnn,原理部分百度上可以找到好多优秀的分析,此处我就不展开了;代码部分我发现一个问题,爬坑过程中遇到的问题大家基本相似,却不容易找到解决办法,各类博主下面的问题也是俄罗斯套娃,一个问上一个问题怎么解决,到最后也没人回答,看来大家爬坑之前都喜欢问,爬坑之后都不怎么喜欢分享,即使是很小的问题。
下面将Mask rcnn 爬过的小坑分享给大家,希望有用,同时也希望后面遇到的坑可以有人一起探讨。
代码位置:https://github.com/matterport/Mask_RCNN
测试数据集来源:https://blog.csdn.net/qq_29462849/article/details/81037343
二
环境搭建
Win10 + RTX2080ti + tensorflow-gpu-1.6.0 + cuda 9.1 + cudnn
三
Win10 pip3 安装慢的问题
临时换源:
pip3 install 包名 -i 源的url
国内源列表:
清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/
阿里云 http://mirrors.aliyun.com/pypi/simple/
中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/
豆瓣(douban) http://pypi.douban.com/simple/
四
Mask RCNN 安装
在工程根目录下:
python install -r requirements.txt
第一步。为了在MS-COCO上训练或者测试,需要安装pycocotools.
pip install git+
https://github.com/philferriere/cocoapi.git#subdirectory=PythonAPI
第二步。在工程根目录下:python setup.py install
五
Mask RCNN 测试
运行sample下demo.py通过下载得预训练模型 mask_rcnn_coco.h5 随机识别一张图片里得mask。
遇到的问题:
(1)YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.
解决掉警告的方法:
yaml.warnings({'YAMLLoadWarning': False})
yaml.load(input, Loader=yaml.FullLoader)
PYTHONWARNINGS=ignore::yaml.YAMLLoadWarning
(2) matplotlib “Agg” 无法显示图像的问题
解决办法:在visualize.py文件中加入:
import matplotlib
matplotlib.use('Qt5Agg')
(3)因为labelme_json_to_datasets生成的mask重名导致cv_mask覆盖的问题
解决办法:修改json_to_dataset.py:
向上滑动阅览
import argparse
import base64
import json
import os
import os.path as osp
import PIL.Image
import yaml
from labelme.logger import logger
from labelme import utils
import warnings
def main():
warnings.warn("This script is aimed to demonstrate how to convert the\n"
"JSON file to a single image dataset, and not to handle\n"
"multiple JSON files to generate a real-use dataset.")
parser = argparse.ArgumentParser()
parser.add_argument('json_file')
parser.add_argument('-o', '--out', default=None)
args = parser.parse_args()
json_file = args.json_file
if args.out is None:
out_dir = osp.basename(json_file).replace('.', '_')
out_dir = osp.join(osp.dirname(json_file), out_dir)
else:
out_dir = args.out
if not osp.exists(out_dir):
os.mkdir(out_dir)
count = os.listdir(json_file)
for i in range(0, len(count)):
path = os.path.join(json_file, count[i])
(filepath, tempfilename) = os.path.split(path)
(filename, extension) = os.path.splitext(tempfilename)
print(filename)
if os.path.isfile(path):
data = json.load(open(path))
if data['imageData']:
imageData = data['imageData']
else:
imagePath = os.path.join(os.path.dirname(path), data['imagePath'])
with open(imagePath, 'rb') as f:
mageData = f.read()
imageData = base64.b64encode(imageData).decode('utf-8')
img = utils.img_b64_to_arr(imageData)
label_name_to_value = {'_background_': 0}
for shape in data['shapes']:
label_name = shape['label']
if label_name in label_name_to_value:
label_value = label_name_to_value[label_name]
else:
label_value = len(label_name_to_value)
label_name_to_value[label_name] = label_value
# label_values must be dense
label_values, label_names = [ ], [ ]
for ln, lv in sorted(label_name_to_value.items(), key=lambda x: x[1]):
label_values.append(lv)
label_names.append(ln)
assert label_values == list(range(len(label_values)))
lbl = utils.shapes_to_label(img.shape, data['shapes'], label_name_to_value)
captions = ['{}: {}'.format(lv, ln)
for ln, lv in label_name_to_value.items()]
lbl_viz = utils.draw_label(lbl, img, captions)
out_dir = osp.basename(count[i]).replace('.', '_')
out_dir = osp.join(osp.dirname(count[i]), out_dir)
if not osp.exists(out_dir):
os.mkdir(out_dir) PIL.Image.fromarray(img).save(osp.join(out_dir, 'img.png'))
#PIL.Image.fromarray(lbl).save(osp.join(out_dir, 'label.png'))
utils.lblsave(osp.join(out_dir, 'label.png'), lbl)
utils.lblsave(osp.join('E:/deeplearning/Mask_RCNN-master/Mask_RCNN-master/train_data/cv2_mask', filename+'.png'), lbl)
PIL.Image.fromarray(lbl_viz).save(osp.join(out_dir, 'label_viz.png'))
with open(osp.join(out_dir, 'label_names.txt'), 'w') as f:
for lbl_name in label_names:
f.write(lbl_name + '\n')
warnings.warn("info.yaml is being replaced by label_names.txt")
info = dict(label_names=label_names)
with open(osp.join(out_dir, 'info.yaml'), 'w') as f:
yaml.safe_dump(info, f, default_flow_style=False)
print('Saved to: %s' % out_dir)
if __name__ == '__main__':
main()
(4)推断不显示结果(应该是训练和推断占用同一GPU导致)
解决办法:指定GPU或关掉训练可以显示结果。
(5)得到的MASK覆盖精度低,且bbox将两个物体连接到一起。
如左图所示,边界覆盖不完整,右图单个物体效果明显更好。
bbox出现问题解决方法:
Labelme 进行标注的过程中应该将同类不同物体进行不同的命名,如:tank tank1 tank2等,每张图片上都从头开始命名,训练时会通过遍历label内是否存在tank的字符串来进行训练:
向上滑动阅览
# 重写load_mask
def load_mask(self, image_id):
"""Generate instance masks for shapes of the given image ID.
"""
global iter_num
print("image_id",image_id)
info = self.image_info[image_id]
count = 1 # number of object
img = Image.open(info['mask_path'])
num_obj = self.get_obj_index(img)
mask = np.zeros([info['height'], info['width'], num_obj], dtype=np.uint8)
mask = self.draw_mask(num_obj, mask, img,image_id)
occlusion = np.logical_not(mask[:, :, -1]).astype(np.uint8)
for i in range(count - 2, -1, -1):
mask[:, :, i] = mask[:, :, i] * occlusion
occlusion = np.logical_and(occlusion, np.logical_not(mask[:, :, i]))
labels = []
labels = self.from_yaml_get_class(image_id)
labels_form = []
for i in range(len(labels)):
if labels[i].find("tank") != -1:
# print "tank"
labels_form.append("tank")
class_ids = np.array([self.class_names.index(s) for s in labels_form])
return mask, class_ids.astype(np.int32)
(6) 精度低解决办法
提高数据集图片数量及标注精度。
(7) 存在误识别的情况
解决办法一:同问题四所述的精度问题,提高数据集图片数量及标注精度;
解决办法二:提高推断过程中的confidence,位于mrcnn的config.py文件中:
# Minimum probability value to accept a detected instance
# ROIs below this threshold are skipped
DETECTION_MIN_CONFIDENCE = 0.85 #默认值是0.7
在model中的用法为:
向上滑动阅览
# Filter out low confidence boxes
if config.DETECTION_MIN_CONFIDENCE:
conf_keep = tf.where(class_scores >= config.DETECTION_MIN_CONFIDENCE)[:, 0]
keep = tf.sets.set_intersection(tf.expand_dims(keep, 0),
tf.expand_dims(conf_keep, 0))
keep = tf.sparse_tensor_to_dense(keep)[0]
(7)推断过程非常慢的问题
论文里叙述可达到5fps,实测推断一张图片需要3秒,显卡配置为两块RTX 2080ti
解决办法:
1)考虑没有正确使用GPU,指定使用GPU:
os.environ["CUDA_VISIBLE_DEVICES"] = "0,1"
2)多次运行看是否有效果:
多次运行后发现只有第一次推断时间较长,后续过程中时间大概为300ms,满足使用要求。
(8)将彩色图推断得到的mask应用到深度图上完成深度图分割
代码参考:visualize.py文件中,就是里面的display_instances函数:
可见我们可以直接更改apply_mask 完成深度图分割的要求:
def apply_depth(image, mask, color, alpha=0.5):
"""Apply the given mask to the image.
"""
image = np.where(mask == 0,0,image)
return image
效果如下:
左彩色图 右深度图
分割完成。
六
后续尝试
工件已经准备好,希望后面测试顺利吧。
—— E N D ——
资源