Bladeren bron

v0.8.2 叶子遮挡识别优化:用叶子点云数量判断是否有遮挡,加上识别的茎的位置,统计植株的个数

chenhongjiang 1 jaar geleden
bovenliggende
commit
884d92a0d6
5 gewijzigde bestanden met toevoegingen van 133 en 55 verwijderingen
  1. 2 1
      ReadMe.txt
  2. 14 14
      gcv_conf.yml
  3. 108 36
      grab_point_rs.cpp
  4. 8 3
      grab_point_rs.h
  5. 1 1
      graft_cv_api.cpp

+ 2 - 1
ReadMe.txt

@@ -110,4 +110,5 @@ v0.7.21 
 v0.7.22 优化茎节位置识别,废弃基于历史平均茎节高度的约束,人工指定范围(高度上限,下限),不在范围内时,按下限位置
 v0.7.23 识别接口返回图片,返回茎的弯曲度,当前苗的数量
 v0.8.0 叶子遮挡识别;去除原来图片识别的内容;修改配置参数仅保留3d相关参数
-v0.8.1 叶子遮挡识别优化:通过x截取范围和穴位个数直接确定茎根中心位置
+v0.8.1 叶子遮挡识别优化:通过x截取范围和穴位个数直接确定茎根中心位置
+v0.8.2 叶子遮挡识别优化:用叶子点云数量判断是否有遮挡,加上识别的茎的位置,统计植株的个数

+ 14 - 14
gcv_conf.yml

@@ -7,35 +7,35 @@ conf_parameters:
    image_backup_days: 7   
 
    rs_grab_xmin: -50
-   rs_grab_xmax: 190
+   rs_grab_xmax: 210
    rs_grab_ymin: -15
    rs_grab_ymax: 20
-   rs_grab_zmin: 335
-   rs_grab_zmax: 390
+   rs_grab_zmin: 340
+   rs_grab_zmax: 395
    rs_grab_stem_diameter: 5.0   
    rs_grab_seedling_dist: 40.0
    rs_grab_stem_min_pts: 45
    rs_grab_seedling_min_pts: 3000
-   rs_grab_ror_ratio: 0.98
+   rs_grab_ror_ratio: 0.92
    rs_grab_offset: 0   
    rs_grab_fork_yup: 15
    rs_grab_fork_ybt: 3
    rs_grab_holes_number: 6
 
-   sc_grab_xmin: -200
-   sc_grab_xmax: 220
-   sc_grab_ymin: -30
-   sc_grab_ymax: 10
-   sc_grab_zmin: 300
+   sc_grab_xmin: -80
+   sc_grab_xmax: 180
+   sc_grab_ymin: -20
+   sc_grab_ymax: 5
+   sc_grab_zmin: 340
    sc_grab_zmax: 400   
    sc_grab_stem_diameter: 5.0   
    sc_grab_seedling_dist: 40.0
    sc_grab_stem_min_pts: 45
-   sc_grab_seedling_min_pts: 2500
-   sc_grab_ror_ratio: 0.85
-   sc_grab_offset: 0   
-   sc_grab_fork_yup: 10
-   sc_grab_fork_ybt: 0
+   sc_grab_seedling_min_pts: 3000
+   sc_grab_ror_ratio: 0.92
+   sc_grab_offset: 10   
+   sc_grab_fork_yup: 5
+   sc_grab_fork_ybt: -20
    sc_grab_holes_number: 6
    
 

+ 108 - 36
grab_point_rs.cpp

@@ -282,14 +282,7 @@ namespace graft_cv {
 				m_pLogger->INFO(buff.str());
 			}
 		}
-		//判断m_root_centers位置上是否有苗
-		//
-		int first_row_seedling_number = 0;
-		seedling_detect_by_point_cloud();
-		for (auto&has_seedling : m_root_center_with_seedling) {
-			if (has_seedling) { first_row_seedling_number += 1; }
-		}		
-
+		
 		////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 		//3 原来的降采样没有意义,改成统计平均距离
 		m_cloud_mean_dist = 0.0;
