可视化coco格式标注的mask(.json 分割)

COCO格式.json掩码可视化教程
本文介绍如何利用代码将COCO数据集的json标签文件转换为可視化的mask,适用于目标检测和语义分割任务。提供批量处理和单个目标的mask掩码可视化方法。

目标检测、分割任务中,常用的标注格式是PASCAL VOC或coco数据集格式,其中coco的标签是以,json文件定义的。

以下的代码段可以帮您可视化数据的mask掩码(文末附完整代码)。

key words:语义分割  coco  .json 掩码mask 可视化


先上结果:(支持单个或多个目标可视化)

 

 

#  首先导入必要的库

import json
import numpy as np
import skimage.io
import cv2
import matplotlib.pyplot as plt
import PIL.Image
import PIL.ImageDraw
import numpy

<think>我们有一个任务:将mask掩码转换为COCO格式的图像标注数据。COCO格式要求每个对象实例都有其对应的分割掩码(多边形或多点坐标)、边界框以及类别信息。根据引用内容,我们可以参考一些已有的方法。 步骤概述: 1. 准备数据:通常,我们有一组图像和对应的mask掩码图像。在mask图像中,每个像素值代表该像素所属的对象类别(或实例)。注意,COCO格式要求每个对象实例单独标注。 2. 转换思路: - 如果mask图像是RGB彩色图(每个类别用不同颜色表示),需要先将其转换为每个对象实例的单独二值掩码(每个对象一个黑白掩码图像)[^2]。 - 或者,如果mask图像已经是每个对象实例单独的二值图像(即每个文件一个对象),则可以直接处理。 3. 生成COCO格式JSON文件:需要构建一个包含images、annotations、categories三个主要部分的字典。 根据引用[1]和[4],我们可以使用以下步骤: a. 遍历所有mask图像,为每个图像生成对应的对象实例的掩码。 b. 对于每个对象实例的掩码,将其转换为多边形(polygon)或RLE(Run Length Encoding)格式COCO支持这两种格式。 c. 计算每个对象实例的边界框(bounding box)。 d. 为每个图像和每个标注分配唯一的ID。 e. 构建类别信息(通常是一个列表,包含每个类别的名称和ID)。 具体步骤: 1. 读取mask图像:假设我们有一个mask图像,其中包含多个对象(例如,不同颜色代表不同实例,或者同一类别的不同实例用不同像素值区分)。注意,在COCO中,每个对象实例都需要单独标注,即使它们属于同一类别。 2.mask图像分解为多个二值掩码:每个二值掩码对应一个对象实例。引用[2]中的代码展示了如何将RGB掩码图像分解为多个黑白掩码图像(每个对象一个)。但是,如果原始mask是单通道的(例如,每个像素的值是0,1,2,...,其中0是背景,1是第一个对象,2是第二个对象等),则可以直接根据像素值分离对象。 3. 对于每个二值掩码,执行以下操作: a. 使用工具(如`pycococreatortools`中的`binary_mask_to_polygon`)将二值掩码转换为多边形(polygon)。注意,多边形是一个点列表,格式为`[x1, y1, x2, y2, ...]`。 b. 计算边界框:可以通过掩码中非零像素的最小最大坐标计算。边界框格式为`[x, y, width, height]`,其中`(x,y)`是左上角坐标。 c. 记录类别ID:根据掩码对应的类别(注意,在分解掩码时,需要知道每个掩码属于哪个类别。如果原始mask是单通道的,则像素值就是类别ID;如果是RGB的,则需要一个颜色到类别ID的映射)。 4. 构建COCO JSON结构: - images: 包含每个图像的信息(id, file_name, height, width等) - annotations: 每个对象一个字典,包含: id: 标注的唯一ID image_id: 对应的图像ID category_id: 类别ID segmentation: 多边形(可以是多个多边形,如果对象有多个部分) area: 对象的面积(像素数) bbox: 边界框 iscrowd: 0(表示单个对象)或1(表示多个对象组成的群组,此时用RLE编码) - categories: 每个类别的id和name 5. 使用工具库:引用[1]提到使用了一个修改过的博客代码,引用[4]提到了使用`pycococreatortools`(来自COCO API)来将二值掩码转换为多边形。 注意:如果对象掩码非常复杂(例如有孔洞),则可能生成多个多边形(每个连续区域一个多边形)。COCO格式允许一个对象有多个多边形(放在一个列表中)。 代码结构示例: 由于代码较长,这里给出一个框架: 步骤1:定义类别列表(例如:categories = [{"id":1, "name":"polyp"}, ...]) 步骤2:遍历所有原始图像和对应的mask图像。 - 为每个原始图像创建一个image信息,并分配一个image_id。 步骤3:对于每个mask图像,分离每个对象实例(通过不同的像素值或颜色)。 - 为每个对象实例创建一个annotation。 - 使用类似引用[2]的方法分离对象(如果是RGB)或直接通过像素值(如果是单通道)。 步骤4:将每个对象实例的二值掩码转换为多边形(使用类似引用[4]的方法:`pycococreatortools.binary_mask_to_polygon`,注意设置tolerance参数,它控制多边形的简化程度)。 步骤5:计算边界框和面积。 步骤6:将annotation添加到列表中。 步骤7:构建完整的COCO字典,并保存为JSON文件。 注意:需要安装pycocotools,其中包含pycococreatortools(注意:pycocotools中可能没有pycococreatortools,但我们可以使用其他方式,比如参考COCO API的示例代码,或者使用其他库如shapely等)。 另外,引用[3]提到了将mask转换为YOLO格式,但这里我们不需要。 由于引用[2]中的代码是将RGB掩码分解为多个黑白掩码,我们可以使用类似的方法。但是,如果我们的mask已经是单通道的,则可以直接用numpy找到不同的像素值。 示例代码框架(伪代码): ```python import os import json import numpy as np from PIL import Image import pycococreatortools # 注意:这个工具可能需要单独下载,它是COCO API的一部分?或者可以参考其实现 # 定义路径和类别 ROOT_DIR = '...' IMAGE_DIR = os.path.join(ROOT_DIR, "images") MASK_DIR = os.path.join(ROOT_DIR, "masks") ANNOTATION_FILE = os.path.join(ROOT_DIR, "annotations.json") # 定义类别 categories = [{"id": 1, "name": "polyp"}] # 创建COCO字典的基本结构 coco_output = { "info": {...}, "licenses": [...], "categories": categories, "images": [], "annotations": [] } # 遍历图像 image_id = 1 annotation_id = 1 for image_file in os.listdir(IMAGE_DIR): # 读取图像,获取尺寸 image = Image.open(os.path.join(IMAGE_DIR, image_file)) image_info = { "id": image_id, "file_name": image_file, "width": image.width, "height": image.height } coco_output["images"].append(image_info) # 读取对应的mask图像(假设mask图像文件名和原图相同,但放在MASK_DIR下) mask_file = os.path.join(MASK_DIR, image_file) mask = np.array(Image.open(mask_file)) # 假设是单通道,或者RGB # 分离mask中的不同对象实例 # 方法1:如果mask是单通道,每个对象用不同的整数表示(背景为0) # 获取所有非零的像素值(每个值代表一个对象实例) # 注意:同一个对象实例的像素值相同,不同实例不同 object_ids = np.unique(mask) object_ids = object_ids[object_ids != 0] # 排除背景 for obj_id in object_ids: # 创建二值掩码:当前对象为1,其他为0 binary_mask = np.where(mask==obj_id, 1, 0).astype(np.uint8) # 将二值掩码转换为多边形 # 注意:pycococreatortools.binary_mask_to_polygon 返回一个多边形列表(每个连续区域一个多边形) # 如果对象有多个不连续的部分,则会有多个多边形 # tolerance参数控制多边形的简化程度(值越大,多边形点越少) segmentation = pycococreatortools.binary_mask_to_polygon(binary_mask, tolerance=2) if len(segmentation) == 0: continue # 计算边界框:通过非零像素的坐标 # 注意:边界框格式为 [x,y,width,height] where = np.nonzero(binary_mask) y_min, y_max = np.min(where[0]), np.max(where[0]) x_min, x_max = np.min(where[1]), np.max(where[1]) bbox = [x_min, y_min, x_max - x_min + 1, y_max - y_min + 1] # 计算面积:非零像素的数量 area = int(np.sum(binary_mask)) # 类别ID:这里假设每个对象都是同一类别(例如,只有一种息肉) # 如果mask中有多个类别,则obj_id可能包含类别信息(比如,前几位是类别,后几位是实例ID)?这里需要根据实际情况调整 # 如果obj_id直接就是类别ID,则可以直接用。但通常,在实例分割中,mask中的每个实例用一个唯一的ID标记,而类别信息需要另外存储(比如,通过一个映射表,将实例ID映射到类别ID)。但这里我们假设每个对象都是类别1(即categories中的第一个类别) category_id = 1 # 创建annotation字典 annotation = { "id": annotation_id, "image_id": image_id, "category_id": category_id, "segmentation": segmentation, "area": area, "bbox": bbox, "iscrowd": 0 } coco_output["annotations"].append(annotation) annotation_id += 1 image_id += 1 # 保存为JSON文件 with open(ANNOTATION_FILE, 'w') as f: json.dump(coco_output, f) ``` 注意:上述代码中,我们假设mask是单通道的,并且每个对象实例用不同的非零整数表示。如果mask是RGB的,则需要先转换为单通道(例如,通过一个颜色到实例ID的映射),或者使用引用[2]中的方法先分解为多个黑白掩码(每个掩码一个文件),然后对每个黑白掩码文件进行上述处理(此时,每个黑白掩码对应一个对象实例,类别需要另外指定或通过文件名映射)。 另外,关于`pycococreatortools`,它可能不是标准库。我们可以从COCO API的示例中获取这个模块,或者自己实现类似功能。以下是一个替代方案(使用shapely和rasterio)来实现二值掩码到多边形的转换,但这里为了简便,我们可以参考引用[4]中的方法,使用`pycococreatortools`(其实现可以在网上找到,例如:https://github.com/waspinator/pycococreator/blob/master/pycococreatortools/pycococreatortools.py) 这里提供`binary_mask_to_polygon`函数的一个可能实现(参考自COCO官方示例): ```python import numpy as np from skimage import measure def binary_mask_to_polygon(binary_mask, tolerance=0): """将二值掩码转换为多边形坐标列表(COCO格式)""" polygons = [] # 使用轮廓检测 contours = measure.find_contours(binary_mask, 0.5, fully_connected='high') for contour in contours: # 简化多边形(如果tolerance>0) contour = measure.approximate_polygon(contour, tolerance) # 坐标转换:轮廓坐标是(y,x),转换为(x,y) contour = np.flip(contour, axis=1) # 将坐标点转换为列表 contour = contour.ravel().tolist() polygons.append(contour) return polygons ``` 注意:这个函数返回一个多边形列表,每个多边形是一个点列表(每个点用x,y表示,连续排列)。如果对象有多个部分(多个连通域),则返回多个多边形。 因此,如果没有现成的`pycococreatortools`,可以使用上述函数替代。 总结:根据mask图像的类型(单通道或RGB)选择合适的分离方法,然后对每个对象实例生成二值掩码,再转换为多边形,计算边界框和面积,最后构建COCO格式JSON文件。 相关问题: 1. 在转换过程中,如何处理重叠的对象实例? 2. 如果mask图像中的对象有孔洞,转换多边形时会怎样? 3. 如何评估转换后的COCO格式标注的准确性? 4. 除了多边形,COCO格式还支持RLE格式,如何将mask转换为RLE格式? 5. 转换过程中常见的错误有哪些?如何避免?</think>要将mask掩码转换为COCO格式的图像标注数据,需遵循以下步骤和关键要点: ### 转换步骤详解 1. **数据准备** - 确保每张图像有对应的mask掩码文件(PNG格式) - Mask要求: - 单通道或三通道图像 - 每个对象实例用**唯一像素值**标识(如实例1=1,实例2=2) - 背景像素值必须为0 2. **分离对象实例** 使用类似引用[2]的方法将彩色/单通道mask分解为独立对象的二值掩码: ```python import cv2 import numpy as np import os def split_masks(mask_path, output_dir): mask = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE) # 读取单通道mask unique_vals = np.unique(mask)[1:] # 排除背景0 for idx, val in enumerate(unique_vals): binary_mask = np.where(mask == val, 255, 0).astype(np.uint8) # 生成二值掩码 cv2.imwrite(f"{output_dir}/{os.path.basename(mask_path)}_{idx}.png", binary_mask) ``` 3. **生成COCO标注** 对每个二值掩码执行: - **多边形转换**:使用`pycococreatortools`(需安装`pycocotools`): ```python from pycococreatortools import binary_mask_to_polygon mask = cv2.imread("binary_mask.png", cv2.IMREAD_GRAYSCALE) polygon = binary_mask_to_polygon(mask, tolerance=2) # tolerance控制简化程度[^4] ``` - **计算边界框**: ```python y, x = np.where(mask > 0) bbox = [int(x.min()), int(y.min()), int(x.max()-x.min()), int(y.max()-y.min())] # [x,y,width,height] ``` 4. **构建JSON结构** COCO格式需包含: ```json { "images": [{"id": 1, "file_name": "image1.jpg", "width": 640, "height": 480}], "annotations": [{ "id": 1, "image_id": 1, "category_id": 1, "segmentation": [[x1,y1,x2,y2,...]], // 多边形坐标 "bbox": [x,y,width,height], "area": 256.5, "iscrowd": 0 }], "categories": [{"id": 1, "name": "polyp"}] } ``` ### 关键注意事项 1. **像素值映射** - 单通道mask中像素值必须对应类别ID(如1=息肉,2=其他病变) - 若使用RGB mask,需建立颜色到ID的映射表(如(255,0,0)→1) 2. **多对象处理** 一张图含多个对象时: - 每个对象生成独立annotation条目 - 共享相同的`image_id` 3. **安装依赖** ```bash pip install pycocotools opencv-python numpy ``` ### 完整流程示例 ```python from pycococreatortools import binary_mask_to_polygon import json import cv2 import glob # 初始化COCO结构 coco_data = { "images": [], "annotations": [], "categories": [{"id": 1, "name": "polyp"}] } image_id = 1 annotation_id = 1 for mask_path in glob.glob("masks/*.png"): # 添加image信息 mask = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE) coco_data["images"].append({ "id": image_id, "file_name": os.path.basename(mask_path).replace("_mask", ""), "width": mask.shape[1], "height": mask.shape[0] }) # 处理每个对象 for val in np.unique(mask): if val == 0: continue # 跳过背景 binary_mask = np.where(mask == val, 1, 0).astype(np.uint8) # 获取多边形和边界框 segmentation = binary_mask_to_polygon(binary_mask, tolerance=2) y, x = np.where(binary_mask > 0) bbox = [int(x.min()), int(y.min()), int(x.max()-x.min()), int(y.max()-y.min())] # 添加annotation coco_data["annotations"].append({ "id": annotation_id, "image_id": image_id, "category_id": int(val), # 像素值即类别ID "segmentation": segmentation, "bbox": bbox, "area": int(np.sum(binary_mask)), "iscrowd": 0 }) annotation_id += 1 image_id += 1 # 保存结果 with open("coco_annotations.json", "w") as f: json.dump(coco_data, f) ``` ### 常见问题解决 - **掩码值非连续整数**:预处理时用`np.unique(mask, return_inverse=True)`重映射 - **复杂形状转换失败**:增大`tolerance`值或使用RLE格式替代多边形 - **小对象丢失**:检查`binary_mask_to_polygon`的阈值参数 > 提示:对于医学图像(如息肉数据集),建议验证转换后的边界框是否包含完整病变区域[^1]。可通过可视化工具如[COCO-Annotator](https://github.com/jsbroks/coco-annotator)检查标注准确性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值