Extended labels with indices and colors

This commit is contained in:
Simon Giraudot 2020-04-06 10:25:21 +02:00
parent a51ce12aa5
commit 39ca0f3bf7
15 changed files with 403 additions and 343 deletions

View File

@ -83,7 +83,7 @@ int main (int argc, char** argv)
std::cerr << "Computing features" << std::endl;
Feature_set features;
features.begin_parallel_additions();
features.begin_parallel_additions(); // No effect in sequential mode
Feature_handle distance_to_plane = features.add<Distance_to_plane> (pts, Pmap(), eigen);
Feature_handle dispersion = features.add<Dispersion> (pts, Pmap(), grid,
@ -91,7 +91,7 @@ int main (int argc, char** argv)
Feature_handle elevation = features.add<Elevation> (pts, Pmap(), grid,
radius_dtm);
features.end_parallel_additions();
features.end_parallel_additions(); // No effect in sequential mode
//! [Features]
///////////////////////////////////////////////////////////////////
@ -100,9 +100,15 @@ int main (int argc, char** argv)
//! [Labels]
Label_set labels;
// Init name only
Label_handle ground = labels.add ("ground");
Label_handle vegetation = labels.add ("vegetation");
Label_handle roof = labels.add ("roof");
// Init name and color
Label_handle vegetation = labels.add ("vegetation", CGAL::Color(0,255,0));
// Init name, Color and standard index (here, ASPRS building index)
Label_handle roof = labels.add ("roof", CGAL::Color (255, 0, 0), 6);
//! [Labels]
///////////////////////////////////////////////////////////////////

View File

@ -37,7 +37,7 @@ typedef Classification::Point_set_feature_generator<Kernel, Point_set, Pmap>
int main (int argc, char** argv)
{
std::string filename = "data/b9_training.ply";
if (argc > 1)
filename = argv[1];
@ -46,7 +46,7 @@ int main (int argc, char** argv)
std::cerr << "Reading input" << std::endl;
in >> pts;
Imap label_map;
bool lm_found = false;
std::tie (label_map, lm_found) = pts.property_map<int> ("label");
@ -57,17 +57,17 @@ int main (int argc, char** argv)
}
Feature_set features;
std::cerr << "Generating features" << std::endl;
CGAL::Real_timer t;
t.start();
Feature_generator generator (pts, pts.point_map(),
5); // using 5 scales
features.begin_parallel_additions();
generator.generate_point_based_features (features);
features.end_parallel_additions();
t.stop();
std::cerr << "Done in " << t.time() << " second(s)" << std::endl;
@ -78,10 +78,10 @@ int main (int argc, char** argv)
Label_handle roof = labels.add ("roof");
std::vector<int> label_indices(pts.size(), -1);
std::cerr << "Using ETHZ Random Forest Classifier" << std::endl;
Classification::ETHZ::Random_forest_classifier classifier (labels, features);
std::cerr << "Training" << std::endl;
t.reset();
t.start();
@ -96,7 +96,7 @@ int main (int argc, char** argv)
generator.neighborhood().k_neighbor_query(12),
0.2f, 1, label_indices);
t.stop();
std::cerr << "Classification with graphcut done in " << t.time() << " second(s)" << std::endl;
std::cerr << "Precision, recall, F1 scores and IoU:" << std::endl;
@ -123,21 +123,12 @@ int main (int argc, char** argv)
for (std::size_t i = 0; i < label_indices.size(); ++ i)
{
label_map[i] = label_indices[i]; // update label map with computed classification
Label_handle label = labels[label_indices[i]];
if (label == ground)
{
red[i] = 245; green[i] = 180; blue[i] = 0;
}
else if (label == vegetation)
{
red[i] = 0; green[i] = 255; blue[i] = 27;
}
else if (label == roof)
{
red[i] = 255; green[i] = 0; blue[i] = 170;
}
Label_handle label = labels[label_indices[i]];
const CGAL::Color& color = label->color();
red[i] = color.red();
green[i] = color.green();
blue[i] = color.blue();
}
// Save configuration for later use
@ -150,6 +141,6 @@ int main (int argc, char** argv)
f << pts;
std::cerr << "All done" << std::endl;
return EXIT_SUCCESS;
}

View File

@ -37,7 +37,7 @@ typedef Classification::Point_set_feature_generator<Kernel, Point_set, Pmap>
int main (int argc, char** argv)
{
std::string filename = "data/b9_training.ply";
if (argc > 1)
filename = argv[1];
@ -46,7 +46,7 @@ int main (int argc, char** argv)
std::cerr << "Reading input" << std::endl;
in >> pts;
Imap label_map;
bool lm_found = false;
std::tie (label_map, lm_found) = pts.property_map<int> ("label");
@ -57,7 +57,7 @@ int main (int argc, char** argv)
}
Feature_set features;
std::cerr << "Generating features" << std::endl;
CGAL::Real_timer t;
t.start();
@ -67,7 +67,7 @@ int main (int argc, char** argv)
features.begin_parallel_additions();
generator.generate_point_based_features (features);
features.end_parallel_additions();
t.stop();
std::cerr << "Done in " << t.time() << " second(s)" << std::endl;
@ -78,10 +78,10 @@ int main (int argc, char** argv)
Label_handle roof = labels.add ("roof");
std::vector<int> label_indices(pts.size(), -1);
std::cerr << "Using OpenCV Random Forest Classifier" << std::endl;
Classification::OpenCV::Random_forest_classifier classifier (labels, features);
std::cerr << "Training" << std::endl;
t.reset();
t.start();
@ -96,12 +96,12 @@ int main (int argc, char** argv)
generator.neighborhood().k_neighbor_query(12),
0.2f, 1, label_indices);
t.stop();
std::cerr << "Classification with graphcut done in " << t.time() << " second(s)" << std::endl;
std::cerr << "Precision, recall, F1 scores and IoU:" << std::endl;
Classification::Evaluation evaluation (labels, pts.range(label_map), label_indices);
for (Label_handle l : labels)
{
std::cerr << " * " << l->name() << ": "
@ -123,21 +123,12 @@ int main (int argc, char** argv)
for (std::size_t i = 0; i < label_indices.size(); ++ i)
{
label_map[i] = label_indices[i]; // update label map with computed classification
Label_handle label = labels[label_indices[i]];
if (label == ground)
{
red[i] = 245; green[i] = 180; blue[i] = 0;
}
else if (label == vegetation)
{
red[i] = 0; green[i] = 255; blue[i] = 27;
}
else if (label == roof)
{
red[i] = 255; green[i] = 0; blue[i] = 170;
}
Label_handle label = labels[label_indices[i]];
const CGAL::Color& color = label->color();
red[i] = color.red();
green[i] = color.green();
blue[i] = color.blue();
}
// Write result
@ -146,6 +137,6 @@ int main (int argc, char** argv)
f << pts;
std::cerr << "All done" << std::endl;
return EXIT_SUCCESS;
}

View File

