MATLAB中图像标注工具——Image Labeler的使用方法

前言

深度学习中无论是什么任务,数据集是必不可少的,我们可以使用公开数据集,但实际情况中由于特定的任务我们可能也不得不手动制作数据集。正好本人最近在一个语义分割任务中涉及自己制作数据集,也就是标注图像,虽然有例如labelme、ITKsnap等软件可以用来标注,但MATLAB也提供了一个非常实用的图像标注工具Image Labeler,可以在APP中找到,可以用来标记矩形感兴趣区域 (ROI) 标签、折线 ROI 标签、像素 ROI 标签和场景标签。语义分割任务中用到的是像素ROI标注功能,因此在本篇博客中记录一下使用的方法,详细的示例可以参考: https://www.mathworks.com/help/vision/ug/get-started-with-the-image-labeler.html.

语义分割

基本概念

个人理解,图像分割是为图像中的每个像素点分配一个标签,表示一个类别。在语义分割中,表示某种属性的所有区域内的像素点往往具有相同的类别,比如常见的分割CT中的肝脏区域,一个街景图像中分割所有的行人。还有一种分割称为实例分割,其实结合面向对象编程从字面意思也可以想到,一个类拥有多个实例,一个街景图像中也有多个行人,实例分割中每个行人的类别都不一样。

标注结果

