欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

VOC-xml标注文件制作及其交互使用(修改,预览,存储)的MATLAB实现

程序员文章站 2024-03-19 23:15:04
...

最近看了看网上的各种图像样本工具,发现好多标注工具存在一些鸡肋或者制作VOC-xml格式的文件太过于繁琐,本文力求标注或制作xml格式使其简单好用。在这里先推荐下matlab2017a版本自带的trainingImageLabel app标记工具或者2017b及其以后版本的imageLabeler app(2017a的兼容升级版,还可以对像素进行标注),非常方便!实用!在工具标记完后“导出ROIs”输出是matlab内置的table类型或者struct类型数据(17b是table或者groundTruth类型),为统一起见,导出选择table格式!下面给出自己的转换过程,只需要第一部分内容就可以!

一、图像标注--->VOC-XML标准格式

只需下面两小步即可!!!

1.下载这个通用的xml/matlab struct互转工具

下载链接http://cn.mathworks.com/matlabcentral/fileexchange/12907-xml-io-tools,解压并添加到你的工作路径下即可使用(或addpath)。目的是要用到这个工具里面的xml_write函数。

2.转换VOC-xml格式

matlab命令行敲入trainingImageLabeler进入APP(或者2017b及以后版本是imageLabeler)打开你自己的图像文件进行交互式标注。这里给出截图


VOC-xml标注文件制作及其交互使用(修改,预览,存储)的MATLAB实现

标注完成后,点击上图工具栏中靠右上角“Export ROIs”导出到工作空间中,类型选择table,变量名自己取,这里我取名mylabel,双击mylabel可以清楚直观查看标记内容,每四个数字组成一个ROI,即[x,y,width,heigth],没有标注的ROI就是空[],如下图所示。


VOC-xml标注文件制作及其交互使用(修改,预览,存储)的MATLAB实现


接下来就是正式把mylabel转换为xml格式了,VOC-xml格式的文件是每个图像对应一个xml文件,我写了个转换函数如下,保存的批量xml文件自动保存到你选择的文件夹内!(比如我的保存在文件夹xmlSaveFolder内,最好跟图片文件在同一文件夹)。

function matlab_to_VOCxml(mylabel)
% 功能:把trainingImageLabel APP数据格式(table类型)转为VOC格式的xml
% 输入: mylabel为导出到工作空间的标注文件
% 输出: 自动生成xmlSaveFolder文件存储,每张图对应一个
%
% Example:
%          matlab_to_VOCxml(mylabel)
%
%%
if nargin<1 || ~istable(mylabel)
    error('请导入trainingImageLabel APP文件的table数据!');
end
folder_name = uigetdir('','请选择保存VOC-xml的文件夹!');
if ~folder_name
    warndlg('当前并没选择任何文件!','警告')
    return;
end