@ -37,7 +37,7 @@ typedef Classification::Point_set_feature_generator<Kernel, Point_set, Pmap>
int main (int argc, char** argv)
{
std::string filename = "data/b9_training.ply";
if (argc > 1)
filename = argv[1];
@ -46,7 +46,7 @@ int main (int argc, char** argv)
std::cerr << "Reading input" << std::endl;
in >> pts;
Imap label_map;
bool lm_found = false;
std::tie (label_map, lm_found) = pts.property_map<int> ("label");
@ -57,17 +57,17 @@ int main (int argc, char** argv)
}
Feature_set features;
std::cerr << "Generating features" << std::endl;
CGAL::Real_timer t;
t.start();
Feature_generator generator (pts, pts.point_map(),
5); // using 5 scales
features.begin_parallel_additions();
generator.generate_point_based_features (features);
features.end_parallel_additions();
t.stop();
std::cerr << "Done in " << t.time() << " second(s)" << std::endl;
@ -78,10 +78,10 @@ int main (int argc, char** argv)
Label_handle roof = labels.add ("roof");
std::vector<int> label_indices(pts.size(), -1);
std::cerr << "Using TensorFlow neural network Classifier" << std::endl;
Classification::TensorFlow::Neural_network_classifier<> classifier (labels, features);
std::cerr << "Training" << std::endl;
t.reset();
t.start();
@ -98,12 +98,12 @@ int main (int argc, char** argv)
generator.neighborhood().k_neighbor_query(12),
0.2f, 1, label_indices);
t.stop();
std::cerr << "Classification with graphcut done in " << t.time() << " second(s)" << std::endl;
std::cerr << "Precision, recall, F1 scores and IoU:" << std::endl;
Classification::Evaluation evaluation (labels, pts.range(ground_truth), label_indices);
for (Label_handle l : labels)
{
std::cerr << " * " << l->name() << ": "
@ -125,21 +125,12 @@ int main (int argc, char** argv)
for (std::size_t i = 0; i < label_indices.size(); ++ i)
{
label_map[i] = label_indices[i]; // update label map with computed classification
Label_handle label = labels[label_indices[i]];
if (label == ground)
{
red[i] = 245; green[i] = 180; blue[i] = 0;
}
else if (label == vegetation)
{
red[i] = 0; green[i] = 255; blue[i] = 27;
}
else if (label == roof)
{
red[i] = 255; green[i] = 0; blue[i] = 170;
}
Label_handle label = labels[label_indices[i]];
const CGAL::Color& color = label->color();
red[i] = color.red();
green[i] = color.green();
blue[i] = color.blue();
}
// Write result
@ -148,6 +139,6 @@ int main (int argc, char** argv)
f << pts;
std::cerr << "All done" << std::endl;
return EXIT_SUCCESS;
}

View File

@ -38,7 +38,6 @@ namespace Classification {
class Evaluation
{
const Label_set& m_labels;
mutable std::map<Label_handle, std::size_t> m_map_labels;
std::vector<std::vector<std::size_t> > m_confusion; // confusion matrix
public:
@ -56,7 +55,7 @@ public:
{
init();
}
/*!
\brief Instantiates an evaluation object and computes all
@ -86,9 +85,6 @@ public:
/// \cond SKIP_IN_MANUAL
void init()
{
for (std::size_t i = 0; i < m_labels.size(); ++ i)
m_map_labels[m_labels[i]] = i;
m_confusion.resize (m_labels.size());
for (std::size_t i = 0; i < m_confusion.size(); ++ i)
m_confusion[i].resize (m_labels.size(), 0);
@ -103,7 +99,7 @@ public:
}
/// \endcond
/*!
\brief Append more items to the evaluation object.
@ -129,11 +125,11 @@ public:
int res = static_cast<int>(get<1>(p));
if (gt == -1 || res == -1)
continue;
++ m_confusion[std::size_t(res)][std::size_t(gt)];
}
}
}
/// @}
/// \name Label Evaluation
@ -149,17 +145,17 @@ public:
*/
float precision (Label_handle label) const
{
std::size_t idx = m_map_labels[label];
std::size_t idx = label->index();
if (!label_has_ground_truth(idx))
return std::numeric_limits<float>::quiet_NaN();
std::size_t total = 0;
for (std::size_t i = 0; i < m_labels.size(); ++ i)
total += m_confusion[idx][i];
if (total == 0)
return 0.f;
return m_confusion[idx][idx] / float(total);
}
@ -173,10 +169,10 @@ public:
*/
float recall (Label_handle label) const
{
std::size_t idx = m_map_labels[label];
std::size_t idx = label->index();
if (!label_has_ground_truth(idx))
return std::numeric_limits<float>::quiet_NaN();
std::size_t total = 0;
for (std::size_t i = 0; i < m_labels.size(); ++ i)
total += m_confusion[i][idx];
@ -201,7 +197,7 @@ public:
if (p == 0.f && r == 0.f)
return 0.f;
return 2.f * p * r / (p + r);
}
@ -215,8 +211,8 @@ public:
*/
float intersection_over_union (Label_handle label) const
{
std::size_t idx = m_map_labels[label];
std::size_t idx = label->index();
std::size_t total = 0;
for (std::size_t i = 0; i < m_labels.size(); ++ i)
{
@ -229,7 +225,7 @@ public:
}
/// @}
/// \name Global Evaluation
/// @{
@ -239,11 +235,11 @@ public:
*/
std::size_t confusion (Label_handle ground_truth, Label_handle result)
{
std::size_t idx_gt = m_map_labels[ground_truth];
std::size_t idx_r = m_map_labels[result];
std::size_t idx_gt = ground_truth->index();
std::size_t idx_r = result->index();
return m_confusion[idx_gt][idx_r];
}
/*!
\brief Returns the number of misclassified items.
*/
@ -287,7 +283,7 @@ public:
}
return true_positives / float(total);
}
/*!
\brief Returns the mean \f$F_1\f$ score of the training over all
labels (see `f1_score()`).
@ -304,7 +300,7 @@ public:
}
return mean / nb;
}
/*!
\brief Returns the mean intersection over union of the training
over all labels (see `intersection_over_union()`).
@ -329,7 +325,7 @@ public:
/// \name Output Formatting Functions
/// @{
/*!
\brief Outputs the evaluation in a simple ASCII format to the stream `os`.
*/
@ -387,7 +383,7 @@ public:
<< "</ul>" << std::endl;
const Label_set& labels = evaluation.m_labels;
os << "<h2>Detailed Results</h2>" << std::endl
<< "<table>" << std::endl
<< " <tr>" << std::endl
@ -414,7 +410,7 @@ public:
<< " <td></td>" << std::endl
<< " <td></td>" << std::endl
<< " </tr>" << std::endl;
os << "</table>" << std::endl;
os << "<h2>Confusion Matrix</h2>" << std::endl
@ -444,7 +440,7 @@ public:
os << " <td><strong>" << sum << "</strong></td>" << std::endl;
os << " </tr>" << std::endl;
}
os << " <tr>" << std::endl
<< " <td><strong>GROUND TRUTH</strong></td>" << std::endl;
std::size_t total = 0;
@ -461,18 +457,17 @@ href=\"https://doc.cgal.org/latest/Classification/index.html\">CGAL \
Classification package</a>.</em></p>" << std::endl
<< "</body>" << std::endl
<< "</html>" << std::endl;
return os;
}
/// @}
};
} // namespace Classification
} // namespace CGAL
#endif // CGAL_CLASSIFICATION_EVALUATION_H

