|
@@ -366,7 +366,7 @@ namespace graft_cv {
|
|
|
occluded_seedling_detect_by_leaf(cloud_ror, leaf_indices);
|
|
|
if (m_pLogger) {
|
|
|
stringstream buff;
|
|
|
- buff << m_pcdId << ": leafoccl status: ";
|
|
|
+ buff << m_pcdId << ": leaf occlusion status: ";
|
|
|
for (auto&st : m_root_center_with_occlusion) {
|
|
|
buff <<st<< "\t";
|
|
|
}
|
|
@@ -724,12 +724,14 @@ namespace graft_cv {
|
|
|
double stem_diameter = m_cparam.rs_grab_stem_diameter;
|
|
|
double y_min = m_cparam.rs_grab_ymin;
|
|
|
double y_max = m_cparam.rs_grab_ymax;
|
|
|
+ double occlusion_height_ratio = m_cparam.rs_grab_valid_occlusion_ratio;
|
|
|
|
|
|
if (m_dtype == 0) {
|
|
|
//th_pcd_size = m_cparam.sc_grab_seedling_min_pts;
|
|
|
stem_diameter = m_cparam.sc_grab_stem_diameter;
|
|
|
y_min = m_cparam.sc_grab_ymin;
|
|
|
y_max = m_cparam.sc_grab_ymax;
|
|
|
+ occlusion_height_ratio = m_cparam.sc_grab_valid_occlusion_ratio;
|
|
|
}
|
|
|
int th_pcd_size = int(0.333 * stem_diameter * (y_max - y_min) / m_cloud_mean_dist / m_cloud_mean_dist);
|
|
|
std::vector<pcl::PointXYZ> aabb_mins_maxs;
|
|
@@ -738,11 +740,12 @@ namespace graft_cv {
|
|
|
for (int i = 0; i < m_root_centers.size(); ++i) {
|
|
|
CStemResult& rc = m_root_centers.at(i);
|
|
|
pcl::PointXYZ aabb_min;
|
|
|
- pcl::PointXYZ aabb_max;
|
|
|
+ pcl::PointXYZ aabb_max;
|
|
|
+ double valid_y_ratio = 0.0;
|
|
|
get_leaf_point_count_inbox(rc, in_cloud, leaf_idx,
|
|
|
aabb_min, aabb_max,
|
|
|
total_cnt, leaf_cnt,
|
|
|
- total_cx, leaf_cx);
|
|
|
+ total_cx, leaf_cx, valid_y_ratio);
|
|
|
|
|
|
double leaf_ratio = 0.0;
|
|
|
if (total_cnt == 0) {
|
|
@@ -759,7 +762,7 @@ namespace graft_cv {
|
|
|
}
|
|
|
pcd_cnt.push_back(total_cnt);
|
|
|
bool has_seedling = total_cnt > th_pcd_size;
|
|
|
- if (has_seedling) {
|
|
|
+ if (has_seedling && valid_y_ratio>occlusion_height_ratio) {
|
|
|
m_root_center_with_occlusion.at(i) = 2;
|
|
|
}
|
|
|
|
|
@@ -957,17 +960,20 @@ namespace graft_cv {
|
|
|
int& total_cnt, //output
|
|
|
int& leaf_cnt, //output
|
|
|
double& total_cx, //output
|
|
|
- double& leaf_cx //output
|
|
|
+ double& leaf_cx, //output
|
|
|
+ double& valid_y_ratio//output
|
|
|
)
|
|
|
{
|
|
|
//计算每一个穴位叶子遮挡的点云数量(以及整体点云数量),并计算x方向的中心
|
|
|
double seedling_distance = m_cparam.rs_grab_seedling_dist;
|
|
|
double min_y = m_cparam.rs_grab_ymin;
|
|
|
double max_y = m_cparam.rs_grab_ymax;
|
|
|
+ double stem_diameter = m_cparam.rs_grab_stem_diameter;
|
|
|
if (m_dtype == 0) {
|
|
|
seedling_distance = m_cparam.sc_grab_seedling_dist;
|
|
|
min_y = m_cparam.sc_grab_ymin;
|
|
|
max_y = m_cparam.sc_grab_ymax;
|
|
|
+ stem_diameter = m_cparam.sc_grab_stem_diameter;
|
|
|
}
|
|
|
double min_x = sr.root_x - 0.5 * seedling_distance;
|
|
|
double max_x = sr.root_x + 0.5 * seedling_distance;
|
|
@@ -986,6 +992,12 @@ namespace graft_cv {
|
|
|
leaf_cx = 1.0e6;
|
|
|
std::vector<double>xs;
|
|
|
|
|
|
+ std::vector<int> y_counts;
|
|
|
+ int y_length = int(max_y - min_y);
|
|
|
+ y_counts.assign(y_length, 0);
|
|
|
+ int y_idx = 0;
|
|
|
+ valid_y_ratio = 0.0;
|
|
|
+
|
|
|
for (auto&pt : in_cloud->points) {
|
|
|
if (pt.y >= min_y && pt.y <= max_y &&
|
|
|
pt.x >= min_x && pt.x <= max_x &&
|
|
@@ -993,12 +1005,22 @@ namespace graft_cv {
|
|
|
{
|
|
|
total_cnt++;
|
|
|
xs.push_back(pt.x);
|
|
|
+ y_idx = int(pt.y - min_y);
|
|
|
+ if (y_idx >= 0 && y_idx < y_length) {
|
|
|
+ y_counts.at(y_idx) += 1;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
if (total_cnt == 0) { return; }
|
|
|
int med_idx = int(0.5 * xs.size());
|
|
|
std::sort(xs.begin(), xs.end());
|
|
|
total_cx = xs.at(med_idx);
|
|
|
+
|
|
|
+ double th_width = stem_diameter / m_cloud_mean_dist;
|
|
|
+ for (auto&c : y_counts) {
|
|
|
+ if (c >= th_width) { valid_y_ratio += 1; }
|
|
|
+ }
|
|
|
+ valid_y_ratio /= (max_y - min_y);
|
|
|
|
|
|
//leaf center
|
|
|
xs.clear();
|
|
@@ -1431,6 +1453,15 @@ void CRootStockGrabPoint::line_filter(
|
|
|
target_filtered_root.clear();
|
|
|
if (target_root.size() == 0) { return; }
|
|
|
|
|
|
+ double stem_height_ratio = m_cparam.rs_grab_valid_stem_ratio;
|
|
|
+ float stem_radius = m_cparam.rs_grab_stem_diameter / 2.0;
|
|
|
+ int min_stem_pts = m_cparam.rs_grab_stem_min_pts;
|
|
|
+ if (m_dtype == 0) {
|
|
|
+ stem_radius = m_cparam.sc_grab_stem_diameter / 2.0;
|
|
|
+ min_stem_pts = m_cparam.sc_grab_stem_min_pts;
|
|
|
+ stem_height_ratio = m_cparam.sc_grab_valid_stem_ratio;
|
|
|
+ }
|
|
|
+
|
|
|
for (auto&p : target_root) {
|
|
|
// 构建box,获取植株点云
|
|
|
pcl::PointCloud<pcl::PointXYZ>::Ptr seedling_inbox(new pcl::PointCloud<pcl::PointXYZ>);
|
|
@@ -1455,11 +1486,7 @@ void CRootStockGrabPoint::line_filter(
|
|
|
pcl::copyPointCloud(*in_cloud, inbox_idx, *seedling_inbox);
|
|
|
|
|
|
//植株点云直线查找
|
|
|
- //找到inbox点云中的直线
|
|
|
- float stem_radius = m_cparam.rs_grab_stem_diameter / 2.0;
|
|
|
- if (m_dtype == 0) {
|
|
|
- stem_radius = m_cparam.sc_grab_stem_diameter / 2.0;
|
|
|
- }
|
|
|
+ //找到inbox点云中的直线
|
|
|
pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients);
|
|
|
pcl::PointIndices::Ptr inliers(new pcl::PointIndices);
|
|
|
pcl::SACSegmentation<pcl::PointXYZ> seg;
|
|
@@ -1489,9 +1516,7 @@ void CRootStockGrabPoint::line_filter(
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- //点数过滤
|
|
|
- int min_stem_pts = m_cparam.rs_grab_stem_min_pts;
|
|
|
- if (m_dtype == 0) { min_stem_pts = m_cparam.sc_grab_stem_min_pts; }
|
|
|
+ //点数过滤
|
|
|
if (inliers->indices.size() < int(min_stem_pts / 2)) { continue; }
|
|
|
//y方向分布范围滤波
|
|
|
float y_length_th = 10.0;
|
|
@@ -1499,7 +1524,7 @@ void CRootStockGrabPoint::line_filter(
|
|
|
pcl::PointXYZ max_v;
|
|
|
pcl::getMinMax3D(*stem_cloud, min_v, max_v);
|
|
|
float dy = max_v.y - min_v.y;
|
|
|
- if (dy<y_length_th && dy / (ymax - ymin) < 0.25) { continue; }
|
|
|
+ if (dy<y_length_th || dy / (ymax - ymin) < stem_height_ratio) { continue; }
|
|
|
//y方向分布中心滤波
|
|
|
float dy_c = 0.5*(max_v.y + min_v.y);
|
|
|
if ((dy_c - ymin) / (ymax - ymin) > 0.75) { continue; }
|
|
@@ -1574,7 +1599,7 @@ void CRootStockGrabPoint::line_filter(
|
|
|
|
|
|
}
|
|
|
|
|
|
- if (longest_segment<10.0 && valid_length / (ymax - ymin) < 0.35) { continue; }
|
|
|
+ if (longest_segment<10.0 || valid_length / (ymax - ymin) < stem_height_ratio) { continue; }
|
|
|
|
|
|
|
|
|
float min_y = 10000.0;
|
|
@@ -1649,11 +1674,21 @@ void CRootStockGrabPoint::line_filter(
|
|
|
)
|
|
|
{
|
|
|
first_row_size = 0;
|
|
|
+
|
|
|
// 确定植株inbox范围
|
|
|
float hole_step = m_cparam.rs_grab_seedling_dist - 5.0; //穴盘中穴间距
|
|
|
+ float ymin = m_cparam.rs_grab_ymin;
|
|
|
+ float ymax = m_cparam.rs_grab_ymax;
|
|
|
+ double stem_height_ratio = m_cparam.rs_grab_valid_stem_ratio;
|
|
|
+ double radius = m_cparam.rs_grab_stem_diameter;
|
|
|
if (m_dtype == 0) {
|
|
|
- hole_step = m_cparam.sc_grab_seedling_dist - 5.0;
|
|
|
+ hole_step = m_cparam.sc_grab_seedling_dist - 5.0;
|
|
|
+ ymin = m_cparam.sc_grab_ymin;
|
|
|
+ ymax = m_cparam.sc_grab_ymax;
|
|
|
+ stem_height_ratio = m_cparam.sc_grab_valid_stem_ratio;
|
|
|
+ radius = m_cparam.sc_grab_stem_diameter;
|
|
|
}
|
|
|
+
|
|
|
float hole_step_radius = 2.0 * hole_step / 3.0;
|
|
|
|
|
|
// 点云降维到xz平面,y=0
|
|
@@ -1663,11 +1698,7 @@ void CRootStockGrabPoint::line_filter(
|
|
|
pt.y = 0.0;
|
|
|
}
|
|
|
|
|
|
- // 在xz平面内统计点的密度
|
|
|
- double radius = m_cparam.rs_grab_stem_diameter;
|
|
|
- if (m_dtype == 0) {
|
|
|
- radius = m_cparam.sc_grab_stem_diameter;
|
|
|
- }
|
|
|
+ // 在xz平面内统计点的密度
|
|
|
std::vector<int> counter;
|
|
|
pcl::KdTreeFLANN<pcl::PointXYZ> kdtree;
|
|
|
kdtree.setInputCloud(cloud2d);
|
|
@@ -1695,13 +1726,7 @@ void CRootStockGrabPoint::line_filter(
|
|
|
}
|
|
|
// 生成植株的中心及box
|
|
|
std::vector<pcl::PointXYZ>clt_root;
|
|
|
- std::vector<pcl::PointXYZ> clt_box;
|
|
|
- float ymin = m_cparam.rs_grab_ymin;
|
|
|
- float ymax = m_cparam.rs_grab_ymax;
|
|
|
- if (m_dtype == 0) {
|
|
|
- ymin = m_cparam.sc_grab_ymin;
|
|
|
- ymax = m_cparam.sc_grab_ymax;
|
|
|
- }
|
|
|
+ std::vector<pcl::PointXYZ> clt_box;
|
|
|
gen_all_seedling_positions(in_cloud->points.at(max_density_idx), clt_root);
|
|
|
// 显示生成的每一个候选框
|
|
|
/*if (m_cparam.image_show) {
|
|
@@ -1728,7 +1753,8 @@ void CRootStockGrabPoint::line_filter(
|
|
|
// 每个位置点云情况,过滤
|
|
|
std::vector<int> valid_index; //初步有效的矩形index
|
|
|
std::vector<int> valid_box_pts; //立方体内点云数量
|
|
|
- std::vector<float>valid_box_cc_dist;//重心和矩形中心距离
|
|
|
+ std::vector<float>valid_box_cc_dist;//重心和矩形中心距离
|
|
|
+
|
|
|
for (size_t i = 0; i < clt_root.size();++i) {
|
|
|
pcl::PointXYZ &p = clt_root.at(i);
|
|
|
pcl::PointCloud<pcl::PointXYZ>::Ptr seedling_inbox(new pcl::PointCloud<pcl::PointXYZ>);
|
|
@@ -1758,7 +1784,7 @@ void CRootStockGrabPoint::line_filter(
|
|
|
pcl::PointXYZ max_v;
|
|
|
pcl::getMinMax3D(*seedling_inbox, min_v, max_v);
|
|
|
float dy = max_v.y - min_v.y;
|
|
|
- if (dy / (ymax - ymin) < 0.35) { continue; }
|
|
|
+ if (dy / (ymax - ymin) < stem_height_ratio) { continue; }
|
|
|
//y方向分布中心滤波
|
|
|
float dy_c = 0.5*(max_v.y + min_v.y);
|
|
|
if ((dy_c-ymin) / (ymax - ymin) > 0.75) { continue; }
|