Skip to content

Commit

Permalink
commented some of the code
Browse files Browse the repository at this point in the history
  • Loading branch information
KeyserGuillaume committed May 21, 2018
1 parent 647fc0b commit 60f4eaa
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 14 deletions.
3 changes: 3 additions & 0 deletions README.md
Expand Up @@ -27,7 +27,10 @@ For preprocessing with this raw data and the voxel_size you want, go into the pr
(with the voxel_size you want, in m. default is 0.05)

For training, use python train.py --config=your_config --log=your_logs
Both scannet and semantic_8 should be trainable.

For interpolating results, first use predict.py --cloud=true --n=100 --ckpt=your_ckpt --dataset=semantic --set=test for example. Files will be created in visu/semantic_test/full_scenes_predictions and will contain predictions on sparse point clouds. The actual interpolation is done in interpolation directory with the command:
./interpolate path/to/raw/data visu/semantic_test/full_scenes_predictions /path/to/where/to/put/results 'voxel_size'
(with the voxel_size you want, in m. default is 0.1)

Please check the source files for more details.
24 changes: 21 additions & 3 deletions interpolation_sem3D/main.cpp
@@ -1,6 +1,9 @@
/*
*code inspired by https://github.com/aboulch/snapnet
*/#include <iostream>
* code inspired by https://github.com/aboulch/snapnet
* The IoUs (per class and average) and the accuracy are computed for each scene that is in the folder passed as argument,
* and then the global IoUs and global accuracy are computed and saved. More information below.
*/
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
Expand Down Expand Up @@ -41,6 +44,19 @@ std::pair<int, std::pair<std::vector<int>, std::vector<int> > > interpolate_labe
const std::string& output_dir,
const std::string& filename,
const float& voxel_size) {
/*
* The pointnet2 network only takes up to a few thousand points at a time, so we do not have the real results yet
* But we can get results on a sparser point cloud (after decimation, and after we dynamically sample inputs on
* the decimated point clouds.
* The job of this function is to take a very sparse point cloud (a few hundred thousand points) with predictions
* by the network and to interpolate the results to the much denser raw point clouds.
* This is achieved by a division of the space into a voxel grid, implemented as a map called voxels.
* First the sparse point cloud is iterated and the map is constructed. We store for each voxel and each label
* the nb of points from the sparse cloud and with the right label was in the voxel.
* Then we assign to each voxel the label which got the most points.
* And finally we can iterate the dense point cloud and dynamically assign labels according to the voxels.
* IoU per class and accuracy are calculated at the end.
*/
std::string filename_sparse =input_sparse_dir + "/" + filename + "_aggregated.txt";
std::string filename_labels_sparse =input_sparse_dir + "/" + filename + "_pred.txt";
std::string filename_dense =input_dense_dir + "/" + filename + ".txt";
Expand Down Expand Up @@ -127,7 +143,7 @@ std::pair<int, std::pair<std::vector<int>, std::vector<int> > > interpolate_labe

Eigen::Vector3i vox(x_id, y_id, z_id);
if (voxels.count(vox)==0) {
label = 0; // pour l'instant
label = 0; // TODO : improve this
}
else{
label = voxels[vox].get_label();
Expand Down Expand Up @@ -185,6 +201,7 @@ int main (int argc, char** argv) {
PossibleFileNames[12] = "sg28_station4_intensity_rgb";
PossibleFileNames[13] = "untermaederbrunnen_station1_xyz_intensity_rgb";
PossibleFileNames[14] = "untermaederbrunnen_station3_xyz_intensity_rgb";
// we try to open the files one by one in order to know which ones are present in the folder
std::vector<std::string> fileNames;
for (unsigned int i=0;i<PossibleFileNames.size(); i++) {
std::string filename_labels_sparse =std::string(argv[2]) + "/prediction_" + PossibleFileNames[i] + ".txt";
Expand All @@ -193,6 +210,7 @@ int main (int argc, char** argv) {
fileNames.push_back(PossibleFileNames[i]);
std::cout << "Found " + PossibleFileNames[i] << std::endl;
}
ifs.close();
}
std::vector<int> unions (9,0);
std::vector<int> successes (9,0);
Expand Down
15 changes: 10 additions & 5 deletions predict.py
@@ -1,5 +1,12 @@
"""
Predict the labels
This file predicts the labels with the weights calculated by train.py or train_multi.py.
You need to give as parameter the ckpt you want to use. A certain number of inputs is generated.
A prediction is made on each of these inputs, to be compared to the ground truth, also exported.
If you set --cloud=False (which is the default usage), each input is saved in a different point
cloud, and there will be n inputs. If you set --cloud=True, they will be aggregated into scenes
and there will be n inputs per scene. These aggregated point clouds is the basis upon which
interpolation is made to give predictions on the full raw point clouds and to truly evaluate
the network's performances.
"""
import argparse
import numpy as np
Expand All @@ -15,11 +22,10 @@
parser = argparse.ArgumentParser()
parser.add_argument('--gpu', type=int, default=0, help='GPU to use [default: GPU 0]')
parser.add_argument('--cloud', type=bool, default=False, help='whether you want full point clouds to be exported')
parser.add_argument('--n', type=int, default=8, help='Number of scenes you want [default : 8]')
parser.add_argument('--n', type=int, default=8, help='Number of inputs you want [default : 8]')
parser.add_argument('--ckpt', default='', help='Checkpoint file')
parser.add_argument('--num_point', type=int, default=8192, help='Point Number [default: 8192]')
parser.add_argument('--set', default="train", help='train or test [default: train]')
parser.add_argument('--batch_size', type=int, default=1, help='Batch size [default: 1]') # LET DEFAULT FOR THE MOMENT!
parser.add_argument('--dataset', default='semantic', help='Dataset [default: semantic]')
parser.add_argument('--config', type=str, default="config.json", metavar='N', help='config file')
FLAGS = parser.parse_args()
Expand All @@ -35,7 +41,6 @@
GPU_INDEX = FLAGS.gpu
NUM_POINT = FLAGS.num_point
SET = FLAGS.set
BATCH_SIZE = FLAGS.batch_size
DATASET_NAME = FLAGS.dataset
N = FLAGS.n

Expand Down Expand Up @@ -82,7 +87,7 @@ def predict():
and helps to debug the network
"""
with tf.device('/gpu:'+str(GPU_INDEX)):
pointclouds_pl, labels_pl, _ = MODEL.placeholder_inputs(BATCH_SIZE, NUM_POINT, hyperparams=PARAMS)
pointclouds_pl, labels_pl, _ = MODEL.placeholder_inputs(1, NUM_POINT, hyperparams=PARAMS)
print (tf.shape(pointclouds_pl))
is_training_pl = tf.placeholder(tf.bool, shape=())

Expand Down
11 changes: 10 additions & 1 deletion preprocessing_sem3D/preprocess.sh
Expand Up @@ -49,5 +49,14 @@ fi

./convert_folder_to_npz.sh tmp_storage/ $2

rm -r tmp_storage
if [ "$(ls -A $tmp_storage)" ]; then
if ! [ "$(ls -A $2)" ]; then
echo "Something went wrong with the conversion from .txt to .npz, but you have your files in tmp_storage in .txt"
else
rm -r tmp_storage
fi
else
rm -r tmp_storage
fi


6 changes: 5 additions & 1 deletion train.py
@@ -1,5 +1,9 @@
"""
Train rework
Use this file to train the network. It is compatible with both semantic.py
and scannet.py accessors to the datasets semantic-8 and scannet.
Training results are stored as .ckpt files. Training records are stored as well.
Training is done by tensorflow, with a queue separating CPU and GPU computations
and multi-CPU support.
"""
import os
import sys
Expand Down
39 changes: 35 additions & 4 deletions visu.py
@@ -1,3 +1,31 @@
"""
This file has two main functionalities : statistics (stats) and batch visualisation
Stats (call python visu.py --stats=true) will first give you statistics on the
class repartition of points (i.e. 10% for class 1, etc.) in the clouds resulting from
preprocessing. Then it produces some inputs from those clouds according to the dataset accessor
you are using, and computes their own class repartition, which is different from before because
some points are favored over others: sometimes because we want them to, and sometimes because we
can't help it. (In fact, the inputs that are generated are usually undersampled to fit into the
nb of points the network can process, but here we skip that step because it's a uniform sampling).
Then those inputs that were generated are used to give you other information : per point probability
of being taken as input when the point's scene is considered. A histogram of these probabilities is
saved and be plotted unless using the option --draw=False. Then all these points are exported with
their probabilities as one point cloud per scene for visualisation in CloudCompare for example. The seeds
(points around which a box is computed and the final input points are sampled in that box) are also
provided in a separate point cloud and may be visualised in CloudCompare for example by giving them
a large radius. In all, stats is a powerful tools that allows you to check that the sampling you're using
fully explores your point clouds.
Batch visualisation will draw batches exactly as they are fed into the network and it will align them on
one horizontal grid. This way you can quickly check whether the input of the network is distinguishable
by humans. You can set the number of batches you want with the --n option (set it to zero if you are not
interested by this functionalities).
This file is of course compatible with both semantic.py and scannet.py. Since scannet.py implements the way
the scannet dataset was fed into the network by the creators of pointnet2, to excellent results,
it is a good idea to compare with it.
"""
import argparse
import numpy as np
import os
Expand All @@ -8,7 +36,10 @@
# Parser
parser = argparse.ArgumentParser()
parser.add_argument('--set', default="train", help='train or test [default: train]')
parser.add_argument('--n', type=int, default=8, help='Number of batches you want [default : 1]')
parser.add_argument('--stats', type=bool, default=False, help='Stats visualisation on inputs [default: False]')
parser.add_argument('--draw', type=bool, default=True, help='Plots in stats visualisation [default: True]')
parser.add_argument('--n', type=int, default=8, help='Number of batches you want to visualise [default : 1]')
parser.add_argument('--nps', type=int, default=100, help='Number of inputs per scene when doing stats [default : 100]')
parser.add_argument('--batch_size', type=int, default=8, help='Batch Size [default: 32]')
parser.add_argument('--num_point', type=int, default=4096, help='Point Number [default: 8192]')
parser.add_argument('--dataset', default='semantic', help='Dataset [default: semantic_color]')
Expand All @@ -26,13 +57,13 @@
BATCH_SIZE = FLAGS.batch_size
NUM_POINT = FLAGS.num_point
DATASET_NAME = FLAGS.dataset
STATS = FLAGS.stats
DRAW_PLOTS = FLAGS.draw
STAT_INPUT_NB = FLAGS.nps # per scene of the dataset

DROPOUT = False
DROPOUT_RATIO = 0.875
AUGMENT = False
STATS = False
DRAW_PLOTS = True
STAT_INPUT_NB = 10 # per scene of the dataset
MAX_EXPORT = 20 # the maximum number of scenes to be exported
GROUP_BY_BATCHES = True

Expand Down

0 comments on commit 60f4eaa

Please sign in to comment.