View File

@ -13,6 +13,7 @@
#define CGAL_CLASSIFICATION_LABEL_H
#include <CGAL/license/Classification.h>
#include <CGAL/IO/Color.h>
#include <memory>
@ -20,6 +21,10 @@ namespace CGAL {
namespace Classification {
/// \cond SKIP_IN_MANUAL
class Label_set;
/// \endcond
/*!
\ingroup PkgClassificationLabel
@ -32,19 +37,56 @@ class Label
private:
std::string m_name;
std::size_t m_index;
std::size_t m_standard_index;
CGAL::Color m_color;
friend Label_set;
public:
/*!
\param name name of the classification label (e.g. vegetation).
*/
Label (std::string name) : m_name (name) { }
/// \cond SKIP_IN_MANUAL
// Undocumented: Labels should be created by the set
Label (std::string name, std::size_t index, std::size_t standard_index,
const CGAL::Color& color)
: m_name (name), m_index (index), m_standard_index (standard_index)
, m_color (color)
{ }
/// \endcond
/*!
returns the name of the classification label (e.g. vegetation).
*/
const std::string& name() const { return m_name; }
/// \cond SKIP_IN_MANUAL
void set_name (const std::string& name) { m_name = name; }
/// \endcond
/*!
returns the index of the classification label in the label set.
\note This index cannot be changed by the user and is handled directly by the label set.
*/
std::size_t index() const { return m_index; }
/*!
returns the standard index of the classification label (i.e. index in the ASPRS standard).
\note This index is purely user-oriented and is not used by the classification algorithms.
*/
std::size_t standard_index() const { return m_standard_index; }
void set_standard_index(std::size_t idx) { m_standard_index = idx; }
/*!
returns the color used to represent the label.
\note The color is purely user-oriented and is not used by the
classification algorithms. It is not to be confused with a color
attribute embedded in a data set which _can_ be used (see
`Color_channel`).
*/
const CGAL::Color& color() const { return m_color; }
void set_color (const Color& color) { m_color = color; }
};
#ifdef DOXYGEN_RUNNING

View File

@ -16,6 +16,8 @@
#include <CGAL/Classification/Label.h>
#include <CGAL/Random.h>
#include <vector>
namespace CGAL {
@ -32,6 +34,8 @@ algorithms.
class Label_set
{
using Base = std::vector<Label_handle>;
CGAL::Random m_random;
Base m_labels;
public:
@ -52,14 +56,69 @@ public:
Label_set(std::initializer_list<const char*> labels)
{
for (const char* l : labels)
m_labels.push_back (std::make_shared<Classification::Label>(l));
add (l);
}
/*!
\brief Adds a label.
\note Names, standard indices and colors are not used for
identification: two labels in the same set can have the same name,
standard index or color, but not the same handle. Each call to
`add()` generates a new distinct label.
\param name name of the label.
\param color used to represent the label.
\param standard_index standard index of the classification label
(i.e. index in the ASPRS standard).
\return a handle to the newly added label.
*/
Label_handle add (const char* name,
CGAL::Color color,
std::size_t standard_index = -1)
{
Label_handle out = std::make_shared<Classification::Label>
(name, m_labels.size(), standard_index, color);
m_labels.push_back (out);
return out;
}
/*!
\brief Adds a label with default standard index and color.
This functions tries to map label names to standard ASPRS labels
and automatically picks the `standard_index` and `color` of the
label:
- \"unassigned\" is given standard index 2 and color `(0, 0, 0)`
- \"ground\" is given standard index 2 and color `(186, 189, 182)`
- \"low_vegetation\" is given standard index 3 and color `(78, 154, 6)`
- \"medium_vegetation\" is given standard index 4 and color `(138, 226, 52)`
- \"high_vegetation\" is given standard index 5 and color `(204, 255, 201)`
- \"building\" is given standard index 6 and color `(245, 121, 0)`
- \"noise\" is given standard index 7 and color `(128, 0, 0)`
- \"reserved\" is given standard index 8 and color `(233, 185, 110)`
- \"water\" is given standard index 9 and color `(114, 159, 207)`
- \"rail\" is given standard index 10 and color `(136, 46, 25)`
- \"road_surface\" is given standard index 11 and color `(56, 56, 56)`
- \"reserved_2\" is given standard index 12 and color `(193, 138, 51)`
- \"wire_guard\" is given standard index 13 and color `(37, 61, 136)`
- \"wire_conductor\" is given standard index 14 and color `(173, 127, 168)`
- \"transmission_tower\" is given standard index 15 and color `(136, 138, 133)`
- \"wire_connect\" is given standard index 16 and color `(145, 64, 236)`
- \"bridge_deck\" is given standard index 17 and color `(213, 93, 93)`
- \"high_noise\" is given standard index 18 and color `(255, 0, 0)`
If the name is not found, the label is given standard index
`std::size_t(-1)` and a random color.
\note Names are not used for identification: two labels in the
same set can have the same name (but not the same handle).
same set can have the same name but not the same handle. Each call
to `add()` generates a new distinct label.
\param name name of the label.
@ -67,10 +126,77 @@ public:
*/
Label_handle add (const char* name)
{
Label_handle out = std::make_shared<Classification::Label> (name);
m_labels.push_back (out);
return out;
static std::unordered_map<std::string, std::pair<std::size_t, CGAL::Color> > init_map;
if (init_map.empty())
{
init_map.insert (std::make_pair ("unassigned",
std::make_pair (2, CGAL::Color (0, 0, 0))));
init_map.insert (std::make_pair ("ground",
std::make_pair (2, CGAL::Color (186, 189, 182))));
init_map.insert (std::make_pair ("low_vegetation",
std::make_pair (3, CGAL::Color (78, 154, 6))));
init_map.insert (std::make_pair ("medium_vegetation",
std::make_pair (4, CGAL::Color (138, 226, 52))));
init_map.insert (std::make_pair ("high_vegetation",
std::make_pair (5, CGAL::Color (204, 255, 201))));
init_map.insert (std::make_pair ("building",
std::make_pair (6, CGAL::Color (245, 121, 0))));
init_map.insert (std::make_pair ("noise",
std::make_pair (7, CGAL::Color (128, 0, 0))));
init_map.insert (std::make_pair ("reserved",
std::make_pair (8, CGAL::Color (233, 185, 110))));
init_map.insert (std::make_pair ("water",
std::make_pair (9, CGAL::Color (114, 159, 207))));
init_map.insert (std::make_pair ("rail",
std::make_pair (10, CGAL::Color (136, 46, 25))));
init_map.insert (std::make_pair ("road_surface",
std::make_pair (11, CGAL::Color (56, 56, 56))));
init_map.insert (std::make_pair ("reserved_2",
std::make_pair (12, CGAL::Color (193, 138, 51))));
init_map.insert (std::make_pair ("wire_guard",
std::make_pair (13, CGAL::Color (37, 61, 136))));
init_map.insert (std::make_pair ("wire_conductor",
std::make_pair (14, CGAL::Color (173, 127, 168))));
init_map.insert (std::make_pair ("wire_conduct",
std::make_pair (14, CGAL::Color (173, 127, 168))));
init_map.insert (std::make_pair ("transmission_tower",
std::make_pair (15, CGAL::Color (136, 138, 133))));
init_map.insert (std::make_pair ("trans_tower",
std::make_pair (15, CGAL::Color (136, 138, 133))));
init_map.insert (std::make_pair ("wire_connect",
std::make_pair (16, CGAL::Color (145, 64, 236))));
init_map.insert (std::make_pair ("bridge_deck",
std::make_pair (17, CGAL::Color (213, 93, 93))));
init_map.insert (std::make_pair ("high_noise",
std::make_pair (18, CGAL::Color (255, 0, 0))));
// Undocumented additions
init_map.insert (std::make_pair ("low_veget",
std::make_pair (3, CGAL::Color (78, 154, 6))));
init_map.insert (std::make_pair ("medium_veget",
std::make_pair (4, CGAL::Color (138, 226, 52))));
init_map.insert (std::make_pair ("vegetation",
std::make_pair (4, CGAL::Color (138, 226, 52))));
init_map.insert (std::make_pair ("high_veget",
std::make_pair (5, CGAL::Color (204, 255, 201))));
init_map.insert (std::make_pair ("roof",
std::make_pair (6, CGAL::Color (245, 121, 0))));
init_map.insert (std::make_pair ("facade",
std::make_pair (-1, CGAL::Color (77, 131, 186))));
}
std::string sname (name);
auto found = init_map.find (sname);
if (found == init_map.end())
return add (name,
CGAL::Color ((unsigned char)(m_random.get_int(64, 192)),
(unsigned char)(m_random.get_int(64, 192)),
(unsigned char)(m_random.get_int(64, 192))));
// else
return add (name, found->second.second, found->second.first);
}
/// \endcond
/*!
\brief Removes a label.
@ -82,17 +208,14 @@ public:
*/
bool remove (Label_handle label)
{
std::size_t idx = (std::size_t)(-1);
for (std::size_t i = 0; i < m_labels.size(); ++ i)
if (m_labels[i] == label)
{
m_labels.erase (m_labels.begin() + i);
idx = i;
break;
}
if (idx == (std::size_t)(-1))
if (label->index() >= m_labels.size()
|| m_labels[label->index()] != label)
return false;
for (std::size_t i = label->index() + 1; i < m_labels.size(); ++ i)
m_labels[i]->m_index --;
m_labels.erase (m_labels.begin() + label->index());
return true;
}
@ -117,7 +240,6 @@ public:
return m_labels[i];
}
/*!
\brief Removes all labels.
*/
@ -125,8 +247,6 @@ public:
{
m_labels.clear();
}
};

View File

@ -34,19 +34,7 @@
#include <CGAL/bounding_box.h>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <CGAL/Real_timer.h>
#include <CGAL/demangle.h>
#ifdef CGAL_LINKED_WITH_TBB
#include <tbb/task_group.h>
#include <mutex>
#endif // CGAL_LINKED_WITH_TBB
namespace CGAL {

View File

@ -34,14 +34,7 @@
#include <CGAL/Classification/Feature_set.h>
#include <CGAL/bounding_box.h>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <CGAL/Real_timer.h>
#include <CGAL/demangle.h>
namespace CGAL {

View File

@ -51,7 +51,7 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po
bool classif_found = false;
boost::tie (m_classif, classif_found) = m_points->point_set()->add_property_map<int>("label", -1);
training_found = !training_found; // add_property_map returns false if
training_found = !training_found; // add_property_map returns false if
classif_found = !classif_found; // property was already there
bool las_found = false;
@ -76,11 +76,11 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po
training_found = true;
}
}
if (training_found || classif_found)
{
std::vector<int> used_indices;
for (Point_set::const_iterator it = m_points->point_set()->begin();
it != m_points->point_set()->first_selected(); ++ it)
{
@ -122,12 +122,12 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po
++ current_idx;
}
for (Point_set::const_iterator it = m_points->point_set()->begin();
it != m_points->point_set()->first_selected(); ++ it)
{
int c = m_cluster_id[*it];
if (training_found)
{
if (std::size_t(current_idx) != used_indices.size()) // Empty indices -> reorder indices in point set
@ -153,7 +153,7 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po
m_clusters[c].label() = m_classif[*it];
}
}
std::map<int, std::string> label_names;
if (las_found) // Use LAS standard
{
@ -196,7 +196,7 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po
}
}
}
for (std::size_t i = 0; i < used_indices.size(); ++ i)
{
if (used_indices[i] == -1)
@ -213,8 +213,6 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po
oss << "label_" << i;
new_label = m_labels.add(oss.str().c_str());
}
m_label_colors.push_back (this->get_new_label_color (new_label->name()));
}
}
else
@ -223,11 +221,8 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po
m_labels.add("vegetation");
m_labels.add("roof");
m_labels.add("facade");
for (std::size_t i = 0; i < m_labels.size(); ++ i)
m_label_colors.push_back (this->get_new_label_color (m_labels[i]->name()));
}
update_comments_of_point_set_item();
m_sowf = new Sum_of_weighted_features (m_labels, m_features);
@ -256,7 +251,7 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po
m_cluster_id)));
std::set<std::pair<int, int> > adjacencies;
for (Delaunay::Finite_edges_iterator it = dt.finite_edges_begin();
it != dt.finite_edges_end(); ++ it)
{
@ -315,13 +310,13 @@ Cluster_classification::~Cluster_classification()
m_classif[*it] = -1;
}
}
// For LAS saving, convert classification info in the LAS standard
// if (m_input_is_las)
{
Point_set::Property_map<unsigned char> las_classif
= m_points->point_set()->add_property_map<unsigned char>("classification", 0).first;
std::vector<unsigned char> label_indices;
unsigned char custom = 19;
@ -372,14 +367,14 @@ Cluster_classification::~Cluster_classification()
unsigned char lc = 1; // unclassified in LAS standard
if (c != -1)
lc = label_indices[std::size_t(c)];
las_classif[*it] = lc;
int t = m_training[*it];
unsigned char lt = 1; // unclassified in LAS standard
if (t != -1)
lt = label_indices[std::size_t(t)];
m_training[*it] = int(lt);
}
@ -406,7 +401,7 @@ void Cluster_classification::backup_existing_colors_and_add_new()
m_points->point_set()->remove_colors();
}
m_points->point_set()->add_colors();
}
@ -419,7 +414,7 @@ void Cluster_classification::reset_colors()
for (Point_set::const_iterator it = m_points->point_set()->begin();
it != m_points->point_set()->first_selected(); ++ it)
m_points->point_set()->set_color(*it, m_color[*it]);
m_points->point_set()->remove_property_map(m_color);
}
}
@ -429,19 +424,19 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax)
m_index_color = index;
int index_color = real_index_color();
// Colors
static Color_ramp ramp;
ramp.build_rainbow();
reset_indices();
if (index_color == -1) // item color
m_points->point_set()->remove_colors();
else
{
if (!m_points->point_set()->has_colors())
m_points->point_set()->add_colors();
if (index_color == 0) // real colors
{
@ -459,11 +454,11 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax)
if (cid != -1)
{
std::size_t c = m_clusters[cid].label();
if (c != std::size_t(-1))
color = m_label_colors[c];
color = label_qcolor (m_labels[std::size_t(c)]);
}
m_points->point_set()->set_color(*it, color);
}
}
@ -475,18 +470,18 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax)
QColor color (0, 0, 0);
int cid = m_cluster_id[*it];
float div = 1;
if (cid != -1)
{
int c = m_clusters[cid].training();
int c2 = m_clusters[cid].label();
if (c != -1)
color = m_label_colors[std::size_t(c)];
color = label_qcolor (m_labels[std::size_t(c)]);
if (c != c2)
div = 2;
}
}
m_points->point_set()->set_color(*it, color.red() / div, color.green() / div, color.blue() / div);
}
}
@ -496,7 +491,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax)
it != m_points->point_set()->first_selected(); ++ it)
{
int cid = m_cluster_id[*it];
if (cid != -1)
{
srand(cid);
@ -549,7 +544,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax)
float min = std::numeric_limits<float>::max();
float max = -std::numeric_limits<float>::max();
if (vmin != NULL && vmax != NULL
&& *vmin != std::numeric_limits<float>::infinity()
&& *vmax != std::numeric_limits<float>::infinity())
@ -572,7 +567,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax)
}
}
}
for (Point_set::const_iterator it = m_points->point_set()->begin();
it != m_points->point_set()->first_selected(); ++ it)
{
@ -582,7 +577,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax)
float v = (feature->value(cid) - min) / (max - min);
if (v < 0.f) v = 0.f;
if (v > 1.f) v = 1.f;
m_points->point_set()->set_color(*it, ramp.r(v) * 255, ramp.g(v) * 255, ramp.b(v) * 255);
}
else
@ -597,7 +592,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax)
}
}
}
for (Point_set::const_iterator it = m_points->point_set()->first_selected();
it != m_points->point_set()->end(); ++ it)
m_points->point_set()->set_color(*it, 255, 0, 0);
@ -606,7 +601,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax)
int Cluster_classification::real_index_color() const
{
int out = m_index_color;
if (out == 0 && m_color == Point_set::Property_map<CGAL::Color>())
out = -1;
return out;
@ -629,7 +624,7 @@ void Cluster_classification::compute_features (std::size_t nb_scales, float voxe
CGAL_assertion (!(m_points->point_set()->empty()));
reset_indices();
std::cerr << "Computing pointwise features with " << nb_scales << " scale(s) and ";
if (voxel_size == -1)
std::cerr << "automatic voxel size" << std::endl;
@ -642,9 +637,9 @@ void Cluster_classification::compute_features (std::size_t nb_scales, float voxe
bool normals = m_points->point_set()->has_normal_map();
if (normals)
normal_map = m_points->point_set()->normal_map();
bool colors = (m_color != Point_set::Property_map<CGAL::Color>());
Point_set::Property_map<boost::uint8_t> echo_map;
bool echo;
boost::tie (echo_map, echo) = m_points->point_set()->template property_map<boost::uint8_t>("echo");
@ -654,10 +649,10 @@ void Cluster_classification::compute_features (std::size_t nb_scales, float voxe
Feature_set pointwise_features;
Generator generator (*(m_points->point_set()), m_points->point_set()->point_map(), nb_scales, voxel_size);
CGAL::Real_timer t;
t.start();
#ifdef CGAL_LINKED_WITH_TBB
pointwise_features.begin_parallel_additions();
#endif
@ -669,11 +664,11 @@ void Cluster_classification::compute_features (std::size_t nb_scales, float voxe
generator.generate_color_based_features (pointwise_features, m_color);
if (echo)
generator.generate_echo_based_features (pointwise_features, echo_map);
#ifdef CGAL_LINKED_WITH_TBB
pointwise_features.end_parallel_additions();
#endif
add_remaining_point_set_properties_as_features(pointwise_features);
t.stop();
@ -692,29 +687,29 @@ void Cluster_classification::compute_features (std::size_t nb_scales, float voxe
m_features.template add<Mean_of_feature> (m_clusters,
pointwise_features[i]);
}
#ifdef CGAL_LINKED_WITH_TBB
m_features.end_parallel_additions();
m_features.begin_parallel_additions();
#endif
for (std::size_t i = 0; i < pointwise_features.size(); ++ i)
{
m_features.template add<Variance_of_feature> (m_clusters,
pointwise_features[i],
m_features[i]);
}
}
add_cluster_features();
#ifdef CGAL_LINKED_WITH_TBB
m_features.end_parallel_additions();
#endif
t.stop();
std::cerr << m_features.size() << " feature(s) computed in " << t.time() << " second(s)" << std::endl;
delete m_sowf;
m_sowf = new Sum_of_weighted_features (m_labels, m_features);
if (m_ethz != NULL)
@ -756,7 +751,7 @@ void Cluster_classification::select_random_region()
selected.push_back (*it);
else
unselected.push_back (*it);
for (std::size_t i = 0; i < unselected.size(); ++ i)
*(m_points->point_set()->begin() + i) = unselected[i];
for (std::size_t i = 0; i < selected.size(); ++ i)
@ -764,13 +759,13 @@ void Cluster_classification::select_random_region()
m_points->point_set()->set_first_selected
(m_points->point_set()->begin() + unselected.size());
}
void Cluster_classification::add_remaining_point_set_properties_as_features(Feature_set& feature_set)
{
const std::vector<std::string>& prop = m_points->point_set()->base().properties();
for (std::size_t i = 0; i < prop.size(); ++ i)
{
if (prop[i] == "index" ||
@ -823,7 +818,7 @@ void Cluster_classification::train(int classifier, const QMultipleInputDialog& d
std::vector<std::size_t> nb_label (m_labels.size(), 0);
std::size_t nb_total = 0;
std::vector<int> training;
training.reserve (m_clusters.size());
for (std::size_t i = 0; i < m_clusters.size(); ++ i)
@ -835,12 +830,12 @@ void Cluster_classification::train(int classifier, const QMultipleInputDialog& d
++ nb_total;
}
}
std::cerr << nb_total << " cluster(s) used for training ("
<< 100. * (nb_total / double(m_clusters.size())) << "% of the total):" << std::endl;
for (std::size_t i = 0; i < m_labels.size(); ++ i)
std::cerr << " * " << m_labels[i]->name() << ": " << nb_label[i] << " clusters(s)" << std::endl;
std::vector<int> indices (m_clusters.size(), -1);
if (classifier == CGAL_CLASSIFICATION_SOWF_NUMBER)
@ -908,14 +903,14 @@ void Cluster_classification::train(int classifier, const QMultipleInputDialog& d
while (iss >> s)
hidden_layers.push_back (std::size_t(s));
}
m_neural_network->train (training,
dialog.get<QCheckBox>("restart")->isChecked(),
dialog.get<QSpinBox>("trials")->value(),
dialog.get<DoubleEdit>("learning_rate")->value(),
dialog.get<QSpinBox>("batch_size")->value(),
hidden_layers);
CGAL::Classification::classify<Concurrency_tag> (m_clusters,
m_labels, *m_neural_network,
indices, m_label_probabilities);
@ -924,7 +919,7 @@ void Cluster_classification::train(int classifier, const QMultipleInputDialog& d
for (std::size_t i = 0; i < m_clusters.size(); ++ i)
m_clusters[i].label() = indices[i];
if (m_index_color == 1 || m_index_color == 2)
change_color (m_index_color);
}
@ -973,7 +968,6 @@ bool Cluster_classification::run (int method, int classifier,
run (method, *m_neural_network, subdivisions, smoothing);
#endif
}
return true;
}

View File

@ -208,7 +208,7 @@ class Cluster_classification : public Item_classification_base
= new Scene_points_with_normal_item;
points_item->setName (QString("%1 (%2)").arg(name).arg(m_labels[label]->name().c_str()));
points_item->setColor (m_label_colors[label]);
points_item->setColor (label_qcolor (m_labels[label]));
for (Point_set::const_iterator it = m_points->point_set()->begin();
it != m_points->point_set()->end(); ++ it)
{
@ -231,7 +231,7 @@ class Cluster_classification : public Item_classification_base
{
points_item[i] = new Scene_points_with_normal_item;
points_item[i]->setName (QString("%1 (%2)").arg(name).arg(m_labels[i]->name().c_str()));
points_item[i]->setColor (m_label_colors[i]);
points_item[i]->setColor (label_qcolor (m_labels[i]));
items.push_back (points_item[i]);
}

View File

@ -52,9 +52,9 @@ public:
#ifdef CGAL_LINKED_WITH_TENSORFLOW
typedef CGAL::Classification::TensorFlow::Neural_network_classifier<> Neural_network;
#endif
public:
Item_classification_base() { }
virtual ~Item_classification_base() { }
@ -66,7 +66,7 @@ public:
virtual void compute_features (std::size_t nb_scales, float voxel_size) = 0;
virtual std::string feature_statistics () const { return std::string(); }
virtual void add_selection_to_training_set (std::size_t label) = 0;
virtual void reset_training_set (std::size_t label) = 0;
virtual void reset_training_set_of_selection() = 0;
@ -76,7 +76,7 @@ public:
virtual void validate_selection () = 0;
virtual void train(int classifier, const QMultipleInputDialog&) = 0;
virtual bool run (int method, int classifier, std::size_t subdivisions, double smoothing) = 0;
virtual void update_color () = 0;
virtual void change_color (int index, float* vmin = NULL, float* vmax = NULL) = 0;
virtual CGAL::Three::Scene_item* generate_one_item (const char* name,
@ -85,19 +85,23 @@ public:
const char* name) const = 0;
bool features_computed() const { return (m_features.size() != 0); }
std::size_t number_of_features() const { return m_features.size(); }
std::size_t number_of_features() const { return m_features.size(); }
Feature_handle feature(std::size_t i) { return m_features[i]; }
float weight (Feature_handle f) const { return m_sowf->weight(f); }
void set_weight (Feature_handle f, float w) const { m_sowf->set_weight(f,w); }
Sum_of_weighted_features::Effect effect (Label_handle l, Feature_handle f) const { return m_sowf->effect(l,f); }
void set_effect (Label_handle l, Feature_handle f, Sum_of_weighted_features::Effect e)
{ m_sowf->set_effect (l, f, e); }
QColor label_qcolor (Label_handle l) const
{
return QColor (l->color().red(), l->color().green(), l->color().blue());
}
virtual QColor add_new_label (const char* name)
{
m_labels.add(name);
m_label_colors.push_back (get_new_label_color (name));
delete m_sowf;
m_sowf = new Sum_of_weighted_features (m_labels, m_features);
@ -113,13 +117,12 @@ public:
delete m_neural_network;
m_neural_network = new Neural_network (m_labels, m_features);
#endif
return m_label_colors.back();
return label_qcolor (m_labels[m_labels.size() - 1]);
}
virtual void remove_label (std::size_t position)
{
m_labels.remove(m_labels[position]);
m_label_colors.erase (m_label_colors.begin() + position);
delete m_sowf;
m_sowf = new Sum_of_weighted_features (m_labels, m_features);
@ -137,11 +140,10 @@ public:
m_neural_network = new Neural_network (m_labels, m_features);
#endif
}
virtual void clear_labels ()
{
m_labels.clear();
m_label_colors.clear();
delete m_sowf;
m_sowf = new Sum_of_weighted_features (m_labels, m_features);
@ -256,69 +258,24 @@ public:
}
}
const QColor& label_color(std::size_t i) const { return m_label_colors[i]; }
QColor label_color(std::size_t i) const
{
return label_qcolor (m_labels[i]);
}
void change_label_color (std::size_t position, const QColor& color)
{
m_label_colors[position] = color;
m_labels[position]->set_color
(CGAL::Color (color.red(), color.green(), color.blue()));
}
void change_label_name (std::size_t position, const std::string& name)
{
m_labels[position]->set_name (name);
}
QColor get_new_label_color (const std::string& name)
{
QColor color (64 + rand() % 192,
64 + rand() % 192,
64 + rand() % 192);
if (name == "ground")
color = QColor (186, 189, 182);
else if (name == "low_veget")
color = QColor (78, 154, 6);
else if (name == "med_veget"
|| name == "vegetation")
color = QColor (138, 226, 52);
else if (name == "high_veget")
color = QColor (204, 255, 201);
else if (name == "building"
|| name == "roof")
color = QColor (245, 121, 0);
else if (name == "noise")
color = QColor (0, 0, 0);
else if (name == "reserved")
color = QColor (233, 185, 110);
else if (name == "water")
color = QColor (114, 159, 207);
else if (name == "rail")
color = QColor (136, 46, 25);
else if (name == "road_surface")
color = QColor (56, 56, 56);
else if (name == "reserved_2")
color = QColor (193, 138, 51);
else if (name == "wire_guard")
color = QColor (37, 61, 136);
else if (name == "wire_conduct")
color = QColor (173, 127, 168);
else if (name == "trans_tower")
color = QColor (136, 138, 133);
else if (name == "wire_connect")
color = QColor (145, 64, 236);
else if (name == "bridge_deck")
color = QColor (213, 93, 93);
else if (name == "high_noise")
color = QColor (255, 0, 0);
else if (name == "facade")
color = QColor (77, 131, 186);
return color;
}
protected:
Label_set m_labels;
Feature_set m_features;
std::vector<QColor> m_label_colors;
Sum_of_weighted_features* m_sowf;
ETHZ_random_forest* m_ethz;
#ifdef CGAL_LINKED_WITH_OPENCV
@ -327,7 +284,7 @@ protected:
#ifdef CGAL_LINKED_WITH_TENSORFLOW
Neural_network* m_neural_network;
#endif
};

View File

@ -48,7 +48,7 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n
bool classif_found = false;
boost::tie (m_classif, classif_found) = m_points->point_set()->add_property_map<int>("label", -1);
training_found = !training_found; // add_property_map returns false if
training_found = !training_found; // add_property_map returns false if
classif_found = !classif_found; // property was already there
bool las_found = false;
@ -73,11 +73,11 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n
training_found = true;
}
}
if (training_found || classif_found)
{
std::vector<int> used_indices;
for (Point_set::const_iterator it = m_points->point_set()->begin();
it != m_points->point_set()->first_selected(); ++ it)
{
@ -140,7 +140,7 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n
}
}
}
std::map<int, std::string> label_names;
if (las_found) // Use LAS standard
{
@ -183,7 +183,7 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n
}
}
}
for (std::size_t i = 0; i < used_indices.size(); ++ i)
{
if (used_indices[i] == -1)
@ -200,8 +200,6 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n
oss << "label_" << i;
new_label = m_labels.add(oss.str().c_str());
}
m_label_colors.push_back (this->get_new_label_color (new_label->name()));
}
}
else
@ -210,11 +208,8 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n
m_labels.add("vegetation");
m_labels.add("roof");
m_labels.add("facade");
for (std::size_t i = 0; i < m_labels.size(); ++ i)
m_label_colors.push_back (this->get_new_label_color (m_labels[i]->name()));
}
update_comments_of_point_set_item();
m_sowf = new Sum_of_weighted_features (m_labels, m_features);
@ -257,7 +252,7 @@ Point_set_item_classification::~Point_set_item_classification()
{
Point_set::Property_map<unsigned char> las_classif
= m_points->point_set()->add_property_map<unsigned char>("classification", 0).first;
std::vector<unsigned char> label_indices;
unsigned char custom = 19;
@ -308,14 +303,14 @@ Point_set_item_classification::~Point_set_item_classification()
unsigned char lc = 1; // unclassified in LAS standard
if (c != -1)
lc = label_indices[std::size_t(c)];
las_classif[*it] = lc;
int t = m_training[*it];
unsigned char lt = 1; // unclassified in LAS standard
if (t != -1)
lt = label_indices[std::size_t(t)];
m_training[*it] = int(lt);
}
@ -365,19 +360,19 @@ void Point_set_item_classification::change_color (int index, float* vmin, float*
m_index_color = index;
int index_color = real_index_color();
// Colors
static Color_ramp ramp;
ramp.build_rainbow();
reset_indices();
if (index_color == -1) // item color
m_points->point_set()->remove_colors();
else
{
if (!m_points->point_set()->has_colors())
m_points->point_set()->add_colors();
if (index_color == 0) // real colors
{
@ -392,9 +387,9 @@ void Point_set_item_classification::change_color (int index, float* vmin, float*
{
QColor color (0, 0, 0);
std::size_t c = m_classif[*it];
if (c != std::size_t(-1))
color = m_label_colors[c];
color = label_qcolor (m_labels[c]);
m_points->point_set()->set_color(*it, color);
}
@ -407,10 +402,10 @@ void Point_set_item_classification::change_color (int index, float* vmin, float*
QColor color (0, 0, 0);
int c = m_training[*it];
int c2 = m_classif[*it];
if (c != -1)
color = m_label_colors[std::size_t(c)];
color = label_qcolor (m_labels[std::size_t(c)]);
float div = 1;
if (c != c2)
div = 2;
@ -449,7 +444,7 @@ void Point_set_item_classification::change_color (int index, float* vmin, float*
return;
}
Feature_handle feature = m_features[corrected_index];
float min = std::numeric_limits<float>::max();
float max = -std::numeric_limits<float>::max();
@ -477,7 +472,7 @@ void Point_set_item_classification::change_color (int index, float* vmin, float*
float v = (feature->value(*it) - min) / (max - min);
if (v < 0.f) v = 0.f;
if (v > 1.f) v = 1.f;
m_points->point_set()->set_color(*it, ramp.r(v) * 255, ramp.g(v) * 255, ramp.b(v) * 255);
}
@ -489,7 +484,7 @@ void Point_set_item_classification::change_color (int index, float* vmin, float*
}
}
}
for (Point_set::const_iterator it = m_points->point_set()->first_selected();
it != m_points->point_set()->end(); ++ it)
m_points->point_set()->set_color(*it, 255, 0, 0);
@ -498,7 +493,7 @@ void Point_set_item_classification::change_color (int index, float* vmin, float*
int Point_set_item_classification::real_index_color() const
{
int out = m_index_color;
if (out == 0 && m_color == Point_set::Property_map<CGAL::Color>())
out = -1;
return out;
@ -524,7 +519,7 @@ void Point_set_item_classification::compute_features (std::size_t nb_scales, flo
delete m_generator;
reset_indices();
std::cerr << "Computing features with " << nb_scales << " scale(s) and ";
if (voxel_size == -1)
std::cerr << "automatic voxel size" << std::endl;
@ -537,9 +532,9 @@ void Point_set_item_classification::compute_features (std::size_t nb_scales, flo
bool normals = m_points->point_set()->has_normal_map();
if (normals)
normal_map = m_points->point_set()->normal_map();
bool colors = (m_color != Point_set::Property_map<CGAL::Color>());
Point_set::Property_map<boost::uint8_t> echo_map;
bool echo;
boost::tie (echo_map, echo) = m_points->point_set()->template property_map<boost::uint8_t>("echo");
@ -550,7 +545,7 @@ void Point_set_item_classification::compute_features (std::size_t nb_scales, flo
CGAL::Real_timer t;
t.start();
#ifdef CGAL_LINKED_WITH_TBB
m_features.begin_parallel_additions();
#endif
@ -562,7 +557,7 @@ void Point_set_item_classification::compute_features (std::size_t nb_scales, flo
m_generator->generate_color_based_features (m_features, m_color);
if (echo)
m_generator->generate_echo_based_features (m_features, echo_map);
#ifdef CGAL_LINKED_WITH_TBB
m_features.end_parallel_additions();
#endif
@ -635,7 +630,7 @@ void Point_set_item_classification::select_random_region()
current_idx ++;
else
unselected.push_back (*it);
}
else
{
@ -651,7 +646,7 @@ void Point_set_item_classification::select_random_region()
else
unselected.push_back (*it);
}
for (std::size_t i = 0; i < unselected.size(); ++ i)
*(m_points->point_set()->begin() + i) = unselected[i];
for (std::size_t i = 0; i < selected.size(); ++ i)
@ -665,7 +660,7 @@ void Point_set_item_classification::select_random_region()
void Point_set_item_classification::add_remaining_point_set_properties_as_features()
{
const std::vector<std::string>& prop = m_points->point_set()->base().properties();
for (std::size_t i = 0; i < prop.size(); ++ i)
{
if (prop[i] == "index" ||
@ -715,13 +710,13 @@ void Point_set_item_classification::train(int classifier, const QMultipleInputDi
m_label_probabilities.resize (m_labels.size());
for (std::size_t i = 0; i < m_label_probabilities.size(); ++ i)
m_label_probabilities[i].resize (m_points->point_set()->size(), -1);
std::vector<int> training (m_points->point_set()->size(), -1);
std::vector<int> indices (m_points->point_set()->size(), -1);
std::vector<std::size_t> nb_label (m_labels.size(), 0);
std::size_t nb_total = 0;
for (Point_set::const_iterator it = m_points->point_set()->begin();
it != m_points->point_set()->first_selected(); ++ it)
{
@ -803,24 +798,24 @@ void Point_set_item_classification::train(int classifier, const QMultipleInputDi
while (iss >> s)
hidden_layers.push_back (std::size_t(s));
}
m_neural_network->train (training,
dialog.get<QCheckBox>("restart")->isChecked(),
dialog.get<QSpinBox>("trials")->value(),
dialog.get<DoubleEdit>("learning_rate")->value(),
dialog.get<QSpinBox>("batch_size")->value(),
hidden_layers);
CGAL::Classification::classify<Concurrency_tag> (*(m_points->point_set()),
m_labels, *m_neural_network,
indices, m_label_probabilities);
#endif
}
for (Point_set::const_iterator it = m_points->point_set()->begin();
it != m_points->point_set()->first_selected(); ++ it)
m_classif[*it] = indices[*it];
if (m_index_color == 1 || m_index_color == 2)
change_color (m_index_color);
}
@ -869,7 +864,6 @@ bool Point_set_item_classification::run (int method, int classifier,
run (method, *m_neural_network, subdivisions, smoothing);
#endif
}
return true;
}

View File

@ -224,7 +224,8 @@ class Point_set_item_classification : public Item_classification_base
= new Scene_points_with_normal_item;
points_item->setName (QString("%1 (%2)").arg(name).arg(m_labels[label]->name().c_str()));
points_item->setColor (m_label_colors[label]);
points_item->setColor (label_qcolor (m_labels[label]));
for (Point_set::const_iterator it = m_points->point_set()->begin();
it != m_points->point_set()->end(); ++ it)
{
@ -243,7 +244,7 @@ class Point_set_item_classification : public Item_classification_base
{
points_item[i] = new Scene_points_with_normal_item;
points_item[i]->setName (QString("%1 (%2)").arg(name).arg(m_labels[i]->name().c_str()));
points_item[i]->setColor (m_label_colors[i]);
points_item[i]->setColor (label_qcolor (m_labels[i]));
items.push_back (points_item[i]);
}

View File

@ -28,10 +28,7 @@ Surface_mesh_item_classification::Surface_mesh_item_classification(Scene_surface
m_labels.add("vegetation");
m_labels.add("roof");
m_labels.add("facade");
for (std::size_t i = 0; i < m_labels.size(); ++ i)
m_label_colors.push_back (this->get_new_label_color (m_labels[i]->name()));
m_sowf = new Sum_of_weighted_features (m_labels, m_features);
m_ethz = NULL;
#ifdef CGAL_LINKED_WITH_OPENCV
@ -106,9 +103,9 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo
{
QColor color (128, 128, 128);
std::size_t c = m_classif[fd];
if (c != std::size_t(-1))
color = m_label_colors[c];
color = label_qcolor (m_labels[c]);
m_color[fd] = CGAL::Color(color.red(), color.green(), color.blue());
}
@ -120,10 +117,10 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo
QColor color (128, 128, 128);
std::size_t c = m_training[fd];
std::size_t c2 = m_classif[fd];
if (c != std::size_t(-1))
color = m_label_colors[c];
color = label_qcolor(m_labels[c]);
float div = 1;
if (c != c2)
div = 2;
@ -166,12 +163,12 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo
std::cerr << "Error: trying to access feature " << corrected_index << " out of " << m_features.size() << std::endl;
return;
}
Feature_handle feature = m_features[corrected_index];
float min = std::numeric_limits<float>::max();
float max = -std::numeric_limits<float>::max();
if (vmin != NULL && vmax != NULL
&& *vmin != std::numeric_limits<float>::infinity()
&& *vmax != std::numeric_limits<float>::infinity())
@ -189,18 +186,18 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo
min = feature->value(fd);
}
}
for(face_descriptor fd : faces(*(m_mesh->polyhedron())))
{
float v = (feature->value(fd) - min) / (max - min);
if (v < 0.f) v = 0.f;
if (v > 1.f) v = 1.f;
m_color[fd] = CGAL::Color((unsigned char)(ramp.r(v) * 255),
(unsigned char)(ramp.g(v) * 255),
(unsigned char)(ramp.b(v) * 255));
}
if (vmin != NULL && vmax != NULL)
{
*vmin = min;
@ -217,16 +214,16 @@ void Surface_mesh_item_classification::compute_features (std::size_t nb_scales,
std::cerr << "automatic voxel size" << std::endl;
else
std::cerr << "voxel size = " << voxel_size << std::endl;
m_features.clear();
if (m_generator != NULL)
delete m_generator;
Face_center_map fc_map (m_mesh->polyhedron());
m_generator = new Generator (*(m_mesh->polyhedron()), fc_map, nb_scales, voxel_size);
#ifdef CGAL_LINKED_WITH_TBB
m_features.begin_parallel_additions();
#endif
@ -237,7 +234,7 @@ void Surface_mesh_item_classification::compute_features (std::size_t nb_scales,
#ifdef CGAL_LINKED_WITH_TBB
m_features.end_parallel_additions();
#endif
delete m_sowf;
m_sowf = new Sum_of_weighted_features (m_labels, m_features);
if (m_ethz != NULL)
@ -280,7 +277,7 @@ void Surface_mesh_item_classification::train (int classifier, const QMultipleInp
std::vector<std::size_t> nb_label (m_labels.size(), 0);
std::size_t nb_total = 0;
for(face_descriptor fd : faces(*(m_mesh->polyhedron())))
{
training[fd] = m_training[fd];
@ -290,12 +287,12 @@ void Surface_mesh_item_classification::train (int classifier, const QMultipleInp
++ nb_total;
}
}
std::cerr << nb_total << " face(s) used for training ("
<< 100. * (nb_total / double(m_mesh->polyhedron()->faces().size())) << "% of the total):" << std::endl;
for (std::size_t i = 0; i < m_labels.size(); ++ i)
std::cerr << " * " << m_labels[i]->name() << ": " << nb_label[i] << " face(s)" << std::endl;
if (classifier == CGAL_CLASSIFICATION_SOWF_NUMBER)
{
m_sowf->train<Concurrency_tag>(training, dialog.get<QSpinBox>("trials")->value());
@ -362,14 +359,14 @@ void Surface_mesh_item_classification::train (int classifier, const QMultipleInp
while (iss >> s)
hidden_layers.push_back (std::size_t(s));
}
m_neural_network->train (training,
dialog.get<QCheckBox>("restart")->isChecked(),
dialog.get<QSpinBox>("trials")->value(),
dialog.get<DoubleEdit>("learning_rate")->value(),
dialog.get<QSpinBox>("batch_size")->value(),
hidden_layers);
CGAL::Classification::classify<Concurrency_tag> (m_mesh->polyhedron()->faces(),
m_labels, *m_neural_network,
indices, m_label_probabilities);
@ -425,6 +422,6 @@ bool Surface_mesh_item_classification::run (int method, int classifier,
run (method, *m_neural_network, subdivisions, smoothing);
#endif
}
return true;
}