Kaynağa Gözat

v0.7.6 优化叶片剔除功能,修改ror,nb_point的数量系数,通过配置文件sc_grab_ror_ratio参数传入

chenhongjiang 1 yıl önce
ebeveyn
işleme
9540f8cea8
7 değiştirilmiş dosya ile 89 ekleme ve 58 silme
  1. 2 1
      ReadMe.txt
  2. 6 6
      config.cpp
  3. 2 2
      data_def_api.h
  4. 3 3
      gcv_conf.yml
  5. 74 45
      grab_point_rs.cpp
  6. 1 0
      grab_point_rs.h
  7. 1 1
      graft_cv_api.cpp

+ 2 - 1
ReadMe.txt

@@ -90,4 +90,5 @@ v0.7.1 
 v0.7.2 增加结果图片输出功能;日志增加image_id信息
 v0.7.3 修改抓取位置,提供茎节分叉的位置(以前提供可抓取的位置,避开茎节的点)
 v0.7.4 增加叶片剔除功能(在boxcrop和降采样后实现,直接采用欧式距离聚类)
-v0.7.5 优化叶片剔除功能(欧式距离聚类没能分割叶片和茎造成误剔除,本次采用ror方法剔除叶片,但有些耗时)
+v0.7.5 优化叶片剔除功能(欧式距离聚类没能分割叶片和茎造成误剔除,本次采用ror方法剔除叶片,但有些耗时)
+v0.7.6 优化叶片剔除功能,修改ror,nb_point的数量系数,通过配置文件sc_grab_ror_ratio参数传入

+ 6 - 6
config.cpp

