Skip to content

Commit

Permalink
Added Code and Results
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidePeron19 committed Sep 8, 2023
1 parent 518ff90 commit 7e5b706
Show file tree
Hide file tree
Showing 26 changed files with 2,382 additions and 0 deletions.
118 changes: 118 additions & 0 deletions Data Preparation/ORION/Modelnet/functions/binlist_to_hdf5.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
function binlist_to_hdf5(bins_list,h5_filename,h5_text_filename,chunk_size,run_on_cluster,write_just_this_chunk)
%%%
%%% In this function we assume the list is formatted as '%s %d %d %d'
%%% where the first integer is ignored, the second is class label and the
%%% 3rd one is the pose_label.
%%% We put the pose-label in the file, eventhough sometimes it's not used; It's safe -- tested!
%%%

%-- Load the list
[files,l1,l2,l3] = textread(bins_list,'%s %d %d %d');
N = numel(files);

if(~exist('chunk_size','var')), chunk_size = 10000;end
nchunks = ceil(N/chunk_size);

%-- Create the target dir(s) if needed
[pathstr,~,~] = fileparts(h5_filename);
system(['wsl mkdir -p ' pathstr]);
[pathstr,~,~] = fileparts(h5_text_filename);
system(['wsl mkdir -p ' pathstr]);

%-- See which chunks should we create
if(exist('write_just_this_chunk','var') && any(write_just_this_chunk))
chunk_list = write_just_this_chunk;
else
chunk_list = 1 : nchunks;
end

%--- create the text file containing names of files (only if we should!)
if(numel(chunk_list) == nchunks)
create_the_text_file(h5_text_filename,h5_filename,nchunks)
end


%--- If we should submit jobs to cluster
if(exist('run_on_cluster','var') && run_on_cluster)


for the_chunk = chunk_list
cmd = sprintf(['matlabD -nosplash -r "run ~/startup.m; '...
'binlist_to_hdf5(''%s'',''%s'',''%s'',%d,0,%d); '...
'exit"'],bins_list,h5_filename,h5_text_filename,chunk_size,the_chunk);

temp_job_dir= [ getenv('HOME') '/temp_cluster_job' ];
[~,~,wait_file{the_chunk}] = cluster_submit_job('lmbtorque',cmd,temp_job_dir,6,'6G',0,'',3,0);
pause(1);
end

return;
end

fprintf('Source: %s\nDestination1: %s\nDestination2: %s\n',bins_list,h5_filename,h5_text_filename);
%--- Load the first bin to obtain the dimensions
temp_v = load_binary_voxelgrid(files{1});
d1= size(temp_v,1);
d2= size(temp_v,2);
d3= size(temp_v,3);


if(~exist('write_just_this_chunk','var')),
write_just_this_chunk = 0;
end

for c = chunk_list
fprintf('Chunk: %d/%d\n',c,nchunks);

written_sofar = (c-1)*chunk_size;
this_chunk_size = min(chunk_size,N-written_sofar);
ind1 = written_sofar+1;
ind2 = ind1+this_chunk_size-1;

%--- Load bins one by one and keep in memory
disp('Loading bin files...');
Data = zeros(d1,d2,d3,1,this_chunk_size);
tic
for i = 1 : this_chunk_size %I have tried parfor here previously. It makes it slower!!
data = load_binary_voxelgrid(files{ind1+i-1});
Data(:,:,:,1,i) = data;
if(~mod(i,50)), fprintf('%d ',i);end
end
fprintf('\n');
toc
Data = uint8(Data);


%-- Write the hdf5 file(s)
disp('Writing the hdf5 file(s)...');

%- get the appropriate filename for this chunk
filename = get_chunk_filename(c,h5_filename);

if(exist(filename,'file')),delete(filename);end

