|
@@ -42,7 +42,8 @@ namespace graft_cv {
|
|
|
m_1st_row_zmean_sc(-1.0),
|
|
|
m_cloud_mean_dist(0.0),
|
|
|
m_pImginfoResult(0),
|
|
|
- m_pStemInfos(0)
|
|
|
+ m_pStemInfos(0),
|
|
|
+ m_pSeedlingStatus(0)
|
|
|
{
|
|
|
}
|
|
|
void CRootStockGrabPoint::clear_imginfo() {
|
|
@@ -59,6 +60,10 @@ namespace graft_cv {
|
|
|
delete m_pStemInfos;
|
|
|
m_pStemInfos = 0;
|
|
|
}
|
|
|
+ if (m_pSeedlingStatus) {
|
|
|
+ delete m_pSeedlingStatus;
|
|
|
+ m_pSeedlingStatus = 0;
|
|
|
+ }
|
|
|
}
|
|
|
float* CRootStockGrabPoint::get_raw_point_cloud(int &data_size)
|
|
|
{
|
|
@@ -193,7 +198,7 @@ namespace graft_cv {
|
|
|
seedling_distance, holes_number,
|
|
|
x_min, x_max, z_min, z_max,
|
|
|
m_pcdId, m_pLogger);
|
|
|
- }
|
|
|
+ }
|
|
|
return rst;
|
|
|
}
|
|
|
|
|
@@ -312,6 +317,28 @@ namespace graft_cv {
|
|
|
buff << m_pcdId <<": cloud_mean_dist = " << m_cloud_mean_dist;
|
|
|
m_pLogger->INFO(buff.str());
|
|
|
}
|
|
|
+
|
|
|
+ if (m_pSeedlingStatus == 0) {
|
|
|
+
|
|
|
+ double x_min = m_cparam.rs_grab_xmin;
|
|
|
+ double x_max = m_cparam.rs_grab_xmax;
|
|
|
+
|
|
|
+ if (m_dtype == 0) {
|
|
|
+ x_min = m_cparam.sc_grab_xmin;
|
|
|
+ x_max = m_cparam.sc_grab_xmax;
|
|
|
+ }
|
|
|
+ m_pSeedlingStatus = new CSeedlingStatus(m_dtype, 5.0, x_min, x_max, m_cloud_mean_dist, m_pLogger);
|
|
|
+ std::vector<double>root_cxs;
|
|
|
+ for (auto&sr : m_root_centers) {
|
|
|
+ root_cxs.push_back(sr.root_x);
|
|
|
+ }
|
|
|
+ m_pSeedlingStatus->set_x_centers(root_cxs);
|
|
|
+ }
|
|
|
+
|
|
|
+ std::vector<int>xhist_inbox;
|
|
|
+ get_point_x_hist(xhist_inbox);
|
|
|
+ m_pSeedlingStatus->append_hist(xhist_inbox, m_root_center_with_seedling_history);
|
|
|
+
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
// 4 对截取的点云进行ror滤除大面积联通区域,剔除叶片
|
|
@@ -333,6 +360,13 @@ namespace graft_cv {
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
//判断m_root_centers位置上是否有叶片遮挡
|
|
|
occluded_seedling_detect_by_leaf(cloud_ror, leaf_indices);
|
|
|
+ //用m_root_center_with_seedling_history对叶子遮挡的结果进行过滤
|
|
|
+ /*for (int j = 0; j < m_root_center_with_seedling.size(); ++j) {
|
|
|
+ if (m_root_center_with_seedling.at(j) && !m_root_center_with_seedling_history.at(j)) {
|
|
|
+ m_root_center_with_seedling.at(j) = false;
|
|
|
+ }
|
|
|
+ }*/
|
|
|
+ m_root_center_with_seedling = m_root_center_with_seedling_history;
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@@ -525,12 +559,21 @@ namespace graft_cv {
|
|
|
|
|
|
double grab_fork_ybt = m_cparam.rs_grab_fork_ybt;
|
|
|
double grab_offset = m_cparam.rs_grab_offset;
|
|
|
+ double grab_seedling_dist = m_cparam.rs_grab_seedling_dist;
|
|
|
if (m_dtype == 0) {
|
|
|
grab_fork_ybt = m_cparam.sc_grab_fork_ybt;
|
|
|
grab_offset = m_cparam.sc_grab_offset;
|
|
|
+ grab_seedling_dist = m_cparam.sc_grab_seedling_dist;
|
|
|
+ }
|
|
|
+
|
|
|
+ //cx位置, 默认选择穴位中心,如果leaf中心有值,用叶子中心
|
|
|
+ double cx = m_root_centers.at(selected_idx).root_x;
|
|
|
+ double leaf_cx = m_root_center_leaf_cx.at(selected_idx);
|
|
|
+ if (fabs(leaf_cx - cx) < grab_seedling_dist*0.33) {
|
|
|
+ cx = leaf_cx;
|
|
|
}
|
|
|
|
|
|
- selected_pt_ref.x = m_root_centers.at(selected_idx).root_x;
|
|
|
+ selected_pt_ref.x = cx;
|
|
|
selected_pt_ref.y = grab_fork_ybt;
|
|
|
selected_pt_ref.z = m_root_centers.at(selected_idx).root_z;
|
|
|
selected_pt = selected_pt_ref;
|
|
@@ -648,7 +691,14 @@ obstructed:
|
|
|
grab_offset = m_cparam.sc_grab_offset;
|
|
|
}
|
|
|
|
|
|
- selected_pt_ref.x = m_root_centers.at(selected_idx).root_x;
|
|
|
+ //cx位置, 默认选择穴位中心,如果leaf中心有值,用叶子中心
|
|
|
+ double cx = m_root_centers.at(selected_idx).root_x;
|
|
|
+ double leaf_cx = m_root_center_leaf_cx.at(selected_idx);
|
|
|
+ if (fabs(leaf_cx - cx) < seedling_distance*0.33) {
|
|
|
+ cx = leaf_cx;
|
|
|
+ }
|
|
|
+
|
|
|
+ selected_pt_ref.x = cx;
|
|
|
selected_pt_ref.y = grab_fork_ybt;
|
|
|
selected_pt_ref.z = m_root_centers.at(selected_idx).root_z;
|
|
|
selected_pt = selected_pt_ref;
|
|
@@ -684,6 +734,10 @@ obstructed:
|
|
|
//所以改成整个空间点云数量做判别--2024-3-2
|
|
|
m_root_center_with_seedling.clear();
|
|
|
m_root_center_with_seedling.assign(m_root_centers.size(), false);
|
|
|
+
|
|
|
+ m_root_center_leaf_cx.clear();
|
|
|
+ m_root_center_leaf_cx.assign(m_root_centers.size(), 1.0e6);
|
|
|
+
|
|
|
std::vector<int> pcd_cnt;
|
|
|
//int th_pcd_size = m_cparam.rs_grab_seedling_min_pts;
|
|
|
double stem_diameter = m_cparam.rs_grab_stem_diameter;
|
|
@@ -696,15 +750,34 @@ obstructed:
|
|
|
y_min = m_cparam.sc_grab_ymin;
|
|
|
y_max = m_cparam.sc_grab_ymax;
|
|
|
}
|
|
|
- int th_pcd_size = 0.333 * stem_diameter * (y_max - y_min) / m_cloud_mean_dist / m_cloud_mean_dist;
|
|
|
- std::vector<pcl::PointXYZ> aabb_mins_maxs;
|
|
|
+ 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;
|
|
|
+ int total_cnt, leaf_cnt; //穴位上inbox的点云数量,叶子点云数量
|
|
|
+ double total_cx, leaf_cx;//穴位上inbox的点云中位x,叶子点云中位x
|
|
|
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;
|
|
|
- int cnt = get_point_count_inbox(rc, aabb_min, aabb_max, in_cloud);
|
|
|
- pcd_cnt.push_back(cnt);
|
|
|
- bool has_seedling = cnt > th_pcd_size;
|
|
|
+ pcl::PointXYZ aabb_max;
|
|
|
+ get_leaf_point_count_inbox(rc, in_cloud, leaf_idx,
|
|
|
+ aabb_min, aabb_max,
|
|
|
+ total_cnt, leaf_cnt,
|
|
|
+ total_cx, leaf_cx);
|
|
|
+
|
|
|
+ double leaf_ratio = 0.0;
|
|
|
+ if (total_cnt == 0) {
|
|
|
+ leaf_ratio = 0.0;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ leaf_ratio = double(leaf_cnt) / double(total_cnt);
|
|
|
+ }
|
|
|
+ if (leaf_ratio > 0.25) {
|
|
|
+ m_root_center_leaf_cx.at(i) = leaf_cx;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ m_root_center_leaf_cx.at(i) = total_cx;
|
|
|
+ }
|
|
|
+ pcd_cnt.push_back(total_cnt);
|
|
|
+ bool has_seedling = total_cnt > th_pcd_size;
|
|
|
m_root_center_with_seedling.at(i) = has_seedling;
|
|
|
aabb_mins_maxs.push_back(aabb_min);
|
|
|
aabb_mins_maxs.push_back(aabb_max);
|
|
@@ -712,7 +785,7 @@ obstructed:
|
|
|
|
|
|
if (m_pLogger) {
|
|
|
stringstream buff;
|
|
|
- buff << m_pcdId << ": root positions points size " << m_root_centers.size() << " centers\n";
|
|
|
+ buff << m_pcdId << ": root positions points size [inbox] " << m_root_centers.size() << " centers, size_threshold: "<< th_pcd_size<<"\n";
|
|
|
for (int i = 0; i < m_root_centers.size();++i) {
|
|
|
CStemResult& sr = m_root_centers.at(i);
|
|
|
|
|
@@ -773,12 +846,99 @@ obstructed:
|
|
|
// return count;
|
|
|
//}
|
|
|
|
|
|
- int CRootStockGrabPoint::get_point_count_inbox(const CStemResult& sr,
|
|
|
- pcl::PointXYZ& aabb_min,
|
|
|
- pcl::PointXYZ& aabb_max,
|
|
|
- pcl::PointCloud<pcl::PointXYZ>::Ptr in_cloud //input 输入点云数据
|
|
|
+ //统计inbox点云在x方向的分布情况
|
|
|
+ void CRootStockGrabPoint::get_point_x_hist(
|
|
|
+ std::vector<int>& x_hist //output
|
|
|
+ )
|
|
|
+ {
|
|
|
+ double seedling_distance = m_cparam.rs_grab_seedling_dist;
|
|
|
+ double x_min = m_cparam.rs_grab_xmin;
|
|
|
+ double x_max = m_cparam.rs_grab_xmax;
|
|
|
+ double y_min = m_cparam.rs_grab_ymin;
|
|
|
+ double y_max = y_min + 150.0;
|
|
|
+ double z_min = m_cparam.rs_grab_zmin - seedling_distance;
|
|
|
+ double z_max = m_cparam.rs_grab_zmax + seedling_distance/4.0;
|
|
|
+
|
|
|
+ if (m_dtype == 0) {
|
|
|
+ //穗苗
|
|
|
+ seedling_distance = m_cparam.sc_grab_seedling_dist;
|
|
|
+ x_min = m_cparam.sc_grab_xmin;
|
|
|
+ x_max = m_cparam.sc_grab_xmax;
|
|
|
+ y_min = m_cparam.sc_grab_ymin;
|
|
|
+ y_max = y_min + 150.0;
|
|
|
+ z_min = m_cparam.sc_grab_zmin - seedling_distance;
|
|
|
+ z_max = m_cparam.sc_grab_zmax;
|
|
|
+ }
|
|
|
+ double binw = 5;
|
|
|
+ int x0 = int(x_min);
|
|
|
+ int x1 = int(x_max);
|
|
|
+ int h_size = int((x1 - x0)/binw);
|
|
|
+ int idx = 0;
|
|
|
+ x_hist.assign(h_size, 0);
|
|
|
+
|
|
|
+ for (auto&pt : m_raw_cloud->points) {
|
|
|
+ if(pt.y >= y_min && pt.y < y_max &&
|
|
|
+ pt.x >=x_min && pt.x < x_max &&
|
|
|
+ pt.z >= z_min && pt.z < z_max)
|
|
|
+ {
|
|
|
+ idx = int((pt.x - x0) / binw);
|
|
|
+ x_hist.at(idx)++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //显示结果
|
|
|
+ if (m_cparam.image_show) {
|
|
|
+ pcl::visualization::PCLVisualizer viewer(m_pcdId + std::string(": x histogram"));
|
|
|
+ viewer.setBackgroundColor(0.35, 0.35, 0.35);
|
|
|
+ viewer.addCoordinateSystem();
|
|
|
+ viewer.addPointCloud<pcl::PointXYZ>(m_raw_cloud, "raw_cloud");
|
|
|
+ viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1, 1, 1, "raw_cloud");
|
|
|
+ viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "raw_cloud");
|
|
|
+
|
|
|
+ viewer.addCube(x_min, x_max, y_min, y_max, z_min, z_max, 0.75, 0.0, 0.0, "AABB_");
|
|
|
+ viewer.setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_REPRESENTATION,
|
|
|
+ pcl::visualization::PCL_VISUALIZER_REPRESENTATION_WIREFRAME, "AABB_");
|
|
|
+
|
|
|
+ pcl::PointXYZ px0, px1, py1, pz1;
|
|
|
+ px0.x = 0;
|
|
|
+ px0.y = 0;
|
|
|
+ px0.z = 0;
|
|
|
+ px1.x = 10.0;
|
|
|
+ px1.y = 0;
|
|
|
+ px1.z = 0;
|
|
|
+
|
|
|
+
|
|
|
+ py1.x = 0;
|
|
|
+ py1.y = 10.0;
|
|
|
+ py1.z = 0;
|
|
|
+ pz1.x = 0;
|
|
|
+ pz1.y = 0;
|
|
|
+ pz1.z = 10.0;
|
|
|
+
|
|
|
+ viewer.addLine(px0, px1, 255, 0, 0, "x");
|
|
|
+ viewer.addLine(px0, py1, 0, 255, 0, "y");
|
|
|
+ viewer.addLine(px0, pz1, 0, 0, 255, "z");
|
|
|
+
|
|
|
+ while (!viewer.wasStopped()) {
|
|
|
+ viewer.spinOnce(100);
|
|
|
+ boost::this_thread::sleep(boost::posix_time::microseconds(100000));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void CRootStockGrabPoint::get_leaf_point_count_inbox(
|
|
|
+ const CStemResult& sr,//input
|
|
|
+ pcl::PointCloud<pcl::PointXYZ>::Ptr in_cloud, //input 输入点云数据
|
|
|
+ std::vector<int>& leaf_idx, //input
|
|
|
+ pcl::PointXYZ& aabb_min,//output
|
|
|
+ pcl::PointXYZ& aabb_max,//output
|
|
|
+ int& total_cnt, //output
|
|
|
+ int& leaf_cnt, //output
|
|
|
+ double& total_cx, //output
|
|
|
+ double& leaf_cx //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;
|
|
@@ -790,25 +950,51 @@ obstructed:
|
|
|
double min_x = sr.root_x - 0.5 * seedling_distance;
|
|
|
double max_x = sr.root_x + 0.5 * seedling_distance;
|
|
|
double min_z = sr.root_z - 0.75 * seedling_distance;
|
|
|
- double max_z = sr.root_z + 0.25 * seedling_distance;
|
|
|
+ double max_z = sr.root_z + 0.25 * seedling_distance;
|
|
|
+ aabb_min.x = min_x;
|
|
|
+ aabb_min.y = min_y;
|
|
|
+ aabb_min.z = min_z;
|
|
|
+ aabb_max.x = max_x;
|
|
|
+ aabb_max.y = max_y;
|
|
|
+ aabb_max.z = max_z;
|
|
|
+
|
|
|
+ total_cnt = 0;
|
|
|
+ leaf_cnt = 0;
|
|
|
+ total_cx = 1.0e6;
|
|
|
+ leaf_cx = 1.0e6;
|
|
|
+ std::vector<double>xs;
|
|
|
|
|
|
- int count = 0;
|
|
|
for (auto&pt : in_cloud->points) {
|
|
|
if (pt.y >= min_y && pt.y <= max_y &&
|
|
|
pt.x >= min_x && pt.x <= max_x &&
|
|
|
pt.z >= min_z && pt.z <= max_z)
|
|
|
{
|
|
|
- count++;
|
|
|
+ total_cnt++;
|
|
|
+ xs.push_back(pt.x);
|
|
|
}
|
|
|
}
|
|
|
- aabb_min.x = min_x;
|
|
|
- aabb_min.y = min_y;
|
|
|
- aabb_min.z = min_z;
|
|
|
- aabb_max.x = max_x;
|
|
|
- aabb_max.y = max_y;
|
|
|
- aabb_max.z = max_z;
|
|
|
+ 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);
|
|
|
|
|
|
- return count;
|
|
|
+ //leaf center
|
|
|
+ xs.clear();
|
|
|
+ for (auto&i : leaf_idx) {
|
|
|
+ pcl::PointXYZ& pt = in_cloud->points.at(i);
|
|
|
+ if (pt.y >= min_y && pt.y <= max_y &&
|
|
|
+ pt.x >= min_x && pt.x <= max_x &&
|
|
|
+ pt.z >= min_z && pt.z <= max_z)
|
|
|
+ {
|
|
|
+ leaf_cnt++;
|
|
|
+ xs.push_back(pt.x);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (leaf_cnt == 0) { return; }
|
|
|
+ med_idx = int(0.5 * xs.size());
|
|
|
+ std::sort(xs.begin(), xs.end());
|
|
|
+ leaf_cx = xs.at(med_idx);
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
//生成结果图片
|