@@ -105,7 +105,7 @@ namespace graft_cv{
 			<< "rs_grab_y_opt" << m_cparam->rs_grab_y_opt
 			<< "rs_grab_seedling_dist" << m_cparam->rs_grab_seedling_dist
 			<< "rs_grab_stem_min_pts" << m_cparam->rs_grab_stem_min_pts
-			<< "rs_grab_voxel_size" << m_cparam->rs_grab_voxel_size
+			<< "rs_grab_ror_ratio" << m_cparam->rs_grab_ror_ratio
 
 			<< "sc_grab_xmin" << m_cparam->sc_grab_xmin
 			<< "sc_grab_xmax" << m_cparam->sc_grab_xmax
@@ -117,7 +117,7 @@ namespace graft_cv{
 			<< "sc_grab_y_opt" << m_cparam->sc_grab_y_opt
 			<< "sc_grab_seedling_dist" << m_cparam->sc_grab_seedling_dist
 			<< "sc_grab_stem_min_pts" << m_cparam->sc_grab_stem_min_pts
-			<< "sc_grab_voxel_size" << m_cparam->sc_grab_voxel_size
+			<< "sc_grab_ror_ratio" << m_cparam->sc_grab_ror_ratio
 			<< "}"; 	
 	};
 	void CGCvConfig::read(const cv::FileNode& node){ //Read serialization for this class
@@ -206,7 +206,7 @@ namespace graft_cv{
 		m_cparam->rs_grab_y_opt = (double)node["rs_grab_y_opt"];
 		m_cparam->rs_grab_seedling_dist = (double)node["rs_grab_seedling_dist"];
 		m_cparam->rs_grab_stem_min_pts = (int)node["rs_grab_stem_min_pts"];
-		m_cparam->rs_grab_voxel_size = (double)node["rs_grab_voxel_size"];
+		m_cparam->rs_grab_ror_ratio = (double)node["rs_grab_ror_ratio"];
 
 		m_cparam->sc_grab_xmin = (double)node["sc_grab_xmin"];
 		m_cparam->sc_grab_xmax = (double)node["sc_grab_xmax"];
@@ -218,7 +218,7 @@ namespace graft_cv{
 		m_cparam->sc_grab_y_opt = (double)node["sc_grab_y_opt"];
 		m_cparam->sc_grab_seedling_dist = (double)node["sc_grab_seedling_dist"];
         m_cparam->sc_grab_stem_min_pts = (int)node["sc_grab_stem_min_pts"];
-		m_cparam->sc_grab_voxel_size = (double)node["sc_grab_voxel_size"];
+		m_cparam->sc_grab_ror_ratio = (double)node["sc_grab_ror_ratio"];
   }
 	string get_cparam_info(ConfigParam*m_cparam)
 	{
@@ -312,7 +312,7 @@ namespace graft_cv{
 			<< "rs_grab_y_opt:\t" << m_cparam->rs_grab_y_opt << endl
             << "rs_grab_seedling_dist:\t" << m_cparam->rs_grab_seedling_dist << endl
 			<< "rs_grab_stem_min_pts:\t" << m_cparam->rs_grab_stem_min_pts << endl
-			<< "rs_grab_voxel_size:\t" << m_cparam->rs_grab_voxel_size << endl
+			<< "rs_grab_ror_ratio:\t" << m_cparam->rs_grab_ror_ratio << endl
 
 
 			<< "sc_grab_xmin:\t" << m_cparam->sc_grab_xmin << endl
@@ -325,7 +325,7 @@ namespace graft_cv{
 			<< "sc_grab_y_opt:\t" << m_cparam->sc_grab_y_opt << endl
 			<< "sc_grab_seedling_dist:\t" << m_cparam->sc_grab_seedling_dist << endl
 			<< "sc_grab_stem_min_pts:\t" << m_cparam->sc_grab_stem_min_pts << endl
-			<< "sc_grab_voxel_size:\t" << m_cparam->sc_grab_voxel_size << endl
+			<< "sc_grab_ror_ratio:\t" << m_cparam->sc_grab_ror_ratio << endl
 			<< "}" << endl; 	
 		return buff.str();
 	}

+ 2 - 2
data_def_api.h

@@ -115,7 +115,7 @@ typedef struct{
 	double rs_grab_y_opt;
 	double rs_grab_seedling_dist;
 	int rs_grab_stem_min_pts;
-	double rs_grab_voxel_size;
+	double rs_grab_ror_ratio;
 
 	// scion grab based points cloud
 	double sc_grab_xmin;
@@ -129,7 +129,7 @@ typedef struct{
 	double sc_grab_y_opt;
 	double sc_grab_seedling_dist;
 	int sc_grab_stem_min_pts;
-	double sc_grab_voxel_size;
+	double sc_grab_ror_ratio;
 
 
 

+ 3 - 3
gcv_conf.yml

@@ -1,6 +1,6 @@
 %YAML:1.0
 conf_parameters:
-   image_show: 0
+   image_show: 1
    image_return: 1
    image_row_grid: 20
    image_col_grid: 100
@@ -75,7 +75,7 @@ conf_parameters:
    rs_grab_y_opt: -30
    rs_grab_seedling_dist: 40.0
    rs_grab_stem_min_pts: 50
-   rs_grab_voxel_size: 0.02
+   rs_grab_ror_ratio: 0.75
    sc_grab_xmin: -200
    sc_grab_xmax: 200
    sc_grab_ymin: -45
@@ -86,6 +86,6 @@ conf_parameters:
    sc_grab_y_opt: -20
    sc_grab_seedling_dist: 40.0
    sc_grab_stem_min_pts: 45
-   sc_grab_voxel_size: 0.02
+   sc_grab_ror_ratio: 0.75
    
 

+ 74 - 45
grab_point_rs.cpp

@@ -183,10 +183,10 @@ namespace graft_cv {
 			buff << m_pcdId <<": RadiusOutlierRemoval filtered point cloud " 
 				<< cloud_ror->width * cloud_ror->height
 				<< " data points. param stem_radius="<<
-				stem_radius<<", nb_points="<< nb_points;
+				stem_radius<<", nb_points="<< nb_points<< "(if < 50, return)";
 			m_pLogger->INFO(buff.str());
 		}
-		if (cloud_ror->width * cloud_ror->height < 1) {
+		if (cloud_ror->width * cloud_ror->height < 50) {
 			return 1;
 		}
 
@@ -198,43 +198,52 @@ namespace graft_cv {
 		}
 		////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 		//3 voxel grid down sampling, 降采样
-		if (m_pLogger) {
-			m_pLogger->INFO(m_pcdId + ": begin down");
-		}
-		pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_dowm_sampled_with_leaf(new pcl::PointCloud<pcl::PointXYZ>);		
-		pcl::VoxelGrid<pcl::PointXYZ> outrem;
-		outrem.setInputCloud(cloud_ror);
-		//outrem.setLeafSize(stem_radius, stem_radius, stem_radius);
-		double voxel_size = m_cparam.rs_grab_voxel_size;
-		if (m_dtype == 0) { voxel_size = m_cparam.sc_grab_voxel_size; }
-		outrem.setLeafSize(voxel_size, voxel_size, voxel_size);
-		outrem.filter(*cloud_dowm_sampled_with_leaf);
-
+		//if (m_pLogger) {
+		//	m_pLogger->INFO(m_pcdId + ": begin down");
+		//}
+		//pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_dowm_sampled_with_leaf(new pcl::PointCloud<pcl::PointXYZ>);		
+		//pcl::VoxelGrid<pcl::PointXYZ> outrem;
+		//outrem.setInputCloud(cloud_ror);
+		////outrem.setLeafSize(stem_radius, stem_radius, stem_radius);
+		//double voxel_size = m_cparam.rs_grab_voxel_size;
+		//if (m_dtype == 0) { voxel_size = m_cparam.sc_grab_voxel_size; }
+		//outrem.setLeafSize(voxel_size, voxel_size, voxel_size);
+		//outrem.filter(*cloud_dowm_sampled_with_leaf);
+
+		double mean_dist = 0.0;
+		cloud_mean_dist(cloud_ror, mean_dist);
 		if (m_pLogger) {
 			stringstream buff;
-			buff << m_pcdId <<": VoxelGrid dowm_sampled point cloud " 
-				<< cloud_dowm_sampled_with_leaf->width * cloud_dowm_sampled_with_leaf->height
-				<< " data points (if < 50, return)";
+			buff << m_pcdId <<": cloud_mean_dist = " << mean_dist;
 			m_pLogger->INFO(buff.str());
 		}
-		if (cloud_dowm_sampled_with_leaf->width * cloud_dowm_sampled_with_leaf->height < 50) {
-			return 1;
-		}
+		
 
-		/*if (m_cparam.image_show) {
-			viewer_cloud(cloud_dowm_sampled, std::string("cloud_dowm_sampled"));
-		}*/
-		if (m_pLogger) {
-			m_pLogger->INFO(m_pcdId + ": end down");
-		}
+		//if (m_pLogger) {
+		//	stringstream buff;
+		//	buff << m_pcdId <<": VoxelGrid dowm_sampled point cloud " 
+		//		<< cloud_dowm_sampled_with_leaf->width * cloud_dowm_sampled_with_leaf->height
+		//		<< " data points (if < 50, return)";
+		//	m_pLogger->INFO(buff.str());
+		//}
+		//if (cloud_dowm_sampled_with_leaf->width * cloud_dowm_sampled_with_leaf->height < 50) {
+		//	return 1;
+		//}
+
+		///*if (m_cparam.image_show) {
+		//	viewer_cloud(cloud_dowm_sampled, std::string("cloud_dowm_sampled"));
+		//}*/
+		//if (m_pLogger) {
+		//	m_pLogger->INFO(m_pcdId + ": end down");
+		//}
 		////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 		// 4 对截取的点云进行聚类分析,剔除叶片
 		pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_dowm_sampled(new pcl::PointCloud<pcl::PointXYZ>);
 		std::vector<int> non_leaf_indices;
-		//leaf_filter(cloud_dowm_sampled_with_leaf, non_leaf_indices);
-		//leaf_filter_morph(cloud_dowm_sampled_with_leaf, non_leaf_indices);
-		leaf_filter_ror(cloud_dowm_sampled_with_leaf, non_leaf_indices);
-		pcl::copyPointCloud(*cloud_dowm_sampled_with_leaf, non_leaf_indices, *cloud_dowm_sampled);
+		//leaf_filter(cloud_ror, non_leaf_indices);
+		//leaf_filter_morph(cloud_ror, non_leaf_indices);
+		leaf_filter_ror(cloud_ror, non_leaf_indices);
+		pcl::copyPointCloud(*cloud_ror, non_leaf_indices, *cloud_dowm_sampled);
 		if (m_pLogger) {
 			stringstream buff;
 			buff << m_pcdId << ": after leaf_filter dowm_sampled point cloud "
@@ -320,8 +329,8 @@ namespace graft_cv {
 		}
 		////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 		//7 保存处理结果到图片
-		cv::Mat rst_img = cv::Mat::zeros(cv::Size(1280,640),CV_8UC1);
-		gen_result_img(cloud_dowm_sampled, selected_pt, rst_img);
+		cv::Mat rst_img = cv::Mat::zeros(cv::Size(1280,640),CV_8UC3);
+		gen_result_img(cloud_ror, cloud_dowm_sampled, selected_pt, rst_img);
 		if (m_ppImgSaver && *m_ppImgSaver) {
 			(*m_ppImgSaver)->saveImage(rst_img, m_pcdId + "_rst_0");
 		}
@@ -373,6 +382,7 @@ namespace graft_cv {
 
 	//生成结果图片
 	void CRootStockGrabPoint::gen_result_img(
+		pcl::PointCloud<pcl::PointXYZ>::Ptr in_cloud_raw,//输入,未经过滤的整体点云in_cloud_raw, 
 		pcl::PointCloud<pcl::PointXYZ>::Ptr in_cloud,	//输入,整体点云cloud_dowm_sampled, 
 		pcl::PointXYZ& selected_pt,				//输入,selected_pt, 
 		cv::Mat& rst_img						//输出,图片, 640*1280
@@ -385,32 +395,44 @@ namespace graft_cv {
 		float res = 0.33333;	//分辨率,1个像素0.333mm
 		//绘制坐标轴
 		int arrow_len = 20;
-		cv::line(rst_img, cv::Point(0, cy), cv::Point(cx, cy), cv::Scalar(128));
-		cv::line(rst_img, cv::Point(0, cy), cv::Point(arrow_len, cy - int(arrow_len/2)), cv::Scalar(128));
-		cv::line(rst_img, cv::Point(0, cy), cv::Point(arrow_len, cy + int(arrow_len/2)), cv::Scalar(128));
+		cv::line(rst_img, cv::Point(0, cy), cv::Point(cx, cy), cv::Scalar(128,128,128));
+		cv::line(rst_img, cv::Point(0, cy), cv::Point(arrow_len, cy - int(arrow_len/2)), cv::Scalar(128, 128, 128));
+		cv::line(rst_img, cv::Point(0, cy), cv::Point(arrow_len, cy + int(arrow_len/2)), cv::Scalar(128, 128, 128));
 
-		cv::line(rst_img, cv::Point(cx, 0), cv::Point(cx, cy), cv::Scalar(128));
-		cv::line(rst_img, cv::Point(cx, 0), cv::Point(cx - int(arrow_len/2), arrow_len), cv::Scalar(128));
-		cv::line(rst_img, cv::Point(cx, 0), cv::Point(cx + int(arrow_len/2), arrow_len), cv::Scalar(128));
+		cv::line(rst_img, cv::Point(cx, 0), cv::Point(cx, cy), cv::Scalar(128, 128, 128));
+		cv::line(rst_img, cv::Point(cx, 0), cv::Point(cx - int(arrow_len/2), arrow_len), cv::Scalar(128, 128, 128));
+		cv::line(rst_img, cv::Point(cx, 0), cv::Point(cx + int(arrow_len/2), arrow_len), cv::Scalar(128, 128, 128));
 
-		cv::putText(rst_img, std::string("x"), cv::Point(20, cy-10), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(128));
-		cv::putText(rst_img, std::string("y"), cv::Point(cx+10, 20), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(128));
+		cv::putText(rst_img, std::string("x"), cv::Point(20, cy-10), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(128, 128, 128));
+		cv::putText(rst_img, std::string("y"), cv::Point(cx+10, 20), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(128, 128, 128));
 		
 		//绘制所有点
 		int x, y;
+		for (auto&pt : in_cloud_raw->points) {
+			x = cx - int(pt.x / res + 0.5);
+			y = cy - int(pt.y / res + 0.5);
+			if (x < 0 || x >= rst_img.cols) { continue; }
+			if (y < 0 || y >= rst_img.rows) { continue; }
+			rst_img.at<cv::Vec3b>(y, x)[0] = 60; 
+			rst_img.at<cv::Vec3b>(y, x)[1] = 20;
+			rst_img.at<cv::Vec3b>(y, x)[2] = 220;
+		}
+
 		for (auto&pt : in_cloud->points) {
 			x = cx - int(pt.x / res + 0.5);
 			y = cy - int(pt.y / res + 0.5);
 			if (x < 0 || x >= rst_img.cols) { continue; }
 			if (y < 0 || y >= rst_img.rows) { continue; }
-			rst_img.at<unsigned char>(y, x) = 255;
+			rst_img.at<cv::Vec3b>(y, x)[0] = 0;
+			rst_img.at<cv::Vec3b>(y, x)[1] = 225; 
+			rst_img.at<cv::Vec3b>(y, x)[2] = 0;
 		}
 		//绘制抓取点坐标
 		int grab_x = cx - int(selected_pt.x / res + 0.5);
 		int grab_y = cy - int(selected_pt.y / res + 0.5);
 		int radius = 30;
-		cv::line(rst_img, cv::Point(grab_x - radius, grab_y - radius), cv::Point(grab_x + radius, grab_y + radius), cv::Scalar(128));
-		cv::line(rst_img, cv::Point(grab_x - radius, grab_y + radius), cv::Point(grab_x + radius, grab_y - radius), cv::Scalar(128));
+		cv::line(rst_img, cv::Point(grab_x - radius, grab_y - radius), cv::Point(grab_x + radius, grab_y + radius), cv::Scalar(0, 215, 255));
+		cv::line(rst_img, cv::Point(grab_x - radius, grab_y + radius), cv::Point(grab_x + radius, grab_y - radius), cv::Scalar(0, 215, 255));
 	}
 	int CRootStockGrabPoint::read_ply_file(const char* fn)
 	{
@@ -870,9 +892,16 @@ void CRootStockGrabPoint::leaf_filter_ror(
 	//计算点云过滤半径和点数阈值
 	double stem_diameter = m_cparam.rs_grab_stem_diameter;
 	if (m_dtype == 0) { stem_diameter = m_cparam.sc_grab_stem_diameter; }
-	
+
 	double remove_radius = stem_diameter;
-	int nb_points = stem_diameter * stem_diameter * 2.57 / mean_dist / mean_dist; // (2d*d + pi *d*d) /2
+	double ror_ratio = m_cparam.rs_grab_ror_ratio;
+	if (m_dtype == 0){ror_ratio = m_cparam.sc_grab_ror_ratio;}
+	int nb_points = ror_ratio*  stem_diameter * stem_diameter * 2.0 / mean_dist / mean_dist; // (2d*d + pi *d*d) /2
+	if (m_pLogger) {
+		stringstream buff;
+		buff << m_pcdId << ": ror_ratio=" << ror_ratio << ", ror filter nb_points=" << nb_points;
+		m_pLogger->INFO(buff.str());
+	}
 
 	//获取叶片的点云
 	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_leaf(new pcl::PointCloud<pcl::PointXYZ>);

+ 1 - 0
grab_point_rs.h

@@ -198,6 +198,7 @@ namespace graft_cv {
 
 		//生成结果图片
 		void gen_result_img(
+			pcl::PointCloud<pcl::PointXYZ>::Ptr in_cloud_raw,//输入,未经过滤的整体点云in_cloud_raw, 
 			pcl::PointCloud<pcl::PointXYZ>::Ptr,	//输入,整体点云cloud_dowm_sampled, 
 			pcl::PointXYZ& selected_pt,				//输入,selected_pt, 
 			cv::Mat& rst_img						//输出,图片, 640*1280

+ 1 - 1
graft_cv_api.cpp

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