如何从COCO数据集中创建遮罩图像?

22

我一直在使用这段代码,尝试从COCO数据集生成图像的原始掩码。

dataDir='G:'
dataType='train2014'
annFile='{}/annotations/instances_{}.json'.format(dataDir,dataType)


coco=COCO(annFile)
annFile = '{}/annotations/person_keypoints_{}.json'.format(dataDir,dataType)
coco_kps=COCO(annFile)


catIds = coco.getCatIds(catNms=['person'])
imgIds = coco.getImgIds(catIds=catIds );
imgIds = coco.getImgIds(imgIds = imgIds[0])
img = coco.loadImgs(imgIds[np.random.randint(0,len(imgIds))])[0]
I = io.imread('G:/train2014/'+img['file_name'])

plt.imshow(I); plt.axis('off')
annIds = coco.getAnnIds(imgIds=img['id'], catIds=catIds, iscrowd=None)
anns = coco.loadAnns(annIds)
coco.showAnns(anns)

但是我得到的结果是这样的:

输入图像描述

但是我想要的是这样的:

输入图像描述

我如何得到每个图像的原始掩码?

5个回答

18
完整的代码没有在答案中,因此我在下面发布它。
请先安装pycocotools
pip install pycocotools

导入所需的模块。我假设您正在使用jupyter笔记本。

from pycocotools.coco import COCO
import os
from PIL import Image
import numpy as np
from matplotlib import pyplot as plt
%matplotlib inline

加载coco数据集的注释。在这里,指定第74张图片。
coco = COCO('../datasets/coco/annotations/instances_train2017.json')
img_dir = '../datasets/coco/train2017'
image_id = 74

img = coco.imgs[image_id]
# loading annotations into memory...
# Done (t=12.70s)
# creating index...
# index created!

加载的img的信息如下。
img
# {'license': 2,
#  'file_name': '000000000074.jpg',
#  'coco_url': # 'http://images.cocodataset.org/train2017/000000000074.jpg',
#  'height': 426,
#  'width': 640,
#  'date_captured': '2013-11-15 03:08:44',
#  'flickr_url': # 'http://farm5.staticflickr.com/4087/5078192399_aaefdb5074_z.jpg# ',
#  'id': 74}

如下显示图像。

image = np.array(Image.open(os.path.join(img_dir, img['file_name'])))
plt.imshow(image, interpolation='nearest')
plt.show()

enter image description here

如果您想查看叠加结果:
plt.imshow(image)
cat_ids = coco.getCatIds()
anns_ids = coco.getAnnIds(imgIds=img['id'], catIds=cat_ids, iscrowd=None)
anns = coco.loadAnns(anns_ids)
coco.showAnns(anns)

enter image description here

如果您只想查看面具,可以按照Farshid Rayhan的回复进行操作:
mask = coco.annToMask(anns[0])
for i in range(len(anns)):
    mask += coco.annToMask(anns[i])

plt.imshow(mask)

enter image description here


1
定义掩码变量mask = coco.annToMask(anns[0]),然后从零开始循环anns将会使第一个索引重复添加两次。Doggo的值为2,而其余的为1。你不应该在循环之前声明mask,在循环内部声明更好。 - colt.exe

13

在遵循Filippo先生的直觉后,我成功编写了正确的代码,大致如下。

mask = coco.annToMask(anns[0])
for i in range(len(anns)):
    mask += coco.annToMask(anns[i])

plt.imshow(mask)

2
很酷,很高兴它有帮助!请注意,这种方法会生成一个二进制掩码。在这种情况下,使用二进制OR比简单加法更安全。将掩码乘以索引i的想法是每个标签都有不同的值,您可以使用类似于图像中的那个(我猜测是nipy_spectral)的颜色映射来在imshow绘图中将它们分开。 - filippo
虽然这并不重要,但你每天更改一次已接受的答案有什么原因吗? - filippo
1
不行!!我一直在接受它,但它又被关闭了。可能是因为我的手机浏览器有漏洞……每当我打开这个页面时,它就会被切换!甚至我的答案也是! - Farshid Rayhan
哈哈 :-) 对不起!尝试重置缓存或类似操作。 - filippo
4
假设mask是一个numpy数组,你是否会将ann[0]加两次? - Javi

9

我来晚了,但如果这能帮助到某人。 我不知道你的代码是否适用于你的应用程序,但是,如果您希望掩码的每个像素具有注释类别ID的值,则不能仅添加掩码,因为有些会重叠。 我使用了numpy的最大值:

cat_ids = coco.getCatIds()
anns_ids = coco.getAnnIds(imgIds=img['id'], catIds=cat_ids, iscrowd=None)
anns = coco.loadAnns(anns_ids)
anns_img = np.zeros((img['height'],img['width']))
for ann in anns:
    anns_img = np.maximum(anns_img,coco.annToMask(ann)*ann['category_id'])

编辑: 以下是我对2017数据集中图像47112的代码示例: Coco2017-47112 使用上述代码 灰度值为类别的ID,如数据集描述所述。 注意,在这里,披萨在多边形的边缘与桌子重叠。如果我们添加掩模,重叠将被赋予相应于披萨和桌子类别总和的ID。然而,使用max,只保留一个类别。在这种情况下,由于类别表的ID大于类别披萨的ID,重叠影响表格类别,即使披萨在视觉上位于其上面。我不确定这个问题是否容易解决。


你是说你的代码会提供与原始问题的最后一张图片类似的输出? - Farshid Rayhan
1
带有灰色阴影。是的,我刚刚编辑了我的帖子并添加了一个例子。 - Duret-Robert Louis
1
你提到的问题不是很重要吗?例如,在一个人站在火车旁边的图像中,如果火车的id更高,它会遮盖住这个人。因此,你的图像只有一个类别(火车),这是错误的标准答案。 - ashnair1

3

我不熟悉 COCO,但我看到这里有一个 annToMask 函数可以为每个注释生成二进制掩码。

所以,在未经测试的伪代码中,假设掩码不重叠,您应该有如下内容:

annIds = coco.getAnnIds(imgIds=img['id'], catIds=catIds, iscrowd=None)

mask = np.zeros_like(img)
for i, ann in enumerate(annIds):
    mask += coco.annToMask(ann) * i 

2

如果您想获取所有注释的二进制掩码,可以按如下方式创建:

#Construct the binary mask
mask = coco.annToMask(anns[0])>0
for i in range(len(anns)):
     mask += coco.annToMask(anns[i])>0

plt.imshow(mask,cmap='gray')

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接