在图像分类任务中,每一张图像都有一个类别,例如猫、狗等,这是整幅图的标签(label)。我们前面也提到语义分割每个像素点都有一个标签,那么他的标注结果将和原图的像素数量一样多,为此我们可以用一个数字表示一个类别,比如在通常的二类分割(binary segmentation)中,往往把像素点分为前景(foreground)和背景(background),用1表示前景,0表示背景,我们就可以得到和原图尺寸一致的标注图像。比如下面一幅胸部的CT图像,(来源:https://www.chinayikao.com/forum.php?mod=viewthread&tid=34849&extra=page%3D1&page=1),原图和其标注的图像如下,标注的图像像素值仅有0和1,0表示除肺部之外的区域,1表示肺部区域,当然为了清晰的显示出来,我们对标注的图像灰度值进行了拉伸:
############此处有图####################

我们可以调用MATLAB中的labeloverlay函数,将标注后的图像叠加在原图上显示:
############此处有图####################

标注过程

其标注的过程如下:

  1. 我们首先在MATLAB APP中找到Image Labeler并打开
    打开Image Labeler
    打开之后如下图所示:
    在这里插入图片描述
  2. 接下来点击ROI Labels下面的Label图标,就会出现这个对话框在这里插入图片描述
    输入你定义的类别,我们分割的是肺部区域,因此输入lung,右侧的下拉菜单中的标注类型选择最后一个,因为我们进行的是像素级别的标注,同时也可以添加一些描述
    在这里插入图片描述
    设置好之后主界面的左侧就出现了一个关于lung的提示。
    在这里插入图片描述
    同样,按照这种方式,你可以添加更多的标签,标签的灰度值从1开始,我们刚刚添加的lung就是1,接着添加的话就是2,3…建立好标签之后我们需要加载你需要标注的图像,在Load下面根据需要选择一种加载图像的方式,选择的时候可以任意数量的图像,该APP会全部包含进来,
    在这里插入图片描述
    图像选择好之后界面为:
    在这里插入图片描述
    准备工作基本做完。
  3. 下面就是标注的过程,在最上方的LABEL PIXELS工具栏中出现的就是我们的标注工具,你想标注哪一类就点击左侧的标签,图中lung这个标签发黄意味着我们现在标注的是lung这一个类。工具栏里的各个工具如下:
    在这里插入图片描述
    从左往右依次为多边形标注工具、Smart Polygon Editor(应该就是Grab Cut的原理)、Assisted Freehand(其实就是一个具有自动吸附功能的多边形标注工具),我们常见的笔刷(Brush)和橡皮(Erase),还有一个自动填充(Flood Fill)的工具。最常用到的应该还是多边形标注工具,当然配合其他的工具使用起来更能提升我们的标注体验,以多边形标注工具为例,我们选择了一个多边形之后
    在这里插入图片描述
    如果放到起始点附近,光标会形成一个圆形,这时点击后就自动闭合构成一个区域,当然,我们可以双击左键自动闭合,闭合后的区域为:
    在这里插入图片描述
    这时你可以用鼠标拖动某个你不满意的多边形顶点修正,之后按回车键确定,也可以不按回车键,直接标注下一个区域这个区域就会自动确定。如果对当前标注的结果不满意,可以按Ctrl+Z撤销,注意:只能撤销上一次的结果,上上次及之前的结果就不可以了。之后我们可以点击Flood Fill图标把边缘区域添加一下,这个Flood Fill用的其实就是区域生长的原理。也可以使用笔刷和橡皮进行细节的修正,分割好的结果为:
    在这里插入图片描述
  4. 分割之后我们需要保存分割的结果,可以点击Export Labels将结果导出至文件或者工作区,我们选择导出至文件后出现
    在这里插入图片描述
    文件夹里就是我们分割的结果,gTruth.mat加载之后是 groundTruth对象,这个文件很有用,当你导出分割结果的时候,你会发现文件夹中的标注文件行为“Label_1.png”、“Label_2.png”这种,和原始图像的文件名称不一样,如何去找他们的对应关系呢?其实,gTruth.DataSource.Source中存储的就是原始的图像路径,这是一个N1的cell数组,每个元素表示一个图像路径,然后gTruth.LabelData.PixelLabelData中存储的就是标注好的文件,同样也是一个N1的cell数组,刚好和上面的原始图像一一对应。通常在后续的处理中,为了避免顺序错乱带来的问题,我们一般都考虑让图像和标注有着相同的文件名而位于不同的文件夹中,我在里面也没找到相应的设置,只能自己动手编程了,其实也不算难,下面我给出一个实现:
%让标注的结果和原始图像有着相同的名字
dataS =  gTruth.DataSource;
dataFiles = dataS.Source;
%新文件夹路径
labeled_data_path = 'newLabels';
for i =  1:numel(dataFiles)
    [~,name,~] = fileparts(dataFiles{i});
    dstfilename = [name,'.png'];
    srcfilename  = ['Label_',num2str(i),'.png'];
  movefile(fullfile(labeled_data_path,srcfilename),fullfile(labeled_data_path,dstfilename));
end

写到这里,整个标注流程算是完了,但是我在实际使用过程中遇到一个非常现实的问题,比如你得到了其他软件标注的文件,想修改部分标注的结果该怎么办呢?

加载其他软件标注的文件

APP中有一个明显的Import Labels图标,你可以从文件或者工作空间加载标注好的文件,但是只能从文件中加载.mat文件,无法加载整个文件夹,这就有点麻烦了,其实你从上面的内容可以想到,导出的是一个 groundTruth对象,加载的时候也必须是这样一个对象。MATLAB官方给出了一个详细的说明关于如何去创建这样一个对象:
https://www.mathworks.com/help/vision/ref/groundtruth.html.这里结合我的理解说一下,首先对于一个完整的标注流程,必须有三个要素:原始图像,标签的定义和标注的结果,MATLAB中打开上面的gTruth.mat可以发现三个属性
在这里插入图片描述
刚好对应那三个要素,你要想在MATLAB中开始一个标注会话,那么你必须要指定这三个要素,你必须创建一个groundTruth对象,这里我们就不使用上面的例子了,如果我们当前路径下的Imgs、Lables分别保存的是一个数据集中的图像和标注结果,有M个文件,那么下面我给出一段代码用于创建这个groundTruth对象:

clc;clear;
%这里的Imgs是指原始的图像文件
dataSource = groundTruthDataSource('Imgs');
%添加标注的定义
ldc = labelDefinitionCreator();
addLabel(ldc,'Target',labelType.PixelLabel);
labelDefs = create(ldc);
%下面的代码,就是将标注文件的路径包含到labelData中
dataFile = cell(length(dataSource.Source),1);
for i = 1:size(dataFile,1)
    [~,name,~] = fileparts(dataSource.Source{i});
    dataFile{i} =  fullfile('Labels',[name,'.png']);
end
labelData = table(dataFile,'VariableNames',{'PixelLabelData'});
% labelData = groundTruthDataSource('Labels');
dataSource = groundTruthDataSource(dataSource.Source);
gTruth =  groundTruth(dataSource,labelDefs,labelData);
  • 32
    点赞
  • 209
    收藏
    觉得还不错? 一键收藏
  • 23
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值