@@ -303,8 +296,9 @@ namespace graft_cv {
 		////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 		// 4 对截取的点云进行ror滤除大面积联通区域,剔除叶片
 		pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_dowm_sampled(new pcl::PointCloud<pcl::PointXYZ>);
-		std::vector<int> non_leaf_indices;		
-		leaf_filter_ror(cloud_ror, non_leaf_indices);
+		std::vector<int> non_leaf_indices;
+		std::vector<int> leaf_indices;
+		leaf_filter_ror(cloud_ror, non_leaf_indices, leaf_indices);
 		pcl::copyPointCloud(*cloud_ror, non_leaf_indices, *cloud_dowm_sampled);
 		if (m_pLogger) {
 			stringstream buff;
@@ -316,6 +310,11 @@ namespace graft_cv {
 			return 1;
 		}
 
+		////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+		//判断m_root_centers位置上是否有叶片遮挡
+		occluded_seedling_detect_by_leaf(cloud_ror, leaf_indices);
+		
+
 		////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 		//5 seedling position,找到第一个位置上的植株
 		std::vector<int> first_seedling_cloud_idx;	//存储找到的第一个位置上植株茎上直线点的index
@@ -324,8 +323,9 @@ namespace graft_cv {
 		if (m_pLogger) {
 			m_pLogger->INFO(m_pcdId + ": begin find seedling position");
 		}
-		int first_row_seedling_number_with_stem = 0;
-		bool fund_seedling = find_seedling_position_key(cloud_dowm_sampled, first_seedling_cloud_idx, xz_center, line_model, first_row_seedling_number_with_stem);
+
+		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 && first_row_seedling_number == 0) {
 			if (m_pLogger) {
 				stringstream buff;
@@ -655,25 +655,37 @@ obstructed:
 
 	}
 	//根据历史根的位置,计算对应位置点云数量,进而判断此位置是否有苗
-	void CRootStockGrabPoint::seedling_detect_by_point_cloud()
+	void CRootStockGrabPoint::occluded_seedling_detect_by_leaf(
+		pcl::PointCloud<pcl::PointXYZ>::Ptr in_cloud,	//input 输入点云数据			
+		std::vector<int>& leaf_idx
+	)
 	{		
 		m_root_center_with_seedling.clear();
+		m_root_center_with_seedling.assign(m_root_centers.size(), false);
 		std::vector<int> pcd_cnt;
-		int th_pcd_size = m_cparam.rs_grab_seedling_min_pts;
+		//int th_pcd_size = m_cparam.rs_grab_seedling_min_pts;
+		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;
+
 		if (m_dtype == 0) {
-			th_pcd_size = m_cparam.sc_grab_seedling_min_pts;
+			//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;
 		}
+		int th_pcd_size = stem_diameter * (y_max - y_min) * m_cloud_mean_dist;
 		std::vector<pcl::PointXYZ> aabb_mins_maxs;		
-		for (auto&rc : m_root_centers) {
+		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);
+			int cnt = get_point_count_inbox(rc, aabb_min, aabb_max, in_cloud, leaf_idx);
 			pcd_cnt.push_back(cnt);			
 			bool has_seedling = cnt > th_pcd_size;
-			m_root_center_with_seedling.push_back(has_seedling);
+			m_root_center_with_seedling.at(i) = has_seedling;
 			aabb_mins_maxs.push_back(aabb_min);
-			aabb_mins_maxs.push_back(aabb_max);
-			
+			aabb_mins_maxs.push_back(aabb_max);			
 		}
 
 		if (m_pLogger) {
@@ -704,28 +716,68 @@ obstructed:
 		}		
 
 	}
-	int CRootStockGrabPoint::get_point_count_inbox(const CStemResult& sr, 
+	//int CRootStockGrabPoint::get_point_count_inbox(const CStemResult& sr, 
+	//	pcl::PointXYZ& aabb_min,
+	//	pcl::PointXYZ& aabb_max)
+	//{
+	//	double seedling_distance = m_cparam.rs_grab_seedling_dist;
+	//	double min_y = m_cparam.rs_grab_ymin;
+	//	if (m_dtype == 0) {
+	//		seedling_distance = m_cparam.sc_grab_seedling_dist;
+	//		min_y = m_cparam.sc_grab_ymin;
+	//	}
+	//	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_y = min_y + 150.0; //假定苗高150mm
+
+	//	int count = 0;
+	//	for (auto&pt : m_raw_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++;
+	//		}
+	//	}
+	//	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;
+
+	//	return count;
+	//}
+
+	int CRootStockGrabPoint::get_point_count_inbox(const CStemResult& sr,
 		pcl::PointXYZ& aabb_min,
-		pcl::PointXYZ& aabb_max)
+		pcl::PointXYZ& aabb_max,
+		pcl::PointCloud<pcl::PointXYZ>::Ptr in_cloud,	//input 输入点云数据			
+		std::vector<int>& leaf_idx)
 	{
 		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;
 		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;
 		}
 		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_y = min_y + 150.0; //假定苗高150mm
+		double max_z = sr.root_z + 0.25 * seedling_distance;		
 
 		int count = 0;
-		for (auto&pt : m_raw_cloud->points) {
-			if(pt.y >= min_y && pt.y <= max_y &&
-				pt.x >=min_x && pt.x<=max_x &&
+		//for (auto&pt : m_raw_cloud->points) {
+		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)
-			{ 
+			{
 				count++;
 			}
 		}
@@ -932,7 +984,8 @@ void CRootStockGrabPoint::leaf_filter(
 // 基于孤立点滤除的方法检测叶子区域
 void CRootStockGrabPoint::leaf_filter_ror(
 	pcl::PointCloud<pcl::PointXYZ>::Ptr in_cloud,	//input 输入点云数据
-	std::vector<int> &stem_cloud_idx				//output, 过滤后的点云序号
+	std::vector<int> &stem_cloud_idx,				//output, 过滤后的点云序号
+	std::vector<int>& leaf_idx						//output, 叶子的点云序号
 )
 {
 	//计算点云平均间距
@@ -976,7 +1029,7 @@ void CRootStockGrabPoint::leaf_filter_ror(
 		}
 	}
 
-	std::vector<int> leaf_idx;
+	leaf_idx.clear();
 	leaf_idx.assign(leaf_idx_set.begin(), leaf_idx_set.end());	
 
 	//in_img是经过开运算的图像,其中像素位置的点云为叶子区域
@@ -1603,7 +1656,27 @@ void CRootStockGrabPoint::line_filter(
 			int raw_idx = first_row_index.at(i);
 			pcl::PointXYZ&pt = target_filtered_root.at(raw_idx);			
 			cluster_index.push_back(pt.x);
+			//update m_root_center_with_seedling
+			double min_dist = hole_step;
+			int min_i = -1;
+			for (int rc_i = 0; rc_i < m_root_centers.size(); ++rc_i)
+			{
+				double dist = fabs(pt.x - m_root_centers.at(rc_i).root_x);
+				if (dist < min_dist) {
+					min_dist = dist;
+					min_i = rc_i;
+				}
+			}
+			if (min_i >= 0) {
+				m_root_center_with_seedling.at(min_i) = true;
+			}
 		}
+		//统计苗数量
+		first_row_size = 0;
+		for (auto&has_seedling : m_root_center_with_seedling) {
+			if (has_seedling) { first_row_size += 1; }
+		}
+
 		
 		int first_idx = std::min_element(cluster_index.begin(), cluster_index.end()) - cluster_index.begin();
 		if (m_dtype == 0) {
@@ -1618,8 +1691,7 @@ void CRootStockGrabPoint::line_filter(
 		xz_center.x = target_filtered_root.at(first_idx).x;
 		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();
+		line_model = target_filtered_models.at(first_idx);		
 
 		if (m_pLogger) {
 			stringstream buff;
@@ -2689,18 +2761,18 @@ void CRootStockGrabPoint::line_filter(
 		for (size_t i = 0; i < cluster_center.size();++i) {
 			pcl::PointXYZ &p = cluster_center.at(i);
 			pcl::PointXYZ px0, px1, py1, py0;
-			px0.x = p.x - 5.0;
+			px0.x = p.x;
 			px0.y = p.y;
 			px0.z = p.z;
-			px1.x = p.x + 5.0;
+			px1.x = p.x + 10.0;
 			px1.y = p.y;
 			px1.z = p.z;
 
 			py0.x = p.x;
-			py0.y = p.y - 5.0;
+			py0.y = p.y;
 			py0.z = p.z;
 			py1.x = p.x;
-			py1.y = p.y + 5.0;
+			py1.y = p.y + 10.0;
 			py1.z = p.z;
 
 			viewer.addLine(px0, px1, 255, 0, 0, "x" + string(_itoa(cnt, buf, 10)));

+ 8 - 3
grab_point_rs.h

@@ -60,7 +60,8 @@ namespace graft_cv {
 		
 		void leaf_filter_ror(
 			pcl::PointCloud<pcl::PointXYZ>::Ptr in_cloud,	//input 输入点云数据
-			std::vector<int> &stem_cloud_idx				//output, 过滤后的点云序号
+			std::vector<int> &stem_cloud_idx,				//output, 过滤后的点云序号
+			std::vector<int>& leaf_idx						//output, 叶子的点云序号
 		);
 		void cloud_mean_dist(
 			pcl::PointCloud<pcl::PointXYZ>::Ptr in_cloud,	//input 输入点云数据
@@ -176,10 +177,14 @@ namespace graft_cv {
 			cv::Mat& rst_img						//输出,图片, 640*1280
 		);
 		//根据历史根的位置,计算对应位置点云数量,进而判断此位置是否有苗
-		void seedling_detect_by_point_cloud();
+		void occluded_seedling_detect_by_leaf(
+			pcl::PointCloud<pcl::PointXYZ>::Ptr in_cloud,	//input 输入点云数据			
+			std::vector<int>& leaf_idx);	//input
 		int get_point_count_inbox(const CStemResult& sr, //input
 			pcl::PointXYZ& aabb_min,	//output
-			pcl::PointXYZ& aabb_max);	//output
+			pcl::PointXYZ& aabb_max,	//output
+			pcl::PointCloud<pcl::PointXYZ>::Ptr in_cloud,	//input 输入点云数据			
+			std::vector<int>& leaf_idx);
 		//没有检测到苗的情况,后处理
 		void no_seedling_detected_post_process(
 			int first_row_seedling_number,		//input

+ 1 - 1
graft_cv_api.cpp

@@ -15,7 +15,7 @@ extern CRITICAL_SECTION g_cs;
 namespace graft_cv
 {
 
-	char *g_version_str = "0.8.1";
+	char *g_version_str = "0.8.2";
 
 	//configure
 	string g_conf_file = "./gcv_conf.yml";