h5create(filename,'/data',[d3 d2 d1 1 this_chunk_size],'Datatype','uint8');
h5create(filename,'/label',[1 this_chunk_size]);
h5create(filename,'/label_pose',[1 this_chunk_size])
h5write(filename,'/data',Data);
h5write(filename,'/label',l2(ind1:ind2)');
h5write(filename,'/label_pose',l3(ind1:ind2)');

end
end

function filename = get_chunk_filename(chunk,h5_filename)
if chunk == 1
filename = h5_filename;
else
filename = sprintf('%s.%04d',h5_filename,chunk);
end
end

function create_the_text_file(textfilename,h5filename,nchunks)
fp = fopen(textfilename,'wt');
for c = 1 : nchunks
fprintf(fp,'%s\n',get_chunk_filename(c,h5filename));
end
fclose(fp);
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
function v = load_binary_voxelgrid(filename)

fp = fopen(filename,'rb');
sz = fread(fp,3,'uint16');
v = zeros(sz');
v(:) = fread(fp,prod(sz),'uint8');
fclose(fp);
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
function modelnet_add_labels_to_list(source_list_file,dest_list_file,rotation_start_index,Pose_file)

list = textread(source_list_file,'%s');
Pose=importdata(Pose_file,'\t');
%parfor
parfor i = 1 : numel(list)
% extracts from folder classname e.g bathtub and from the filename it
% extracts the index of the rotation e.g 1
[class_name,rotation] = modelnet_extract_classname_and_rot_from_filename(list{i});
% rotation-rotation_start_index to bring rotation index in [0, maxrot-1]
% return the class label [0, maxclass-1] anc the pose label
% if all_singlerots_to_zero=1 then fo all the classes with only 1
% orientation it gives the the label 0 (independently from the class)
% otherwise it gives an increasing number based on actual orientation,
% class number and previus classes orientation labelling
[class_label,pose_label] = modelnet_generate_class_and_pose_labels(class_name,rotation-rotation_start_index,Pose);
list{i} = sprintf('%s %d %d %d' ,list{i},1,class_label,pose_label);
end

%--- write the modified list to the destination file
fp = fopen(dest_list_file,'wt');
fprintf(fp,'%s\n',list{:});
fclose(fp);
end


function [class_name,rotation] = modelnet_extract_classname_and_rot_from_filename(filename)

s = strsplit(filename,{'.','/'});
class_name = s{end-4};
r = strsplit(s{end-1},'_');
rotation = str2double(r(end));
end

function [class_label,pose_label] = modelnet_generate_class_and_pose_labels(class_name,rotation,Pose)

%%% Note: Class Label and Pose Label both start from 0.
classes=Pose.textdata';
nrot=Pose.data';

%--- Find the Class Label
[valid_class,class_label] = ismember(class_name,classes);
if(~valid_class)
class_label = -1;
pose_label = -1;
return;
end
class_label = class_label - 1; %to start from 0

%--- Find the rotation label
cr = cumsum(nrot);
cr = circshift(cr,[0,1]);
cr(1) = 0;
pose_label = cr(class_label+1) + mod(rotation,nrot(class_label+1));

end

39 changes: 39 additions & 0 deletions Data Preparation/ORION/Modelnet/main.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
addpath(genpath('polygon2voxel/'));
addpath(genpath('functions/'));

modelnet10_classes = {'bathtub','bed','chair','desk','dresser','monitor','night_stand','sofa','table','toilet'};
modelnet40_classes = {'airplane','bathtub','bed','bench','bookshelf','bottle','bowl','car',...
'chair','cone','cup','curtain','desk','door','dresser','flower_pot','glass_box',...
'guitar','keyboard','lamp','laptop','mantel','monitor','night_stand','person',...
'piano','plant','radio','range_hood','sink','sofa','stairs','stool','table',...
'tent','toilet','tv_stand','vase','wardrobe','xbox'};


%-------------------- Modelnet Data Preparation ---------------
%----------------------------------------------------------------
%----------------------------------------------------------------
off_path='../../datasets/ModelNet40';
mat_path='../../datasets/ModelNet40_voxelized_mat';
bin_path = '../../datasets/ModelNet40_bin_from_mat/';

%--- convert original .off to .mat files------
%----------------(voxel grids)----------------
%---------------------------------------------
volume_size = 24;
pad_size = 3;
angle_inc = 15;
modelnet_off2mat(off_path,mat_path,modelnet40_classes,volume_size,pad_size,angle_inc);

%---------------------------------------------
%---------- convert .mat to .bin files -------
%---------------------------------------------
D = 3; %padding on each side.
%We convert 30 to 36, such that after cropping we get 32, similar to what voxnet does
modelnet_mat2bin(D,mat_path,bin_path, angle_inc);

%---------------------------------------------
%--------- convert bin to HDF5 chunks --------
%---------------------------------------------
Pose_plan='poseplan_MN40_24';
modelnet_binlist2hdf5(bin_path,Pose_plan,angle_inc);
%---------------------------------------------
27 changes: 27 additions & 0 deletions Data Preparation/ORION/Modelnet/modelnet_binlist2hdf5.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
function modelnet_binlist2hdf5(DestinationFolder,Pose_plan,angle_inc)

Pose_file=['../poseplans/' Pose_plan '.txt'];
if ~exist(strcat(DestinationFolder,Pose_plan,'/'), 'dir')
mkdir(strcat(DestinationFolder,Pose_plan,'/'));
end
copyfile(Pose_file,strcat(DestinationFolder,Pose_plan,'/'));

%% ---- Create the lists
rotation_start_index = 1; %this is the original Shapenet convention
lists_dir = sprintf('%s/%s',DestinationFolder,Pose_plan);
alllist_file = sprintf('%s/all.txt',lists_dir);

system(sprintf('wsl find %s -path "*/%s/*" -iname ''*.%s'' | wsl sort -V > %s', DestinationFolder,num2str(angle_inc),'bin',alllist_file));
%
modelnet_add_labels_to_list(alllist_file,alllist_file,rotation_start_index,Pose_file);

% preparing training validation test lists
for set = {'train','test','validation'}
dest_filename = sprintf('%s/%s.txt',lists_dir,set{1});
system(sprintf('wsl grep ''/%s/'' %s > %s',set{1},alllist_file,dest_filename));
end

%% --- Create some special HDF5 datasets
binlist_to_hdf5([lists_dir '/train.txt'],[DestinationFolder '/' Pose_plan '/hdf5/train/train.hdf5'],[DestinationFolder '/' Pose_plan '/hdf5/train/train.txt'],1000);
binlist_to_hdf5([lists_dir '/validation.txt'],[DestinationFolder '/' Pose_plan '/hdf5/validation/validation.hdf5'],[DestinationFolder '/' Pose_plan '/hdf5/validation/validation.txt'],1000);
binlist_to_hdf5([lists_dir '/test.txt'],[DestinationFolder '/' Pose_plan '/hdf5/test/test.hdf5'],[DestinationFolder '/' Pose_plan '/hdf5/test/test.txt'],1000);
59 changes: 59 additions & 0 deletions Data Preparation/ORION/Modelnet/modelnet_mat2bin.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
function modelnet_mat2bin(D,SourceFolder,DestinationFolder, angle_inc)
%%% This function loads the files in the folders one by one, and saves the bin
%%% versions to a similar subdir in the destination (tries to create it).
%%% We go folder by folder, so that Matlab doesn't need to call the SLOW
%%% fileparts function to find the folder names

%--- Generate folders list
temp_folders_list_file = 'temp_modelnet_folders.txt';
disp('Generating folders list...');
system(sprintf('wsl find %s -mindepth 3 -type d -path "*/%s/*"> %s',SourceFolder,num2str(angle_inc),temp_folders_list_file));

%--- Load the folders list
folders_list = textread(temp_folders_list_file,'%s');

%--- Loop on the folders
disp('Converting files...');
tic;
for d = 1 : numel(folders_list)
d
folder = folders_list{d};

%--- Make the destination subfolder
relative_folder = folder(length(SourceFolder)+2:end);
system(sprintf('wsl mkdir %s/classes/%s -p',DestinationFolder,relative_folder));

%--- Get the list of files in each folder
files_list = dir(sprintf('%s/*mat',folder));

%--- Loop on file names
parfor f = 1 : numel(files_list)

filename = [files_list(f).name];
fullfilename = [SourceFolder '/' relative_folder '/' filename];

%- Load the Mat file
v = load(fullfilename);
v = v.instance;

%-- padding
avoxel = zeros(size(v)+2*D);
avoxel(1+D:end-D,1+D:end-D,1+D:end-D) = v;
v = avoxel;

%- Generate the bin filename
dest_filename = [DestinationFolder '/classes/' relative_folder '/' filename(1:end-3) 'bin'];

%- Save the bin
fp = fopen(dest_filename,'w');
fwrite(fp,uint16(size(v)),'uint16');
fwrite(fp,uint8(v),'uint8');
fclose(fp);

end
end

disp('Done');
toc


70 changes: 70 additions & 0 deletions Data Preparation/ORION/Modelnet/modelnet_off2mat.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
function modelnet_off2mat(off_path, data_path, classes, volume_size, pad_size, angle_inc)
% Put the mesh object in a volume grid and save the volumetric
% represenation file.
% This is the input volumetric data for 3D ShapeNets.
% off_path: root off data folder
% data_path: destination volumetric data folder

phases = {'train', 'test', 'validation'};

for c = 1 : length(classes)
fprintf('writing the %s category\n', classes{c});
category_path = [off_path '/' classes{c}];
dest_path = [data_path '/' classes{c} '/' num2str(angle_inc)];
if ~exist(dest_path, 'dir')
mkdir(dest_path);
end
% for train, test, validation phases
for t = 1 : numel(phases)
phase = phases{t};
off_list = [category_path '/' phase];
dest_tsdf_path = [dest_path '/' phase];
if ~exist(dest_tsdf_path, 'dir')
mkdir(dest_tsdf_path);
end
files = dir(off_list);
for i = 1 : length(files)
if strcmp(files(i).name, '.') || strcmp(files(i).name, '..') || files(i).isdir == 1 || ~strcmp(files(i).name(end-2:end), 'off')
continue;
end

filename = [off_list '/' files(i).name];
for viewpoint = 1 : 360/angle_inc
destname = [dest_tsdf_path '/' files(i).name(1:end-4) '_' num2str(viewpoint) '.mat'];
off_data = off_loader(filename, (viewpoint-1)*angle_inc);
instance = polygon2voxel(off_data, [volume_size, volume_size, volume_size], 'auto');
instance = padarray(instance, [pad_size, pad_size, pad_size]);
instance = int8(instance);
save(destname, 'instance');
end
end
end
end

function offobj = off_loader(filename, theta)

offobj = struct();
fid = fopen(filename, 'rb');
OFF_sign = fscanf(fid, '%c', 3);
assert(strcmp(OFF_sign, 'OFF') == 1);

info = fscanf(fid, '%d', 3);
offobj.vertices = reshape(fscanf(fid, '%f', info(1)*3), 3, info(1))';
offobj.faces = reshape(fscanf(fid, '%d', info(2)*4), 4, info(2))';

% do some translation and rotation
center = (max(offobj.vertices) + min(offobj.vertices)) / 2;
offobj.vertices = bsxfun(@minus, offobj.vertices, center);

% and rotation
theta = theta * pi / 180;
R = [cos(theta), -sin(theta), 0;
sin(theta), cos(theta) , 0;
0 , 0 , 1];

offobj.vertices = offobj.vertices * R;

% These vertices to define faces should be offset by one to follow the matlab convention.
offobj.faces = offobj.faces(:,2:end) + 1;

fclose(fid);
Loading

0 comments on commit 7e5b706

Please sign in to comment.