1. 为什么医学图像标注需要格式转换?
如果你正在做医学影像的AI项目,比如用深度学习模型识别CT片子里的病灶、分割X光片上的骨骼,或者像我之前做过的口腔内窥镜图像分析,那你肯定绕不开一个环节:数据标注。标注好的数据是模型的“粮食”,但喂给模型之前,你得先把“粮食”加工成它能消化的格式。
这就好比你去西餐厅,总不能端上一盘没切块的整只烤鸡让客人直接啃吧?你得按照西餐的规矩,切成适口的牛排或者鸡排。在AI的世界里,Labelme 就像我们手里那把好用的、可以自由切割的厨刀,而 COCO格式 就是大多数深度学习框架(比如PyTorch的Torchvision、MMDetection)期待的那套标准“摆盘”。
我刚开始做医学图像项目时,也在这个环节卡了很久。Labelme用起来是真方便,鼠标点点画画,多边形、矩形、点,想怎么标就怎么标,每个标注结果都存成一个独立的.json文件。但问题来了,当你攒了几百上千张标注好的图像,准备扔进模型训练时,你会发现主流的检测、分割模型库,它们默认读取的数据格式往往是COCO。直接拿Labelme的json去训练?模型会直接“懵掉”,因为它不认识这种“私房菜”的摆盘方式。
所以,从Labelme到COCO的格式转换,不是一个可选项,而是一个必须高效、准确完成的“数据预处理”关键步骤。这个过程的核心,就是把Labelme那种“一个图片对应一个json,里面记录了所有标注形状”的松散结构,整理成COCO那种“一个总json文件,结构化地描述所有图片、所有类别、所有标注框和分割区域”的严谨格式。搞定了它,你的数据流水线才算真正打通。
2. 动手之前:理解两种格式的“基因差异”
磨刀不误砍柴工。在写代码转换之前,我们得先弄明白Labelme和COCO这两种格式到底长什么样。只有理解了它们的“基因”,转换时才不会出乱子。
Labelme的JSON(一个文件管一张图) 用Labelme标一张图后,会生成一个同名的.json文件。用文本编辑器打开,它的结构非常直观:
{
"version": "5.3.1",
"flags": {},
"shapes": [
{
"label": "tumor",
"points": [[120.5, 80.2], [150.3, 80.2], [150.3, 110.7], [120.5, 110.7]],
"group_id": null,
"shape_type": "polygon",
"flags": {}
},
{
"label": "cyst",
"points": [[200, 300], [250, 300], [250, 350]],
"group_id": null,
"shape_type": "polygon",
"flags": {}
}
],
"imagePath": "patient_001_slice_050.png",
"imageData": "很长很长的Base64编码字符串...",
"imageHeight": 512,
"imageWidth": 512
}
你看,关键在shapes这个列表里。每个标注对象都独立成字典,包含了label(类别名)、points(多边形各个顶点的坐标)、shape_type(标注类型,如polygon、rectangle)。imageData里甚至直接嵌入了图片的Base64编码数据,这样即使原图移动了,json文件自己也能“还原”出图像,非常贴心。但这也导致了文件体积较大。
COCO的JSON(一个文件管整个数据集) COCO格式则是一种数据库式的结构。它通常是一个庞大的JSON文件(比如instances_train2017.json),里面包含了几个顶级字段:
images: 一个列表,记录数据集中所有图像的信息(ID、文件名、宽、高)。annotations: 一个列表,记录所有图像的所有标注实例。每个实例都通过image_id关联到对应的图像,通过category_id关联到类别。categories: 一个列表,定义数据集中所有类别的ID和名称。
一个简化的COCO标注片段看起来是这样的:
{
"images": [
{"id": 1, "file_name": "patient_001_slice_050.png", "height": 512, "width": 512},
{"id": 2, "file_name": "patient_001_slice_051.png", "height": 512, "width": 512}
],
"annotations": [
{"id": 1, "image_id": 1, "category_id": 1, "segmentation": [[120.5, 80.2, 150.3, 80.2, 150.3, 110.7, 120.5, 110.7]], "bbox": [120.5, 80.2, 29.8, 30.5], "area": 908.9, "iscrowd": 0},
{"id": 2, "image_id": 1, "category_id": 2, "segmentation": [[200, 300, 250, 300, 250, 350, 200, 350]], "bbox": [200, 300, 50, 50], "area": 2500, "iscrowd": 0}
],
"categories": [
{"id": 1, "name": "tumor", "supercategory": "lesion"},
{"id": 2, "name": "cyst", "supercategory": "lesion"}
]
}
这里有几个关键点需要特别注意:
- ID是唯一的桥梁:
image_id和annotation_id必须是全局唯一的整数,category_id也需要预先定义好。这是COCO格式关联数据的核心。 - bbox的格式:COCO的边界框
bbox是[x_min, y_min, width, height],即左上角坐标加宽高。而Labelme里矩形的points是两个点[[x1,y1],[x2,y2]],多边形的points是一系列点,需要计算外接矩形。 - segmentation的格式:COCO的

6万+

被折叠的 条评论
为什么被折叠?