%%
tableLabel = mylabel; %这里是自己的标注好的table类型数据
variableNames = tableLabel.Properties.VariableNames; %cell类型
numSamples = size(mylabel,1);
numVariables = size(variableNames,2);
h = waitbar(0,'Please wait...');
steps = numSamples;
%%
for i = 1:numSamples
    rowTable = tableLabel(i,:);
    imageFullPathName = rowTable.(variableNames{1});%cell
    path = char(imageFullPathName);
    [pathstr,name,ext] = fileparts(path);
    index =strfind(pathstr,'\');
    
    annotation.folder = pathstr(index(end)+1:end);
    annotation.filename = [name,ext];
    annotation.path = path;
    annotation.source.database = 'Unknow';
    image = imread(annotation.path);
    
    annotation.size.width = size(image,2);
    annotation.size.height = size(image,1);
    annotation.size.depth = size(image,3);
    annotation.segmented = 0;
    
    objectnum = 0;
    for j = 2:numVariables %对于每个变量
        ROI_matrix = rowTable.(variableNames{j} );%cell
        if iscell(ROI_matrix)
             ROI_matrix = cell2mat(ROI_matrix);
        end
        numROIS = size(ROI_matrix,1);
        for ii = 1: numROIS % 对于每个ROI
            objectnum= objectnum+1;
            annotation.object(objectnum).name = variableNames{1,j};
            annotation.object(objectnum).pose = 'Unspecified';
            annotation.object(objectnum).truncated = 0;
            annotation.object(objectnum).difficult= 0;
            annotation.object(objectnum).bndbox.xmin = ROI_matrix(ii,1);
            annotation.object(objectnum).bndbox.ymin = ROI_matrix(ii,2);
            annotation.object(objectnum).bndbox.xmax = ROI_matrix(ii,1)+ROI_matrix(ii,3);
            annotation.object(objectnum).bndbox.ymax = ROI_matrix(ii,2)+ROI_matrix(ii,4);
        end
    end
    
    filename = fullfile(folder_name,[name,'_temp.xml']);
    xml_write(filename,annotation);
      
     %% 整理
     fid_r = fopen(filename,'r');
     fid_w = fopen(fullfile(folder_name,[name,'.xml']),'w');
     fgetl(fid_r);
     flagOffset = 0;flagObjects = 0;
     while(~feof(fid_r))
         tline = fgetl(fid_r);
         if contains(tline,'<object>')||contains(tline,'</object>') 
             t_next_line = fgetl(fid_r);
             if contains(t_next_line,'<item>')
                 flagOffset = mod(flagOffset+1,2);
                 flagObjects = 1;
                 newStr = strrep(t_next_line,'item','object');
                 fprintf(fid_w,'%s\r\n',newStr(4:end));
                 continue;
             end
             if ~flagObjects 
                 fprintf(fid_w,'%s\r\n',tline);
                 fprintf(fid_w,'%s\r\n',t_next_line);
             else % 多个objects
                 fprintf(fid_w,'%s\r\n',t_next_line);
             end
         elseif contains(tline,'<item>')||contains(tline,'</item>')
             newStr = strrep(tline,'item','object');
             fprintf(fid_w,'%s\r\n',newStr(4:end));
         elseif flagOffset
             fprintf(fid_w,'%s\r\n',tline(4:end));
         else
             fprintf(fid_w,'%s\r\n',tline);% 写objects前面若干行
         end
     end
     fclose(fid_r);
     fclose(fid_w);
     delete(filename);    
     clear annotation;
     waitbar(i / steps);
end
close(h);

VOC-xml标注文件制作及其交互使用(修改,预览,存储)的MATLAB实现

转出的标准的VOC-xml格式如上所示~


二,VOC-xml--->图像标注/查看/修改/添加/删除

这一部分非必须,根据自己需要选择是否使用,是第一部分的逆向过程。下面给出VOCxml_to_matlab_main()函数实现,交互式选择你自己的xml路径即可。
上面函数需要调用这个xml_to_matlab(),给出如下:

function  outputTable = VOCxml_to_matlab_main()
% 功能:批量导入VOC-xml格式文件到matlab中
% 输入:无: 交互式选择xml路径。
% 输出:outputTable: 可以导入到MATLAB app预览/修改的table类型数据。
%
% Example: 
%        outputTable = VOCxml_to_matlab_main('F:\imagesData\stopSignImages\*.xml')
%
% if nargin<1
%     error('输入参数太少!')
% end
global folder_name;
folder_name = uigetdir('','请选择导入的VOC-xml标记文件路径(文件夹)!');
if ~folder_name
    warndlg('当前并没选择任何文件!','警告')
    return;
end
xmls_path = fullfile(folder_name,'*.xml');
s = dir(xmls_path);
numSamples = length(s);
waitbar(0,'Please wait...');
steps = numSamples;
for i =1:numSamples
    xml_path = fullfile(folder_name,s(i).name);
    rowTable = xml_to_matlab(xml_path);
    structTem = table2struct(rowTable);
    if i == 1
        ss(1) = structTem;
        prevNames = fieldnames(structTem);
        continue;
    else
        currentNames = fieldnames(structTem);
        index = ismember(currentNames,prevNames);
        
        for j = 1:length(index)
            ss(i).(currentNames{j}) = structTem.(currentNames{j});
        end
        prevNames = fieldnames(ss);
    end
    waitbar(i / steps);
end
outputTable = struct2table(ss);

function output = xml_to_matlab(xmlName)
% 功能:读取VOC-xml标准格式文件,转化为MATLAB table类型数据,导入到APP中,
% 用于预览标记或进行二次标记修改,此函数只能对单张图片进行处理,批量处理见xml_to_matlab_main.m函数
%
% 输入:xmlName,输入xml的标注文件
% 输出:Output,输出为table类型数据,可直接加载到App标注工具中查看
%
% example:
%       output = xml_to_matlab('image001.xml')
% 
global folder_name;
if nargin<1
    error('输入参数过少!');
end
structLabel = xml_read(xmlName);
if isfield(structLabel,'path')
    imageFilenames = structLabel.path;
elseif isfield(structLabel,'filename')
    imageFilenames = fullfile(folder_name,structLabel.filename);
else
    error('请检查图像xml的路径名是否正确!')
end
outputStu.imageFilename = imageFilenames;%获取绝对路径
if ~isfield(structLabel,'object')
    output = struct2table(outputStu);
    return;
end
labelNum = length(structLabel.object);
names = cell(labelNum,1);
rects = cell(labelNum,1);
for i = 1:labelNum
    stuCON = structLabel.object(i);   
    names{i} = stuCON.name;
    rects{i} = [stuCON.bndbox.xmin,stuCON.bndbox.ymin,...
        stuCON.bndbox.xmax-stuCON.bndbox.xmin,...
        stuCON.bndbox.ymax-stuCON.bndbox.ymin];   
end
%
variableNames = unique(names);%cell
variableNum = length(variableNames);
varRect = cell(1,variableNum);
for i = 1:length(names)
    index = strcmp(names{i},variableNames);
    varRect{index} = [varRect{index};rects{i}]; 
end
for i = 1:variableNum
    field = variableNames{i};
    outputStu.(field) = varRect(i);
end
output = struct2table(outputStu);

VOC-xml标注文件制作及其交互使用(修改,预览,存储)的MATLAB实现

VOC-xml标注文件制作及其交互使用(修改,预览,存储)的MATLAB实现

VOC-xml标注文件制作及其交互使用(修改,预览,存储)的MATLAB实现

ok!成功,又可以导入到APP中查看修改~\(≧▽≦)/~啦


附:以上所有代码下载地址,VOC_XML标准格式制作转换

相关标签: 图像标注