看了cityscape和NYUv2生成边界GT的代码后,因为自己使用的是NYUv2数据集,所以需要对自己的数据集进行处理。CASENet生成边界GT所使用的代码是MATLAB,所以又重新看了一下MATLAB的代码,并进行修改,生成了自己的边界代码。
前提知识:
1:NYUv2有四十个类别,0像素代表空,1像素代表墙,所以标签上共有41个像素,在计算时候要忽略掉空像素。
2:MATLAB生成的是.bin文件,需要将.bin文件转化为.png文件,一是方便网络读取,二是对每一个通道都保存下来。
3:unit8可以保存2的8次方,共256个数字,unit32可以保存2的32次方个数字,unit64可以保存2的64次方个数字。
4:自己的NYUv2数据集存放结构:
MATLAB代码:
function demo()
clc; clear; close all;
%% Parameters
dataRoot = '../data_orig';
genDataRoot = '../data_proc';
%scaleSet = [1];
numCls = 40; % Number of defined semantic classes in SBD
radius = 2; % Defined search radius for label changes (related to edge thickness, default value of the CASENet CVPR paper)
edge_type = 'regular';
%% Setup Parallel Pool
numWorker = 4; % Number of matlab workers for parallel computing
matlabVer = version('-release');
if( str2double(matlabVer(1:4)) > 2013 || (str2double(matlabVer(1:4)) == 2013 && strcmp(matlabVer(5), 'b')) )
delete(gcp('nocreate'));
parpool('local', numWorker);
else
if(matlabpool('size')>0) %#ok<*DPOOL>
matlabpool close
end
matlabpool open 8
end
%% Generate Preprocessed Dataset
setList = {'train', 'test'};
for setID = 1:length(setList)
setName = setList{setID};%train
% Create output directories
if(strcmp(setName, 'train'))%如果setname等于train
% Train,生成文件夹
if(exist([genDataRoot '/train/rgb'], 'file')==0)
mkdir([genDataRoot '/train/rgb']);%生成train/rgb文件夹
end
if(exist([genDataRoot '/train/labels_40'], 'file')==0)
mkdir([genDataRoot '/train/labels_40']);%生成train/label文件夹
end
if(exist([genDataRoot '/train/depth'], 'file')==0)
mkdir([genDataRoot '/train/depth']);%生成train/label文件夹
end
if(exist([genDataRoot '/train/edge_labels_40'], 'file')==0)
mkdir([genDataRoot '/train/edge_labels_40']);%生成train/label文件夹
end
else
% Test (correspond to val set in the original SBD Dataset)
if(exist([genDataRoot '/test/rgb'], 'file')==0)
mkdir([genDataRoot '/test/rgb']);
end
if(exist([genDataRoot '/test/labels_40'], 'file')==0)
mkdir([genDataRoot '/test/labels_40']);
end
if(exist([genDataRoot '/test/depth'], 'file')==0)
mkdir([genDataRoot '/test/depth']);%生成train/label文件夹
end
if(exist([genDataRoot '/test/edge_labels_40'], 'file')==0)
mkdir([genDataRoot '/test/edge_labels_40']);
end
end
fidIn = fopen([dataRoot '/' setName '.txt']);%打开data_orig/train.txt,返回等于或大于 3 的整数文件标识符,当setName为test时
fileName = fgetl(fidIn);%读取文件中的行,并删除换行符,
fileList = cell(1,1);%创建一个元胞数组[]。
countFile = 0;
while ischar(fileName)%确定输入是否为字符数组
countFile = countFile + 1;%1/2...train文件有多少行,countFile等于多少
fileList{countFile} = fileName;%向元胞中添加filename即第一张图片的name。
fileName = fgetl(fidIn);%data_orig/train.txt中第一行的名字,作为输出到while中
end
fclose(fidIn);
% Compute boundaries and write labels
disp(['Computing ' setName ' set boundaries'])
parfor_progress(countFile);
parfor idxFile = 1:countFile
%for idxFile = 1:countFile %795
fileName = fileList{idxFile};%根据idxFile索引去文件list里面查找
if(strcmp(setName, 'train'))
scaleSetRun = 1;
else
scaleSetRun = 1;
end
for idxScale = 1:length(scaleSetRun)
%scale = scaleSetRun(idxScale);%取scaleSet第一个即1
%img = imread([dataRoot '/img/' fileName '.jpg']);
%imgScale = imresize(img, scale, 'bicubic');
%变量的地方不能加''。
rgb = imread([dataRoot '/' setName '/rgb/' fileName '.png']);
depth = imread([dataRoot '/' setName '/depth/' fileName '.png']);
label = imread([dataRoot '/' setName '/labels_40/' fileName '.png']);
gt = imread([dataRoot '/' setName '/labels_40/' fileName '.png']);%载入标签
%seg = gt.GTcls.Segmentation;%将mat文件转换为png文件,375X500
%segScale = imresize(seg, scale, 'nearest');
segScale = gt;
[height, width, chn] = size(segScale);%480x640x1
assert(chn==1, 'Incorrect label. Input label must have single channel.');
labelEdge = zeros(height, width, 'uint64');%563X750全0矩阵
for idx_cls = 1:numCls %1:40
idxSeg = segScale == idx_cls;%将segScale中不等于idx_cls的全部设置为0。
if(sum(idxSeg(:))~=0)%将idxSeg全部展开为一维数组,然后相加
idxEdge = seg2edge(idxSeg, radius, [], edge_type);
labelEdge(idxEdge) = labelEdge(idxEdge) + 2^(idx_cls-1);
end
end
if(strcmp(setName, 'train'))
% Write image file,将train/rgb的图片写入到data_proc/train/
imwrite(rgb, [genDataRoot '/train/rgb/' fileName '.png'], 'png')
% Write depth file,将train/rgb的图片写入到data_proc/train/
imwrite(depth,[genDataRoot '/train/depth/' fileName '.png'], 'png')
% Write label file,将train/label的图片写入到data_proc/train/
imwrite(label, [genDataRoot '/train/labels_40/' fileName '.png'], 'png')
% Write label file,打开data_proc\label\train,将数据写入二进制文件
fidLabel = fopen([genDataRoot '/train/edge_labels_40/' fileName '.bin'], 'w');
fwrite(fidLabel, labelEdge', 'uint64'); % Important! Transpose input matrix to become row major.
fclose(fidLabel);
else
% Write image file
imwrite(rgb, [genDataRoot '/test/rgb/' fileName '.png'], 'png')%imwrite将图像写入图形文件
imwrite(depth,[genDataRoot '/test/depth/' fileName '.png'], 'png')
imwrite(label, [genDataRoot '/test/labels_40/' fileName '.png'], 'png')
% Write label file
fidLabel = fopen([genDataRoot '/test/edge_labels_40/' fileName '.bin'], 'w');
fwrite(fidLabel, labelEdge', 'uint64'); % Important! Transpose input matrix to become row major.将数据写入二进制文件
fclose(fidLabel);
end
end
parfor_progress();
end
parfor_progress(0);
% Write file lists
%disp(['Creating ' setName ' set file lists'])
%if(strcmp(setName, 'train'))
%fidListTrainAug = fopen([genDataRoot '/train_aug.txt'], 'w');
%fidListTrain = fopen([genDataRoot '/train.txt'], 'w');
%else
%fidListTest = fopen([genDataRoot '/test.txt'], 'w');
%end
%parfor_progress(countFile);
%for idxFile = 1:countFile
%fileName = fileList{idxFile};
%if(strcmp(setName, 'train'))
%scaleSetRun = 1;%scaleSet = [0.5 0.75 1 1.25 1.5]
%else
%scaleSetRun = 1;
%end
%for idxScale = 1:length(scaleSetRun)
%scale = scaleSetRun(idxScale);
%if(strcmp(setName, 'train'))
% Add to train_aug list
%fprintf(fidListTrainAug, ['/image/train/scale_' num2str(scale) '/' fileName '.png '...
%'/label/train/scale_' num2str(scale) '/' fileName '.bin\n']);
%if(scale == 1)
% Add to train list
%fprintf(fidListTrain, [' fileName ']);
%end
%else
% Add to test list
%fprintf(fidListTest, ['/image/test/' fileName '.png /label/test/' fileName '.bin\n']);
%end
%end
%parfor_progress();
%end
%parfor_progress(0);
%if(strcmp(setName, 'train'))
%fclose(fidListTrainAug);
%fclose(fidListTrain);
%else
%fclose(fidListTest);
%end
end
end
1:首先指定所需要的参数,dataRoot 是原始数据的地址,genDataRoot 是生成的数据的地址。一共有40个类别,因为后面循环的时候是从1开始,40结束,所以会忽略掉0像素,因此numcls不需要设置为41,接着是半径等于2,和edge_type ,这是生成边界所需要的参数,和CASENet保持一致。
%% Parameters
dataRoot = '../data_orig';
genDataRoot = '../data_proc';
%scaleSet = [1];
numCls = 40; % Number of defined semantic classes in SBD
radius = 2; % Defined search radius for label changes (related to edge thickness, default value of the CASENet CVPR paper)
edge_type = 'regular';
2:MATLAB初始化并行操作(新手),线程为4。注意如果使用并行处理的话,无法进行单步调试,所以在debug时候需要将并行计算注释掉。
%% Setup Parallel Pool
numWorker = 4; % Number of matlab workers for parallel computing
matlabVer = version('-release');
if( str2double(matlabVer(1:4)) > 2013 || (str2double(matlabVer(1:4)) == 2013 && strcmp(matlabVer(5), 'b')) )
delete(gcp('nocreate'));
parpool('local', numWorker);
else
if(matlabpool('size')>0) %#ok<*DPOOL>
matlabpool close
end
matlabpool open 8
end
3:我们有两个set,分别是train和test,这个根据自己数据集修改就好了,执行for循环,首先取第一个setname=‘train’。
setList = {'train', 'test'};
for setID = 1:length(setList)
setName = setList{setID};%train
4:生成输出文件夹,首先strcmp函数比较setname这个字符串是否等于train,如果不晓得函数的作用,选中函数,然后按F1即可。接着判断genDataRoot '/train/rgb,即D:\datasets\data_proc\train\rgb是否存在,如果==0的话那就是不存在,通过mkdir生成D:\datasets\data_proc\train\rgb文件夹存放RGB。同理生成D:\datasets\data_proc\train\depth生成Depth,生成D:\datasets\data_proc\train\label_40用于存放标签,最后生成一个D:\datasets\data_proc\train\edge_labels_40用于存放生成的边界GT。给每一个图片找一个自己的归属。
for
% Create output directories
if(strcmp(setName, 'train'))%如果setname等于train
% Train,生成文件夹
if(exist([genDataRoot '/train/rgb'], 'file')==0)
mkdir([genDataRoot '/train/rgb']);%生成train/rgb文件夹
end
if(exist([genDataRoot '/train/labels_40'], 'file')==0)
mkdir([genDataRoot '/train/labels_40']);%生成train/label文件夹
end
if(exist([genDataRoot '/train/depth'], 'file')==0)
mkdir([genDataRoot '/train/depth']);%生成train/label文件夹
end
if(exist([genDataRoot '/train/edge_labels_40'], 'file')==0)
mkdir([genDataRoot '/train/edge_labels_40']);%生成train/label文件夹
end
5:这里的else连接的是train中的for,即下面是setname=test的代码,通train一样生成四个文件夹。
else
% Test (correspond to val set in the original SBD Dataset)
if(exist([genDataRoot '/test/rgb'], 'file')==0)
mkdir([genDataRoot '/test/rgb']);
end
if(exist([genDataRoot '/test/labels_40'], 'file')==0)
mkdir([genDataRoot '/test/labels_40']);
end
if(exist([genDataRoot '/test/depth'], 'file')==0)
mkdir([genDataRoot '/test/depth']);%生成train/label文件夹
end
if(exist([genDataRoot '/test/edge_labels_40'], 'file')==0)
mkdir([genDataRoot '/test/edge_labels_40']);
end
end
6:假设我们现在setname还为true,打开data_orig的train.txt文件,里面存放的是所训练需要的数据文件名即索引。接着读取txt里面的数据作为文件名。train.txt里面的索引和RGB,label_40,depth都是一一对应的。
fidIn = fopen([dataRoot '/' setName '.txt']);%打开data_orig/train.txt,返回等于或大于 3 的整数文件标识符,当setName为test时
fileName = fgetl(fidIn);%读取文件中的行,并删除换行符,
fileList = cell(1,1);%创建一个元胞数组[]。
countFile = 0;
while ischar(fileName)%确定输入是否为字符数组
countFile = countFile + 1;%1/2...train文件有多少行,countFile等于多少
fileList{countFile} = fileName;%向元胞中添加filename即第一张图片的name。
fileName = fgetl(fidIn);%data_orig/train.txt中第一行的名字,作为输出到while中
end
fclose(fidIn);
然后创建一个元胞数组{},初始化一个计数器,执行一个循环,假设执行第一次,countFile =1,那么fileList{1} = fileName,就是向元胞数组里面添加第一张图片的name。接着执行第二次循环,不断的向元胞里面添加数组,直至结束,可以把元胞理解为python里面的字典,乡里面添加键值对。执行结束后,fileList里面就存放者全部的fileName 。
7:在窗口中显示如何标识和进程表:
disp(['Computing ' setName ' set boundaries'])
parfor_progress(countFile);
8:并行执行for循环,大大的运行减少时间。
8.1:countFile就是7中的txt文件中读取了几行,795行,假设idxFile=1,则去 fileList元胞数组中取文件名,即0003。因为SBD将原图进行了多个尺度的变换,这里代码只更改了不需要多尺度,idxScale 就为1。
8.2:接着读取RGB,depth,label,判断一下gt的形状,然后生成和gt大小一样的0矩阵。
8.3:然后执行for循环,假设idx_cls =1,和gt进行一个逻辑运算,将gt中等于1的全部设为1,不等于1的地方去全部设为0.
可视化:将全部像素拿出来,和0003.png比较发现背景为1,下面的阴影即桌子为0。
8.4:idxSeg就是480x640大小的逻辑矩阵,然后将idxSeg展平为1行,所有值相加,如果相加不等于0,则进行边界提取。
注:为什么全部像素要相加?
因为只有相加不为0说明才有有效像素,才能进行提边,当一张图片,假设0003中存在的几个类别相加才不为0,如果不存在某个类别,则idxSeg就全为0像素,0003.png就没有这个类别,就无法提边。
8.5:将idxSeg等参数输入到seg2seg,这个函数进行提边,这里暂时不考虑函数内部如何写的,把它看做一个包来调用它,有空再细看。
8.6:向labelEdge中添加idxEdge ,然后再添加2^(idx_cls-1),
假设idx_cls=9,则2^(idx_cls-1)=1024,即labelEdge中就会存在1024像素,至于为什么要这样写,是为了将.bin文件转换文.png文件,后面会进行解释,这里相当于一个加密过程,后面进行解密。将生成的labelEdge像素全部拿出来(显示不完全):
8.7:接着将train中orig的图片写入到proc中,test同理,这里也可以用copyfile,cityscape就是用的copyfile。同时将labelEdge写入到新建的文件夹edge_labels_40中,以.bin格式存储。
parfor idxFile = 1:countFile
%for idxFile = 1:countFile %795
fileName = fileList{idxFile};%根据idxFile索引去文件list里面查找
if(strcmp(setName, 'train'))
scaleSetRun = 1;
else
scaleSetRun = 1;
end
for idxScale = 1:length(scaleSetRun)
%scale = scaleSetRun(idxScale);%取scaleSet第一个即1
%img = imread([dataRoot '/img/' fileName '.jpg']);
%imgScale = imresize(img, scale, 'bicubic');
%变量的地方不能加''。
rgb = imread([dataRoot '/' setName '/rgb/' fileName '.png']);
depth = imread([dataRoot '/' setName '/depth/' fileName '.png']);
label = imread([dataRoot '/' setName '/labels_40/' fileName '.png']);
gt = imread([dataRoot '/' setName '/labels_40/' fileName '.png']);%载入标签
%seg = gt.GTcls.Segmentation;%将mat文件转换为png文件,375X500
%segScale = imresize(seg, scale, 'nearest');
segScale = gt;
[height, width, chn] = size(segScale);%480x640x1
assert(chn==1, 'Incorrect label. Input label must have single channel.');
labelEdge = zeros(height, width, 'uint64');%563X750全0矩阵
for idx_cls = 1:numCls %1:40
idxSeg = segScale == idx_cls;%将segScale中不等于idx_cls的全部设置为0。
if(sum(idxSeg(:))~=0)%将idxSeg全部展开为一维数组,然后相加
idxEdge = seg2edge(idxSeg, radius, [], edge_type);
labelEdge(idxEdge) = labelEdge(idxEdge) + 2^(idx_cls-1);
end
end
if(strcmp(setName, 'train'))
% Write image file,将train/rgb的图片写入到data_proc/train/
imwrite(rgb, [genDataRoot '/train/rgb/' fileName '.png'], 'png')
% Write depth file,将train/rgb的图片写入到data_proc/train/
imwrite(depth,[genDataRoot '/train/depth/' fileName '.png'], 'png')
% Write label file,将train/label的图片写入到data_proc/train/
imwrite(label, [genDataRoot '/train/labels_40/' fileName '.png'], 'png')
% Write label file,打开data_proc\label\train,将数据写入二进制文件
fidLabel = fopen([genDataRoot '/train/edge_labels_40/' fileName '.bin'], 'w');
fwrite(fidLabel, labelEdge', 'uint64'); % Important! Transpose input matrix to become row major.
fclose(fidLabel);
else
% Write image file
imwrite(rgb, [genDataRoot '/test/rgb/' fileName '.png'], 'png')%imwrite将图像写入图形文件
imwrite(depth,[genDataRoot '/test/depth/' fileName '.png'], 'png')
imwrite(label, [genDataRoot '/test/labels_40/' fileName '.png'], 'png')
% Write label file
fidLabel = fopen([genDataRoot '/test/edge_labels_40/' fileName '.bin'], 'w');
fwrite(fidLabel, labelEdge', 'uint64'); % Important! Transpose input matrix to become row major.将数据写入二进制文件
fclose(fidLabel);
end
end
parfor_progress();
end
parfor_progress(0);
9:这样生成的文件夹如下: