Skip to content

Commit 5817ce5

Browse files
committed
Option to crop interest zone and filter min dbh trees
1 parent 8e3397d commit 5817ce5

File tree

5 files changed

+70
-8
lines changed

5 files changed

+70
-8
lines changed

raycloudtools/rayextract/rayextract.cpp

+20-4
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,14 @@ void usage(int exit_code = 1)
5555
std::cout << " --crop_length 1.0 - (-p) crops small branches to this distance from end" << std::endl;
5656
std::cout << " --distance_limit 1 - (-d) maximum distance between neighbour points in a tree" << std::endl;
5757
std::cout << " --height_min 2 - (-h) minimum height counted as a tree" << std::endl;
58+
std::cout << " --min_radius 0.01 - (-r) minimum tree radius to consider" << std::endl;
5859
std::cout << " --girth_height_ratio 0.12 - (-i) the amount up tree's height to estimate trunk girth" << std::endl;
5960
std::cout << " --global_taper 0.024 - (-a) force a taper value (diameter per length) for trees under global_taper_factor of max tree height. Use 0 to estimate global taper from the data" << std::endl;
6061
std::cout << " --global_taper_factor 0.3- (-o) 1 estimates same taper for whole scan, 0 is per-tree tapering. Like a soft cutoff at this amount of max tree height" << std::endl;
6162
std::cout << " --gravity_factor 0.3 - (-f) larger values preference vertical trees" << std::endl;
6263
std::cout << " --branch_segmentation- (-b) _segmented.ply is per branch segment" << std::endl;
6364
std::cout << " --grid_width 10 - (-w) crops results assuming cloud has been gridded with given width" << std::endl;
65+
std::cout << " --grid_origin 0,0,0 - location of origin within grid cell that overlaps it. Defaults to a cell-centre origin (at grid_width/2 in each axis) matching raysplit grid. 0,0,0 is for a vertex origin." << std::endl;
6466
std::cout << " --use_rays - (-u) use rays to reduce trunk radius overestimation in noisy cloud data" << std::endl;
6567
std::cout << " (for internal constants -c -g -s see source file rayextract)" << std::endl;
6668
// These are the internal parameters that I don't expose as they are 'advanced' only, you shouldn't need to adjust them
@@ -92,6 +94,9 @@ int rayExtract(int argc, char *argv[])
9294
}
9395
ray::FileArgument cloud_file, mesh_file, trunks_file, trees_file, leaf_file;
9496
ray::TextArgument forest("forest"), trees("trees"), trunks("trunks"), terrain("terrain"), leaves("leaves");
97+
98+
ray::Vector3dArgument grid_origin;
99+
ray::OptionalKeyValueArgument grid_origin_option("grid_origin", &grid_origin);
95100
ray::OptionalKeyValueArgument groundmesh_option("ground", 'g', &mesh_file);
96101
ray::OptionalKeyValueArgument trunks_option("trunks", 't', &trunks_file);
97102
ray::DoubleArgument gradient(0.001, 1000.0, 1.0), global_taper(0.0, 1.0), global_taper_factor(0.0, 1.0);
@@ -102,7 +107,7 @@ int rayExtract(int argc, char *argv[])
102107
ray::DoubleArgument max_diameter(0.01, 100.0), distance_limit(0.01, 10.0), height_min(0.01, 1000.0),
103108
min_diameter(0.01, 100.0), leaf_area(0.00001, 1.0, 0.002), leaf_droop(0.0, 10.0, 0.1), crop_length(0.01, 100.0);;
104109
ray::DoubleArgument girth_height_ratio(0.001, 0.5), length_to_radius(0.01, 10000.0), cylinder_length_to_width(0.1, 20.0), gap_ratio(0.01, 10.0),
105-
span_ratio(0.01, 10.0);
110+
span_ratio(0.01, 10.0), min_radius(0.01, 100.0);
106111
ray::DoubleArgument gravity_factor(0.0, 100.0), grid_width(1.0, 100000.0),
107112
grid_overlap(0.0, 0.9);
108113
ray::OptionalKeyValueArgument max_diameter_option("max_diameter", 'm', &max_diameter);
@@ -112,6 +117,8 @@ int rayExtract(int argc, char *argv[])
112117
ray::OptionalKeyValueArgument girth_height_ratio_option("girth_height_ratio", 'i', &girth_height_ratio);
113118
ray::OptionalKeyValueArgument cylinder_length_to_width_option("cylinder_length_to_width", 'c',
114119
&cylinder_length_to_width);
120+
121+
ray::OptionalKeyValueArgument min_radius_option("min_radius", 'r', &min_radius);
115122
ray::OptionalKeyValueArgument gap_ratio_option("gap_ratio", 'g', &gap_ratio);
116123
ray::OptionalKeyValueArgument span_ratio_option("span_ratio", 's', &span_ratio);
117124
ray::OptionalKeyValueArgument gravity_factor_option("gravity_factor", 'f', &gravity_factor);
@@ -137,7 +144,8 @@ int rayExtract(int argc, char *argv[])
137144
argc, argv, { &trees, &cloud_file, &mesh_file },
138145
{ &max_diameter_option, &distance_limit_option, &height_min_option, &crop_length_option, &girth_height_ratio_option,
139146
&cylinder_length_to_width_option, &gap_ratio_option, &span_ratio_option, &gravity_factor_option,
140-
&segment_branches, &grid_width_option, &global_taper_option, &global_taper_factor_option, &use_rays, &verbose });
147+
&segment_branches, &grid_width_option, &global_taper_option, &global_taper_factor_option, &use_rays, &verbose,
148+
&grid_origin_option, &min_radius_option });
141149
bool extract_leaves = ray::parseCommandLine(argc, argv, { &leaves, &cloud_file, &trees_file }, { &leaf_option, &leaf_area_option, &leaf_droop_option, &stalks });
142150

143151

@@ -226,8 +234,16 @@ int rayExtract(int argc, char *argv[])
226234
if (global_taper_factor_option.isSet())
227235
{
228236
params.global_taper_factor = global_taper_factor.value();
229-
}
230-
params.use_rays = use_rays.isSet();
237+
}
238+
if (grid_origin_option.isSet())
239+
{
240+
params.grid_origin = grid_origin.value();
241+
}
242+
if (min_radius_option.isSet())
243+
{
244+
params.min_radius = min_radius.value();
245+
}
246+
params.use_rays = use_rays.isSet();
231247
params.segment_branches = segment_branches.isSet();
232248

233249
ray::Trees trees(cloud, offset, mesh, params, verbose.isSet());

raylib/extraction/raytrees.cpp

+13-3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ TreesParams::TreesParams()
2323
, segment_branches(false)
2424
, global_taper(0.012)
2525
, global_taper_factor(0.3)
26+
, grid_origin(0, 0, 0)
2627
{}
2728

2829
/// The main reconstruction algorithm
@@ -141,7 +142,15 @@ Trees::Trees(Cloud &cloud, const Eigen::Vector3d &offset, const Mesh &mesh, cons
141142
sections_[sec_].total_weight = 1e-10;
142143
sections_[sec_].ends.clear(); // so this trunk is not ever used
143144
continue;
144-
}
145+
}
146+
147+
if (params_->min_radius && estimated_radius < params_->min_radius)
148+
{
149+
sections_[sec_].tip = base + Eigen::Vector3d(0, 0, 0.01);
150+
sections_[sec_].total_weight = 1e-10;
151+
sections_[sec_].ends.clear();
152+
continue;
153+
}
145154
sections_[sec_].tip = best_tip;
146155
sections_[sec_].ends = best_ends;
147156
nodes = best_nodes;
@@ -1050,13 +1059,14 @@ void Trees::removeOutOfBoundSections(const Cloud &cloud, Eigen::Vector3d &min_bo
10501059
{
10511060
const double width = params_->grid_width;
10521061
cloud.calcBounds(&min_bound, &max_bound);
1053-
const Eigen::Vector3d mid = (min_bound + max_bound)/2.0 + offset;
1062+
const Eigen::Vector3d mid = (min_bound + max_bound) / 2.0 + offset + params_->grid_origin;
10541063
const Eigen::Vector2d inds(std::round(mid[0] / width), std::round(mid[1] / width));
10551064
min_bound[0] = width * (inds[0] - 0.5) - offset[0];
10561065
min_bound[1] = width * (inds[1] - 0.5) - offset[1];
10571066
max_bound[0] = width * (inds[0] + 0.5) - offset[0];
10581067
max_bound[1] = width * (inds[1] + 0.5) - offset[1];
1059-
std::cout << "min bound: " << (min_bound+offset).transpose() << ", max bound: " << (max_bound+offset).transpose() << std::endl;
1068+
std::cerr << "min bound: " << (min_bound + offset).transpose() << ", max bound: " << (max_bound + offset).transpose()
1069+
<< " offset " << offset << std::endl;
10601070

10611071
// disable trees out of bounds
10621072
for (auto &section : sections_)

raylib/extraction/raytrees.h

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ struct RAYLIB_EXPORT TreesParams
3232
double global_taper; // forced global taper, uses global_taper_factor to define how much it is applied
3333
double global_taper_factor; // 0 estimates per-tree tapering, 1 uses per-scan tapering, 0.5 is mid-way on mid-weight trees
3434
bool use_rays; // use the full rays in order to estimate a smaller radius when points are not all on the real branch
35+
Eigen::Vector3d grid_origin; // if using a grid, then this is the left corner of the interest zone
36+
double min_radius; // minimum radius for a branch
3537
};
3638

3739
struct BranchSection; // forwards declaration

raylib/raylaz.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@ bool readLas(const std::string &file_name,
2323
{
2424
#if RAYLIB_WITH_LAS
2525
std::cout << "readLas: filename: " << file_name << std::endl;
26+
std::ifstream file(file_name);
27+
28+
if (file)
29+
{
30+
std::cout << "File exists!" << std::endl;
31+
}
32+
else
33+
{
34+
std::cout << "File does not exist." << std::endl;
35+
}
2636

2737
std::ifstream ifs;
2838
ifs.open(file_name.c_str(), std::ios::in | std::ios::binary);

raylib/rayparse.cpp

+25-1
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ bool Vector3dArgument::parse(int argc, char *argv[], int &index, bool set_value)
240240
if (val < min_value_ || val > max_value_)
241241
{
242242
std::cout << "Please set argument " << index << " within the range: " << min_value_ << " to " << max_value_
243-
<< std::endl;
243+
<< " provided " << val << std::endl;
244244
return false;
245245
}
246246
value_[i] = val;
@@ -412,4 +412,28 @@ bool OptionalKeyValueArgument::parse(int argc, char *argv[], int &index, bool se
412412
return false;
413413
}
414414

415+
bool Optional3DVectorArgument::parse(int argc, char *argv[], int &index, bool set_value)
416+
{
417+
if (index >= argc)
418+
return false;
419+
420+
std::string str(argv[index]);
421+
if (str == ("--" + name_))
422+
{
423+
if (set_value)
424+
is_set_ = true;
425+
426+
index++;
427+
if (!value_->parse(argc, argv, index, set_value))
428+
{
429+
index--;
430+
return false;
431+
}
432+
433+
return true;
434+
}
435+
436+
return false;
437+
}
438+
415439
} // namespace ray

0 commit comments

Comments
 (0)