|
@@ -40,11 +40,20 @@ namespace graft_cv {
|
|
|
m_ppImgSaver(0),
|
|
|
m_1st_row_zmean_rs(-1.0),
|
|
|
m_1st_row_zmean_sc(-1.0),
|
|
|
- m_cloud_mean_dist(0.0)
|
|
|
+ m_cloud_mean_dist(0.0),
|
|
|
+ m_pImginfoResult(0)
|
|
|
{
|
|
|
}
|
|
|
+ void CRootStockGrabPoint::clear_imginfo() {
|
|
|
+ if (m_pImginfoResult) {
|
|
|
+ imginfo_release(&m_pImginfoResult);
|
|
|
+ m_pImginfoResult = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- CRootStockGrabPoint::~CRootStockGrabPoint() {}
|
|
|
+ CRootStockGrabPoint::~CRootStockGrabPoint() {
|
|
|
+ this->clear_imginfo();
|
|
|
+ }
|
|
|
float* CRootStockGrabPoint::get_raw_point_cloud(int &data_size)
|
|
|
{
|
|
|
data_size = m_raw_cloud->width * m_raw_cloud->height;
|
|
@@ -262,8 +271,9 @@ namespace graft_cv {
|
|
|
pcl::ModelCoefficients::Ptr line_model; //存储找到的第一个位置上植株茎直线模型
|
|
|
if (m_pLogger) {
|
|
|
m_pLogger->INFO(m_pcdId + ": begin find seedling position");
|
|
|
- }
|
|
|
- bool fund_seedling = find_seedling_position_key(cloud_dowm_sampled, first_seedling_cloud_idx, xz_center, line_model);
|
|
|
+ }
|
|
|
+ int first_row_seedling_number = 0;
|
|
|
+ bool fund_seedling = find_seedling_position_key(cloud_dowm_sampled, first_seedling_cloud_idx, xz_center, line_model, first_row_seedling_number);
|
|
|
if (!fund_seedling) {
|
|
|
if (m_pLogger) {
|
|
|
stringstream buff;
|
|
@@ -305,13 +315,18 @@ namespace graft_cv {
|
|
|
pcl::PointXYZ selected_pt;//抓取点坐标,根据茎节点的偏移
|
|
|
pcl::PointXYZ selected_pt_ref; //返回茎节点,作为抓取点偏的基点
|
|
|
std::vector<int> optimal_seeds_idx;
|
|
|
+ float stem_width_mu;
|
|
|
+ float stem_deflection;
|
|
|
get_optimal_seed_compare(
|
|
|
cloud_dowm_sampled, //input
|
|
|
cloud_seedling_seed, //input
|
|
|
line_model, //input
|
|
|
selected_pt, //output
|
|
|
selected_pt_ref, //output
|
|
|
- optimal_seeds_idx); //output
|
|
|
+ optimal_seeds_idx, //output
|
|
|
+ stem_width_mu, //output
|
|
|
+ stem_deflection //output
|
|
|
+ ); //output
|
|
|
|
|
|
if (selected_pt.z < 0) {
|
|
|
if (m_pLogger) {
|
|
@@ -326,11 +341,17 @@ namespace graft_cv {
|
|
|
posinfo.sc_grab_x = selected_pt.x;
|
|
|
posinfo.sc_grab_y = selected_pt.y;
|
|
|
posinfo.sc_grab_z = selected_pt.z;
|
|
|
+ posinfo.sc_count = (double)first_row_seedling_number;
|
|
|
+ posinfo.sc_width = (double)stem_width_mu;
|
|
|
+ posinfo.sc_tortuosity = (double)stem_deflection;
|
|
|
}
|
|
|
else {
|
|
|
posinfo.rs_grab_x = selected_pt.x;
|
|
|
posinfo.rs_grab_y = selected_pt.y;
|
|
|
posinfo.rs_grab_z = selected_pt.z;
|
|
|
+ posinfo.rs_count = (double)first_row_seedling_number;
|
|
|
+ posinfo.rs_width = (double)stem_width_mu;
|
|
|
+ posinfo.rs_tortuosity = (double)stem_deflection;
|
|
|
}
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
//7 保存处理结果到图片
|
|
@@ -340,7 +361,13 @@ namespace graft_cv {
|
|
|
(*m_ppImgSaver)->saveImage(rst_img, m_pcdId + "_rst_0");
|
|
|
}
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
- //7 debug 显示结果
|
|
|
+ //8 页面显示结果
|
|
|
+ this->clear_imginfo();
|
|
|
+ m_pImginfoResult = mat2imginfo(rst_img);
|
|
|
+ posinfo.pp_images[0] = m_pImginfoResult;
|
|
|
+
|
|
|
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
+ //9 debug 显示结果
|
|
|
if (m_cparam.image_show) {
|
|
|
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_cand_demo(new pcl::PointCloud<pcl::PointXYZRGB>);
|
|
|
pcl::copyPointCloud(*cloud_dowm_sampled, *cloud_cand_demo);
|
|
@@ -445,6 +472,10 @@ namespace graft_cv {
|
|
|
int fork_y = cy - int(selected_pt_ref.y / res + 0.5);
|
|
|
radius = 15;
|
|
|
cv::line(rst_img, cv::Point(fork_x - radius, fork_y), cv::Point(fork_x + radius, fork_y), cv::Scalar(153, 51, 255));
|
|
|
+
|
|
|
+ //在图片中写入文件名字
|
|
|
+ cv::putText(rst_img, m_pcdId, cv::Point(20, 20), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(128, 128, 128));
|
|
|
+
|
|
|
|
|
|
}
|
|
|
int CRootStockGrabPoint::read_ply_file(const char* fn)
|
|
@@ -1272,9 +1303,11 @@ void CRootStockGrabPoint::line_filter(
|
|
|
pcl::PointCloud<pcl::PointXYZ>::Ptr in_cloud,
|
|
|
std::vector<int> &first_seedling_cloud_idx,
|
|
|
pcl::PointXYZ&xz_center,
|
|
|
- pcl::ModelCoefficients::Ptr& line_model
|
|
|
+ pcl::ModelCoefficients::Ptr& line_model,
|
|
|
+ int& first_row_size
|
|
|
)
|
|
|
- {
|
|
|
+ {
|
|
|
+ first_row_size = 0;
|
|
|
// 确定植株inbox范围
|
|
|
float hole_step = m_cparam.rs_grab_seedling_dist - 5.0; //穴盘中穴间距
|
|
|
if (m_dtype == 0) {
|
|
@@ -1570,6 +1603,7 @@ void CRootStockGrabPoint::line_filter(
|
|
|
xz_center.y = target_filtered_root.at(first_idx).y;
|
|
|
xz_center.z = target_filtered_root.at(first_idx).z;
|
|
|
line_model = target_filtered_models.at(first_idx);
|
|
|
+ first_row_size = first_row_index.size();
|
|
|
|
|
|
if (m_pLogger) {
|
|
|
stringstream buff;
|
|
@@ -2309,14 +2343,19 @@ void CRootStockGrabPoint::line_filter(
|
|
|
pcl::ModelCoefficients::Ptr line_model, //input
|
|
|
pcl::PointXYZ&pt, // 返回抓取的点坐标,基于pt_ref的偏移点
|
|
|
pcl::PointXYZ &pt_ref, // 返回点茎节的参考点
|
|
|
- std::vector<int>& valid_line_index // 返回有效直线点index
|
|
|
+ std::vector<int>& valid_line_index, // 返回有效直线点index
|
|
|
+ float& stem_width_mu, // 茎宽度,直径
|
|
|
+ float& stem_deflection //茎的最大挠度,最大弯曲处的偏离直径轴心的距离,毫米
|
|
|
)
|
|
|
{
|
|
|
+ // stem_deflection 的计算方法:计算点云到拟合轴线的平均距离
|
|
|
valid_line_index.clear();
|
|
|
float th_ratio = 1.5; //原始点云和直线点云邻域尺寸增加原来的20%,不能当做抓取点
|
|
|
pt.x = -1000.0;
|
|
|
pt.y = -1000.0;
|
|
|
pt.z = -1000.0;
|
|
|
+ stem_width_mu = 0.0;
|
|
|
+ stem_deflection = 0.0;
|
|
|
|
|
|
|
|
|
float ymin, ymax;
|
|
@@ -2389,12 +2428,13 @@ void CRootStockGrabPoint::line_filter(
|
|
|
pt_ref.z = z_mu;
|
|
|
return;
|
|
|
}*/
|
|
|
-
|
|
|
// 如果opt_y_valid==false,就是用户没有指定抓取的y高度
|
|
|
float max_dist_to_boundary = 0.0;
|
|
|
int max_idx_to_boundary = -1;
|
|
|
find_fork(in_line_cloud, max_dist_to_boundary, max_idx_to_boundary);
|
|
|
|
|
|
+ stem_deflection = static_cast<float>(calculate_deflection(in_line_cloud, line_model));
|
|
|
+
|
|
|
cy = ymin;
|
|
|
//计算茎上的直径
|
|
|
while(cy<ymax){
|
|
@@ -2439,8 +2479,12 @@ void CRootStockGrabPoint::line_filter(
|
|
|
}
|
|
|
}
|
|
|
float mu = get_hist_mean(valid_stem_width);
|
|
|
+ stem_width_mu = mu;
|
|
|
float stdv = get_hist_std(valid_stem_width, mu);
|
|
|
|
|
|
+ //0)计算点云到轴线的最大距离
|
|
|
+
|
|
|
+
|
|
|
//1) original max position
|
|
|
int max_pos = std::max_element(stem_width.begin(), stem_width.end()) - stem_width.begin();
|
|
|
int max_pos_ref = max_pos;
|
|
@@ -2610,6 +2654,35 @@ void CRootStockGrabPoint::line_filter(
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ //计算茎的弯曲度:点云到直线的距离95分位
|
|
|
+ double CRootStockGrabPoint::calculate_deflection(
|
|
|
+ pcl::PointCloud<pcl::PointXYZ>::Ptr in_line_cloud, //input
|
|
|
+ pcl::ModelCoefficients::Ptr line_model //input
|
|
|
+ )
|
|
|
+ {
|
|
|
+ double deflection = 0.0;
|
|
|
+ std::vector<double> dists;
|
|
|
+ Eigen::Vector4f line_pt = { line_model->values[0],line_model->values[1],line_model->values[2],0.0 };
|
|
|
+ Eigen::Vector4f line_dir = { line_model->values[3],line_model->values[4],line_model->values[5],0.0 };
|
|
|
+ for (auto ptc : in_line_cloud->points) {
|
|
|
+ //Get the square distance from a point to a line (represented by a point and a direction)
|
|
|
+ Eigen::Vector4f pt = { ptc.x, ptc.y, ptc.z, 0.0 };
|
|
|
+ double dist = (line_dir.cross3(line_pt - pt)).squaredNorm() / line_dir.squaredNorm();
|
|
|
+
|
|
|
+ dists.push_back(sqrt(dist));
|
|
|
+ }
|
|
|
+
|
|
|
+ //deflection = get_hist_mean(dists);
|
|
|
+
|
|
|
+ //95 percentile
|
|
|
+ if (dists.size() > 0) {
|
|
|
+ int idx_95 = int(0.95 * dists.size());
|
|
|
+ std::sort(dists.begin(), dists.end());
|
|
|
+ deflection = dists.at(idx_95);
|
|
|
+ }
|
|
|
+ return deflection;
|
|
|
+ }
|
|
|
+
|
|
|
void CRootStockGrabPoint::find_fork(
|
|
|
pcl::PointCloud<pcl::PointXYZ>::Ptr in_line_cloud,
|
|
|
float& max_dist,
|