Forráskód Böngészése

v0.8.0 叶子遮挡识别;去除原来图片识别的内容;修改配置参数仅保留3d相关参数

chenhongjiang 2 éve
szülő
commit
85151f15c9
23 módosított fájl, 1087 hozzáadás és 7187 törlés
  1. 2 1
      ReadMe.txt
  2. 34 190
      config.cpp
  3. 0 7
      cut_point_impl_rs.h
  4. 0 961
      cut_point_rs.cpp
  5. 0 129
      cut_point_rs.h
  6. 0 710
      cut_point_rs_reid.cpp
  7. 0 86
      cut_point_rs_reid.h
  8. 0 595
      cut_point_sc.cpp
  9. 0 66
      cut_point_sc.h
  10. 8 135
      data_def_api.h
  11. 0 1633
      demo.cpp
  12. 0 131
      fork_rs.cpp
  13. 0 31
      fork_rs.h
  14. 15 89
      gcv_conf.yml
  15. 400 0
      grab_occlusion.cpp
  16. 80 0
      grab_occlusion.h
  17. 441 614
      grab_point_rs.cpp
  18. 33 36
      grab_point_rs.h
  19. 43 248
      graft_cv_api.cpp
  20. 31 97
      graft_cv_api.h
  21. 0 1207
      optimal_angle.cpp
  22. 0 180
      optimal_angle.h
  23. 0 41
      test.cpp

+ 2 - 1
ReadMe.txt

@@ -108,4 +108,5 @@ v0.7.19 
 v0.7.20 优化茎节位置识别,在v0.7.19基础上加上历史均值位置约束,rs_grab_fork_th和sc_grab_fork_th是茎节粗和茎粗的比值系数
 v0.7.21 优化茎节位置识别,增加偏离平均茎节高度的距离参数rs_grab_to_meanfork_max_dist和sc_grab_to_meanfork_max_dist
 v0.7.22 优化茎节位置识别,废弃基于历史平均茎节高度的约束,人工指定范围(高度上限,下限),不在范围内时,按下限位置
-v0.7.23 识别接口返回图片,返回茎的弯曲度,当前苗的数量
+v0.7.23 识别接口返回图片,返回茎的弯曲度,当前苗的数量
+v0.8.0 叶子遮挡识别;去除原来图片识别的内容;修改配置参数仅保留3d相关参数

+ 34 - 190
config.cpp

@@ -20,65 +20,11 @@ namespace graft_cv{
 		assert(m_cparam!=0);
 		fs << "{" 
 			<< "image_show"<<  m_cparam->image_show
-			<< "image_return"<<  m_cparam->image_return
-			<< "image_row_grid"<<  m_cparam->image_row_grid
-			<< "image_col_grid"<<  m_cparam->image_col_grid
-			<< "self_camera"<< m_cparam->self_camera
-
-			<<"timeout_proc"<<m_cparam->timeout_proc
-			<<"timeout_append"<<m_cparam->timeout_append
+			<< "image_return"<<  m_cparam->image_return		
 
 			<<"image_save"<<m_cparam->image_save
 			<<"image_depository"<<m_cparam->image_depository
-			<<"image_backup_days"<<m_cparam->image_backup_days
-
-			<< "oa_y_flip"<<  m_cparam->oa_y_flip 	
-			<< "oa_morph_radius"<<  m_cparam->oa_morph_radius 	
-			<< "oa_morph_iteration" << m_cparam->oa_morph_iteration
-			<< "oa_min_leaf_area"<< m_cparam->oa_min_leaf_area			
-
-			<< "rs_y_flip"<<  m_cparam->rs_y_flip 	
-			<< "rs_min_hist_value"<< m_cparam->rs_min_hist_value
-			<< "rs_col_th_ratio" << m_cparam->rs_col_th_ratio		
-			<< "rs_row_th_ratio" << m_cparam->rs_row_th_ratio
-			<< "rs_stem_x_padding" << m_cparam->rs_stem_x_padding
-			<< "rs_stem_dia_min" << m_cparam->rs_stem_dia_min
-			<< "rs_stem_dia_mp" << m_cparam->rs_stem_dia_mp
-			<< "rs_stem_fork_y_min" << m_cparam->rs_stem_fork_y_min			
-			<< "rs_stem_edge_detect_window" << m_cparam->rs_stem_edge_detect_window
-			<< "rs_cand_corner_box_width_ratio" << m_cparam->rs_cand_corner_box_width_ratio
-			<< "rs_cand_corner_box_xoffset_ratio" << m_cparam->rs_cand_corner_box_xoffset_ratio
-			<< "rs_opt_corner_xoffset_ratio" << m_cparam->rs_opt_corner_xoffset_ratio
-			<< "rs_opt_corner_yoffset_ratio" << m_cparam->rs_opt_corner_yoffset_ratio
-			<<"rs_corner_mask_rad_ratio"<<m_cparam->rs_corner_mask_rad_ratio
-			<< "rs_morph_radius" << m_cparam->rs_morph_radius
-			<< "rs_morph_iteration" << m_cparam->rs_morph_iteration
-			<< "rs_morph_iteration_gray" << m_cparam->rs_morph_iteration_gray
-			<< "rs_max_corner_num" << m_cparam->rs_max_corner_num
-			<< "rs_corner_qaulity_level" << m_cparam->rs_corner_qaulity_level
-			<< "rs_corner_min_distance" << m_cparam->rs_corner_min_distance
-			<< "rs_cut_angle" << m_cparam->rs_cut_angle
-			<< "rs_cut_point_offset_ratio"<< m_cparam->rs_cut_point_offset_ratio
-			   
-			<< "sc_y_flip"<<  m_cparam->sc_y_flip 	
-			<< "sc_col_th_ratio" << m_cparam->sc_col_th_ratio
-			<< "sc_row_th_ratio" << m_cparam->sc_row_th_ratio
-			<< "sc_stem_x_padding" << m_cparam->sc_stem_x_padding
-			<< "sc_stem_dia_min"<< m_cparam->sc_stem_dia_min
-			<< "sc_clip_padding" << m_cparam->sc_clip_padding
-			<< "sc_stem_ymax_padding" << m_cparam->sc_stem_ymax_padding
-			<< "sc_default_cut_length" << m_cparam->sc_default_cut_length	
-
-			<< "sc_stem_edge_detect_window" << m_cparam->sc_stem_edge_detect_window
-			<< "sc_r2_th" << m_cparam->sc_r2_th
-			<< "sc_r2_window" << m_cparam->sc_r2_window
-			<< "sc_average_window" << m_cparam->sc_average_window
-			<< "sc_morph_radius" << m_cparam->sc_morph_radius
-			<< "sc_morph_iteration" << m_cparam->sc_morph_iteration
-			   
-			<< "rs_oa_pixel_ratio" << m_cparam->rs_oa_pixel_ratio
-			<< "rs_cut_pixel_ratio" << m_cparam->rs_cut_pixel_ratio
-			<< "sc_cut_pixel_ratio" << m_cparam->sc_cut_pixel_ratio
+			<<"image_backup_days"<<m_cparam->image_backup_days			
 
 			<< "rs_grab_xmin" << m_cparam->rs_grab_xmin
 			<< "rs_grab_xmax" << m_cparam->rs_grab_xmax
@@ -89,11 +35,12 @@ namespace graft_cv{
 			<< "rs_grab_stem_diameter" << m_cparam->rs_grab_stem_diameter			
 			<< "rs_grab_seedling_dist" << m_cparam->rs_grab_seedling_dist
 			<< "rs_grab_stem_min_pts" << m_cparam->rs_grab_stem_min_pts
+			<< "rs_grab_seedling_min_pts" << m_cparam->rs_grab_seedling_min_pts
 			<< "rs_grab_ror_ratio" << m_cparam->rs_grab_ror_ratio
-			<< "rs_grab_offset" << m_cparam->rs_grab_offset
-			<< "rs_grab_fork_th" << m_cparam->rs_grab_fork_th
+			<< "rs_grab_offset" << m_cparam->rs_grab_offset			
 			<< "rs_grab_fork_yup" << m_cparam->rs_grab_fork_yup
 			<< "rs_grab_fork_ybt" << m_cparam->rs_grab_fork_ybt
+			<< "rs_grab_read_history_root_positon" << m_cparam->rs_grab_read_history_root_positon
 
 			<< "sc_grab_xmin" << m_cparam->sc_grab_xmin
 			<< "sc_grab_xmax" << m_cparam->sc_grab_xmax
@@ -104,75 +51,23 @@ namespace graft_cv{
 			<< "sc_grab_stem_diameter" << m_cparam->sc_grab_stem_diameter			
 			<< "sc_grab_seedling_dist" << m_cparam->sc_grab_seedling_dist
 			<< "sc_grab_stem_min_pts" << m_cparam->sc_grab_stem_min_pts
+			<< "sc_grab_seedling_min_pts" << m_cparam->sc_grab_seedling_min_pts
 			<< "sc_grab_ror_ratio" << m_cparam->sc_grab_ror_ratio
-			<< "sc_grab_offset" << m_cparam->sc_grab_offset
-			<< "sc_grab_fork_th" << m_cparam->sc_grab_fork_th
+			<< "sc_grab_offset" << m_cparam->sc_grab_offset			
 			<< "sc_grab_fork_yup" << m_cparam->sc_grab_fork_yup
 			<< "sc_grab_fork_ybt" << m_cparam->sc_grab_fork_ybt
+			<< "sc_grab_read_history_root_positon" << m_cparam->sc_grab_read_history_root_positon
+
 			<< "}"; 	
 	};
 	void CGCvConfig::read(const cv::FileNode& node){ //Read serialization for this class
 		assert(m_cparam!=0);
 		m_cparam->image_show = (bool)(int)node["image_show"];
 		m_cparam->image_return = (bool)(int)node["image_return"];
-		m_cparam->image_row_grid = (int)node["image_row_grid"];
-		m_cparam->image_col_grid = (int)node["image_col_grid"];
-		m_cparam->self_camera = (bool)(int)node["self_camera"];
-
-		m_cparam->timeout_proc = (int)node["timeout_proc"];
-		m_cparam->timeout_append = (int)node["timeout_append"];
-
+		
 		m_cparam->image_save = (bool)(int)node["image_save"];
 		m_cparam->image_depository	=(string)node["image_depository"];
-		m_cparam->image_backup_days = (int)node["image_backup_days"];
-
-		m_cparam->oa_y_flip = (bool)(int)node["oa_y_flip"];
-		/*m_cparam->rs_min_hist_value = (int)node["rs_min_hist_value"];*/
-	    m_cparam->oa_morph_radius = (int)node["oa_morph_radius"];
-		m_cparam->oa_morph_iteration  = (int)node["oa_morph_iteration"];
-		m_cparam->oa_min_leaf_area = (int)node["oa_min_leaf_area"];
-		
-		m_cparam->rs_y_flip = (bool)(int)node["rs_y_flip"];
-		m_cparam->rs_col_th_ratio  = (double)node["rs_col_th_ratio"];
-		m_cparam->rs_row_th_ratio  = (double)node["rs_row_th_ratio"];
-		m_cparam->rs_stem_x_padding  = (int)node["rs_stem_x_padding"];
-		m_cparam->rs_stem_dia_min  = (int)node["rs_stem_dia_min"];
-		m_cparam->rs_stem_dia_mp  = (double)node["rs_stem_dia_mp"];
-		m_cparam->rs_stem_fork_y_min  = (int)node["rs_stem_fork_y_min"];		
-		m_cparam->rs_stem_edge_detect_window  = (int)node["rs_stem_edge_detect_window"];
-		m_cparam->rs_cand_corner_box_width_ratio  = (double)node["rs_cand_corner_box_width_ratio"];
-		m_cparam->rs_cand_corner_box_xoffset_ratio  = (double)node["rs_cand_corner_box_xoffset_ratio"];
-		m_cparam->rs_opt_corner_xoffset_ratio   = (double)node["rs_opt_corner_xoffset_ratio"];
-		m_cparam->rs_opt_corner_yoffset_ratio   = (double)node["rs_opt_corner_yoffset_ratio"];
-		m_cparam->rs_corner_mask_rad_ratio = (double)node["rs_corner_mask_rad_ratio"];
-		m_cparam->rs_morph_radius  = (int)node["rs_morph_radius"];
-		m_cparam->rs_morph_iteration  = (int)node["rs_morph_iteration"];
-		m_cparam->rs_morph_iteration_gray  = (int)node["rs_morph_iteration_gray"];
-		m_cparam->rs_max_corner_num  = (int)node["rs_max_corner_num"];
-		m_cparam->rs_corner_qaulity_level  = (double)node["rs_corner_qaulity_level"];
-		m_cparam->rs_corner_min_distance  = (double)node["rs_corner_min_distance"];
-		m_cparam->rs_cut_angle = (double)node["rs_cut_angle"];
-		m_cparam->rs_cut_point_offset_ratio = (double)node["rs_cut_point_offset_ratio"];
-
-		m_cparam->sc_y_flip = (bool)(int)node["sc_y_flip"];
-		m_cparam->sc_col_th_ratio  = (double)node["sc_col_th_ratio"];
-		m_cparam->sc_row_th_ratio  = (double)node["sc_row_th_ratio"];
-		m_cparam->sc_stem_x_padding  = (int)node["sc_stem_x_padding"];
-		m_cparam->sc_stem_dia_min  = (int)node["sc_stem_dia_min"];
-		m_cparam->sc_clip_padding  = (int)node["sc_clip_padding"];
-		m_cparam->sc_stem_ymax_padding  = (int)node["sc_stem_ymax_padding"];
-		m_cparam->sc_default_cut_length  = (int)node["sc_default_cut_length"];
-
-		m_cparam->sc_stem_edge_detect_window = (int)node["sc_stem_edge_detect_window"];
-		m_cparam->sc_r2_th  = (double)node["sc_r2_th"];
-		m_cparam->sc_r2_window  = (int)node["sc_r2_window"];
-		m_cparam->sc_average_window  = (int)node["sc_average_window"];
-		m_cparam->sc_morph_radius  = (int)node["sc_morph_radius"];
-		m_cparam->sc_morph_iteration  = (int)node["sc_morph_iteration"];		
-
-		m_cparam->rs_oa_pixel_ratio  = (double)node["rs_oa_pixel_ratio"];
-		m_cparam->rs_cut_pixel_ratio  = (double)node["rs_cut_pixel_ratio"];
-		m_cparam->sc_cut_pixel_ratio  = (double)node["sc_cut_pixel_ratio"]; 
+		m_cparam->image_backup_days = (int)node["image_backup_days"];	
 
 		m_cparam->rs_grab_xmin = (double)node["rs_grab_xmin"];
 		m_cparam->rs_grab_xmax = (double)node["rs_grab_xmax"];
@@ -183,11 +78,12 @@ namespace graft_cv{
 		m_cparam->rs_grab_stem_diameter = (double)node["rs_grab_stem_diameter"];		
 		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_seedling_min_pts = (int)node["rs_grab_seedling_min_pts"];
 		m_cparam->rs_grab_ror_ratio = (double)node["rs_grab_ror_ratio"];
-		m_cparam->rs_grab_offset = (double)node["rs_grab_offset"];
-		m_cparam->rs_grab_fork_th = (double)node["rs_grab_fork_th"];
+		m_cparam->rs_grab_offset = (double)node["rs_grab_offset"];		
 		m_cparam->rs_grab_fork_yup = (double)node["rs_grab_fork_yup"];
 		m_cparam->rs_grab_fork_ybt = (double)node["rs_grab_fork_ybt"];
+		m_cparam->rs_grab_read_history_root_positon = (bool)(int)node["rs_grab_read_history_root_positon"];
 
 		m_cparam->sc_grab_xmin = (double)node["sc_grab_xmin"];
 		m_cparam->sc_grab_xmax = (double)node["sc_grab_xmax"];
@@ -198,95 +94,41 @@ namespace graft_cv{
 		m_cparam->sc_grab_stem_diameter = (double)node["sc_grab_stem_diameter"];		
 		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_seedling_min_pts = (int)node["sc_grab_seedling_min_pts"];
 		m_cparam->sc_grab_ror_ratio = (double)node["sc_grab_ror_ratio"];
-		m_cparam->sc_grab_offset = (double)node["sc_grab_offset"];
-		m_cparam->sc_grab_fork_th = (double)node["sc_grab_fork_th"];
+		m_cparam->sc_grab_offset = (double)node["sc_grab_offset"];		
 		m_cparam->sc_grab_fork_yup = (double)node["sc_grab_fork_yup"];
 		m_cparam->sc_grab_fork_ybt = (double)node["sc_grab_fork_ybt"];
-
+		m_cparam->sc_grab_read_history_root_positon = (bool)(int)node["sc_grab_read_history_root_positon"];
   }
 	string get_cparam_info(ConfigParam*m_cparam)
 	{
 		if(!m_cparam){return string("");}
 
 		stringstream buff;
-		buff << "{" <<endl
-			<< "image_show:\t"<<  m_cparam->image_show << endl
-			<< "image_return:\t"<<  m_cparam->image_return << endl
-			<< "image_row_grid:\t"<<  m_cparam->image_row_grid << endl
-			<< "image_col_grid:\t"<<  m_cparam->image_col_grid << endl
-			<< "self_camera:\t"<< m_cparam->self_camera << endl
-
-			<<"timeout_proc:\t"<<m_cparam->timeout_proc << endl
-			<<"timeout_append:\t"<<m_cparam->timeout_append << endl
-
-			<<"image_save:\t"<<m_cparam->image_save << endl
-			<<"image_depository:\t"<<m_cparam->image_depository << endl
-			<<"image_backup_days:\t"<<m_cparam->image_backup_days << endl
-
-			<< "oa_y_flip:\t"<<  m_cparam->oa_y_flip 	 << endl
-			<< "oa_morph_radius:\t"<<  m_cparam->oa_morph_radius 	 << endl
-			<< "oa_morph_iteration:\t" << m_cparam->oa_morph_iteration << endl
-			<< "oa_min_leaf_area:\t"<< m_cparam->oa_min_leaf_area << endl		
-
-
-			<< "rs_y_flip:\t"<<  m_cparam->rs_y_flip 	 << endl
-			<< "rs_min_hist_value:\t"<< m_cparam->rs_min_hist_value << endl
-			<< "rs_col_th_ratio:\t" << m_cparam->rs_col_th_ratio		 << endl
-			<< "rs_row_th_ratio:\t" << m_cparam->rs_row_th_ratio << endl
-			<< "rs_stem_x_padding:\t" << m_cparam->rs_stem_x_padding << endl
-			<< "rs_stem_dia_min:\t" << m_cparam->rs_stem_dia_min << endl
-			<< "rs_stem_dia_mp:\t" << m_cparam->rs_stem_dia_mp << endl
-			<< "rs_stem_fork_y_min:\t" << m_cparam->rs_stem_fork_y_min			 << endl
-			<< "rs_stem_edge_detect_window:\t" << m_cparam->rs_stem_edge_detect_window << endl
-			<< "rs_cand_corner_box_width_ratio:\t" << m_cparam->rs_cand_corner_box_width_ratio << endl
-			<< "rs_cand_corner_box_xoffset_ratio:\t" << m_cparam->rs_cand_corner_box_xoffset_ratio << endl
-			<< "rs_opt_corner_xoffset_ratio:\t" << m_cparam->rs_opt_corner_xoffset_ratio << endl
-			<< "rs_opt_corner_yoffset_ratio:\t" << m_cparam->rs_opt_corner_yoffset_ratio << endl
-			<<"rs_corner_mask_rad_ratio:\t"<<m_cparam->rs_corner_mask_rad_ratio << endl
-			<< "rs_morph_radius:\t" << m_cparam->rs_morph_radius << endl
-			<< "rs_morph_iteration:\t" << m_cparam->rs_morph_iteration << endl
-			<< "rs_morph_iteration_gray:\t" << m_cparam->rs_morph_iteration_gray << endl
-			<< "rs_max_corner_num:\t" << m_cparam->rs_max_corner_num << endl
-			<< "rs_corner_qaulity_level:\t" << m_cparam->rs_corner_qaulity_level << endl
-			<< "rs_corner_min_distance:\t" << m_cparam->rs_corner_min_distance << endl
-			<< "rs_cut_angle:\t" << m_cparam->rs_cut_angle << endl
-			<< "rs_cut_point_offset_ratio:\t"<< m_cparam->rs_cut_point_offset_ratio << endl
-			   
-			<< "sc_y_flip:\t"<<  m_cparam->sc_y_flip 	 << endl
-			<< "sc_col_th_ratio:\t" << m_cparam->sc_col_th_ratio << endl
-			<< "sc_row_th_ratio:\t" << m_cparam->sc_row_th_ratio << endl
-			<< "sc_stem_x_padding:\t" << m_cparam->sc_stem_x_padding << endl
-			<< "sc_stem_dia_min:\t"<< m_cparam->sc_stem_dia_min << endl
-			<< "sc_clip_padding:\t" << m_cparam->sc_clip_padding << endl
-			<< "sc_stem_ymax_padding:\t" << m_cparam->sc_stem_ymax_padding << endl
-			<< "sc_default_cut_length:\t" << m_cparam->sc_default_cut_length	 << endl
-
-			<< "sc_stem_edge_detect_window:\t" << m_cparam->sc_stem_edge_detect_window << endl
-			<< "sc_r2_th:\t" << m_cparam->sc_r2_th << endl
-			<< "sc_r2_window:\t" << m_cparam->sc_r2_window << endl
-			<< "sc_average_window:\t" << m_cparam->sc_average_window << endl
-			<< "sc_morph_radius:\t" << m_cparam->sc_morph_radius << endl
-			<< "sc_morph_iteration:\t" << m_cparam->sc_morph_iteration			    << endl
-
-			<< "rs_oa_pixel_ratio:\t" << m_cparam->rs_oa_pixel_ratio << endl
-			<< "rs_cut_pixel_ratio:\t" << m_cparam->rs_cut_pixel_ratio << endl
-			<< "sc_cut_pixel_ratio:\t" << m_cparam->sc_cut_pixel_ratio << endl
-
+		buff << "{" << endl
+			<< "image_show:\t" << m_cparam->image_show << endl
+			<< "image_return:\t" << m_cparam->image_return << endl			
+
+			<< "image_save:\t" << m_cparam->image_save << endl
+			<< "image_depository:\t" << m_cparam->image_depository << endl
+			<< "image_backup_days:\t" << m_cparam->image_backup_days << endl
+			
 			<< "rs_grab_xmin:\t" << m_cparam->rs_grab_xmin << endl
 			<< "rs_grab_xmax:\t" << m_cparam->rs_grab_xmax << endl
 			<< "rs_grab_ymin:\t" << m_cparam->rs_grab_ymin << endl
 			<< "rs_grab_ymax:\t" << m_cparam->rs_grab_ymax << endl
 			<< "rs_grab_zmin:\t" << m_cparam->rs_grab_zmin << endl
 			<< "rs_grab_zmax:\t" << m_cparam->rs_grab_zmax << endl
-			<< "rs_grab_stem_diameter:\t" << m_cparam->rs_grab_stem_diameter << endl			
-            << "rs_grab_seedling_dist:\t" << m_cparam->rs_grab_seedling_dist << endl
+			<< "rs_grab_stem_diameter:\t" << m_cparam->rs_grab_stem_diameter << 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_seedling_min_pts:\t" << m_cparam->rs_grab_seedling_min_pts << endl
 			<< "rs_grab_ror_ratio:\t" << m_cparam->rs_grab_ror_ratio << endl
-			<< "rs_grab_offset:\t" << m_cparam->rs_grab_offset << endl
-			<< "rs_grab_fork_th:\t" << m_cparam->rs_grab_fork_th << endl
+			<< "rs_grab_offset:\t" << m_cparam->rs_grab_offset << endl			
 			<< "rs_grab_fork_yup:\t" << m_cparam->rs_grab_fork_yup << endl
 			<< "rs_grab_fork_ybt:\t" << m_cparam->rs_grab_fork_ybt << endl
+			<< "rs_grab_read_history_root_positon:\t" << m_cparam->rs_grab_read_history_root_positon << endl
 
 			<< "sc_grab_xmin:\t" << m_cparam->sc_grab_xmin << endl
 			<< "sc_grab_xmax:\t" << m_cparam->sc_grab_xmax << endl
@@ -297,11 +139,13 @@ namespace graft_cv{
 			<< "sc_grab_stem_diameter:\t" << m_cparam->sc_grab_stem_diameter << 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_seedling_min_pts:\t" << m_cparam->sc_grab_seedling_min_pts << endl
 			<< "sc_grab_ror_ratio:\t" << m_cparam->sc_grab_ror_ratio << endl
-			<< "sc_grab_offset:\t" << m_cparam->sc_grab_offset << endl
-			<< "sc_grab_fork_th:\t" << m_cparam->sc_grab_fork_th << endl
+			<< "sc_grab_offset:\t" << m_cparam->sc_grab_offset << endl			
 			<< "sc_grab_fork_yup:\t" << m_cparam->sc_grab_fork_yup << endl
 			<< "sc_grab_fork_ybt:\t" << m_cparam->sc_grab_fork_ybt << endl
+			<< "sc_grab_read_history_root_positon:\t" << m_cparam->sc_grab_read_history_root_positon << endl
+
 			<< "}" << endl; 	
 		return buff.str();
 	}

+ 0 - 7
cut_point_impl_rs.h

@@ -1,7 +0,0 @@
-#pragma once
-
-#include <opencv.hpp>
-//using namespace cv;
-namespace graft_cv{
-
-}

+ 0 - 961
cut_point_rs.cpp

@@ -1,961 +0,0 @@
-/*
-  砧木切割点识别
-
-  1)压左侧叶
-  2)识别左侧叶柄分割点,
-  3)切割角度:-45度
-
-*/
-#include <opencv2\imgproc\imgproc.hpp>
-#include <math.h>
-#include <algorithm>
-
-#include "cut_point_rs.h"
-#include "utils.h"
-#include "data_def.h"
-#include "logger.h"
-//using namespace cv;
-
-namespace graft_cv{
-
-CRootStockCutPoint::CRootStockCutPoint(ConfigParam&cp,CGcvLogger*pLog/*=0*/)
-:m_cparam(cp),
-m_pLogger(pLog),
-m_pImginfoBinFork(0),
-m_pImgCorners(0),
-m_pImgCutPoint(0),
-m_imgId(""),
-m_ppImgSaver(0)
-{	
-}
-CRootStockCutPoint::~CRootStockCutPoint()
-{
-	this->clear_imginfo();	
-}
-
-void CRootStockCutPoint::clear_imginfo(){
-	if (m_pImginfoBinFork){
-		imginfo_release(&m_pImginfoBinFork);
-		m_pImginfoBinFork=0;
-	}
-	if (m_pImgCorners){
-		imginfo_release(&m_pImgCorners);
-		m_pImgCorners=0;
-	}
-	if (m_pImgCutPoint){
-		imginfo_release(&m_pImgCutPoint);
-		m_pImgCutPoint=0;
-	}
-}
-
-int CRootStockCutPoint::up_point_detect(
-	ImgInfo* imginfo, 
-	cv::Mat&cimg,
-	PositionInfo& posinfo,
-	map<string, cv::Mat>& img_cache
-	)
-{
-	// cimg --- color image, bgr
-	/*
-	# 找到竖直的径,并对径两侧兴趣区域进行分析:茎位置,分叉位置,用于协助确定上切割点位置,或下切割点位置
-    #     1)如果找到切割位置的角点,用角点作为上切割点,确定下切割点
-    #     2)如果没有找到上切割点,通过分叉位置确定下切割点,根据径粗推导出上切割点
-    h_ratio = 0.7 # 垂直方向hist,最高点的70%作为阈值,判断茎的位置
-    v_ration = 1.2 # 水平方向hist,茎粗确定后,茎粗的1.2倍断定为分叉点    
-    */
-    m_imgId = getImgId(img_type::rs);
-	//1 image segment
-	if(m_pLogger){				
-		m_pLogger->INFO(m_imgId +" rootstock cut_pt detect begin");				
-	}
-
-	clock_t t;
-	clock_t t0 = clock();
-	
-	
-
-	cv::Mat img;
-	if(imginfo){
-		if(m_pLogger){		
-			stringstream buff;
-			buff<<m_imgId<<" rootstock image, width="<<imginfo->width
-				<<"\theight="<<imginfo->height;
-			m_pLogger->INFO(buff.str());
-		}
-		if(!isvalid(imginfo)){
-			if(m_pLogger){				
-				m_pLogger->ERRORINFO(m_imgId+" rootstock input image invalid.");				
-			}
-			throw_msg(m_imgId+" invalid input image");	
-			
-		}	
-		img = imginfo2mat(imginfo);
-	}
-	else{
-		if(m_pLogger){		
-			stringstream buff;
-			buff<<m_imgId<<"rootstock image, width="<<cimg.cols
-				<<"\theight="<<cimg.rows;
-			m_pLogger->INFO(buff.str());
-		}
-		if(cimg.empty()){
-			if(m_pLogger){				
-				m_pLogger->ERRORINFO(m_imgId+" rootstock input image invalid.");				
-			}
-			throw_msg(m_imgId +" invalid input image");
-			
-		}
-		img = cimg;
-	}
-	
-	if(m_cparam.self_camera){
-		image_set_bottom(img,20,8);
-        if(m_pLogger){				
-			m_pLogger->DEBUG(m_imgId+" image set bottom with pixel value 20.");				
-		}
-	}
-	if(m_cparam.rs_y_flip){
-		flip(img,img,0);
-        if(m_pLogger){				
-			m_pLogger->DEBUG(m_imgId+" image y fliped.");				
-		}
-	}
-	
-	//image saver
-	if(m_ppImgSaver && *m_ppImgSaver){
-		(*m_ppImgSaver)->saveImage(img, m_imgId);
-	}
-    if(m_pLogger){				
-		m_pLogger->DEBUG(m_imgId+" before image segment.");				
-	}	
-	///////////////////////////////////////////////////////
-	// image segment
-	this->img_segment(img);
-	// image save to cache, clear first
-	img_cache.clear();
-	img_cache.insert(pair<string, cv::Mat>(m_imgId, m_grayImg.clone()));
-
-    if(m_pLogger){	
-		m_pLogger->DEBUG(m_imgId+" after image segment.");				
-	}
-
-	if(m_cparam.image_show){
-		cv::destroyAllWindows();
-		imshow_wait("rs_bin",m_binImg);		
-	}
-	else{
-		t = clock();
-		if(1000.0*((float)(t-t0))/CLOCKS_PER_SEC>(float)m_cparam.timeout_proc){
-			if(m_pLogger){				
-				m_pLogger->ERRORINFO(m_imgId+" rootstock timeout.");				
-			}
-			throw_msg(m_imgId+" time out");
-		}
-	}
-    if(m_pLogger){	
-		m_pLogger->DEBUG(m_imgId+" after m_binImg image show.");				
-	}
-	
-	//2 茎位置:x方向位置范围
-	// 2.1 计算砧木x方向位置,中心
-	vector<int> hist_col_pre;
-	mat_histogram(m_binImg, hist_col_pre, 0);		
-
-	int min_idx, max_idx;
-	min_idx = hist_col_pre.size();
-	max_idx = 0;
-	vector<int>::const_iterator it0 = hist_col_pre.begin();
-	for(vector<int>::const_iterator it = hist_col_pre.begin();it!=hist_col_pre.end();++it){
-		if(*it>=m_cparam.rs_min_hist_value){
-			int idx = it - it0;
-			if(idx<min_idx){min_idx = idx;}
-			if(idx > max_idx) {max_idx = idx;}
-		}
-	}
-	if(max_idx<=min_idx){
-		throw_msg(m_imgId+" invalid binary image, not exist valid objects");		
-	}
-
-	if(m_cparam.image_show){			
-		cv::Mat tmp = m_binImg.clone();
-		cv::line(tmp, cv::Point(min_idx,0), cv::Point(min_idx,tmp.rows), cv::Scalar(156),3);
-		cv::line(tmp, cv::Point(max_idx,0), cv::Point(max_idx,tmp.rows), cv::Scalar(156),3);
-
-		imshow_wait("rs_bin_x_range", tmp);		
-	}
-    int width = max_idx-min_idx+1;	
-	int cent_x = (int)(0.5*(double) (max_idx-min_idx));
-
-    
-	vector<int> hist_col;
-	mat_histogram_w(m_binImg,hist_col);
-
-	if(m_cparam.image_show){		
-		cv::Mat hist_col_img;
-		hist2image(hist_col,hist_col_img,1,m_cparam.image_col_grid,m_cparam.image_row_grid);		
-		imshow_wait("rs_hist_col", hist_col_img);		
-	}
-
-    if(m_pLogger){	
-		m_pLogger->DEBUG(m_imgId+" after histogram col.");				
-	}
-	int x0,x1,stem_x0, stem_x1;
-	get_stem_x_range_rscut(
-		hist_col,
-		m_cparam.rs_col_th_ratio,
-		m_cparam.rs_stem_x_padding,
-		cent_x,
-		width,
-		x0,
-		x1,
-		stem_x0,
-		stem_x1);
-
-	if(m_pLogger){		
-		stringstream buff;
-		buff<<m_imgId<<" rootstock image, x0="<<x0
-			<<"\tx1="<<x1
-			<<"\tstem_x0="<<stem_x0
-			<<"\tstem_x1="<<stem_x1;
-		m_pLogger->INFO(buff.str());
-	}
-
-	if(m_cparam.image_show){		
-		cv::Mat tmp_img = m_binImg.clone();
-
-		cv::line(tmp_img, cv::Point(x0,0), cv::Point(x0,m_binImg.rows-1), cv::Scalar(100),2);
-		cv::line(tmp_img, cv::Point(x1,0), cv::Point(x1,m_binImg.rows-1), cv::Scalar(100),2);
-		//fork right point
-		imshow_wait("rs_x_field", tmp_img);				
-	}
-	
-	//3 茎分叉位置:y方向分叉位置识别
-	vector<int> hist_row;
-	mat_histogram(m_binImg,hist_row,1,-1,-1,x0,x1+1);
-	hist_filter(hist_row,0,5);
-	if(m_pLogger){	
-		m_pLogger->DEBUG(m_imgId+" after histogram row.");				
-	}
-
-	if(m_cparam.image_show){		
-		cv::Mat hist_row_img;
-		hist2image(hist_row,hist_row_img, 0,m_cparam.image_col_grid,m_cparam.image_row_grid);		
-		imshow_wait("rs_hist_row", hist_row_img);		
-	}
-	else{
-		t = clock();
-		if(1000.0*((float)(t-t0))/CLOCKS_PER_SEC>(float)m_cparam.timeout_proc){
-			if(m_pLogger){				
-				m_pLogger->ERRORINFO(m_imgId+" rootstock timeout.");				
-			}
-			throw_msg(m_imgId+" time out");
-		}
-	}
-
-	int stem_fork_y_pre=-1,stem_fork_y=-1,stem_end_y=-1,stem_dia=-1;
-	
-	int roi_max_y=-1;
-	get_stem_y_fork_rs(
-		hist_row,
-		m_cparam.rs_row_th_ratio,
-		m_cparam.rs_stem_dia_min,
-		m_cparam.rs_stem_fork_y_min,
-		m_cparam.rs_stem_dia_mp,
-		stem_fork_y_pre,
-		stem_end_y,
-		stem_dia,
-		roi_max_y);
-
-	
-	cv::Point fork_cent;
-	double max_radius;
-	double stem_angle;
-	get_stem_y_fork_rs_update(
-		m_binImg,
-		m_cparam.rs_stem_x_padding,
-		x0,
-		x1,
-		roi_max_y,
-		stem_end_y,
-		stem_dia,
-		m_cparam.image_show,
-		m_cparam.rs_cut_point_offset_ratio,
-		fork_cent,
-		max_radius,
-		stem_angle
-	);
-	stem_fork_y = fork_cent.y;
-
-	if(m_pLogger){		
-		stringstream buff;
-		buff<<m_imgId<<" rootstock image, stem_fork_y="<<stem_fork_y
-			<<"\tstem_end_y="<<stem_end_y
-			<<"\tstem_dia="<<stem_dia;
-		m_pLogger->INFO(buff.str());
-	}
-
-	//4 茎分叉位置,茎左侧边缘点识别
-	int stem_fork_left_x, stem_fork_right_x;
-	get_stem_fork_xs(
-		m_binImg,
-		stem_fork_y,
-		stem_x0,
-		stem_x1,
-		x0,
-		x1,		
-		stem_fork_left_x,
-		stem_fork_right_x);
-	int stem_fork_dia = stem_fork_right_x - stem_fork_left_x;
-
-	gcv_point<int> cut_pt = gcv_point<int>((int)(stem_fork_left_x + 0.5*(stem_fork_right_x - stem_fork_left_x)),stem_fork_y);
-
-	if(m_pLogger){		
-		stringstream buff;
-		buff<<m_imgId<<" rootstock image, stem_fork_x0="<<stem_fork_left_x
-			<<"\tstem_fork_x1="<<stem_fork_right_x
-			<<"\tstem_fork_diameter="<<stem_fork_dia;
-		m_pLogger->INFO(buff.str());
-	}
-
-	
-	//lower cut point	
-	gcv_point<int> lower_cut_pt = gcv_point<int>(-1,-1);	
-	find_lower_cut_point(m_binImg,cut_pt, lower_cut_pt, m_cparam.rs_cut_angle, stem_dia);
-	if(m_cparam.image_show){
-		cv::Mat stem_img = m_binImg.clone();
-		cv::line(stem_img, cv::Point(stem_x0,0), cv::Point(stem_x0,stem_img.rows-1), cv::Scalar(100),2);
-		cv::line(stem_img, cv::Point(stem_x1,0), cv::Point(stem_x1,stem_img.rows-1), cv::Scalar(100),2);
-		//fork left point
-		circle(stem_img, cv::Point(stem_fork_left_x,stem_fork_y),5, cv::Scalar(128,0,128), -1, 8,0);
-		circle(stem_img, cv::Point(stem_fork_right_x,stem_fork_y),5, cv::Scalar(128,0,128), -1, 8,0);
-		
-		cv::Mat gray_img = m_grayImg.clone();
-		cv::circle(gray_img, cv::Point(stem_fork_left_x,stem_fork_y),5, cv::Scalar(128,0,128), -1, 8,0);
-		cv::circle(gray_img, cv::Point(stem_fork_right_x,stem_fork_y),5, cv::Scalar(128,0,128), -1, 8,0);
-		cv::circle(gray_img, cv::Point((int)cut_pt.x,cut_pt.y),5, cv::Scalar(200,0,200), -1, 8,0);
-		cv::circle(gray_img, cv::Point(lower_cut_pt.x,lower_cut_pt.y),5, cv::Scalar(200,0,200), -1, 8,0);
-		image_draw_line(gray_img,cut_pt.x,cut_pt.y,lower_cut_pt.x,lower_cut_pt.y);
-		imshow_wait("rs_fork_left_right_point", stem_img);		
-		imshow_wait("rs_fork_left_right_point", gray_img);
-	}
-	else{
-		t = clock();
-		if(1000.0*((float)(t-t0))/CLOCKS_PER_SEC>(float)m_cparam.timeout_proc){
-			if(m_pLogger){				
-				m_pLogger->ERRORINFO(m_imgId+" rootstock timeout.");				
-			}
-			throw_msg(m_imgId+" time out");
-		}
-	}
-
-	if(m_pLogger){		
-		stringstream buff;
-		buff<<m_imgId<<" rootstock image, upper_cut_point("<<cut_pt.x
-			<<","<<cut_pt.y<<")"<<", lower_cut_pt( "<<lower_cut_pt.x
-			<<","<<lower_cut_pt.y<<")";
-		m_pLogger->INFO(buff.str());
-	}
-
-	//////////////////////////////////////start
-	//v0.5.9.3 更改(2022-01-02)
-	//cut_pt.x = stem_fork_left_x + 0.5*(stem_fork_right_x - stem_fork_left_x);
-	//cut_pt.y = stem_fork_y;
-	///////////////////////////////////////end
-
-	double rs_cut_upoint_x = (double)cut_pt.x;
-	//rs_cut_upoint_x -= (double)(img.cols/2.0);
-	//rs_cut_upoint_x *= m_cparam.rs_cut_pixel_ratio;
-
-	double rs_cut_upoint_y = (double)cut_pt.y;
-	//rs_cut_upoint_y = (double)(img.rows/2.0) - rs_cut_upoint_y;
-	//rs_cut_upoint_y *= m_cparam.rs_cut_pixel_ratio;
-
-	//double rs_stem_diameter = stem_dia * m_cparam.rs_cut_pixel_ratio;
-	double rs_stem_diameter = stem_dia;
-
-	double rs_cut_lpoint_x = lower_cut_pt.x;
-	//rs_cut_lpoint_x -= (double)(img.cols/2.0);
-	//rs_cut_lpoint_x *= m_cparam.rs_cut_pixel_ratio;
-
-	double rs_cut_lpoint_y = lower_cut_pt.y;
-	//rs_cut_lpoint_y = (double)(img.rows/2.0) - rs_cut_lpoint_y;
-	//rs_cut_lpoint_y *= m_cparam.rs_cut_pixel_ratio;
-
-	//posinfo.rs_cut_edge_length = 0.0;
-	posinfo.rs_cut_upoint_x = rs_cut_upoint_x;
-	posinfo.rs_cut_upoint_y = rs_cut_upoint_y;
-    posinfo.rs_stem_diameter = rs_stem_diameter;
-	posinfo.rs_cut_lpoint_x = rs_cut_lpoint_x;
-	posinfo.rs_cut_lpoint_y = rs_cut_lpoint_y;
-
-	if(m_pLogger){		
-		stringstream buff;
-		buff<<m_imgId<<" rootstock image, rs_cut_upoint(mm)("<<rs_cut_upoint_x
-			<<","<<rs_cut_upoint_y<<")"
-			<<", rs_stem_diameter(mm)="<<rs_stem_diameter
-			<<", lower_cut_pt(mm)("<<rs_cut_lpoint_x
-			<<","<<rs_cut_lpoint_y<<")";
-		m_pLogger->INFO(buff.str());
-	}
-
-	//  return images:	posinfo.pp_images
-	if(m_cparam.image_return){
-		this->clear_imginfo();
-		//0) image id
-		strcpy_s(posinfo.rs_img_id,m_imgId.c_str());
-
-		//1) 		
-		//stem x-range
-		cv::line(m_binImg, cv::Point(stem_x0,0), cv::Point(stem_x0,m_binImg.cols-1), cv::Scalar(100),2);
-		cv::line(m_binImg, cv::Point(stem_x1,0), cv::Point(stem_x1,m_binImg.cols-1), cv::Scalar(100),2);
-		//fork right point
-		cv::circle(m_binImg, cv::Point(stem_fork_left_x,stem_fork_y),5, cv::Scalar(128,0,128), -1, 8,0);
-		m_pImginfoBinFork=mat2imginfo(m_binImg);	
-
-		//3 cut point int gray image	
-		cv::circle(m_grayImg, cv::Point(stem_fork_left_x,stem_fork_y),5, cv::Scalar(128,0,128), -1, 8,0);
-		cv::circle(m_grayImg, cv::Point(stem_fork_right_x,stem_fork_y),5, cv::Scalar(128,0,128), -1, 8,0);//v0.5.9.3 reference point
-		cv::circle(m_grayImg, cv::Point(cut_pt.x,stem_fork_y),5, cv::Scalar(128,0,128), -1, 8,0);//v0.5.9.3 reference point
-		cv::circle(m_grayImg, cv::Point(cut_pt.x,stem_fork_y),2, cv::Scalar(255,0,255), -1, 8,0);
-		cv::circle(m_grayImg, cv::Point(lower_cut_pt.x,lower_cut_pt.y),5, cv::Scalar(200,0,200), -1, 8,0);
-		image_draw_line(m_grayImg,cut_pt.x,cut_pt.y,lower_cut_pt.x,lower_cut_pt.y);
-	
-		m_pImgCutPoint = mat2imginfo(m_grayImg);			
-		posinfo.pp_images[0]=m_pImginfoBinFork;
-		posinfo.pp_images[1]=m_pImgCutPoint;
-
-		if(m_ppImgSaver && *m_ppImgSaver){
-			(*m_ppImgSaver)->saveImage(m_binImg, m_imgId+"_rst_0");
-			(*m_ppImgSaver)->saveImage(m_grayImg, m_imgId+"_rst_1");
-		}		
-	}
-	if(m_pLogger){				
-		m_pLogger->INFO(m_imgId +" rootstock cut_pt detect finished.");				
-	}
-	return 0;
-}
-
-void CRootStockCutPoint::get_stem_root_y(
-		vector<int>&hist,		
-		double stem_dia_min,			
-		int & end_y)
-{
-	end_y = -1;
-
-	int start_idx, max_start_idx, max_end_idx, max_len;
-	start_idx= max_start_idx= max_end_idx=-1;
-	max_len=0;
-    
-	for(size_t i = 0; i<hist.size(); i++){
-		if(i==0 && hist[i]>=stem_dia_min){
-			start_idx=0;
-		}
-		if(i==0){continue;}
-
-		if(hist[i]>=stem_dia_min && hist[i-1]<stem_dia_min){
-			start_idx = i;
-			continue;
-		}
-		if(hist[i]<stem_dia_min && hist[i-1]>=stem_dia_min){
-			int lenth = i - start_idx;
-			if(lenth>max_len){
-				max_start_idx= start_idx;
-				max_end_idx = i;
-				max_len = lenth;
-			}
-			continue;
-		}
-		if(i==hist.size()-1){
-			if(hist[i]>=stem_dia_min){
-				int lenth = i - start_idx;
-				if(lenth>max_len){
-					max_start_idx= start_idx;
-					max_end_idx = i;
-					max_len = lenth;
-				}
-			}
-		}
-		
-	}
-	end_y = max_end_idx;	
-}
-
-void CRootStockCutPoint::get_default_cutpoint(
-		int fork_cent_x,
-		int fork_cent_y,
-		int fork_stem_dia,
-	    cv::Point2f& cut_pt)
-{
-	gcv_point<int> start_pt(fork_cent_x,fork_cent_y);
-	gcv_point<int> lower_cut_pt = gcv_point<int>(-1,-1);
-
-	find_lower_cut_point(m_binImg,start_pt,lower_cut_pt,m_cparam.rs_cut_angle+180.0, fork_stem_dia);
-	if(lower_cut_pt.x<0 || lower_cut_pt.y<0){
-		throw_msg(m_imgId+" invalid end points");	
-	}
-	double dist = start_pt.distance(lower_cut_pt);
-	if(dist>fork_stem_dia){
-		double ca = (m_cparam.rs_cut_angle+180.0)*0.0174532925199433;
-		cut_pt.x = start_pt.x+fork_stem_dia*cos(ca);
-		cut_pt.y = start_pt.y-fork_stem_dia*sin(ca);
-	}
-	else{
-		cut_pt.x = lower_cut_pt.x;
-		cut_pt.y = lower_cut_pt.y;
-	}
-}
-void CRootStockCutPoint::img_segment(cv::Mat&img)
-{
-	cv::Mat b_img;
-	if(img.channels()!=1){
-		//color image ,bgr, for testing		
-		cvtColor(img,m_grayImg, cv::COLOR_BGR2GRAY);
-	}
-	else{
-		m_grayImg = img.clone();
-	}
-
-	cv::Mat kernel = cv::getStructuringElement(
-		cv::MORPH_ELLIPSE,
-		cv::Size( 2*m_cparam.rs_morph_radius + 1, 2*m_cparam.rs_morph_radius+1 ),
-		cv::Point( m_cparam.rs_morph_radius, m_cparam.rs_morph_radius )
-		);    
-	/*
-	morphologyEx(
-		g_img, 
-		m_grayImg, 
-		MORPH_CLOSE,
-		kernel,
-		Point(-1,-1),
-		m_cparam.rs_morph_iteration_gray
-		);*/
-
-	double th = threshold(m_grayImg, b_img, 255, 255, cv::THRESH_OTSU);
-
-	morphologyEx(
-		b_img, 
-		m_binImg, 
-		cv::MORPH_CLOSE,
-		kernel,
-		cv::Point(-1,-1),
-		m_cparam.rs_morph_iteration
-		);
-
-	//Canny(m_binImg, m_edgeImg,30,100);
-	
-}
-int CRootStockCutPoint::get_optimal_corner( 
-	int ref_x, 
-	int ref_y,
-	std::vector<cv::Point2f>& corners,
-	int stem_dia,
-	double cand_corner_box_width_ratio,
-	double cand_corner_box_xoffset_ratio,
-	double opt_corner_xoffset_ratio,
-	double opt_corner_yoffset_ratio,	
-	double corner_mask_radius_ratio,
-	cv::Point2f& cut_pt)
-{
-
-	/*"""
-    通过茎左侧分叉点坐标( ref_x, ref_y)判别最优角点
-    stem_img, 二值图像,茎部分的局部图像
-    ref_x, ref_y, 检测到的茎分叉的左侧x,y坐标
-    corners, 图像中的角点
-
-    方法:
-    1 reference点上区域的角点,定义区域
-    2 评价角点
-       角点与直线ref_x的距离
-       角点与参考点间联通性(是否都是前景)
-       角点与参考点的距离(1.5倍茎粗)
-
-    """
-	*/
-	cut_pt.x = -1;
-	cut_pt.y = -1;
-
-    int cand_corner_box_window = (int)(cand_corner_box_width_ratio*stem_dia);
-	int bx = ref_x + (int)(cand_corner_box_xoffset_ratio*stem_dia) - cand_corner_box_window;
-    int by = ref_y - cand_corner_box_window;
-
-    roi_box<int> candidate_box = roi_box<int>(bx,by,cand_corner_box_window,cand_corner_box_window);
-    vector<cv::Point2f>cand_pts;
-    for(size_t i=0; i<corners.size(); ++i){
-        int pt_x = corners[i].x;
-		int pt_y = corners[i].y;
-        if (candidate_box.isInBox(pt_x,pt_y)){
-			cv::Point2f pt;
-			pt.x=corners[i].x;
-			pt.y=corners[i].y;
-            cand_pts.push_back(pt);
-		}
-	}
-
-	if(cand_pts.size()==0){
-		return 1;
-	}
-	//calculate corner pts' corner score of binary image
-	vector<double> cor_mag_scores;
-	corner_magnificence(
-		cand_pts,
-		stem_dia,
-		m_cparam.rs_corner_mask_rad_ratio,
-		cor_mag_scores
-		);
-    //# estimate candidate points' score
-    vector<double>cand_pts_score;
-	int optx = ref_x + (int)(opt_corner_xoffset_ratio * stem_dia);
-	int opty = ref_y + (int)(opt_corner_yoffset_ratio * stem_dia);
-    for(size_t i=0; i<cand_pts.size(); ++i){
-		int ptx = cand_pts[i].x;
-		int pty = cand_pts[i].y;        
-        double score = (double)(abs(ptx - optx));
-        double dist =sqrt((double)((ptx - optx)*(ptx - optx)) +
-			              (double)((pty - opty)* (pty - opty)));
-		double mag_score = stem_dia * (1.0 - cor_mag_scores[i]);
-        score += dist;
-		score += mag_score;
-        cand_pts_score.push_back(score);
-	}
-
-	auto smallest = min_element(begin(cand_pts_score),end(cand_pts_score));
-	size_t min_idx = distance(begin(cand_pts_score), smallest);
-    
-	cut_pt.x = cand_pts[min_idx].x;
-	cut_pt.y = cand_pts[min_idx].y;   
-	return 0;
-}
-
-void CRootStockCutPoint::corner_magnificence(
-		const vector<cv::Point2f>& cand_pts,
-		int stem_dia,
-		double corner_mask_radius_ratio,
-		vector<double>& scores
-		)
-{
-	int r = int(stem_dia*corner_mask_radius_ratio);
-	if (r<=0){r = 1;}
-	int ptx,pty,x,y;
-	double cnt,cnt_pos,score;
-	for(size_t i=0; i<cand_pts.size();++i){
-		ptx = (int)(cand_pts[i].x);
-		pty = (int)(cand_pts[i].y); 
-		cnt = 0.0;
-		cnt_pos = 0.0;
-		for(int dx=-r;dx<=r;++dx){
-			x = ptx+dx;
-			if(x<0 || x>=m_binImg.cols){continue;}
-			for(int dy = -r;dy<=r;++dy){
-				y = pty+dy;
-				if(y<0 || y>=m_binImg.rows){continue;}
-				cnt+=1.0;
-				if(m_binImg.at<unsigned char>(y,x)>0 ){
-					cnt_pos+=1.0;
-				}
-			}
-		}
-		if(cnt>0){score = cnt_pos/cnt;}
-		else{score=0.0;}
-		scores.push_back(score);
-	}
-
-}
-
-double CRootStockCutPoint::get_cut_edge_length
-		(
-			cv::Mat& bin_img,
-			cv::Mat& edge_img,
-		gcv_point<int>& start_pt, //up cut point
-		gcv_point<int>& lower_cut_pt,//output
-		gcv_point<int>& root_pt,//output
-		double cut_angle,
-		int y_max,
-		int stem_dia,
-	    clock_t t0
-		)
-	{
-		double curve_lenth = 0.0;
-		gcv_point<int> pt_tmp = gcv_point<int>(-1,-1);
-		lower_cut_pt = pt_tmp;
-		
-		find_lower_cut_point(bin_img,start_pt, lower_cut_pt, m_cparam.rs_cut_angle, stem_dia);
-		curve_lenth = start_pt.distance(lower_cut_pt);
-
-		if(m_pLogger){		
-			stringstream buff;
-			buff<<m_imgId<<" rootstock image, found lower_cut_point("<<lower_cut_pt.x
-				<<", "<<lower_cut_pt.y<<"), upper_cut_point("<<start_pt.x<<","<<start_pt.y<<") to lower_cut_point length: "<<curve_lenth;
-			m_pLogger->INFO(buff.str());
-		}
-		//Mat edge_img;		
-		root_pt = pt_tmp;
-		//Canny(bin_img, edge_img,30,100);
-		double stem_curve_len = calculate_edge_length(edge_img,lower_cut_pt,root_pt,y_max,t0);
-		curve_lenth+=stem_curve_len;
-		return curve_lenth;
-	}
-	
-	void CRootStockCutPoint::find_lower_cut_point(
-		cv::Mat& bin_img,
-		gcv_point<int>&start_pt,
-		gcv_point<int>&end_pt,//output
-		double cut_angle,
-		int stem_dia)
-	{
-		end_pt.x = -1;
-		end_pt.y = -1;
-
-		double step = 5.0;    
-		double polar_radius = step;
-		int height,width;
-		height = bin_img.rows;
-		width = bin_img.cols;
-
-		//ca = cut_angle*math.pi/180.0
-		double ca = cut_angle*0.0174532925199433;
-		int state = 0;
-		int nxt_x,nxt_y;
-		while(true) {
-			nxt_x = int(start_pt.x+polar_radius*cos(ca));
-			nxt_y = int(start_pt.y-polar_radius*sin(ca));
-			if (nxt_x<0 || nxt_x >= width){
-				state = 1;
-				break;
-			}
-			if (nxt_y < 0 || nxt_y >= height){
-				state = 1;
-				break;
-			}
-			if (bin_img.at<unsigned char>(nxt_y,nxt_x)==0){
-				//#在cur_pt和 nxt_pt两点间找到边缘点
-				int small_step=1;
-				double pr = polar_radius;
-				int pre_x, pre_y;
-				while (pr>0){
-					pr-=small_step;
-					pre_x = int(start_pt.x + pr * cos(ca));
-					pre_y = int(start_pt.y - pr * sin(ca));
-					if (bin_img.at<unsigned char>(pre_y, pre_x) > 0){						
-						end_pt.x = pre_x;
-						end_pt.y = pre_y;
-						double dd = start_pt.distance(end_pt);
-						if (dd <(double)(stem_dia *0.66)){
-							break;
-						}
-						else{
-							state = 2;
-							break;
-						}
-					}
-				}
-            
-			}
-			if(state==2){
-				break;
-			}
-
-			polar_radius += step;
-		}//while
-		if(state==1){//超出图像范围,直接计算
-			end_pt.x = start_pt.x + stem_dia/2;
-			end_pt.y = start_pt.y + (int)(0.5*stem_dia*fabs(tan(ca))+0.5);
-		}
-	}
-	double CRootStockCutPoint::calculate_edge_length(
-		cv::Mat& edge_img,
-		gcv_point<int>&lower_cut_pt,
-		gcv_point<int>&root_pt,//output
-		int y_max,
-	    clock_t t0
-		)
-	{
-		double sum_len = 0.0;
-
-		//cur_x, cur_y = int(start_pt[0]), int(start_pt[1])
-		root_pt.x = -1;
-		root_pt.y = -1;
-
-		gcv_point<int> cur_pt = gcv_point<int>(lower_cut_pt);
-		gcv_point<int> pre_pt = gcv_point<int>(-1,-1);
-		gcv_point<int> nxt_pt = gcv_point<int>(-1,-1);
-		int state = 0;
-		double root2 = sqrt(2.0);
-	    clock_t t;	
-		int cnt = 0;
-		if(m_pLogger){				
-			stringstream buff;
-			buff<<m_imgId<<"  before curve crawling, finishing conditions: 1) ymax="<<y_max<<" 2) crawling to start_point("<<lower_cut_pt.x
-				<<","<<lower_cut_pt.y<<")";
-			m_pLogger->DEBUG(buff.str());
-		}
-		while (true){
-			cnt +=1;			
-			if (!m_cparam.image_show && cnt%50 == 0){
-				t = clock();
-				if(1000.0*((float)(t-t0))/CLOCKS_PER_SEC>(float)m_cparam.timeout_proc){
-					throw_msg(m_imgId+" time out");
-				}
-			}
-			get_next_pt(edge_img, cur_pt, pre_pt,nxt_pt,false);
-			if( nxt_pt.x == cur_pt.x || nxt_pt.y == cur_pt.y){
-				sum_len += 1.0;
-			}
-			if( nxt_pt.x != cur_pt.x && nxt_pt.y != cur_pt.y){
-				sum_len += root2;
-			}
-			pre_pt = cur_pt;			
-			cur_pt = nxt_pt;
-            
-			if(m_pLogger){		
-				stringstream buff;
-				buff<<m_imgId<<" index: "<<cnt<<"\tcurrent point ("<<pre_pt.x
-					<<", "<<pre_pt.y<<")";
-				m_pLogger->DEBUG(buff.str());
-			}
-			if( nxt_pt.y == y_max){
-				state = 1;
-				root_pt = nxt_pt;
-				break;
-			}
-
-			if (nxt_pt == lower_cut_pt){
-				state = 2;
-				break;
-			}
-		}
-		if (m_pLogger){
-			m_pLogger->DEBUG(m_imgId + " finished curve crawling!");
-		}
-		if (state == 2){
-			return 0.0;
-		}
-		if (state == 1){			
-			return sum_len;
-		}
-		else{
-			return 0.0;
-		}
-
-	}
-
-	int CRootStockCutPoint::get_root_point_reid(
-		int x0,
-		int x1,
-		int stem_end_y,		
-		bool is_right  //是否右侧根部点, true-右侧,false-左侧
-		)
-	{
-		int stem_end_x=-1;
-		int start_x,end_x,max_start_x,max_end_x, max_len;
-		start_x = end_x = -1;
-		max_start_x = max_end_x = -1;
-		max_len = -1;
-
-		
-
-		for(int i =x0; i<x1;++i){
-			if(i==x0 && m_binImg.at<unsigned char>(stem_end_y,i)>0){
-				start_x = i;
-				continue;
-			}
-			if(i==x1-1 && m_binImg.at<unsigned char>(stem_end_y,i)>0){
-				end_x = i;
-				int length = end_x - start_x+1;
-				if (length >max_len){
-					max_len = length;
-					max_start_x = start_x;
-					max_end_x = end_x;
-				}
-			}
-			if(m_binImg.at<unsigned char>(stem_end_y,i)>0 && 
-				m_binImg.at<unsigned char>(stem_end_y,i-1)==0){
-				start_x = i;
-				continue;
-			}
-			if(m_binImg.at<unsigned char>(stem_end_y,i)==0 && 
-				m_binImg.at<unsigned char>(stem_end_y,i-1)>0){
-				end_x = i;
-				int length = end_x - start_x+1;
-				if (length >max_len){
-					max_len = length;
-					max_start_x = start_x;
-					max_end_x = end_x;
-				}
-			}
-
-		}
-		if (is_right){
-			return max_end_x;
-		}
-		return max_start_x;    
-	}
-
-	void  CRootStockCutPoint::find_upper_cut_point_reid(
-		cv::Mat& edge_img,
-		gcv_point<int>&start_pt,
-		gcv_point<int>&end_pt,//output
-		double curve_length
-		)
-		{
-			end_pt.x  =-1;
-			end_pt.y = -1;
-		gcv_point<int> cur_pt = gcv_point<int>(start_pt);
-		gcv_point<int> pre_pt = gcv_point<int>(-1,-1);
-		gcv_point<int> nxt_pt = gcv_point<int>(-1,-1);
-		//pre_x=-1
-		//pre_y=-1
-		double root2 = sqrt(2.0);
-		double sum_len =0.0;
-		int state = 0;
-
-		if(m_pLogger){				
-			stringstream buff;
-			buff<<m_imgId<<"  reid,  before curve crawling, finishing conditions: curve length="<<curve_length
-			<<", start_point(root)("<<start_pt.x
-				<<","<<start_pt.y<<")";
-			m_pLogger->DEBUG(buff.str());
-
-		}
-
-		while (true){
-			get_next_pt(edge_img,cur_pt,pre_pt,nxt_pt,true);
-			if (nxt_pt.x==cur_pt.x || nxt_pt.y==cur_pt.y){
-				sum_len+=1.0;
-			}
-			if ( nxt_pt.x!=cur_pt.x && nxt_pt.y!=cur_pt.y){
-				sum_len += root2;
-			}			
-			pre_pt = cur_pt;
-			cur_pt = nxt_pt;
-			if(m_pLogger){		
-				stringstream buff;
-				buff<<m_imgId<<"current point ("<<pre_pt.x
-					<<", "<<pre_pt.y<<")";
-				m_pLogger->DEBUG(buff.str());
-			}
-
-			if (sum_len>=curve_length){
-				state = 1;
-				break;
-			}
-			if (nxt_pt == start_pt){
-				state = 2;
-				break;
-			}
-		}
-
-		if (state==2){
-			end_pt.x  =-1;
-			end_pt.y = -1;
-		}
-		if (state == 1){
-			end_pt = cur_pt;
-		}			
-		else{
-			end_pt.x  =-1;
-			end_pt.y = -1;
-		}
-	}
-
-};

+ 0 - 129
cut_point_rs.h

@@ -1,129 +0,0 @@
-//cut point recognization for rootstock plant
-#pragma once
-#include <time.h>
-#include <opencv.hpp>
-#include "data_def_api.h"
-#include "data_def.h"
-#include "logger.h"
-#include "imstorage_manager.h"
-
-//using namespace cv;
-namespace graft_cv{
-
-class CRootStockCutPoint{
-public:
-	CRootStockCutPoint(ConfigParam&c,CGcvLogger*pLog=0);
-	~CRootStockCutPoint();
-	int up_point_detect(//上切割点,切前识别
-		ImgInfo*, 
-		cv::Mat&,
-		PositionInfo& posinfo,
-		map<string, cv::Mat>& img_cache
-		);
-
-	//int up_point_reid( // 上切割点,切后重识别
-	//	ImgInfo*, 
-	//	Mat&,
-	//	double edge_length,
-	//	PositionInfo& posinfo
-	//	);
-	void set_image_saver(CImStoreManager** ppis){m_ppImgSaver=ppis;}
-private:	
-	cv::Mat m_binImg;// binary image
-	cv::Mat m_grayImg;// gray image
-	cv::Mat m_edgeImg;
-	string m_imgId;
-	CImStoreManager** m_ppImgSaver;
-
-	//返回图片,用于调试
-	ImgInfo* m_pImginfoBinFork;//fork-y, right-x
-	ImgInfo* m_pImgCorners;//corners, reference-point, candidate box
-	ImgInfo* m_pImgCutPoint;//reference-point, cutpoint
-
-
-	//global configure parameters
-	ConfigParam& m_cparam;
-	CGcvLogger * m_pLogger;
-	// image segment
-	void img_segment(cv::Mat&);
-	
-	// get_optimal_corner()
-	// return 0--success, 1--error
-	int get_optimal_corner( 
-		int ref_x, 
-		int ref_y,
-		std::vector<cv::Point2f>& corners,
-		int stem_dia,
-		double cand_corner_box_width_ratio,
-		double cand_corner_box_xoffset_ratio,
-		double opt_corner_xoffset_ratio,
-	    double opt_corner_yoffset_ratio,
-		double corner_mask_radius_ratio,
-		cv::Point2f& cut_pt);
-	void get_default_cutpoint(
-		int fork_cent_x,
-		int fork_cent_y,
-		int fork_stem_dia,
-		cv::Point2f& cut_pt);
-
-	void clear_imginfo();
-
-	/// pre-cut calculationo
-	//# 通过砧木切前切割点识别结果(切割点)、二值图像,茎根y值,刀角度
-	//# 输出切割点到根部的边缘曲线长度
-	double get_cut_edge_length(
-		cv::Mat& bin_img,
-		cv::Mat& edge_img,
-		gcv_point<int>& start_pt, //up cut point
-		gcv_point<int>& lower_cut_pt,//output
-		gcv_point<int>& root_pt,//output
-		double cut_angle,
-		int y_max,
-		int stem_dia,
-	    clock_t t0
-		);
-
-	void find_lower_cut_point(
-		cv::Mat& bin_img,
-		gcv_point<int>&start_pt,
-		gcv_point<int>&end_pt,//output
-		double cut_angle,
-		int stem_dia);
-	double calculate_edge_length(
-		cv::Mat& edge_img,
-		gcv_point<int>&lower_cut_pt,
-		gcv_point<int>&root_pt,//output
-		int y_max,
-	    clock_t t0
-		);
-
-	//corner evluation
-	void corner_magnificence(
-		const vector<cv::Point2f>& cand_pts,
-		int stem_dia,
-		double corner_mask_radius_ratio,
-		vector<double>& scores
-		);
-
-
-	//functions for reid 
-	int get_root_point_reid(
-		int x0,
-		int x1,
-		int stem_end_y,		
-		bool is_right  //是否右侧根部点, true-右侧,false-左侧
-		);
-	void  find_upper_cut_point_reid(
-		cv::Mat& edge_img,
-		gcv_point<int>&start_pt,
-		gcv_point<int>&end_pt,//output
-		double curve_length
-		);
-	void get_stem_root_y(
-		vector<int>&hist_row,		
-		double rs_stem_dia_min,			
-		int &stem_end_y);
-
-
-};
-};

+ 0 - 710
cut_point_rs_reid.cpp

@@ -1,710 +0,0 @@
-/*
-  砧木切割点后识别
-
-*/
-#include <opencv2\imgproc\imgproc.hpp>
-#include <opencv2\features2d\features2d.hpp>
-//#include <opencv2\nonfree\features2d.hpp>
-#include <math.h>
-#include <algorithm>
-
-#include "cut_point_rs_reid.h"
-#include "utils.h"
-#include "data_def.h"
-#include "logger.h"
-//using namespace cv;
-
-namespace graft_cv{
-
-CRootStockCutPointReid::CRootStockCutPointReid(ConfigParam&cp,CGcvLogger*pLog/*=0*/)
-:m_cparam(cp),
-m_pLogger(pLog),
-m_pImginfoBinFork(0),
-m_pImgCorners(0),
-m_pImgCutPoint(0),
-m_imgId(""),
-m_ppImgSaver(0)
-{	
-}
-CRootStockCutPointReid::~CRootStockCutPointReid()
-{
-	this->clear_imginfo();	
-}
-
-void CRootStockCutPointReid::clear_imginfo(){
-	if (m_pImginfoBinFork){
-		imginfo_release(&m_pImginfoBinFork);
-		m_pImginfoBinFork=0;
-	}
-	if (m_pImgCorners){
-		imginfo_release(&m_pImgCorners);
-		m_pImgCorners=0;
-	}
-	if (m_pImgCutPoint){
-		imginfo_release(&m_pImgCutPoint);
-		m_pImgCutPoint=0;
-	}
-}
-
-int CRootStockCutPointReid::cut_point_reid(
-	ImgInfo* imginfo, 
-	cv::Mat&cimg,
-	const char * pre_img_id,
-	PositionInfo& posinfo,
-	map<string, cv::Mat>& img_cache
-	)
-{
-	// cimg --- color image, bgr
-	
-	if(m_pLogger){				
-			m_pLogger->INFO(m_imgId +" rootstock cut_pt reid begin");
-	}
-	if(!pre_img_id){
-		if(m_pLogger){				
-			m_pLogger->ERRORINFO(m_imgId +" pre-image id is NULL");
-		}	
-		return 1;
-	} 
-	string pre_imgid(pre_img_id);
-	map<string, cv::Mat>::iterator iter = img_cache.find(pre_imgid);
-	if(iter==img_cache.end()){
-		if(m_pLogger){				
-			m_pLogger->ERRORINFO(m_imgId +" pre-image NOT in cache");
-		}	
-		return 1;
-	}
-	m_preGrayImg = iter->second;
-    m_imgId = getImgId(img_type::rs_reid);
-	 
-	//1 image segment	
-	clock_t t;
-	clock_t t0 = clock();	
-
-	cv::Mat img;
-	if(imginfo){
-		if(m_pLogger){		
-			stringstream buff;
-			buff<<m_imgId<<" rootstock image, width="<<imginfo->width
-				<<"\theight="<<imginfo->height;
-			m_pLogger->INFO(buff.str());
-		}
-		if(!isvalid(imginfo)){
-			if(m_pLogger){				
-				m_pLogger->ERRORINFO(m_imgId+" rootstock input image invalid.");				
-			}
-			throw_msg(m_imgId+" invalid input image");	
-			
-		}	
-		img = imginfo2mat(imginfo);
-	}
-	else{
-		if(m_pLogger){		
-			stringstream buff;
-			buff<<m_imgId<<"rootstock image, width="<<cimg.cols
-				<<"\theight="<<cimg.rows;
-			m_pLogger->INFO(buff.str());
-		}
-		if(cimg.empty()){
-			if(m_pLogger){				
-				m_pLogger->ERRORINFO(m_imgId+" rootstock input image invalid.");				
-			}
-			throw_msg(m_imgId +" invalid input image");
-			
-		}
-		img = cimg;
-	}
-	
-	if(m_cparam.self_camera){
-		image_set_bottom(img,20,8);
-        if(m_pLogger){				
-			m_pLogger->DEBUG(m_imgId+" image set bottom with pixel value 20.");				
-		}
-	}
-	if(m_cparam.rs_y_flip){
-		flip(img,img,0);
-        if(m_pLogger){				
-			m_pLogger->DEBUG(m_imgId+" image y fliped.");				
-		}
-	}
-	
-	//image saver
-	if(m_ppImgSaver && *m_ppImgSaver){
-		(*m_ppImgSaver)->saveImage(img, m_imgId);
-	}
-    if(m_pLogger){				
-		m_pLogger->DEBUG(m_imgId+" before image segment.");				
-	}	
-	///////////////////////////////////////////////////////
-	// image segment
-	this->img_preprocess(img);
-    if(m_pLogger){	
-		m_pLogger->DEBUG(m_imgId+" after image gray.");				
-	}
-
-	if(m_cparam.image_show){
-		cv::destroyAllWindows();
-		imshow_wait("rs_pre_gray",m_preGrayImg);	
-		imshow_wait("rs_gray",m_grayImg);		
-	}
-	else{
-		t = clock();
-		if(1000.0*((float)(t-t0))/CLOCKS_PER_SEC>(float)m_cparam.timeout_proc){
-			if(m_pLogger){				
-				m_pLogger->ERRORINFO(m_imgId+" rootstock reid timeout.");				
-			}
-			throw_msg(m_imgId+" time out");
-		}
-	}
-    if(m_pLogger){	
-		m_pLogger->DEBUG(m_imgId+" after pre- and cur- gray image show.");				
-	}
-	
-	//特征提取
-	//int max_feature = 500;
-	//cv::OrbFeatureDetector fts_detector(max_feature);
-	////SurfFeatureDetector fts_detector(max_feature);
-	//std::vector<cv::KeyPoint> keypoints_pre, keypoints_cur;
-	//fts_detector.detect( m_preGrayImg, keypoints_pre );
-	//fts_detector.detect( m_grayImg, keypoints_cur );
-
-	//cv::SurfDescriptorExtractor extractor;
-	//cv::Mat descriptors_pre, descriptors_cur;
-	//extractor.compute( m_preGrayImg, keypoints_pre, descriptors_pre );
-	//extractor.compute( m_grayImg, keypoints_cur, descriptors_cur );
-	////-- Step 3: Matching descriptor vectors with a brute force matcher
-	//cv::BFMatcher matcher(cv::NORM_L2);
-	//std::vector< cv::DMatch > matches;
-	//cv::matcher.match( descriptors_pre, descriptors_cur, matches );
-	//if(m_cparam.image_show){
-	//	//-- Draw matches
-	//	cv::Mat img_matches;
-	//	cv::drawMatches( m_preGrayImg, keypoints_pre, m_grayImg, keypoints_cur, matches, img_matches );
-	//	//-- Show detected matches
-	//	cv::imshow("Matches", img_matches );
-	//	cv::waitKey(-1);
-	//}
-
-	posinfo.rs_reid_upoint_x = 10.0;
-	posinfo.rs_reid_upoint_y = 10.0;
-	posinfo.rs_reid_lpoint_x = 20.0;
-	posinfo.rs_reid_lpoint_y = 20.0;
-
-
-	//if(m_pLogger){		
-	//	stringstream buff;
-	//	buff<<m_imgId<<" rootstock image, rs_cut_upoint(mm)("<<rs_cut_upoint_x
-	//		<<","<<rs_cut_upoint_y<<")"
-	//		<<", rs_stem_diameter(mm)="<<rs_stem_diameter
-	//		<<", lower_cut_pt(mm)("<<rs_cut_lpoint_x
-	//		<<","<<rs_cut_lpoint_y<<")";
-	//	m_pLogger->INFO(buff.str());
-	//}
-
-	////  return images:	posinfo.pp_images
-	//if(m_cparam.image_return){
-	//	this->clear_imginfo();
-	//	//0) image id
-	//	strcpy(posinfo.rs_img_id,m_imgId.c_str());
-
-	//	//1) 		
-	//	//stem x-range
-	//	line(m_binImg,Point(stem_x0,0),Point(stem_x0,m_binImg.cols-1),Scalar(100),2);
-	//	line(m_binImg,Point(stem_x1,0),Point(stem_x1,m_binImg.cols-1),Scalar(100),2);
-	//	//fork right point
-	//	circle(m_binImg, Point(stem_fork_left_x,stem_fork_y),5, Scalar(128,0,128), -1, 8,0);
-	//	m_pImginfoBinFork=mat2imginfo(m_binImg);	
-
-	//	//3 cut point int gray image	
-	//	circle(m_grayImg, Point(stem_fork_left_x,stem_fork_y),5, Scalar(128,0,128), -1, 8,0);
-	//	circle(m_grayImg, Point(stem_fork_right_x,stem_fork_y),5, Scalar(128,0,128), -1, 8,0);//v0.5.9.3 reference point
-	//	circle(m_grayImg, Point(cut_pt.x,stem_fork_y),5, Scalar(128,0,128), -1, 8,0);//v0.5.9.3 reference point
-	//	circle(m_grayImg, Point(cut_pt.x,stem_fork_y),2, Scalar(255,0,255), -1, 8,0);
-	//	circle(m_grayImg, Point(lower_cut_pt.x,lower_cut_pt.y),5, Scalar(200,0,200), -1, 8,0);
-	//	image_draw_line(m_grayImg,cut_pt.x,cut_pt.y,lower_cut_pt.x,lower_cut_pt.y);
-	//
-	//	m_pImgCutPoint = mat2imginfo(m_grayImg);			
-	//	posinfo.pp_images[0]=m_pImginfoBinFork;
-	//	posinfo.pp_images[1]=m_pImgCutPoint;
-
-	//	if(m_ppImgSaver && *m_ppImgSaver){
-	//		(*m_ppImgSaver)->saveImage(m_binImg, m_imgId+"_rst_0");
-	//		(*m_ppImgSaver)->saveImage(m_grayImg, m_imgId+"_rst_1");
-	//	}		
-	//}
-	if(m_pLogger){				
-		m_pLogger->INFO(m_imgId +" rootstock cut reid detect finished.");				
-	}
-	return 0;
-};
-
-void CRootStockCutPointReid::img_preprocess(cv::Mat&img)
-{
-	//灰度化
-	cv::Mat b_img;
-	if(img.channels()!=1){
-		//color image ,bgr, for testing		
-		cvtColor(img,m_grayImg, cv::COLOR_BGR2GRAY);
-	}
-	else{
-		m_grayImg = img.clone();
-	}
-
-	/*Mat kernel = getStructuringElement(
-		MORPH_ELLIPSE, 
-		Size( 2*m_cparam.rs_morph_radius + 1, 2*m_cparam.rs_morph_radius+1 ),
-		Point( m_cparam.rs_morph_radius, m_cparam.rs_morph_radius )
-		);    	
-	double th = threshold(m_grayImg, b_img, 255, 255,THRESH_OTSU);		
-
-	morphologyEx(
-		b_img, 
-		m_binImg, 
-		MORPH_CLOSE,
-		kernel,
-		Point(-1,-1),
-		m_cparam.rs_morph_iteration
-		);*/
-
-
-	
-}
-
-///////////////////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////////////
-CSolaCutPointReid::CSolaCutPointReid(ConfigParam&cp, int stemType, CGcvLogger*pLog)
-	:m_cparam(cp),
-	m_pLogger(pLog),	
-	m_stem_type(stemType),
-	m_imgId(""),
-	m_ppImgSaver(0),
-	m_pImginfoBin(0),
-	m_pImgCutPoint(0)
-{
-	//m_stem_type -- 0-接穗, 1-砧木
-
-}
-
-CSolaCutPointReid::~CSolaCutPointReid()
-{}
-void CSolaCutPointReid::clear_imginfo() {
-	if (m_pImginfoBin) {
-		imginfo_release(&m_pImginfoBin);
-		m_pImginfoBin = 0;
-	}	
-	if (m_pImgCutPoint) {
-		imginfo_release(&m_pImgCutPoint);
-		m_pImgCutPoint = 0;
-	}
-}
-int CSolaCutPointReid::cut_point_reid(
-	ImgInfo* imginfo,
-	cv::Mat&cimg,	
-	PositionInfo& posinfo
-)
-{
-	if (m_stem_type == 0) {
-		m_imgId = getImgId(img_type::sola_sc_reid);
-	}
-	else {
-		m_imgId = getImgId(img_type::sola_rs_reid);
-	}
-	
-	//1 image segment	
-	clock_t t;
-	clock_t t0 = clock();
-
-	cv::Mat img;
-	if (imginfo) {
-		if (m_pLogger) {
-			stringstream buff;
-			buff << m_imgId<<" "<<get_stem_type_name() << " image, width=" << imginfo->width
-				<< "\theight=" << imginfo->height;
-			m_pLogger->INFO(buff.str());
-		}
-		if (!isvalid(imginfo)) {
-			if (m_pLogger) {
-				m_pLogger->ERRORINFO(m_imgId +string(" ")+get_stem_type_name() + " input image invalid.");
-			}
-			throw_msg(m_imgId + string(" ") + get_stem_type_name() + " invalid input image");
-
-		}
-		img = imginfo2mat(imginfo);
-	}
-	else {
-		if (m_pLogger) {
-			stringstream buff;
-			buff << m_imgId << " " << get_stem_type_name() << " image, width=" << cimg.cols
-				<< "\theight=" << cimg.rows;
-			m_pLogger->INFO(buff.str());
-		}
-		if (cimg.empty()) {
-			if (m_pLogger) {
-				m_pLogger->ERRORINFO(m_imgId +string(" ")+ get_stem_type_name() + " input image invalid.");
-			}
-			throw_msg(m_imgId + string(" ") +get_stem_type_name() + " invalid input image");
-
-		}
-		img = cimg;
-	}
-
-	/*if (m_cparam.self_camera) {
-		image_set_bottom(img, 20, 8);
-		if (m_pLogger) {
-			m_pLogger->DEBUG(m_imgId + " image set bottom with pixel value 20.");
-		}
-	}*/
-	if (m_cparam.rs_y_flip) {
-		flip(img, img, 0);
-		if (m_pLogger) {
-			m_pLogger->DEBUG(m_imgId + string(" ") + get_stem_type_name() + " image y fliped.");
-		}
-	}
-
-	//image saver
-	if (m_ppImgSaver && *m_ppImgSaver) {
-		(*m_ppImgSaver)->saveImage(img, m_imgId);
-	}
-	if (m_pLogger) {
-		m_pLogger->DEBUG(m_imgId + string(" ") + get_stem_type_name() + " before image segment.");
-	}
-	///////////////////////////////////////////////////////
-	// image segment
-	this->img_preprocess(img);
-	if (m_pLogger) {
-		m_pLogger->DEBUG(m_imgId + " after image gray.");
-	}
-
-	if (m_cparam.image_show) {
-		cv::destroyAllWindows();		
-		imshow_wait("gray", m_grayImg);
-		imshow_wait("binary", m_binImg);
-	}
-	else {
-		t = clock();
-		if (1000.0*((float)(t - t0)) / CLOCKS_PER_SEC>(float)m_cparam.timeout_proc) {
-			if (m_pLogger) {
-				m_pLogger->ERRORINFO(m_imgId + " sola cut points reid timeout.");
-			}
-			throw_msg(m_imgId + " time out");
-		}
-	}
-	if (m_pLogger) {
-		m_pLogger->DEBUG(m_imgId + " after gray image show.");
-	}
-
-   // find object
-	vector<vector<cv::Point>> contours;
-	vector<cv::Vec4i> hierarchy;	
-	contours.clear();
-	hierarchy.clear();
-	int obj_area_th = 100;//m_cparam
-	double max_area = 0;
-	int max_idx = -1;
-	
-	findContours(m_binImg, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
-	for (int i = 0; i<contours.size(); ++i) {
-		double area = contourArea(contours[i]);
-		if (area < obj_area_th) { continue; }
-		if(area<max_area) { continue; }
-		max_area = area;
-		max_idx = i;
-	}
-
-	if (max_idx < 0 || contours[max_idx].size()==0) {
-		throw_msg(m_imgId + " no valid object");
-	}
-
-	// 找到切口处y值
-	int minx, maxx, miny, maxy;
-	int cut_miny, cut_midy, cut_maxy;
-
-	find_cut_ys(contours[max_idx],
-			minx,  maxx, miny, maxy,
-			cut_miny, cut_midy, cut_maxy);
-	int box_width, box_height;
-	box_width = abs(maxx - minx);
-	box_height = abs(maxy - miny);
-	if (box_width < 5) {
-		throw_msg(m_imgId + " no valid object");
-	}
-	float hw_ratio = (float)(box_height) / (float)(box_width);
-	if (hw_ratio < 1.0) {
-		throw_msg(m_imgId + " no valid object");
-	}
-	float area_th = (float)(m_grayImg.rows*m_grayImg.cols) / 5.0;
-	if (max_area > area_th) {
-		throw_msg(m_imgId + " no valid object");
-	}
-
-    // 夹爪基面的y
-	int base_y = maxy;	//	砧木情况
-	if (m_stem_type == 0) {//	接穗情况
-		base_y = miny;
-	}
-	if (m_cparam.image_show) { 		
-		cv::Mat tmp = m_grayImg.clone();
-		cv::line(tmp, cv::Point(minx, cut_miny), cv::Point(maxx, cut_miny), cv::Scalar(200));
-		cv::line(tmp, cv::Point(minx, cut_midy), cv::Point(maxx, cut_midy), cv::Scalar(200));
-		cv::line(tmp, cv::Point(minx, cut_maxy), cv::Point(maxx, cut_maxy), cv::Scalar(200));	
-		cv::line(tmp, cv::Point(minx, base_y), cv::Point(maxx, base_y), cv::Scalar(255));
-		imshow_wait("gray_lines", tmp);
-	}
-	if (m_stem_type == 0) {//接穗,坐标左上角位0点
-		posinfo.sc_reid_sola_upoint_x = base_y;  //夹爪基面的y, 砧木在下方(夹爪的上沿),接穗在上方(夹爪的下沿)
-		posinfo.sc_reid_sola_upoint_y = fabs(cut_miny - base_y) + 1 ;
-		posinfo.sc_reid_sola_cpoint_x = minx;
-		posinfo.sc_reid_sola_cpoint_y = fabs(cut_midy - base_y) + 1;
-		posinfo.sc_reid_sola_lpoint_x = minx;
-		posinfo.sc_reid_sola_lpoint_y = fabs(cut_maxy - base_y) + 1;
-	}
-	else {//砧木,坐标左下角位0点
-		posinfo.rs_reid_sola_upoint_x = m_grayImg.rows - base_y - 1;  //夹爪基面的y, 砧木在下方(夹爪的上沿),接穗在上方(夹爪的下沿)
-		posinfo.rs_reid_sola_upoint_y = fabs(cut_miny - base_y) + 1;
-		posinfo.rs_reid_sola_cpoint_x = minx;
-		posinfo.rs_reid_sola_cpoint_y = fabs(cut_midy - base_y) + 1;
-		posinfo.rs_reid_sola_lpoint_x = minx;
-		posinfo.rs_reid_sola_lpoint_y = fabs(cut_maxy - base_y) + 1;
-	}
-	
-
-	if(m_pLogger){		
-		stringstream buff;
-		buff<<m_imgId<<" sola rootstock(scion) image, rs_cut_upoint("<< posinfo.rs_reid_sola_upoint_x
-			<<","<< posinfo.rs_reid_sola_upoint_y <<")"
-			<<", rs_cut_cpoint=("<< posinfo.rs_reid_sola_cpoint_x
-			<< "," << posinfo.rs_reid_sola_cpoint_y << ")"
-			<<", rs_cut_lpoint(mm)("<< posinfo.rs_reid_sola_lpoint_x
-			<<","<< posinfo.rs_reid_sola_lpoint_y <<")";
-		m_pLogger->INFO(buff.str());
-	}
-
-	//  return images:	posinfo.pp_images
-	if(m_cparam.image_return){
-		this->clear_imginfo();
-		//0) image id
-		strcpy(posinfo.rs_img_id,m_imgId.c_str());
-
-		//1) bin image				
-		m_pImginfoBin=mat2imginfo(m_binImg);	
-
-		//2 cut point int gray image
-		cv::Mat tmp = m_grayImg.clone();
-		cv::line(tmp, cv::Point(minx, cut_miny), cv::Point(maxx, cut_miny), cv::Scalar(200));
-		cv::line(tmp, cv::Point(minx, cut_midy), cv::Point(maxx, cut_midy), cv::Scalar(200));
-		cv::line(tmp, cv::Point(minx, cut_maxy), cv::Point(maxx, cut_maxy), cv::Scalar(200));
-	
-		m_pImgCutPoint = mat2imginfo(tmp);
-
-		posinfo.pp_images[0] = m_pImginfoBin;
-		posinfo.pp_images[1] = m_pImgCutPoint;
-		
-		if(m_ppImgSaver && *m_ppImgSaver){
-			(*m_ppImgSaver)->saveImage(m_binImg, m_imgId+"_rst_0");
-			(*m_ppImgSaver)->saveImage(tmp, m_imgId+"_rst_1");
-		}		
-	}
-	if (m_pLogger) {
-		if (m_stem_type == 0) {
-			m_pLogger->INFO(m_imgId + " sola scion cut reid detect finished.");
-		}
-		else {
-			m_pLogger->INFO(m_imgId + " sola rootstock cut reid detect finished.");
-		}
-		
-	}
-	return 0;
-};
-void CSolaCutPointReid::find_cut_ys(
-	vector<cv::Point>&points,
-	int&minx,int& maxx,
-	int&miny,int&maxy,
-	int&cut_miny, int&cut_midy, int&cut_maxy
-)
-{
-	//找到切口的y值
-
-	// 找到边框	
-	minx = miny = 1000;
-	maxx = maxy = -1;
-	for (auto &pt : points) {
-		if (pt.x > maxx) { maxx = pt.x; }
-		if (pt.x < minx) { minx = pt.x; }
-		if (pt.y > maxy) { maxy = pt.y; }
-		if (pt.y < miny) { miny = pt.y; }
-	}
-   // 找到水平的边
-	std::vector<int> hist(maxy-miny+1,0);
-	std::vector<int> hist_x0(maxy - miny + 1, 1000);
-	std::vector<int> hist_x1(maxy - miny + 1, 0);
-	std::vector<int> hist_width(maxy - miny + 1, 0);
-	
-	for (auto&pt : points) {
-		int idx = pt.y - miny;
-		hist.at(idx) += 1;
-		if (pt.x > hist_x1.at(idx)) {
-			hist_x1.at(idx) = pt.x;
-		}
-		if (pt.x < hist_x0.at(idx)) {
-			hist_x0.at(idx) = pt.x;
-		}
-	}
-	for (int i = 0; i < hist.size(); ++i) {
-		hist_width.at(i) = hist_x1.at(i) - hist_x0.at(i);
-	}
-
-    //计算茎的直径
-	std::vector<int> hist_width_copy(hist_width);
-	sort(hist_width_copy.begin(), hist_width_copy.end());
-	int pert_idx = int(0.95*hist_width_copy.size());
-	int stem_width = hist_width_copy.at(pert_idx);
-
-	int max_idx = max_element(hist.begin(), hist.end()) - hist.begin();
-	if (max_idx<int(hist.size() / 2.0)) {
-		//下锥,
-		std::vector<int> hist_width_rev;
-		for (int i = hist_width.size()-1; i >=0 ; i--) {
-			hist_width_rev.push_back(hist_width.at(i));
-		}
-		//在茎的指导下进行查找
-		int pos = trend_detect_pos(hist_width_rev, stem_width);
-		cut_miny = maxy - pos;
-		cut_maxy = maxy;
-		cut_midy = int((cut_miny + cut_maxy) / 2);
-	}
-	else {
-		//上锥,找到上锥点
-		int pos = trend_detect_pos(hist_width, stem_width);
-		cut_miny = miny;
-		cut_maxy = miny + pos;
-		cut_midy = int((cut_miny + cut_maxy) / 2);
-	}
-
-}
-void CSolaCutPointReid::find_cut_curve(vector<cv::Point>&curve_points, 
-	vector<cv::Point>&cut_curve, cv::RotatedRect& retval)
-{
-	int max_y = curve_points[0].y;
-	int min_y = curve_points[0].y;
-	int max_x = curve_points[0].x;
-	int min_x = curve_points[0].x;
-	for (auto&pt : curve_points) {
-		if (pt.y > max_y) {
-			max_y = pt.y;
-		}
-		if (pt.y < min_y) {
-			min_y = pt.y;
-		}
-		if (pt.x > max_x) {
-			max_x = pt.x;
-		}
-		if (pt.x < min_x) {
-			min_x = pt.x;
-		}
-	}
-	vector<int>stem_width;
-	int line_min_x, line_max_x;
-	for (int y = min_y; y <= max_y;++y) {
-		line_min_x = max_x;
-		line_max_x = min_x;
-		for (auto&pt : curve_points) {
-			if (pt.y != y) { continue; }
-			if (pt.x < line_min_x) { line_min_x = pt.x; }
-			if (pt.x > line_max_x) { line_max_x = pt.x; }
-		}
-		stem_width.push_back(line_max_x - line_min_x + 1);		
-	}
-
-	//计算茎的直径
-	std::vector<int> hist_width_copy(stem_width);
-	sort(hist_width_copy.begin(), hist_width_copy.end());
-	int max_idx = int(0.98*hist_width_copy.size());
-	int max_stem_width = hist_width_copy.at(max_idx);
-
-	// find y range curve
-	int min_yc = min_y;
-	int max_yc = max_y;
-	if (m_stem_type != 0) {//砧木
-		int pos = trend_detect_pos(stem_width, max_stem_width,15);
-		if (pos > 0) {
-			max_yc = min_yc + pos;
-		}
-		else {
-			throw(m_imgId + " not found cut curve range");
-		}
-	}
-	else { //接穗
-		vector<int> stem_width_r;
-		vector<int>::reverse_iterator rit = stem_width.rbegin();
-		for (; rit != stem_width.rend(); ++rit) {
-			stem_width_r.push_back(*rit);
-		}
-		int pos = trend_detect_pos(stem_width_r, max_stem_width, 15);
-		if (pos > 0) {
-			min_yc = max_yc - pos;
-		}
-		else {
-			throw(m_imgId + " not found cut curve range");
-		}
-	}
-
-	// copy cut curve points
-	vector<cv::Point>cut_curve_points;
-	for (auto&pt : curve_points) {
-		if (pt.y >= min_yc && pt.y <= max_yc) {
-			cut_curve_points.push_back(cv::Point(pt));
-		}
-	}
-
-	// ecllipse fit
-	retval = cv::fitEllipse(cut_curve_points);
-	//if (m_cparam.image_show) {
-	//	//cv::destroyAllWindows();
-	//	cv::Mat tmp = m_grayImg.clone();
-	//	for (auto&pt : cut_curve_points) {
-	//		tmp.at<cv::uint8_t>(pt.y, pt.x+500) = 200;
-	//	}
-
-	//	//cv::ellipse(tmp, retval, cv::Scalar(200));
-	//	imshow_wait("cut_curve", tmp);
-	//}
-	
-}
-string CSolaCutPointReid::get_stem_type_name() {
-	if (m_stem_type == 0) {
-		return string("solanaceae scion");
-	}
-	else {
-		return string("solanaceae rootstock");
-	}
-}
-void CSolaCutPointReid::img_preprocess(cv::Mat&img)
-{
-	//灰度化
-	cv::Mat b_img;
-	if (img.channels() != 1) {
-		//color image ,bgr, for testing		
-		cvtColor(img, m_grayImg, cv::COLOR_BGR2GRAY);
-	}
-	else {
-		m_grayImg = img.clone();
-	}	
-
-	cv::Mat kernel = cv::getStructuringElement(
-		cv::MORPH_ELLIPSE,
-		cv::Size(5, 5),
-		cv::Point(2,2)
-	);	
-
-	double th = threshold(m_grayImg, b_img, 255, 255, cv::THRESH_OTSU);
-
-	morphologyEx(
-		b_img,
-		m_binImg,
-		cv::MORPH_CLOSE,
-		kernel,
-		cv::Point(-1, -1),
-		2
-	);
-
-}
-}

+ 0 - 86
cut_point_rs_reid.h

@@ -1,86 +0,0 @@
-//cut point reid for rootstock plant
-#pragma once
-#include <time.h>
-#include <opencv.hpp>
-#include "data_def_api.h"
-#include "data_def.h"
-#include "logger.h"
-#include "imstorage_manager.h"
-
-//using namespace cv;
-namespace graft_cv{
-
-class CRootStockCutPointReid{
-public:
-	CRootStockCutPointReid(ConfigParam&c,CGcvLogger*pLog=0);
-	~CRootStockCutPointReid();
-	int cut_point_reid(			//切后切割点识别
-		ImgInfo*,				//切后图片
-		cv::Mat&,					//切后图片,测试用
-		const char * pre_img_id,		//切前图像id
-		PositionInfo& posinfo,	
-		map<string, cv::Mat>& img_cache
-		);	
-	void set_image_saver(CImStoreManager** ppis){m_ppImgSaver=ppis;}
-private:
-	cv::Mat m_preGrayImg;// gray image
-	//Mat m_binImg;// binary image
-	cv::Mat m_grayImg;// gray image
-	cv::Mat m_edgeImg;
-	string m_imgId;
-	CImStoreManager** m_ppImgSaver;
-
-	//返回图片,用于调试
-	ImgInfo* m_pImginfoBinFork;//fork-y, right-x
-	ImgInfo* m_pImgCorners;//corners, reference-point, candidate box
-	ImgInfo* m_pImgCutPoint;//reference-point, cutpoint
-
-
-	//global configure parameters
-	ConfigParam& m_cparam;
-	CGcvLogger * m_pLogger;
-	// image segment
-	void img_preprocess(cv::Mat&);
-	void clear_imginfo();
-	
-};
-
-// 茄科切割点识别
-// 切后识别
-class CSolaCutPointReid {
-public:
-	CSolaCutPointReid(ConfigParam&c, int stemType=0, CGcvLogger*pLog=0);
-	~CSolaCutPointReid();
-	int cut_point_reid(			//切后切割点识别
-		ImgInfo*,				//切后图片
-		cv::Mat&,					//切后图片,测试用		
-		PositionInfo& posinfo
-	);
-	void set_image_saver(CImStoreManager** ppis) { m_ppImgSaver = ppis; }
-private:
-	int m_stem_type; //植株类别:0--穗苗;1--砧木
-					 //global configure parameters
-	ConfigParam& m_cparam;
-	CGcvLogger * m_pLogger;
-	string m_imgId;
-	CImStoreManager** m_ppImgSaver;
-	cv::Mat m_grayImg;// gray image
-	cv::Mat m_binImg; // bin image
-
-	//返回图片,用于调试
-	ImgInfo* m_pImginfoBin;//	
-	ImgInfo* m_pImgCutPoint;//reference-point, cutpoint
-
-	void clear_imginfo();
-	inline string get_stem_type_name();
-	void img_preprocess(cv::Mat&img);
-	void find_cut_curve(vector<cv::Point>&points,
-		vector<cv::Point>&cut_curve,
-		cv::RotatedRect& retval);
-	void find_cut_ys(vector<cv::Point>&points,
-		int&minx, int& maxx,
-		int&miny, int&maxy,
-		int&cut_miny, int&cut_midy, int&cut_maxy
-	);
-};
-};

+ 0 - 595
cut_point_sc.cpp

@@ -1,595 +0,0 @@
-#include <opencv2\imgproc\imgproc.hpp>
-#include "cut_point_sc.h"
-#include "utils.h"
-//using namespace cv;
-
-namespace graft_cv{
-
-CScionCutPoint::CScionCutPoint(ConfigParam&cp,CGcvLogger*pLog/*=0*/)
-:m_cparam(cp),
-m_pLogger(pLog),
-m_pImginfoBinFork(0),
-m_imgId(""),
-m_ppImgSaver(0),
-m_folder_th(-1)
-{	
-	
-}
-CScionCutPoint::~CScionCutPoint()
-{
-	this->clear_imginfo();
-}
-
-void CScionCutPoint::clear_imginfo(){
-	if (m_pImginfoBinFork){
-		imginfo_release(&m_pImginfoBinFork);
-		m_pImginfoBinFork=0;
-	}	
-}
-
-int CScionCutPoint::up_point_detect(
-	ImgInfo* imginfo, 
-	cv::Mat&cimg,
-	PositionInfo& posinfo
-	)
-{
-	clock_t t;
-	clock_t t0 = clock();
-	m_imgId = getImgId(img_type::sc);
-
-	if(m_pLogger){				
-		m_pLogger->INFO(m_imgId +" scion cut_pt detect begin.");				
-	}
-	
-	// cimg --- color image, bgr
-	cv::Mat img;
-	if(imginfo){
-		if(m_pLogger){		
-			stringstream buff;
-			buff<<m_imgId<<" scion image, width="<<imginfo->width
-				<<"\theight="<<imginfo->height;
-			m_pLogger->INFO(buff.str());
-		}
-
-		if(!isvalid(imginfo)){
-			if(m_pLogger){				
-				m_pLogger->ERRORINFO(m_imgId+" scion input image invalid.");				
-			}
-			throw_msg( m_imgId+" invalid input image");
-		}
-		img = imginfo2mat(imginfo);
-	}
-	else{
-		if(m_pLogger){		
-			stringstream buff;
-			buff<<m_imgId<<" scion image, width="<<cimg.cols
-				<<"\theight="<<cimg.rows;
-			m_pLogger->INFO(buff.str());
-		}
-		if(cimg.empty()){
-			if(m_pLogger){				
-				m_pLogger->ERRORINFO(m_imgId+" scion input image invalid.");				
-			}
-			throw_msg(m_imgId+" invalid input image");
-		}
-		img = cimg;
-	}
-
-	
-
-	if(m_cparam.self_camera){
-		image_set_bottom(img,20,8);
-		if(m_pLogger){				
-			m_pLogger->DEBUG(m_imgId+" scion image set bottom with pixel value 20.");				
-		}
-	}
-	if(m_cparam.sc_y_flip){
-		flip(img,img,0);
-		if(m_pLogger){				
-			m_pLogger->DEBUG(m_imgId+" scion image y fliped.");				
-		}
-	}
-	//image saver
-	if(m_ppImgSaver && *m_ppImgSaver){
-		(*m_ppImgSaver)->saveImage(img, m_imgId);
-		if(m_pLogger){				
-			m_pLogger->DEBUG(m_imgId+" scion after image save.");				
-		}
-	}
-	if(m_pLogger){				
-		m_pLogger->DEBUG(m_imgId+" scion before image segment.");				
-	}
-
-	//////////////////////////////////////////////////////////////////
-	//image segment
-	img_segment(img);
-	if(m_pLogger){	
-		m_pLogger->DEBUG(m_imgId+" scion after scion image segment.");				
-	}
-
-	if(m_cparam.image_show){
-		cv::destroyAllWindows();
-		imshow_wait("sc_gray", m_grayImg);	
-		imshow_wait("sc_bin", m_binImg);		
-	}
-	
-	if(m_pLogger){	
-		m_pLogger->DEBUG(m_imgId+" scion after m_binImg\m_grayImg image show.");				
-	}
-
-	//////////////////////////////////////////////////////////////////
-	//stem x-range
-	vector<int> hist_col;
-	mat_histogram(m_binImg,hist_col);
-
-	if(m_cparam.image_show){		
-		cv::Mat hist_col_img;
-		hist2image(hist_col,hist_col_img,1,m_cparam.image_col_grid,m_cparam.image_row_grid);		
-		imshow_wait("sc_hist_col", hist_col_img);		
-	}
-
-	if(m_pLogger){	
-		m_pLogger->DEBUG(m_imgId+" scion after histogram col.");				
-	}
-
-	int x0,x1,stem_x0, stem_x1;
-	get_stem_x_range_scion(hist_col,
-		m_cparam.sc_col_th_ratio,
-		m_cparam.sc_stem_x_padding,
-		x0,
-		x1,
-		stem_x0,
-		stem_x1
-		);
-
-	if(m_pLogger){		
-		stringstream buff;
-		buff<<m_imgId<<" scion image, x0="<<x0
-			<<"\tx1="<<x1
-			<<"\tstem_x0="<<stem_x0
-			<<"\tstem_x1="<<stem_x1;
-		m_pLogger->INFO(buff.str());
-	}
-
-	if(m_cparam.image_show){		
-		cv::Mat tmp_img = m_binImg.clone();
-
-		cv::line(tmp_img, cv::Point(x0,0), cv::Point(x0,m_binImg.rows-1), cv::Scalar(100),2);
-		cv::line(tmp_img, cv::Point(x1,0), cv::Point(x1,m_binImg.rows-1), cv::Scalar(100),2);
-		//fork right point
-		imshow_wait("sc_x_field", tmp_img);				
-	}	
-	/////////////////////////////////////////////////////
-	// 茎分离,通过高亮夹子分割
-	vector<int> hist_row;
-	mat_histogram(m_binImg,hist_row,1,-1,-1,x0,x1+1);
-
-	if(m_pLogger){	
-		m_pLogger->DEBUG(m_imgId+" scion after histogram row.");				
-	}
-
-	if(m_cparam.image_show){		
-		cv::Mat hist_row_img;
-		hist2image(hist_row,hist_row_img, 0,m_cparam.image_col_grid,m_cparam.image_row_grid);		
-		imshow_wait("sc_hist_row", hist_row_img);		
-	}
-	else{
-		t = clock();
-		if(1000.0*((float)(t-t0))/CLOCKS_PER_SEC>(float)m_cparam.timeout_proc){
-			throw_msg(m_imgId+" time out");
-		}
-		
-	}
-	int stem_y_min=-1;//,stem_dia=-1,stem_root_y=-1;
-	vector<int> sub_hist_col;
-	vector<int> sub_hist_row;
-	int sub_stem_x0,sub_stem_x1,sub_x0,sub_x1;
-	sub_x0 = sub_x1=sub_stem_x0=sub_stem_x1=-1;
-	cv::Mat scionBinImg;
-	get_stem_local_img(
-		hist_row,		
-		m_cparam.sc_stem_dia_min,
-		x0,
-		x1,
-		stem_y_min,
-		sub_hist_col,
-		sub_hist_row,
-		scionBinImg);	
-
-	get_stem_x_range_scion(
-		sub_hist_col,
-		m_cparam.sc_col_th_ratio,
-		m_cparam.sc_stem_x_padding,
-		sub_x0,
-		sub_x1,
-		sub_stem_x0,
-		sub_stem_x1);
-	
-	int ymin=-1,ymax=-1;
-	get_cut_up_point(
-		sub_hist_row,
-		stem_y_min,		
-		m_cparam.sc_r2_th,
-		m_cparam.sc_average_window,
-		m_cparam.sc_r2_window,
-		ymin,
-		ymax);		
-
-    int slop_fold_x = get_stem_fork_left(
-		scionBinImg,
-		ymin,
-		sub_stem_x0, 
-		sub_stem_x1,
-		m_cparam.sc_stem_edge_detect_window);
-
-	int slop_cent_y = (int)((float)(ymin+ymax)/2.0);
-	int slop_cent_x = get_stem_fork_left(
-		scionBinImg,
-		slop_cent_y,
-		sub_stem_x0, 
-		sub_stem_x1,
-		m_cparam.sc_stem_edge_detect_window);
-
-	int slop_lower_x = get_stem_fork_left(
-		scionBinImg,
-		ymax,
-		sub_stem_x0, 
-		sub_stem_x1,
-		m_cparam.sc_stem_edge_detect_window);
-
-	//update sub_stem_x0, sub_stem_x1
-	stem_x0 = x0 + sub_stem_x0;
-	stem_x1	= x0 + sub_stem_x1;	
-	slop_fold_x += x0;
-	slop_cent_x += x0;
-	slop_lower_x += x0;
-
-	//update ymin,ymax
-	ymin += stem_y_min;
-	ymax += stem_y_min;
-	slop_cent_y += stem_y_min;
-
-	cv::Mat binRoi = m_binImg(cv::Rect(x0,stem_y_min,scionBinImg.cols,scionBinImg.rows));
-	scionBinImg.copyTo(binRoi);
-	//imshow_wait("m_binImg", m_binImg);
-
-	if(m_pLogger){		
-		stringstream buff;
-		buff<<m_imgId<<" scion image result(pixel) x0="<<x0
-			<<", x1="<<x1
-			<<", stem_x0="<<stem_x0
-			<<", stem_x1="<<stem_x1
-			<<", cut_pt=("<<slop_fold_x<<","<<ymin<<")"
-			<<", cut_cent_pt=("<<slop_cent_x<<","<<slop_cent_y<<")"
-			<<", cut_lower_pt=("<<slop_lower_x<<","<<ymax<<")"
-			<<", stem_y_max="<<ymax;
-		m_pLogger->INFO(buff.str());
-	}
-
-	if(m_cparam.image_show){		
-		cv::Mat result_img = m_binImg.clone();
-		//stem x-range
-		cv::line(result_img, cv::Point(stem_x0,0), cv::Point(stem_x0,m_binImg.rows-1), cv::Scalar(100),2);
-		cv::line(result_img, cv::Point(stem_x1,0), cv::Point(stem_x1,m_binImg.rows-1), cv::Scalar(100),2);
-
-		//fork y line
-		cv::line(result_img, cv::Point(stem_x0,stem_y_min), cv::Point(stem_x1,stem_y_min), cv::Scalar(100),2);
-		cv::line(result_img, cv::Point(stem_x0,ymax), cv::Point(stem_x1,ymax), cv::Scalar(100),2);
-		//fold right point
-		cv::circle(result_img, cv::Point(slop_fold_x,ymin),2, cv::Scalar(150,0,128), -1, 8,0);
-		cv::circle(result_img, cv::Point(slop_cent_x,slop_cent_y),2, cv::Scalar(150,0,128), -1, 8,0);
-		cv::circle(result_img, cv::Point(slop_lower_x,ymax),2, cv::Scalar(150,0,128), -1, 8,0);
-		imshow_wait("sc_result", result_img);		
-	}
-
-	
-
-	double sc_cut_upoint_x, sc_cut_upoint_y,sc_cut_cpoint_x, sc_cut_cpoint_y, sc_cut_lpoint_x, sc_cut_lpoint_y;
-	sc_cut_upoint_x = (double)slop_fold_x;
-	sc_cut_upoint_x	-= (double)(img.cols/2.0);
-	sc_cut_upoint_x *= m_cparam.sc_cut_pixel_ratio;
-
-	sc_cut_upoint_y = (double)ymin;
-	sc_cut_upoint_y = (double)(img.rows/2.0) - sc_cut_upoint_y;
-	sc_cut_upoint_y *= m_cparam.sc_cut_pixel_ratio;
-
-
-	sc_cut_cpoint_x = (double)slop_cent_x;
-	sc_cut_cpoint_x	-= (double)(img.cols/2.0);
-	sc_cut_cpoint_x *= m_cparam.sc_cut_pixel_ratio;
-
-	sc_cut_cpoint_y = (double)slop_cent_y;
-	sc_cut_cpoint_y = (double)(img.rows/2.0) - sc_cut_cpoint_y;
-	sc_cut_cpoint_y *= m_cparam.sc_cut_pixel_ratio;
-
-	
-	sc_cut_lpoint_x = (double)slop_lower_x;
-	sc_cut_lpoint_x	-= (double)(img.cols/2.0);
-	sc_cut_lpoint_x *= m_cparam.sc_cut_pixel_ratio;
-
-	sc_cut_lpoint_y = (double)ymax;
-	sc_cut_lpoint_y = (double)(img.rows/2.0) - sc_cut_lpoint_y;
-	sc_cut_lpoint_y *= m_cparam.sc_cut_pixel_ratio;
-
-
-	posinfo.sc_cut_upoint_x = sc_cut_upoint_x;
-	posinfo.sc_cut_upoint_y = sc_cut_upoint_y;
-	posinfo.sc_cut_cpoint_x = sc_cut_cpoint_x;
-	posinfo.sc_cut_cpoint_y = sc_cut_cpoint_y;
-
-	posinfo.sc_cut_lpoint_x = sc_cut_lpoint_x;
-	posinfo.sc_cut_lpoint_y = sc_cut_lpoint_y;
-
-
-	if(m_pLogger){		
-		stringstream buff;
-		buff<<m_imgId<<" scion image result(mm)"
-			<<", cut_pt=("<<sc_cut_upoint_x<<","<<sc_cut_upoint_y<<")"
-			<<", cut_cent_pt=("<<sc_cut_cpoint_x<<","<<sc_cut_cpoint_y<<")"
-			<<", cut_lower_pt=("<<sc_cut_lpoint_x<<","<<sc_cut_lpoint_y<<")";
-		m_pLogger->INFO(buff.str());
-	}
-
-	// posinfo.pp_images  	
-	if(m_cparam.image_return){
-		this->clear_imginfo();
-		//1) 		
-		//stem x-range
-		cv::line(m_binImg, cv::Point(stem_x0,0), cv::Point(stem_x0,m_binImg.cols-1), cv::Scalar(100),2);
-		cv::line(m_binImg, cv::Point(stem_x1,0), cv::Point(stem_x1,m_binImg.cols-1), cv::Scalar(100),2);
-
-		//fork y line
-		cv::line(m_binImg, cv::Point(stem_x0,stem_y_min), cv::Point(stem_x1,stem_y_min), cv::Scalar(100),2);
-		cv::line(m_binImg, cv::Point(stem_x0,ymax), cv::Point(stem_x1,ymax), cv::Scalar(100),2);
-		//fold right point
-		cv::circle(m_binImg, cv::Point(slop_fold_x,ymin),5, cv::Scalar(128,0,128), -1, 8,0);
-		cv::circle(m_binImg, cv::Point(slop_cent_x,slop_cent_y),5, cv::Scalar(128,0,128), -1, 8,0);
-		cv::circle(m_binImg, cv::Point(slop_lower_x,ymax),5, cv::Scalar(128,0,128), -1, 8,0);
-		m_pImginfoBinFork=mat2imginfo(m_binImg);		
-		//
-		posinfo.pp_images[0]=m_pImginfoBinFork;		
-		if(m_ppImgSaver && *m_ppImgSaver){
-			(*m_ppImgSaver)->saveImage(m_binImg, m_imgId+"_rst_0");			
-		}
-	}
-	if(m_pLogger){				
-		m_pLogger->INFO(m_imgId +" scion cut_pt detect finished.");				
-	}
-	return ymin;
-}
-void CScionCutPoint::img_segment(cv::Mat&img)
-{
-	if(img.channels()!=1){
-		//color image ,bgr, for testing
-		cv::Mat b_img;
-		cvtColor(img,m_grayImg, cv::COLOR_BGR2GRAY);
-		double th = threshold(
-			m_grayImg,
-			b_img,
-			255,
-			255,
-			cv::THRESH_OTSU
-			);
-	   
-		cv::Mat kernel = getStructuringElement(
-			cv::MORPH_RECT,
-			cv::Size( 2*m_cparam.sc_morph_radius + 1, 2*m_cparam.sc_morph_radius+1),
-			cv::Point( m_cparam.sc_morph_radius, m_cparam.sc_morph_radius)
-			);  
-		morphologyEx(
-			b_img,
-			m_binImg,
-			cv::MORPH_CLOSE,
-			kernel,
-			cv::Point(-1,-1),
-			m_cparam.sc_morph_iteration);
-		
-	}
-	else{
-		//from imginfo image, gray image 
-		//int morph_size = 1;	
-		m_grayImg = img.clone();
-		cv::Mat b_img;
-		double th = threshold(img, b_img, 255, 255, cv::THRESH_OTSU);
-		cv::Mat kernel = cv::getStructuringElement(
-			cv::MORPH_RECT,
-			cv::Size( 2*m_cparam.sc_morph_radius + 1, 2*m_cparam.sc_morph_radius+1 ),
-			cv::Point( m_cparam.sc_morph_radius, m_cparam.sc_morph_radius)
-			);    
-		cv::morphologyEx(
-			b_img, 
-			m_binImg, 
-			cv::MORPH_OPEN,
-			kernel,
-			cv::Point(-1,-1),
-			m_cparam.sc_morph_iteration
-			);
-	}	
-}
-void CScionCutPoint::get_stem_local_img(
-	const std::vector<int>& hist,	
-	int stem_dia_min,
-	int x0, 
-	int x1,
-	int& stem_y_min,
-	vector<int>& hist_col,
-	vector<int>& hist_row,
-	cv::Mat& scionBinImg
-	)
-{
-	//1 夹子被罩上背景板,不能以高亮夹子定位
-	//2 直接找x范围内下方的大目标作为识别对象,目标像素面积
-    //3 截取部分图像单独做二值化得到二值图像
-    //4 局部图的histogram
-
-	//0 设定目标面积最小值
-	int min_obj_area = 100;
-
-    //1 reverse histogram
-	std::vector<int>reversed_hist;	
-	for(int i=hist.size()-1; i>=0;i--){		
-		reversed_hist.push_back(hist[i]);
-	}    	
-	stem_y_min = -1;
-	int stem_y_max = -1;
-	int start_idx, end_idx;
-	start_idx = end_idx = -1;
-	for(size_t i=0; i < reversed_hist.size(); ++i){
-		if(i==0){
-			if(reversed_hist[i]>=stem_dia_min){start_idx=i;}
-			continue;
-		}
-		if(reversed_hist[i]>=stem_dia_min && reversed_hist[i-1]<stem_dia_min){
-			start_idx=i;
-			continue;
-		}
-		if(reversed_hist[i]<stem_dia_min && reversed_hist[i-1]>=stem_dia_min){
-			//计算面积
-			int area = 0;
-			for(int oi=start_idx;oi<i;++oi){
-				area +=reversed_hist[oi];
-			}
-			if(area >= min_obj_area){
-				end_idx = i-1;
-				break;
-			}
-		}
-		if(i==reversed_hist.size()-1){
-			if(reversed_hist[i]>=stem_dia_min){
-				int area = 0;
-				for(int oi=start_idx;oi<=i;++oi){
-					area +=reversed_hist[oi];
-				}
-				if(area >= min_obj_area){
-					end_idx = i;
-					break;
-				}
-			}	
-		}
-	}
-	if(start_idx<0 || end_idx<0 || end_idx<=start_idx){		
-		throw_msg( m_imgId+string(" scion stem NOT exists valid sub-image"));
-	}
-
-	stem_y_min = end_idx + m_cparam.sc_clip_padding;
-	stem_y_max = start_idx - 10* m_cparam.sc_clip_padding;
-
-	if(stem_y_min>=m_grayImg.rows){stem_y_min = m_grayImg.rows;}
-	if(stem_y_max<0){stem_y_max=0;}
-	
-	//2	
-	if(m_cparam.image_show){
-		cv::Mat grayimg = m_grayImg.clone();
-		cv::rectangle(grayimg,
-			cv::Point(x0,grayimg.rows-stem_y_min),
-			cv::Point(x1,grayimg.rows-stem_y_max),
-			cv::Scalar(128));
-		imshow_wait("gray_rect",grayimg);
-	}
-
-	cv::Mat scionImg = m_grayImg(cv::Rect(x0,
-		m_grayImg.rows-stem_y_min,
-		x1-x0,
-		stem_y_min-stem_y_max));
-
-	if(m_pLogger){		
-		stringstream buff;
-		buff<<m_imgId<<" scion image, sub image(x0,y0,width,height), x0="<<x0
-			<<", y0="<<m_grayImg.rows-stem_y_min
-			<<", width="<<x1-x0
-			<<", height="<<stem_y_min-stem_y_max;
-		m_pLogger->INFO(buff.str());
-	}
-	
-	//Mat scionBinImg;
-	double th = threshold(scionImg, scionBinImg, 255, 255, cv::THRESH_OTSU);
-	if(m_cparam.image_show){
-	   imshow_wait("scion_sub_bin",scionBinImg);
-	   vector<int>hist;
-	   mat_histogram(scionBinImg,hist,1);
-	   cv::Mat hist_col_img;
-	   hist2image(hist,hist_col_img,1,m_cparam.image_col_grid,m_cparam.image_row_grid);
-		imshow_wait("sc_sub_hist_col", hist_col_img);
-	}
-	//3
-	hist_row.clear();
-	mat_histogram(scionBinImg,hist_row,1,-1,-1,-1,-1);
-	hist_col.clear();
-	mat_histogram(scionBinImg,hist_col,0,-1,-1,-1,-1);
-	stem_y_min = m_grayImg.rows-stem_y_min;
-};
-void CScionCutPoint::get_cut_up_point(
-	const std::vector<int>& sub_hist,
-	int stem_y_min,	
-	double r2_ratio_th, 
-	int average_window,
-	int r2_window,
-	int& ymin, 
-	int& ymax)
-{
-
-	int start_idx=-1;
-	int max_len=0;
-	int max_start_idx = -1;
-	int max_end_idx = -1;
-	for(size_t i=0;i<sub_hist.size();++i){		
-		if(i==0 && sub_hist[i]>0){
-			start_idx=i;
-			continue;
-		}
-		if(i==0){continue;}
-		if(sub_hist[i]>0 && sub_hist[i-1]==0){
-			start_idx=i;
-			continue;
-		}
-		if((sub_hist[i]==0 && sub_hist[i-1]>0) ||
-			(i==sub_hist.size()-1 && sub_hist[i]>0)){
-			if((i-start_idx) >max_len ){
-				max_end_idx=i;
-				max_start_idx = start_idx;
-				max_len = i-start_idx;
-			}
-			continue;
-		}
-	}
-	if(max_end_idx<0){
-		throw_msg(m_imgId+" scion stem sub-image histogram is all zero");
-	}
-   
-    ymin = max_start_idx;
-    ymax = max_end_idx-1;   
-	
-	vector<int>ys;   
-    for (size_t i = ymin; i < ymax+1; ++i){       
-	    ys.insert(ys.begin(),sub_hist[i]);        
-	}	
-    int fold_point = -1;
-	vector<int> ys_tmp;
-	for(size_t i=0;i<ys.size();++i){ys_tmp.push_back(ys[i]);}
-	int mid_idx = (int)((float)ys.size() * 0.5);	
-	sort(ys_tmp.begin(), ys_tmp.end());
-	int mid_stem_dia = ys_tmp[mid_idx];
-	int th_stem_dia = (int)((double)mid_stem_dia*0.95 +0.5);
-
-	for(size_t i=0;i<ys.size();++i){
-		if(ys[i]>=th_stem_dia){
-			fold_point = i;
-			break;
-		}
-	}
-	int offset=10;
-	if(m_folder_th<0){
-		double ca = (75.+m_cparam.rs_cut_angle)*0.0174532925199433;
-		m_folder_th = (int)(offset * fabs(tan(ca)) + 0.5);
-	}
-	while(true){
-		int pre_idx = fold_point-offset;
-		if(pre_idx<=0){break;}
-		if(ys[fold_point] - ys[pre_idx] >=m_folder_th){break;}
-		fold_point--;
-	}
-	ymin = ymax-fold_point;
-	
-}
-
-};

+ 0 - 66
cut_point_sc.h

@@ -1,66 +0,0 @@
-//cut point recognization for scion plant
-#pragma once
-
-#include <opencv.hpp>
-#include "data_def_api.h"
-#include "logger.h"
-#include "imstorage_manager.h"
-
-//using namespace cv;
-
-namespace graft_cv{
-class CScionCutPoint{
-	public:
-		CScionCutPoint(ConfigParam&, CGcvLogger*pLog=0);
-		~CScionCutPoint();
-		int up_point_detect(
-			ImgInfo*, 
-			cv::Mat&,
-            PositionInfo& posinfo
-			);
-		void set_image_saver(CImStoreManager** ppis){m_ppImgSaver=ppis;}
-
-private:	
-	cv::Mat m_binImg;// binary image
-	cv::Mat m_grayImg;//gray image
-	string m_imgId;
-	CImStoreManager**m_ppImgSaver;
-	//·µ»ØÍ¼Æ¬£¬ÓÃÓÚµ÷ÊÔ
-	ImgInfo* m_pImginfoBinFork;//fork-y, right-x	
-	int m_folder_th;	
-
-	ConfigParam& m_cparam;//global configure parameters
-	CGcvLogger* m_pLogger;
-	// image segment
-	void img_segment(cv::Mat&);
-	
-	void get_stem_local_img(
-		const std::vector<int>& hist,		
-		int stem_dia_min,
-		int x0, 
-		int x1,
-		int& stem_y_min,
-		vector<int>& hist_col,
-		vector<int>& hist_row,
-		cv::Mat& scionBinImg
-	);
-		
-	void get_cut_up_point(
-		const std::vector<int>& hist,
-		int stem_fork_y,		
-		double r2_ratio_th, 
-		int average_window, 
-		int r2_window, 
-		int& ymin, 
-		int& ymax
-		);
-	void get_slop_center(
-		int stem_x0,
-		int stem_x1,
-		int slop_cent_y,
-		int& slop_cent_x);
-
-	void clear_imginfo();
-};
-
-};

+ 8 - 135
data_def_api.h

@@ -11,98 +11,15 @@ typedef struct
 }ImgInfo;
 
 typedef struct{
-	// 调试控制 (5)
+	// 调试控制 (2)
 	bool image_show;//true--显示处理过程中的中间图片,需要人工回车才能继续执行; false--无图片显示
 	bool image_return;//true--返回结果positoninfo中添加返回的图片; false--无图片返回
-	int image_row_grid;
-	int image_col_grid;
-	bool self_camera;
-
-	// timeout (2)
-	int timeout_proc; //单个接口处理时间,500ms
-	int timeout_append; //100ms
 
 	//image storage parameters(3)
 	bool image_save;//是否保存图像
 	std::string image_depository;//保存图像目录
 	int image_backup_days;//保存图像天数,过期删除
 	
-
-	// optimal angle parameters (15)
-	bool oa_y_flip;
-	int oa_morph_radius;//optimal-angle, open-operation morph-size, = 1;-->COptimalAngle::imgproc(Mat& img)
-	int oa_morph_iteration; //optimal-angle, open-operation times, = 5; -->COptimalAngle::imgproc(Mat& img)
-	int oa_min_leaf_area; //最小叶片像素面积
-	//int oa_min_hist_value;// optimal-angle, columns-histogram, threshold; -->COptimalAngle::imgproc(Mat& img)
-	//double oa_col_th_ratio;//  = 0.7, rootstock binary image column histogram, threshold ratio for max-value, for 
-	                       // detect stem x-range
-	//double oa_row_th_ratio; // = 1.2, row histogram of stem x-range subimage, stem diameter ratio for detect 
-	                        // stem fork position
-	//int oa_stem_x_padding; // = 20;
-	//int oa_stem_dia_min;   //=20,  
-    //int oa_stem_fork_y_min;//=10,茎分叉点到茎根最下像素数量
-	//double oa_stem_dia_mp;   //=0.8,
-	//int oa_morph_radius_base;//基质二值化参数
-	//int oa_morph_iteration_base; //基质二值化参数
-	//int oa_min_hist_value_base;//基质二值化参数
-	//int oa_clip_y_min;//定位夹子上边缘y值
-	//int oa_clip_y_max;//定位夹子下边缘y值
-
-	
-	//rootstock cut parameters (20)
-	bool rs_y_flip;
-	int   rs_min_hist_value;
-	double rs_col_th_ratio;//  = 0.7, rootstock binary image column histogram, threshold ratio for max-value, for 
-	                       // detect stem x-range
-	double rs_row_th_ratio; // = 1.2, row histogram of stem x-range subimage, stem diameter ratio for detect 
-	                        // stem fork position
-	int rs_stem_x_padding; // = 20;
-	int rs_stem_dia_min;   //=20,    
-	double rs_stem_dia_mp;   //=0.8,
-    int rs_stem_fork_y_min;//=10,茎分叉点到茎根最下像素数量
-	int rs_stem_edge_detect_window;//=5, 茎单侧边缘点检测,检测时的窗口像素数量
-	                                //和茎粗相关,此数据应小于茎粗(像素数)
-	double rs_cand_corner_box_width_ratio;//=3.0 基于茎fork点,茎右侧边缘点为参考点,检测候选角点区域, 茎粗的倍数
-	double rs_cand_corner_box_xoffset_ratio;//=-10,cand_corner_box x方向偏移量, 茎粗的倍数
-	double rs_opt_corner_xoffset_ratio;//=0.75, 最优切割角点,与参考点间的距离,与茎粗的比率,也就是
-	                            // 最优切割点距离参考点有几倍的茎粗
-	double rs_opt_corner_yoffset_ratio;
-	double rs_corner_mask_rad_ratio;//二值图像角点检测后,度量角点质量用模板半径系数,为茎粗的几倍
-	 
-	int rs_morph_radius;//=1, open-operation morph-size, = 1;-->COptimalAngle::imgproc(Mat& img)
-	int rs_morph_iteration;// = 2
-	int rs_morph_iteration_gray;//=5
-	int rs_max_corner_num;//=100;
-	double rs_corner_qaulity_level;// = 0.1;
-	double rs_corner_min_distance;// = 10;
-	double rs_cut_angle; //=-135 以上切割点为中心,切削茎的方向,(-180.0,180.0)
-	double rs_cut_point_offset_ratio;//向下偏移比例,内接圆半径的倍数0-1.0	
-
-	//scion cut parameters (14)
-	bool sc_y_flip;
-	double sc_col_th_ratio;//  = 0.7, scion binary image column histogram, threshold ratio for max-value, for 
-	                      // detect stem x-range
-	double sc_row_th_ratio; // = 0.66, row histogram of stem x-range subimage, stem diameter ratio for detect 
-	                       // stem fork position, x0----x1范围内横向投影,投影值除以(x1-x0)大于此系数即找到边界
-	int sc_stem_x_padding; // = 50; 
-	int sc_stem_dia_min;   //=20,    
-	int sc_clip_padding;//=5 夹子向下间隔,这个间隔向下开始当做茎来处理
-	int sc_stem_ymax_padding;//=50 第一次检测到茎最下端(因夹子影响,茎偏小),加大检测范围
-	int sc_default_cut_length;//如果没有找到fold_point,直接估计出fold_point
-
-	int sc_stem_edge_detect_window;//=5, 茎单侧边缘点检测,检测时的窗口像素数量
-	                               //和茎粗相关,此数据应小于茎粗(像素数)
-	double sc_r2_th; //threshold for r2 ratio
-	int sc_r2_window; //= 5; the radius for calculate r2 index
-	int sc_average_window;// =10; 
-	int sc_morph_radius;//scion, open-operation morph-size, = 1;-->COptimalAngle::imgproc(Mat& img)
-	int sc_morph_iteration; //scion, open-operation times, = 5; -->COptimalAngle::imgproc(Mat& img)
-	 
-	// camera pixel ratio (3)
-	double rs_oa_pixel_ratio; // rootstock optimal-angle camera pixel ratio for millimeter, mm/piexel
-	double rs_cut_pixel_ratio; // rootstock cutting camera  pixel ratio for millimeter, mm/piexel
-	double sc_cut_pixel_ratio; // scion cutting camera  pixel ratio for millimeter, mm/piexel
-	
 	// rootstock grab based points cloud
 	double rs_grab_xmin;
 	double rs_grab_xmax;
@@ -114,11 +31,12 @@ typedef struct{
 	double rs_grab_stem_diameter;	
 	double rs_grab_seedling_dist;
 	int rs_grab_stem_min_pts;
+	int rs_grab_seedling_min_pts;
 	double rs_grab_ror_ratio;
-	double rs_grab_offset;
-	double rs_grab_fork_th;	
+	double rs_grab_offset;	
 	double rs_grab_fork_yup; //茎节高度上限
 	double rs_grab_fork_ybt; //茎节高度下限, 不在范围内,按下限
+	bool rs_grab_read_history_root_positon; //是否读取历史根中心位置信息,默认要读取,除非更改托盘尺寸
 
 	// scion grab based points cloud
 	double sc_grab_xmin;
@@ -131,14 +49,12 @@ typedef struct{
 	double sc_grab_stem_diameter;	
 	double sc_grab_seedling_dist;
 	int sc_grab_stem_min_pts;
+	int sc_grab_seedling_min_pts;
 	double sc_grab_ror_ratio;
-	double sc_grab_offset;
-	double sc_grab_fork_th;
+	double sc_grab_offset;	
 	double sc_grab_fork_yup; //茎节高度上限
 	double sc_grab_fork_ybt; //茎节高度下限, 不在范围内,按下限
-	
-
-
+	bool sc_grab_read_history_root_positon; //是否读取历史根中心位置信息,默认要读取,除非更改托盘尺寸
 } ConfigParam;
 
 typedef struct 
@@ -156,50 +72,7 @@ typedef struct
 	double sc_grab_z;//穗苗上苗抓取位置z,毫米
 	double sc_width;		//茎的宽度(直径),毫米
 	double sc_tortuosity;	//弯曲度,离茎中心轴线最大距离,毫米
-	double sc_count;		//当前第一排共有多少株
-
-	double rs_oa;//砧木最优角度
-	//double rs_oa_base;//砧木基质最优角度
-	//double rs_oa_stem_y_fork;//茎分叉点y,毫米
-	//double rs_oa_clamp_y_end;//茎可视下端y,毫米
-	//int rs_oa_width;//每一帧返回叶展宽度
-	//int rs_oa_width_base;//每一帧返回基质宽度
-	
-	double rs_cut_upoint_x;//砧木上切割点x位置,毫米
-	double rs_cut_upoint_y;//砧木上切割点y位置,毫米
-	double rs_stem_diameter;//砧木茎粗,毫米	
-	double rs_cut_lpoint_x;//砧木下切割点x位置,毫米
-	double rs_cut_lpoint_y;//砧木下切割点y位置,毫米
-	char rs_img_id[64]; 
-	double rs_reid_upoint_x;//切后砧木上切割点x位置,毫米
-	double rs_reid_upoint_y;//切后砧木上切割点y位置,毫米
-	double rs_reid_lpoint_x;//切后砧木下切割点x位置,毫米
-	double rs_reid_lpoint_y;//切后砧木下切割点y位置,毫米
-
-	double rs_reid_sola_upoint_x;//茄科切后砧木上切割点x位置,毫米
-	double rs_reid_sola_upoint_y;//茄科切后砧木上切割点y位置,毫米
-	double rs_reid_sola_cpoint_x;//茄科切后砧木中切割点x位置,毫米
-	double rs_reid_sola_cpoint_y;//茄科切后砧木中切割点y位置,毫米
-	double rs_reid_sola_lpoint_x;//茄科切后砧木下切割点x位置,毫米
-	double rs_reid_sola_lpoint_y;//茄科切后砧木下切割点y位置,毫米
-
-	double sc_reid_sola_upoint_x;//茄科穗苗切后上切割点x位置,毫米
-	double sc_reid_sola_upoint_y;//茄科穗苗切后上切割点y位置,毫米
-	double sc_reid_sola_cpoint_x;//茄科穗苗切后中切割点x位置,毫米
-	double sc_reid_sola_cpoint_y;//茄科穗苗切后中切割点y位置,毫米
-	double sc_reid_sola_lpoint_x;//茄科穗苗切后下切割点x位置,毫米
-	double sc_reid_sola_lpoint_y;//茄科穗苗切后下切割点y位置,毫米
-
-
-
-
-	double sc_cut_upoint_x;//穗苗上切割点x位置,毫米
-	double sc_cut_upoint_y;//穗苗上切割点y位置,毫米
-	double sc_cut_cpoint_x;//穗苗切割中点x位置,毫米
-	double sc_cut_cpoint_y;//穗苗切割中点y位置,毫米
-	double sc_cut_lpoint_x;//穗苗切割下点x位置,毫米
-	double sc_cut_lpoint_y;//穗苗切割下点y位置,毫米
-	
+	double sc_count;		//当前第一排共有多少株	
 	ImgInfo* pp_images[5];//参考图片,只读,从前向后,没有的会被置零
 	
 }PositionInfo;

+ 0 - 1633
demo.cpp

@@ -1,1633 +0,0 @@
-// demo.cpp : 定义控制台应用程序的入口点。
-//
-
-#include "stdafx.h"
-#include <iostream>
-#include <opencv2\highgui\highgui.hpp> 
-#include <opencv2\imgproc\imgproc.hpp> 
-#include <opencv2\opencv.hpp>
-#include <map>
-#include <fstream>
-#include <time.h>
-#include <iomanip>
-#include <fstream>
-#include <stdlib.h>
-
-#include "utils.h"
-#include "config.h"
-#include "data_def.h"
-#include "optimal_angle.h"
-#include "cut_point_sc.h"
-#include "cut_point_rs.h"
-#include "cut_point_rs_reid.h"
-#include "graft_cv_api.h"
-#include "logger.h"
-
-using namespace cv;
-using namespace graft_cv;
-
-ofstream logger_ofs;
-CGcvLogger g_logger = CGcvLogger(
-		logger_ofs,
-		CGcvLogger::file_and_terminal,
-		CGcvLogger::info,
-		"D:\\logs\\gcv.log");
-
-void test_init_cp(ConfigParam&cp){
-	cp.image_show=true;//
-	cp.image_return=true;//
-	cp.image_row_grid=20;
-	cp.image_col_grid=100;
-	cp.timeout_append=100;
-	cp.timeout_proc=500;
-	cp.self_camera=true;
-
-	cp.image_save=true;
-	cp.image_depository="D:\\logs\\img_depo";
-	cp.image_backup_days=7;
-
-
-	cp.oa_y_flip=true;
-	cp.oa_morph_radius = 1;
-	cp.oa_morph_iteration=2; 
-	/*cp.oa_min_hist_value=10;
-	cp.oa_morph_radius_base = 1;
-	cp.oa_morph_iteration_base=2; 
-	cp.oa_min_hist_value_base=10;
-
-	cp.oa_col_th_ratio=0.7;	                       
-	cp.oa_row_th_ratio=1.2; 	                        
-	cp.oa_stem_x_padding=100; 
-	cp.oa_stem_dia_min=10; 
-    cp.oa_stem_fork_y_min=10;
-	cp.oa_stem_dia_mp=0.9; 
-	cp.oa_clip_y_min=245;
-	cp.oa_clip_y_max = 355;*/
-
-	cp.rs_y_flip=false;
-	cp.rs_col_th_ratio= 0.7; 	                      
-	cp.rs_row_th_ratio= 1.15; 
-	cp.rs_stem_x_padding= 40;
-	cp.rs_stem_dia_min=12; 
-	cp.rs_stem_fork_y_min=10;     
-    cp.rs_stem_dia_mp=0.98;
-	cp.rs_stem_edge_detect_window=5;
-	cp.rs_morph_radius=1;
-	cp.rs_morph_iteration=2;
-	cp.rs_morph_iteration_gray=5;
-	cp.rs_max_corner_num=500;
-	cp.rs_corner_qaulity_level= 0.1;
-	cp.rs_corner_min_distance= 10;
-	cp.rs_cand_corner_box_width_ratio=3.0;
-	cp.rs_cand_corner_box_xoffset_ratio=0.75;
-	cp.rs_opt_corner_xoffset_ratio = 0.2;
-	cp.rs_opt_corner_yoffset_ratio = -0.5;
-	cp.rs_corner_mask_rad_ratio=0.25;
-	cp.rs_cut_angle=-45;
-
-	cp.sc_y_flip=false;
-	cp.sc_col_th_ratio=0.7;
-	cp.sc_row_th_ratio=2.5; //2-3.0
-	cp.sc_stem_x_padding=50; 
-	cp.sc_stem_dia_min=3;   
-   	cp.sc_clip_padding=5;
-	cp.sc_stem_ymax_padding=50;
-	cp.sc_default_cut_length=20;
-
-	cp.sc_stem_edge_detect_window=5;
-	cp.sc_r2_th=1.05;
-	cp.sc_r2_window=10;
-	cp.sc_average_window=10;
-	cp.sc_morph_radius=1;
-	cp.sc_morph_iteration=2;
-
-	cp.rs_oa_pixel_ratio=1.0; 
-	cp.rs_cut_pixel_ratio=1.0; 
-	cp.sc_cut_pixel_ratio=1.0;
-}
-void test_imginfo2mat()
-{
-	int t=0;
-	ImgInfo* ii = new ImgInfo();
-	ii->angle=0;
-	ii->width = ii->height = 13;
-	ii->data = new graft_cv::byte[ii->width*ii->height];
-	for (int i=0;i<ii->height;++i){
-		for (int j=0;j<ii->width;++j){
-			if (i==j || i+j==ii->width-1){
-				ii->data[i*ii->width+j]=255;
-			}
-			else{
-				ii->data[i*ii->width+j]=0;
-			}
-		}
-	}
-	Mat img = imginfo2mat(ii);
-
-	/*namedWindow("3_3", 0);
-	imshow("3_3", img);
-	waitKey(1);
-	destroyAllWindows();*/
-	delete [] ii->data;
-	delete ii;
-
-
-
-};
-void test_camconfig_write()
-{
-	ConfigParam cp0, cp1;
-	memset(&cp1, 0, sizeof(ConfigParam));
-	cp0 = cp1;
-	CGCvConfig cam0 = CGCvConfig();
-	CGCvConfig cam1 = CGCvConfig();
-	cam0.setConfParam(&cp0);
-	cam1.setConfParam(&cp1);
-
-	FileStorage fs("cam_config.yml", FileStorage::WRITE);
-	fs<<"conf_parameters";	
-	fs<<cam0;
-	//fs<<cam1;
-	//fs<<"]";	
-	fs.release();
-	
-
-};
-void test_camconfig_read()
-{
-	ConfigParam cp0, cp1;
-	memset(&cp1, 0, sizeof(ConfigParam));
-	cp0 = cp1;
-	//cp0.oa_min_hist_value = 100;
-	cout<<&cp0<<endl;
-
-	CGCvConfig cam0 = CGCvConfig();
-	//CGCvConfig cam1 = CGCvConfig();
-	cam0.setConfParam(&cp0);
-	//cam1.setConfParam(cp1);
-
-	FileStorage fs("cam_config.yml", FileStorage::READ);
-	cam0.read(fs["conf_parameters"]);	
-	
-	//fs<<cam1;
-	//fs<<"]";	
-	fs.release();
-	
-
-};
-
-void test_anglefit_readdata(vector<map<int,int>>& data){
-	string ifile = "E:\\projects\\grafting_robots\\py_code\\test.txt";
-	ifstream ifs(ifile.c_str(), ifstream::in );
-	data.clear();
-	if( ifs.is_open()){
-		string line;
-		map<int,int> tmp;
-		while(getline(ifs,line)){
-			std::cout<<line<<std::endl;
-			size_t found = line.find(",");
-			if(found !=string::npos){
-				//found
-				string sub0 = line.substr(0,found);
-				string sub1 = line.substr(found+1);
-				int an = int(stod(sub0));
-				int wi = stoi(sub1);
-				if(an==0){
-					tmp.clear();
-				}
-				tmp.insert(make_pair<int,int>(an,wi));
-				if(an==180){
-					data.push_back(tmp);
-				}
-
-			}
-		}
-
-		ifs.close();
-	}
-};
-//void test_anglefit()
-//{
-//	ConfigParam cp;
-//	COptimalAnglePart opa = COptimalAnglePart(cp);
-//	vector<map<int,int>> data;
-//	//test_anglefit_readdata(data);
-//	map<int,int>tmp;
-//	/*tmp.insert(make_pair<int,int>(0,216));
-//	tmp.insert(make_pair<int,int>(30,189));
-//	tmp.insert(make_pair<int,int>(60,112));
-//	tmp.insert(make_pair<int,int>(90,151));
-//	tmp.insert(make_pair<int,int>(120,188));*/
-//
-//	tmp.insert(make_pair<int,int>(0,315));
-//	tmp.insert(make_pair<int,int>(30,270));
-//	tmp.insert(make_pair<int,int>(60,218));
-//	tmp.insert(make_pair<int,int>(90,141));
-//	tmp.insert(make_pair<int,int>(120,127));
-//
-//	data.push_back(tmp);
-//	for(vector<map<int,int>>::iterator it = data.begin(); it!=data.end(); ++it){
-//
-//		map<int,int>& an2width = *it;		
-//		double oa = opa.angle_fit(an2width);
-//		cout<<oa<<endl;
-//	}
-//
-//};
-//void test_optimal_angle(){
-//	//string folder = "E:\\projects\\grafting_robots\\py_code\\tmp";
-//	string folder = "D:\\grafting_robot\\samples\\tmp";
-//	namedWindow("pic", 0);
-//	vector<cv::String>filenames;	
-//	ConfigParam cp;
-//	test_init_cp(cp);	
-//	/*cp.oa_min_hist_value=10;
-//	cp.oa_morph_iteration=2;
-//	cp.oa_morph_radius = 1;*/
-//	COptimalAngle opa(cp);
-//	
-//
-//	for(int i = 1;i<=5;++i){
-//		for(int j = 0;j<=1;++j){
-//			ostringstream ostr;
-//			ostr<<i<<j;
-//			string subfold = ostr.str();
-//			string src_folder = folder+"\\p"+subfold;
-//			
-//			cv::glob(src_folder, filenames);
-//			opa.reset();
-//
-//			PositionInfo posinfo;
-//
-//			clock_t t,t0;
-//			t = clock();
-//			for(size_t idx=0; idx<filenames.size();++idx){
-//				//cout<<filenames[idx]<<endl;
-//				size_t found0 = filenames[idx].rfind("\\");
-//				size_t found1 = filenames[idx].rfind(".");
-//				int an = stoi(filenames[idx].substr(found0+1, found1-found0))*20;
-//				if(an >=200){
-//					an-=200;
-//				}
-//
-//				Mat img = imread(filenames[idx], cv::IMREAD_GRAYSCALE);
-//				ImgInfo* imginfo = mat2imginfo(img);
-//				imginfo->angle = an;
-//				int obj_width=0;
-//				try{
-//					t0 = clock();
-//					obj_width = opa.append(imginfo,posinfo);
-//					t0 =  clock() - t0;				
-//
-//				imginfo_release(&imginfo);
-//				}
-//				catch(int i)
-//				{	
-//					cout<<"i= "<<i<<"异常了"<<endl;
-//					continue;
-//				}
-//				catch(string& msg){
-//					cout<<"error: "<<msg<<endl;
-//					continue;
-//				}
-//				catch(...)
-//				{
-//					continue;
-//				}
-//
-//
-//
-//
-//				//imshow("pic", img);
-//				//waitKey(1);
-//
-//				cout<<"angle="<<an<<"  rootstock_width="<<obj_width<<"   time(seconds): "<<((float)t0)/CLOCKS_PER_SEC<<endl;
-//
-//			}
-//			double oa = opa.infer(posinfo);
-//			t = clock() - t;
-//			cout<<"optimal angle: "<<oa<<endl;
-//			cout<<"time(seconds): "<<((float)t)/CLOCKS_PER_SEC<<endl;
-//
-//			cout<<"\n\n";
-//
-//
-//		}
-//	}
-//		destroyAllWindows();
-//};
-//void test_optimal_angle_simulate(){
-//
-//		
-//	//string folder = "E:\\projects\\grafting_robots\\py_code\\tmp";
-//	string folder = "D:\\grafting_robot\\samples\\tmp";
-//	//string folder = "D:\\grafting_robot\\samples\\rootstock_rotate_part";
-//	//string folder = "D:\\private\\grafting_robot\\samples\\rootstock_rotate_part";
-//	//string folder = "D:\\private\\grafting_robot\\samples\\20211215\\rotate";
-//	namedWindow("pic", CV_WINDOW_NORMAL);
-//	vector<cv::String>filenames;	
-//	ConfigParam cp;
-//	test_init_cp(cp);
-//	cp.image_return=true;
-//	cp.image_show=true;
-//	cp.oa_y_flip=false;
-//	cp.oa_clip_y_min=750;
-//	
-//	COptimalAnglePart opa(cp,&g_logger);
-//	
-//
-//	for(int i = 1;i<=1;++i){
-//		//for(int j = 0;j<=1;++j){
-//			ostringstream ostr;
-//			ostr<<i;
-//			string subfold = ostr.str();
-//			string src_folder = folder+"\\"+subfold;
-//			
-//			cv::glob(src_folder, filenames);
-//			opa.reset();			
-//
-//			PositionInfo posinfo;			
-//
-//			clock_t t,t0;
-//			t = clock();
-//			for(size_t idx=0; idx<filenames.size();++idx){
-//				//cout<<filenames[idx]<<endl;
-//				size_t found0 = filenames[idx].rfind("\\");
-//				size_t found1 = filenames[idx].rfind(".");
-//				int an = stoi(filenames[idx].substr(found0+1, found1-found0));
-//				if(an >=200){
-//					an-=200;
-//				}
-//
-//				Mat img = imread(filenames[idx], cv::IMREAD_GRAYSCALE);
-//				//Rect rect(Point(0,0),Point(img_.cols,cp.oa_clip_y_min));
-//				//Mat img = img_(rect);
-//
-//				ImgInfo* imginfo = mat2imginfo(img);
-//				imginfo->angle = an;
-//				int obj_width=0;
-//				try{
-//					memset(&posinfo,0,sizeof(PositionInfo));
-//					t0 = clock();
-//					obj_width = opa.append(imginfo,posinfo);
-//					t0 =  clock() - t0;				
-//
-//				imginfo_release(&imginfo);
-//				}
-//				catch(int i)
-//				{	
-//					cout<<"i= "<<i<<"异常了"<<endl;
-//					continue;
-//				}
-//				catch(string& msg){
-//					cout<<"error: "<<msg<<endl;
-//					continue;
-//				}
-//				catch(...)
-//				{
-//					continue;
-//				}
-//
-//
-//				//show return images
-//     			for (int i =0;i<5;++i){
-//					if (!posinfo.pp_images[i]){continue;}
-//					Mat tmp_img = imginfo2mat(posinfo.pp_images[i]);
-//					imshow("pic", tmp_img);
-//					waitKey(-1);
-//				}			
-//
-//				
-//
-//				cout<<"angle="<<an<<"  rootstock_width="<<obj_width<<"   time(seconds): "<<((float)t0)/CLOCKS_PER_SEC<<endl;
-//
-//			}
-//			try{
-//			double oa = opa.infer(posinfo);
-//			t = clock() - t;
-//			cout<<"optimal angle: "<<oa<<endl;
-//			cout<<"time(seconds): "<<((float)t)/CLOCKS_PER_SEC<<endl;
-//
-//			cout<<"\n\n";
-//			}
-//			catch(string& msg){
-//					cout<<"error: "<<msg<<endl;
-//					continue;
-//				}
-//			catch(...)
-//				{
-//					continue;
-//				}
-//
-//
-//		//}
-//	}
-//		destroyAllWindows();
-//};
-//void test_optimal_angle_part(){
-//	/*
-//	string data_file = "D:\\private\\grafting_robot\\py_code\\test.txt";
-//	ifstream ifs;
-//	ifs.open(data_file, fstream::out);
-//	std::vector<std::map<int,int>>data;
-//	std::vector<string> answer;
-//	if(ifs.is_open()){
-//		string line;
-//		std::map<int,int>tmp;
-//		while(!ifs.eof()){
-//		getline(ifs, line);
-//		//cout<<line<<endl;
-//		size_t ptmp = line.find("tmp");
-//		if(ptmp!=string::npos){
-//			tmp.clear();
-//		}
-//		else{
-//			size_t pos = line.find(",");
-//			if(pos==string::npos){
-//				data.push_back(tmp);
-//				tmp.clear();
-//				answer.push_back(line);
-//			}
-//			else{
-//				string ang = line.substr(0,pos);
-//				int an = atoi(ang.c_str());
-//				string wid = line.substr(pos+1,string::npos);
-//				int wi = atoi(wid.c_str());
-//				//cout<<ang<<"    "<<wid<<endl;
-//				tmp.insert(make_pair<int,int>(an,wi));
-//			}
-//		}		
-//		}
-//		ifs.close();
-//	}
-//	
-//   
-//	
-//	//calculate
-//	ConfigParam cp;
-//	test_init_cp(cp);
-//	cp.image_return=true;
-//	cp.image_show=true;
-//	
-//	COptimalAnglePart opa(cp);
-//	for(size_t i=0;i< data.size();++i){
-//		cout<<"optimal angle: "<<answer[i]<<endl;
-//		for(size_t j=0;j<5;++j){
-//			int start_angle = j*20;
-//			std::map<int,int> impl_data;
-//			int impl_an = start_angle;
-//			if (impl_an==80 && data[i][impl_an]==277)
-//			{
-//				cout<<"debug"<<endl;
-//			}
-//			while(true){
-//				if((impl_an-start_angle)>110){break;}
-//				if(impl_an>180){break;}
-//				impl_data.insert(make_pair<int,int>(impl_an,data[i][impl_an]));
-//				cout<<impl_an<<"\t"<<data[i][impl_an]<<endl;
-//				impl_an+=20;
-//			}
-//			
-//			double a = opa.angle_fit(impl_data);
-//			cout<<"angle: "<<a<<"\n"<<endl;
-//		}
-//		
-//	}*/
-//
-//	ConfigParam cp;
-//	test_init_cp(cp);
-//	cp.image_return=true;
-//	cp.image_show=true;
-//	
-//	COptimalAnglePart* opa=new COptimalAnglePart(cp);
-//	 map<int,int> d;
-//	d.insert(make_pair<int,int>(0,167));
-//	d.insert(make_pair<int,int>(30,126));
-//	d.insert(make_pair<int,int>(60,202));
-//	d.insert(make_pair<int,int>(90,193));
-//	d.insert(make_pair<int,int>(120,121));	
-//	double a = opa->angle_fit(d);
-//	cout<<"angle: "<<a<<"\n"<<endl;
-//};
-void test_sc_cut_point()
-{
-
-	//string src_folder = "E:\\projects\\grafting_robots\\samples\\scion1_part";
-	//string src_folder = "D:\\private\\grafting_robot\\samples\\scion1_part";
-	string src_folder = "D:\\grafting_robot\\samples\\scion1_part";
-	vector<cv::String>filenames;
-	cv::glob(src_folder, filenames);
-	ConfigParam cp;
-	test_init_cp(cp);
-	/*
-	//cp.sc_col_th_ratio=0.7;//  = 0.7, scion binary image column histogram, threshold ratio for max-value, for 
-	//                       // detect stem x-range
-	// cp.sc_row_th_ratio=1.2; // = 1.2, row histogram of stem x-range subimage, stem diameter ratio for detect 
-	//                        // stem fork position
-	// cp.sc_stem_x_padding=50; // = 50; 
-	// cp.sc_stem_dia_min=20;   //=20,
- //    cp.sc_stem_dia_max=60;   //=60,
- //    cp.sc_stem_fork_y_min=80;//=80, cut slop length, jump this range for seaching stem fork position
-	// cp.sc_fork_down=10; // stem fork down X pixels, below this line to calculate r2 ratio
-	// cp.sc_r2_th=1.05; //threshold for r2 ratio
-	// cp.sc_r2_window=5; //= 5; the radius for calculate r2 index
-	// cp.sc_average_window=10;// =10; 
-
-	//cp.sc_morph_radius=1;//scion, open-operation morph-size, = 1;-->COptimalAngle::imgproc(Mat& img)
-	// cp.sc_morph_iteration=2; //
-	//
-	*/
-	 PositionInfo posinfo;
-	CScionCutPoint scp(cp); 
-	//namedWindow("pic", WINDOW_NORMAL);
-	ofstream g_logger_ofs;
-	CGcvLogger g_logger = CGcvLogger(
-		g_logger_ofs,
-		CGcvLogger::file_and_terminal,
-		CGcvLogger::warning,
-		"./gcv_debug.log");
-
-	clock_t t;
-	
-	for(size_t idx=0; idx<filenames.size();++idx){	
-		//cout<<idx<<"\t"<<filenames[idx]<<endl;
-		//if(idx<38){continue;}
-		//string fn = "D:\\private\\grafting_robot\\samples\\scion1_part\\IMG_20210830_153852.jpg";
-		//Mat img_src = imread(fn, cv::IMREAD_COLOR);
-
-		Mat img_src = imread(filenames[idx], cv::IMREAD_COLOR);
-		Mat img;
-		resize(img_src,img,Size(img_src.cols/4, img_src.rows/4));
-		//ImgInfo* imginfo = mat2imginfo(img); 
-		int fold_y = 0;
-		try{
-			t = clock();
-			fold_y = scp.up_point_detect(0,img,posinfo);
-			t = clock() - t;	
-		}
-		catch(exception &err){
-			cout<<err.what()<<endl;
-		}
-		catch(const char* msg){
-			cout<<msg<<endl;
-			g_logger.ERRORINFO(msg);
-			g_logger.INFO(filenames[idx]);
-			
-		}
-		catch(string msg){
-			cout<<msg<<endl;
-			g_logger.ERRORINFO(msg);
-			g_logger.INFO(filenames[idx]);
-
-		}
-		catch(...){
-			cout<<"============================================unknown error"<<endl;
-			cout<<filenames[idx]<<endl<<endl;
-		}
-
-		//cv::line(img,Point(0,fold_y), Point(img.cols,fold_y),Scalar(0,0,255));
-
-		//imshow("pic", img);
-		//waitKey(-1);
-			
-		cout<<"time(seconds): "<<((float)t)/CLOCKS_PER_SEC<<endl;
-
-		cout<<"\n";
-
-	}	
-	
-};
-void test_sc_cut_point_simulate()
-{
-
-	//string src_folder = "E:\\projects\\grafting_robots\\samples\\scion1_part";
-	//string src_folder = "D:\\private\\grafting_robot\\samples\\scion1_part";
-	//string src_folder = "D:\\grafting_robot\\samples\\scion1_simulate";
-	string src_folder = "D:\\private\\grafting_robot\\samples\\20211222\\scion";
-	vector<cv::String>filenames;
-	cv::glob(src_folder, filenames);
-	ConfigParam cp;
-	test_init_cp(cp);	
-	cp.image_return=true;
-	cp.image_show=true;
-	cp.rs_y_flip=false;
-	cp.self_camera=false;
-
-	 PositionInfo posinfo;
-	 memset(&posinfo,0,sizeof(PositionInfo));
-	CScionCutPoint scp(cp,&g_logger); 
-	//namedWindow("pic", WINDOW_NORMAL);
-	/*ofstream g_logger_ofs;
-	Logger g_logger = Logger(
-		g_logger_ofs,
-		Logger::file_and_terminal,
-		Logger::warning,
-		"./gcv_debug.log");*/
-
-	clock_t t;
-	
-	for(size_t idx=0; idx<filenames.size();++idx){	
-		//cout<<idx<<"\t"<<filenames[idx]<<endl;
-		//if(idx<38){continue;}
-		//string fn = "D:\\private\\grafting_robot\\samples\\scion1_part\\IMG_20210830_153852.jpg";
-		//Mat img_src = imread(fn, cv::IMREAD_COLOR);
-		cout<<idx<<"\t"<<filenames[idx]<<endl;
-		//if(filenames[idx].find("0-4-504")==string::npos){continue;}
-
-		Mat img = imread(filenames[idx], cv::IMREAD_COLOR);		
-		int fold_y = 0;
-		try{
-			t = clock();
-			fold_y = scp.up_point_detect(0,img,posinfo);
-			t = clock() - t;	
-		}
-		catch(exception &err){
-			cout<<err.what()<<endl;
-		}
-		catch(const char* msg){
-			cout<<msg<<endl;
-			g_logger.ERRORINFO(msg);
-			g_logger.INFO(filenames[idx]);
-			
-		}
-		catch(string msg){
-			cout<<msg<<endl;
-			g_logger.ERRORINFO(msg);
-			g_logger.INFO(filenames[idx]);
-
-		}
-		catch(...){
-			cout<<"============================================unknown error"<<endl;
-			cout<<filenames[idx]<<endl<<endl;
-		}
-
-		//show return images
-		for (int i =0;i<5;++i){
-			if (!posinfo.pp_images[i]){continue;}
-			Mat tmp_img = imginfo2mat(posinfo.pp_images[i]);
-			imshow("pic", tmp_img);
-			waitKey(-1);
-		}			
-
-		//cv::line(img,Point(0,fold_y), Point(img.cols,fold_y),Scalar(0,0,255));
-
-		//imshow("pic", img);
-		//waitKey(-1);
-			
-		cout<<"time(seconds): "<<((float)t)/CLOCKS_PER_SEC<<endl;
-
-		cout<<"\n";
-
-	}	
-	
-};
-//void test_rs_cut_point(){
-//	ConfigParam cp;
-//	test_init_cp(cp);	
-//
-//	 namedWindow("pic", CV_WINDOW_NORMAL);
-//	 CRootStockCutPoint rscp(cp);
-//	 ofstream g_logger_ofs;
-//	CGcvLogger g_logger = CGcvLogger(
-//		g_logger_ofs,
-//		CGcvLogger::file_and_terminal,
-//		CGcvLogger::warning,
-//		"./gcv_debug.log");
-//	 clock_t t;
-//	for(int i=4;i<193;++i){
-//		//if (/*i !=11 &&*/ D:\private\grafting_robot\samples\rs_cut_simulate
-//		//	i !=32 && 
-//		//	i !=48 && 
-//		//	i != 49 && 
-//		//	i != 53 && 
-//		//	i != 103 && 
-//		//	i != 104 && 
-//		//	i != 106 && 
-//		//	i != 110 && 
-//		//	i != 125 && 
-//		//	i !=182 && 
-//		//	i != 187 && 
-//		//	i != 191)
-//		//{
-//		//	continue;
-//		//}
-//
-//		stringstream buff;
-//		buff<<setw(3) << setfill('0') << i;
-//		cout<<buff.str()<<endl;
-//
-//		//string img_file= "E:/projects/grafting_robots/samples/rootstlock_pumpkin/"+buff.str()+"/6.jpg";
-//		//string img_file= "D:/private/grafting_robot/samples/rootstlock_pumpkin/"+buff.str()+"/6.jpg";
-//		string img_file= "D:/grafting_robot/samples/rootstlock_pumpkin/"+buff.str()+"/6.jpg";
-//	
-//		
-//		Mat img = imread(img_file,CV_LOAD_IMAGE_COLOR  );
-//		//ImgInfo* imginfo = mat2imginfo(img);
-//		PositionInfo pinfo;
-//		try{
-//		t = clock();
-//		int fold_y = rscp.up_point_detect(0,img, pinfo);
-//		t = clock() - t;	
-//		}
-//		catch(exception &err){
-//			cout<<err.what()<<endl;
-//		}
-//		catch(string msg){
-//		 cout<<msg<<endl;
-//		 cout<<img_file<<endl<<endl;
-//		 g_logger.ERRORINFO(msg);
-//		 g_logger.INFO(buff.str());
-//		}
-//		catch(...){
-//			cout<<"============================================unknown error"<<endl;
-//			cout<<img_file<<endl<<endl;
-//		}
-//		//cv::line(img,Point(0,fold_y), Point(img.cols,fold_y),Scalar(0,0,255));
-//
-//		imshow("pic", img);
-//		waitKey(1);
-//			
-//		cout<<"time(seconds): "<<((float)t)/CLOCKS_PER_SEC<<endl;
-//
-//		cout<<"\n\n";
-//
-//	}
-//
-//
-//};
-//void test_rs_cut_point_simulate(){
-//	ConfigParam cp;
-//	test_init_cp(cp);
-//	cp.image_show=true;
-//	cp.image_return = true;
-//
-//	 namedWindow("pic", CV_WINDOW_NORMAL);
-//	 CRootStockCutPoint rscp(cp,&g_logger);
-//	 /*ofstream g_logger_ofs;
-//	Logger g_logger = Logger(
-//		g_logger_ofs,
-//		Logger::file_and_terminal,
-//		Logger::warning,
-//		"./gcv_debug.log");*/
-//
-//	//string src_folder = "D:\\private\\grafting_robot\\samples\\rs_cut_simulate";	
-//	//string src_folder = "D:\\private\\grafting_robot\\samples\\rootstock_hold_down";
-//	//string src_folder = "D:\\grafting_robot\\samples\\rootstock_hold_down";
-//	 string src_folder = "D:\\private\\grafting_robot\\samples\\20211215\\rootstock";
-//	vector<cv::String>filenames;
-//	cv::glob(src_folder, filenames);
-//
-//	 clock_t t;
-//	 for(int i=0;i<filenames.size();++i){
-//		
-//		string img_file= filenames[i];
-//		
-//		Mat img = imread(img_file,CV_LOAD_IMAGE_COLOR  );
-//		//ImgInfo* imginfo = mat2imginfo(img);
-//		PositionInfo pinfo;
-//		memset(&pinfo,0,sizeof(PositionInfo));
-//		try{
-//		t = clock();
-//		int fold_y = rscp.up_point_detect(0,img, pinfo);
-//		t = clock() - t;	
-//		}
-//		catch(exception &err){
-//			cout<<err.what()<<endl;
-//		}
-//		catch(string msg){
-//		 cout<<msg<<endl;
-//		 cout<<img_file<<endl<<endl;
-//		 g_logger.ERRORINFO(msg);
-//		 g_logger.INFO(img_file);
-//		}
-//		catch(...){
-//			cout<<"============================================unknown error"<<endl;
-//			cout<<img_file<<endl<<endl;
-//		}
-//		//cv::line(img,Point(0,fold_y), Point(img.cols,fold_y),Scalar(0,0,255));
-//
-//		imshow("pic", img);
-//		waitKey(1);
-//
-//		//show return images
-//		for (int i =0;i<5;++i){
-//			if (!pinfo.pp_images[i]){continue;}
-//			Mat tmp_img = imginfo2mat(pinfo.pp_images[i]);
-//			imshow("pic", tmp_img);
-//			waitKey(-1);
-//		}			
-//		cout<<"time(seconds): "<<((float)t)/CLOCKS_PER_SEC<<endl;
-//
-//		cout<<"\n\n";
-//
-//	}
-//
-//
-//};
-//void test_rs_cp_reid()
-//{
-//	ConfigParam cp;
-//	test_init_cp(cp);
-//	cp.image_show=false;
-//	cp.image_return = true;
-//	cp.self_camera=false;
-//	cp.oa_y_flip=false;
-//
-//	 namedWindow("pic", CV_WINDOW_NORMAL);
-//	 CRootStockCutPoint rscp(cp,&g_logger);	
-//
-//	//string src_folder = "D:\\private\\grafting_robot\\samples\\rs_cut_simulate";	
-//	//string src_folder = "D:\\private\\grafting_robot\\samples\\rootstock_hold_down";
-//	//string src_folder = "D:\\grafting_robot\\samples\\rootstock_hold_down";
-//	 string src_folder = "D:\\private\\grafting_robot\\samples\\20211215\\reid";
-//	vector<cv::String>filenames;
-//	cv::glob(src_folder, filenames);
-//
-//	 clock_t t;
-//	 for(int i=0;i<filenames.size();++i){
-//		
-//		string img_file= filenames[i];
-//		
-//		Mat img = imread(img_file,CV_LOAD_IMAGE_COLOR);
-//		//img = img(Rect(0,0,img.cols,(int)(img.rows/2)));
-//		imshow("pic", img);
-//		waitKey(-1);
-//
-//		//ImgInfo* imginfo = mat2imginfo(img);
-//		PositionInfo pinfo;
-//		memset(&pinfo,0,sizeof(PositionInfo));
-//		try{
-//		t = clock();
-//		int fold_y = rscp.up_point_reid(0,img,100.0, pinfo);
-//		t = clock() - t;	
-//		}
-//		catch(exception &err){
-//			cout<<err.what()<<endl;
-//		}
-//		catch(string msg){
-//		 cout<<msg<<endl;
-//		 cout<<img_file<<endl<<endl;
-//		 g_logger.ERRORINFO(msg);
-//		 g_logger.INFO(img_file);
-//		}
-//		catch(...){
-//			cout<<"============================================unknown error"<<endl;
-//			cout<<img_file<<endl<<endl;
-//		}
-//		//cv::line(img,Point(0,fold_y), Point(img.cols,fold_y),Scalar(0,0,255));
-//
-//		imshow("pic", img);
-//		waitKey(1);
-//
-//		//show return images
-//		for (int i =0;i<5;++i){
-//			if (!pinfo.pp_images[i]){continue;}
-//			Mat tmp_img = imginfo2mat(pinfo.pp_images[i]);
-//			imshow("pic", tmp_img);
-//			waitKey(-1);
-//		}			
-//		cout<<"time(seconds): "<<((float)t)/CLOCKS_PER_SEC<<endl;
-//
-//		cout<<"\n\n";
-//
-//	}
-//}
-void test_api_scion(){
-	// 0 ConfigParam cp;
-	ConfigParam cp;
-
-	//0 	
-	//char* lpath="D:\\grafting_robot\\cpp_code\\logs\\gcv.log";
-	//char* lpath = "D:\\private\\grafting_robot\\logs\\gcv.log";
-	//cv_set_logpath(lpath);
-	//cv_set_loglevel(0);
-	//cout<<"test"<<endl;
-	
-	// 1 get version
-	//test_init_cp(cp);
-	
-
-	char* ver = new char[10];
-	get_version(ver);
-	cout<<ver<<endl;
-	delete [] ver;
-	ver=0;
-
-	//2 cv_set_param
-	//cp.image_show=false;
-	//cv_set_param(cp);
-	//cv_save_param(0);
-
-	//3 set log
-	//cv_set_logpath("D:\\logs");
-	//cv_set_loglevel(0);
-
-	//3 cv_get_param();
-	//ConfigParam cp_tmp;	
-	//cv_get_param(cp_tmp);
-
-	//4 void cv_get_conf_file
-	//char* conf_file_ret = new char[128];
-	//cv_get_conf_file(conf_file_ret);
-	//cout<<conf_file_ret<<endl;
-	//delete [] conf_file_ret;
-	//conf_file_ret=0;
-
-	//5 cv_init()
-	//char *conf_file = "D:\\private\\grafting_robot\\cpp_code\\demo\\demo\\gcv_conf.yml";
-	//char *conf_file = "D:\\grafting_robot\\cpp_code\\demo\\demo\\gcv_conf.yml";
-	char *conf_file = "E:\\projects\\grafting_robot\\cpp_code\\demo\\demo\\gcv_conf.yml";
-	int rst = cv_init(conf_file);
-	ConfigParam cp_ret;	
-	cv_get_param(cp_ret);
-	cv_set_loglevel(0);
-
-	cv_init_image_saver();
-	//return;
-
-	//
-	//string work_folder = "D:\\private\\grafting_robot\\samples\\20211215\\scion";
-	string work_folder = "E:\\projects\\grafting_robot\\samples\\20220115\\scion";
-	vector<cv::String>filenames;
-	cv::glob(work_folder, filenames);
-	for(size_t i=0;i<filenames.size();++i){		
-		string fname = filenames[i];
-		PositionInfo posinfo;
-
-		Mat img = imread(fname, cv::IMREAD_GRAYSCALE);
-		if(img.empty()){continue;}
-		image_set_top(img,20,8);
-		ImgInfo* imginfo = mat2imginfo(img);
-		int rst = sc_cut_point(imginfo,posinfo);
-		for (int i =0;i<5;++i){
-			if (!posinfo.pp_images[i]){continue;}
-			Mat tmp_img = imginfo2mat(posinfo.pp_images[i]);			
-			imshow("pic", tmp_img);
-			waitKey(-1);						
-		}			
-	}
-
-
-	cv_release();
-}
-void test_sc_batch(){
-
-	// 0 version;
-	char* ver = new char[10];
-	get_version(ver);
-	cout<<ver<<endl;
-	delete [] ver;
-	ver=0;
-	
-	//2 cv_init()
-	//char *conf_file = "D:\\private\\grafting_robot\\cpp_code\\demo\\demo\\gcv_conf.yml";
-	//char *conf_file = "D:\\grafting_robot\\cpp_code\\demo\\demo\\gcv_conf.yml";
-	char *conf_file = "E:\\projects\\grafting_robot\\cpp_code\\demo\\demo\\gcv_conf.yml";
-	int rst = cv_init(conf_file);
-	ConfigParam cp_ret;	
-	cv_get_param(cp_ret);
-	cv_set_loglevel(0);
-	cv_init_image_saver();
-
-	//cp_ret.image_show = true;	
-	//cv_set_param(cp_ret);
-
-	//namedWindow("pic", CV_WINDOW_NORMAL);
-	
-	string work_folder = "E:\\projects\\grafting_robot\\samples\\20220223\\scion";
-	//string work_folder = "D:\\private\\grafting_robot\\samples\\20220220\\scion";
-	vector<cv::String>filenames;
-	cv::glob(work_folder, filenames);			
-	for(size_t idx=0; idx<filenames.size();++idx){		
-		/*stringstream buff;
-		buff<<work_folder<<"\\"<<i;
-		string batch_folder = buff.str();*/
-		PositionInfo posinfo;
-		string filename = filenames[idx];
-		if(filename.find("rst_")!=string::npos){
-			continue;
-		}
-		cout<<idx<<"\t"<<filename<<endl;
-		Mat img = imread(filename, cv::IMREAD_GRAYSCALE);
-		if(img.empty()){continue;}
-		image_set_top(img,20,8);
-		ImgInfo* imginfo = mat2imginfo(img);		
-		try{
-			//if(filename.find("1947_3.jpg")!=string::npos){
-			//	int ooo=0;
-			//	/*cp_ret.image_show=true;
-			//	cv_set_param(cp_ret);*/
-			//}
-			//else{
-			//	continue;
-			//}
-
-			int rst = sc_cut_point(imginfo, posinfo);
-			imginfo_release(&imginfo);
-			if(rst){
-				cout<<"error"<<endl;
-				continue;
-			}
-			for (int i =0;i<5;++i){
-				if (!posinfo.pp_images[i]){continue;}
-				Mat tmp_img = imginfo2mat(posinfo.pp_images[i]);			
-				/*imshow("pic", tmp_img);
-				waitKey(-1);*/
-
-				stringstream bbu;
-				bbu<<filename<<".rst_"<<i<<".jpg";
-				string fnn = bbu.str();
-				cv::imwrite(fnn,tmp_img);
-			}			
-		}
-		catch(...){
-			std::cout<<"some error ..."<<endl;
-		}			
-			
-	}
-	cv_release();
-}
-void test_rs_batch(){
-
-	// 0 version;
-	char* ver = new char[10];
-	get_version(ver);
-	cout<<ver<<endl;
-	delete [] ver;
-	ver=0;
-	
-	//2 cv_init()
-	//char *conf_file = "D:\\private\\grafting_robot\\cpp_code\\demo\\demo\\gcv_conf.yml";
-	//char *conf_file = "D:\\grafting_robot\\cpp_code\\demo\\demo\\gcv_conf.yml";
-	char *conf_file = "E:\\projects\\grafting_robot\\cpp_code\\demo\\demo\\gcv_conf.yml";
-	int rst = cv_init(conf_file);
-	ConfigParam cp_ret;	
-	cv_get_param(cp_ret);
-	cv_set_loglevel(0);
-	cv_init_image_saver();
-
-	//cp_ret.image_show = true;	
-	//cv_set_param(cp_ret);
-	//namedWindow("pic", CV_WINDOW_NORMAL);
-	
-	string work_folder = "E:\\projects\\grafting_robot\\samples\\20220620\\rootstock";
-	//string work_folder = "D:\\private\\grafting_robot\\samples\\20220220\\rootstock";
-	vector<cv::String>filenames;
-	cv::glob(work_folder, filenames);	
-	int cnter=0;
-	for(size_t idx=0; idx<filenames.size();++idx){	
-		string rs_filename = filenames[idx];
-		if(rs_filename.find("rst_")!=string::npos){
-			continue;
-		}
-		//if(rs_filename.find("\\379.bmp")==string::npos){continue;}
-		cout<<idx<<"\t"<<rs_filename<<endl;
-
-
-		PositionInfo posinfo;
-		Mat img = imread(rs_filename,cv::IMREAD_GRAYSCALE);
-		image_set_top(img,20,8);
-		ImgInfo* rs_imginfo = mat2imginfo(img);			
-
-		memset(&posinfo,0,sizeof(PositionInfo));
-		try{
-			/*if(cnter==4){
-				int test_tmp=0;
-			}*/
-			int fold_y = rs_cut_point(rs_imginfo, posinfo);		
-			imginfo_release(&rs_imginfo);
-
-			for (int i =0;i<5;++i){
-				if (!posinfo.pp_images[i]){continue;}
-				Mat tmp_img = imginfo2mat(posinfo.pp_images[i]);			
-				/*imshow("pic", tmp_img);
-				waitKey(-1);*/
-
-				stringstream bbu;
-				bbu<<rs_filename<<".rst_"<<i<<".jpg";
-				string fnn = bbu.str();
-				cv::imwrite(fnn,tmp_img);
-			}			
-
-		}
-		catch(exception &err){
-			cout<<err.what()<<endl;
-		}
-		catch(string msg){
-		 cout<<msg<<endl;
-		 cout<<rs_filename<<endl<<endl;
-		 //g_logger.ERRORINFO(msg);
-		 //g_logger.INFO(img_file);
-		}
-		catch(...){
-			cout<<"============================================unknown error"<<endl;
-			cout<<rs_filename<<endl<<endl;
-		}	
-		cnter+=1;
-	}
-	cv_release();
-}
-void test_rs_batch_camera(){
-
-	// 0 version;
-	char* ver = new char[10];
-	get_version(ver);
-	cout<<ver<<endl;
-	delete [] ver;
-	ver=0;
-	
-	//2 cv_init()
-	//char *conf_file = "D:\\private\\grafting_robot\\cpp_code\\demo\\demo\\gcv_conf.yml";
-	//char *conf_file = "D:\\grafting_robot\\cpp_code\\demo\\demo\\gcv_conf.yml";
-	char *conf_file = "E:\\projects\\grafting_robot\\cpp_code\\demo\\demo\\gcv_conf.yml";
-	int rst = cv_init(conf_file);
-	ConfigParam cp_ret;	
-	cv_get_param(cp_ret);
-	cv_set_loglevel(0);
-	cv_init_image_saver();
-	//cp_ret.image_show = true;
-	//cv_set_param(cp_ret);
-	//namedWindow("pic", CV_WINDOW_NORMAL);
-	
-	string work_folder = "E:\\projects\\grafting_robot\\samples\\20220119\\rootstock_cut_compare";
-	//string work_folder = "D:\\private\\grafting_robot\\samples\\20220104\\batch";
-	vector<string> sub_path;
-	sub_path.push_back("20220119133425");
-	sub_path.push_back("20220119134921");
-	sub_path.push_back("20220119135818");
-	sub_path.push_back("20220119140720");
-	sub_path.push_back("20220119141511");
-	sub_path.push_back("20220119142616");
-	sub_path.push_back("20220119143048");
-
-	//vector<cv::String>filenames;
-	//cv::glob(work_folder, filenames);	
-	vector<string> fileidx;
-	fileidx.push_back("3.bmp");
-	fileidx.push_back("11.bmp");
-	fileidx.push_back("19.bmp");
-	fileidx.push_back("27.bmp");
-	fileidx.push_back("35.bmp");
-	fileidx.push_back("43.bmp");
-	fileidx.push_back("51.bmp");
-	fileidx.push_back("59.bmp");
-	fileidx.push_back("67.bmp");
-	fileidx.push_back("75.bmp");
-	fileidx.push_back("83.bmp");
-	fileidx.push_back("91.bmp");
-	fileidx.push_back("99.bmp");
-	fileidx.push_back("107.bmp");
-	fileidx.push_back("115.bmp");
-	fileidx.push_back("123.bmp");
-
-	
-
-	for(size_t idx=0; idx<sub_path.size();++idx){
-		string subp = sub_path[idx];
-		for(size_t i=0;i<fileidx.size();++i){
-			string rs_filename = work_folder+"\\"+subp+ "\\"+fileidx[i];
-
-			PositionInfo posinfo;
-			Mat img = imread(rs_filename,cv::IMREAD_GRAYSCALE);
-			if(img.empty()){continue;}
-
-			ImgInfo* rs_imginfo = mat2imginfo(img);	
-			memset(&posinfo,0,sizeof(PositionInfo));
-			try{		
-				int fold_y = rs_cut_point(rs_imginfo, posinfo);		
-				imginfo_release(&rs_imginfo);
-
-				for (int i =0;i<5;++i){
-					if (!posinfo.pp_images[i]){continue;}
-					Mat tmp_img = imginfo2mat(posinfo.pp_images[i]);			
-					/*imshow("pic", tmp_img);
-					waitKey(-1);*/
-
-					stringstream bbu;
-					bbu<<rs_filename<<".rst_"<<i<<".jpg";
-					string fnn = bbu.str();
-					cv::imwrite(fnn,tmp_img);
-				}			
-
-			}
-			catch(exception &err){
-				cout<<err.what()<<endl;
-			}
-			catch(string msg){
-			 cout<<msg<<endl;
-			 cout<<rs_filename<<endl<<endl;
-			 //g_logger.ERRORINFO(msg);
-			 //g_logger.INFO(img_file);
-			}
-			catch(...){
-				cout<<"============================================unknown error"<<endl;
-				cout<<rs_filename<<endl<<endl;
-			}		
-		}
-	}
-	cv_release();
-}
-void test_oa_batch(){
-
-	// 0 version;
-	char* ver = new char[10];
-	get_version(ver);
-	cout<<ver<<endl;
-	delete [] ver;
-	ver=0;
-	
-	//2 cv_init()
-	//char *conf_file = "D:\\private\\grafting_robot\\cpp_code\\demo\\demo\\gcv_conf.yml";
-	//char *conf_file = "D:\\grafting_robot\\cpp_code\\demo\\demo\\gcv_conf.yml";
-	char *conf_file = "E:\\projects\\grafting_robot\\cpp_code\\demo\\demo\\gcv_conf.yml";
-	int rst = cv_init(conf_file);
-	ConfigParam cp_ret;	
-	cv_get_param(cp_ret);	
-	cv_set_loglevel(0);
-	cv_init_image_saver();
-
-	//cp_ret.image_show=true;
-	//cv_set_param(cp_ret);
-	//namedWindow("pic", CV_WINDOW_NORMAL);
-	
-	string work_folder = "E:\\projects\\grafting_robot\\samples\\20220831\\top_cpy_sim";
-	//string work_folder = "D:\\private\\grafting_robot\\samples\\20220220\\rotate";
-	vector<cv::String>filenames;
-	cv::glob(work_folder, filenames);			
-	for(size_t idx=0; idx<filenames.size();++idx){	
-			string filename = filenames[idx];
-			if(filename.find(".rst_")!=string::npos){continue;}
-			//if(filename.find("\\249.bmp")==string::npos){continue;}
-			PositionInfo posinfo;
-			Mat img = imread(filename, cv::IMREAD_GRAYSCALE);//IMREAD_GRAYSCALE IMREAD_COLOR
-			if(img.empty()){continue;}
-			//image_set_top(img,20,8);
-			ImgInfo* imginfo = mat2imginfo(img);
-			//ImgInfo* imginfo = (ImgInfo*)(&img);
-			//imginfo->angle = j*30;
-			try{
-				//rs_oa_init();
-				//rs_oa_append(imginfo, posinfo);
-				rs_oa_get_result(imginfo, posinfo);
-
-				for (int i =0;i<5;++i){
-					if (!posinfo.pp_images[i]){continue;}
-					Mat tmp_img = imginfo2mat(posinfo.pp_images[i]);			
-					imshow("pic", tmp_img);
-					waitKey(-1);
-
-					stringstream bbu;
-					bbu<<filename<<".rst_"<<i<<".jpg";
-					string fnn = bbu.str();
-					cv::imwrite(fnn,tmp_img);
-				}			
-			}
-			catch(...){
-				std::cout<<"some error ..."<<endl;
-			}			
-			
-			//imginfo_release(&imginfo);
-			
-
-		
-	}
-	cv_release();
-}
-void test_rs_batch_reid(){
-
-	// 0 version;
-	char* ver = new char[10];
-	get_version(ver);
-	cout<<ver<<endl;
-	delete [] ver;
-	ver=0;
-	
-	//2 cv_init()
-	//char *conf_file = "D:\\private\\grafting_robot\\cpp_code\\demo\\demo\\gcv_conf.yml";
-	//char *conf_file = "D:\\grafting_robot\\cpp_code\\demo\\demo\\gcv_conf.yml";
-	char *conf_file = "E:\\projects\\grafting_robot\\cpp_code\\demo\\demo\\gcv_conf.yml";
-	int rst = cv_init(conf_file);
-	ConfigParam cp_ret;	
-	cv_get_param(cp_ret);	
-	cv_set_loglevel(0);
-	cv_init_image_saver();
-
-	//cp_ret.image_show=true;
-	//cv_set_param(cp_ret);
-	//namedWindow("pic", CV_WINDOW_NORMAL);
-	
-	string work_folder = "E:\\projects\\grafting_robot\\samples\\20221003";
-	//string work_folder = "D:\\private\\grafting_robot\\samples\\20220220\\rotate";
-	vector<cv::String>filenames;
-	cv::glob(work_folder, filenames);	
-	map<string, Mat> img_cache;
-	for(size_t idx=0; idx<filenames.size();++idx){
-			
-		    if(idx %2 ==0){
-				continue;
-			}
-			img_cache.clear();
-
-			string filename_pre = filenames[idx-1];
-			string filename = filenames[idx];
-			if(filename_pre.find(".rst_")!=string::npos){continue;}
-			if(filename.find(".rst_")!=string::npos){continue;}
-			//if(filename.find("\\249.bmp")==string::npos){continue;}
-			PositionInfo posinfo;
-			memset(&posinfo,0,sizeof(PositionInfo));
-			Mat img_pre = imread(filename_pre, cv::IMREAD_GRAYSCALE);
-			Mat img = imread(filename, cv::IMREAD_GRAYSCALE);//IMREAD_GRAYSCALE  IMREAD_COLOR
-			if(img_pre.empty() || img.empty()){continue;}
-			//image_set_top(img,20,8);
-			//ImgInfo* imginfo = mat2imginfo(img);
-			//ImgInfo* imginfo = (ImgInfo*)(&img);
-			//imginfo->angle = j*30;
-
-			//for DEBUG			
-			int m_width = img.cols/2;
-			int m_height = img.rows/2;
-			cv::resize(img, img, cv::Size(m_width,m_height ));
-			cv::resize(img_pre, img_pre, cv::Size(m_width,m_height ));
-			//for DEBUG end
-
-			string imgid_pre("1");
-			img_cache.insert(make_pair<string, Mat>(imgid_pre,img_pre ));
-
-			try{
-				//rs_oa_init();
-				//rs_oa_append(imginfo, posinfo);
-
-				CRootStockCutPointReid rs_reid(cp_ret,0);
-				rs_reid.cut_point_reid(NULL, 
-					img, 
-					imgid_pre.c_str(),
-					posinfo,
-					img_cache);				
-
-				for (int i =0;i<5;++i){
-					if (!posinfo.pp_images[i]){continue;}
-					Mat tmp_img = imginfo2mat(posinfo.pp_images[i]);			
-					imshow("pic", tmp_img);
-					waitKey(-1);
-
-					//stringstream bbu;
-					//bbu<<filename<<".rst_"<<i<<".jpg";
-					//string fnn = bbu.str();
-					//cv::imwrite(fnn,tmp_img);
-				}			
-			}
-			catch(...){
-				std::cout<<"some error ..."<<endl;
-			}			
-			
-			//imginfo_release(&imginfo);
-			
-
-		
-	}
-	cv_release();
-}
-void test_api_batch(){
-
-	// 0 version;
-	char* ver = new char[10];
-	get_version(ver);
-	cout<<ver<<endl;
-	delete [] ver;
-	ver=0;
-	
-	//2 cv_init()
-	//char *conf_file = "D:\\private\\grafting_robot\\cpp_code\\demo\\demo\\gcv_conf.yml";
-	//char *conf_file = "D:\\grafting_robot\\cpp_code\\demo\\demo\\gcv_conf.yml";
-	char *conf_file = "E:\\projects\\grafting_robot\\cpp_code\\demo\\demo\\gcv_conf.yml";
-	int rst = cv_init(conf_file);
-	ConfigParam cp_ret;	
-	cv_get_param(cp_ret);
-	cv_set_loglevel(0);
-	cv_init_image_saver();
-	namedWindow("pic", CV_WINDOW_NORMAL);
-	
-	string work_folder = "E:\\projects\\grafting_robot\\samples\\20220105\\batch2";
-	//string work_folder = "D:\\private\\grafting_robot\\samples\\20211215\\scion";
-	//string work_folder = "D:\\grafting_robot\\samples\\20220102\\batch";
-	for(size_t i=1;i<19;++i){
-		stringstream buff;
-		buff<<work_folder<<"\\"<<i;
-		//buff<<work_folder<<"\\"<<"0-4-489.bmp";
-		string batch_folder = buff.str();
-		PositionInfo posinfo;
-		PositionInfo posinfo_cut;
-		///////////////////////////////////////////////////////
-		// 1 optimal angle
-		/*rs_oa_init();		
-		for(size_t j=0;j<5;++j){
-			stringstream bf;
-			bf<<batch_folder<<"\\"<<2*j+1<<".bmp";
-			string filename = bf.str();
-			Mat img = imread(filename, cv::IMREAD_GRAYSCALE);
-			if(img.empty()){continue;}
-			image_set_top(img,20,8);
-			ImgInfo* imginfo = mat2imginfo(img);
-			imginfo->angle = j*30;
-			try{
-				rs_oa_append(imginfo, posinfo);
-			}
-			catch(...){
-				std::cout<<"some error ..."<<endl;
-			}			
-			std::cout<<"angle="<<imginfo->angle<<"  rootstock_width="<<posinfo.rs_oa_width<<endl;
-			imginfo_release(&imginfo);
-			
-			
-			for (int i =0;i<5;++i){
-				if (!posinfo.pp_images[i]){continue;}
-				Mat tmp_img = imginfo2mat(posinfo.pp_images[i]);
-				imshow("pic", tmp_img);
-				waitKey(-1);
-			}			
-		}
-		rs_oa_get_result(posinfo);
-		cout<<"optimal angle="<<posinfo.rs_oa<<endl;
-		double opt_angle = posinfo.rs_oa;*/
-
-		//////////////////////////////////////////////////////////////////
-		// 2 rootstock cut point
-		//if(!(i==4 || i==6 ||i==8 || i==12 || i==15) ){continue;}
-		if(i!=10){continue;}
-		
-		string rs_filename = batch_folder+"\\11.bmp";
-		string cut_filename = batch_folder+"\\13.bmp";
-		/*if (i==15){
-			rs_filename = batch_folder+"\\11.jpg";
-		}*/
-		Mat img = imread(rs_filename,cv::IMREAD_GRAYSCALE);
-		image_set_top(img,20,8);
-		ImgInfo* rs_imginfo = mat2imginfo(img);
-
-		Mat img_cut = imread(cut_filename,cv::IMREAD_GRAYSCALE);
-		image_set_top(img_cut,20,8);
-		ImgInfo* cut_imginfo = mat2imginfo(img_cut);
-
-
-		clock_t t;
-
-		memset(&posinfo,0,sizeof(PositionInfo));
-		memset(&posinfo_cut,0,sizeof(PositionInfo));
-		try{
-			t = clock();
-			int fold_y = rs_cut_point(rs_imginfo, posinfo);
-			t = clock() - t;
-			imginfo_release(&rs_imginfo);
-
-			int reid = rs_cut_point_reid(cut_imginfo,posinfo.rs_img_id,  posinfo_cut);
-			int x = posinfo_cut.rs_reid_upoint_x;
-
-		}
-		catch(exception &err){
-			cout<<err.what()<<endl;
-		}
-		catch(string msg){
-		 cout<<msg<<endl;
-		 cout<<rs_filename<<endl<<endl;
-		 //g_logger.ERRORINFO(msg);
-		 //g_logger.INFO(img_file);
-		}
-		catch(...){
-			cout<<"============================================unknown error"<<endl;
-			cout<<rs_filename<<endl<<endl;
-		}
-		//show return images
-		/*stringstream tu;
-		tu<<batch_folder<<"\\rst_"<<int(opt_angle)<<"_"<<11<<".jpg";
-		string tuu = tu.str();
-		cv::imwrite(tuu,img);*/
-
-		/*for (int i =0;i<5;++i){
-			if (!posinfo.pp_images[i]){continue;}
-			Mat tmp_img = imginfo2mat(posinfo.pp_images[i]);			
-			imshow("pic", tmp_img);
-			waitKey(-1);
-
-			stringstream bbu;
-			bbu<<batch_folder<<"\\rst_"<<i<<".jpg";
-			string fnn = bbu.str();
-			cv::imwrite(fnn,tmp_img);
-		}			*/
-		cout<<"time(seconds): "<<((float)t)/CLOCKS_PER_SEC<<endl;
-
-		cout<<"\n\n";
-
-		
-		
-	}
-	cv_release();
-}
-void drawline_rs()
-{
-	string rs_filename = "D:\\grafting_robot\\samples\\20220108\\rootstock\\27.jpg";
-	Mat img = imread(rs_filename,cv::IMREAD_GRAYSCALE);
-	double angle = -40.0 * 3.1415926 /180.0;
-	//angle =tan(angle );
-
-
-	int x0=259;
-	int y0 = 461;
-	int b = x0-y0;
-	Point p0=Point(x0,y0);
-	int x1 = img.cols-1;
-	double dx=x1-x0;
-	double dy = tan(angle) * dx;
-	if(dy<0){dy = -dy;}
-	int y1 = y0+(int)(dy+0.5);
-	Point p1 = Point(x1,y1);
-	int x2=0;
-	int y2 = x0*tan(angle )+y0;
-	Point p2 = Point(x2,y2);
-
-	line(img,p0,p1,Scalar(255,255,255));
-	line(img,p2,p1,Scalar(255,255,255));
-	string fnn = "./tmp27.bmp";
-	cv::imwrite(fnn,img);
-			
-
-}
-void drawline_sc()
-{
-	string rs_filename = "D:\\grafting_robot\\samples\\20220108\\rootstock\\26.jpg";
-	Mat img = imread(rs_filename,cv::IMREAD_GRAYSCALE);
-	double angle = -40.0 * 3.1415926 /180.0;
-	//angle =tan(angle );
-
-
-	int x0=395;
-	int y0 = 340;
-	int b = x0-y0;
-	Point p0=Point(x0,y0);
-	int x1 = img.cols-1;
-	double dx=x1-x0;
-	double dy = tan(angle) * dx;
-	if(dy<0){dy = -dy;}
-	int y1 = y0+(int)(dy+0.5);
-	Point p1 = Point(x1,y1);
-	int x2=0;
-	int y2 = x0*tan(angle )+y0;
-	Point p2 = Point(x2,y2);
-
-	line(img,p0,p1,Scalar(255,255,255));
-	line(img,p2,p1,Scalar(255,255,255));
-	string fnn = "./tmp26.bmp";
-	cv::imwrite(fnn,img);
-			
-
-}
-void drawline_dist()
-{
-	double x0=260.0;
-	double y0=292.0;
-
-	double angle = -45.0 * 3.1415926 /180.0;
-	double k=tan(angle );
-	double b = -k*260.0-435.0;
-	double yy = -(k*x0 +b);
-	double dy = yy-y0;
-
-	double r = 5.8479999999999997e-002;
-	double dyy = dy *r;
-	cout<<dy<<"\t"<<dyy;
-
-
-}
-
-int _tmain(int argc, _TCHAR* argv[])
-{		
-	//test_imginfo2mat();
-	//test_camconfig_write();
-	//test_camconfig_read();
-	//test_anglefit();
-	//test_optimal_angle();
-	//test_optimal_angle_simulate();
-	//test_optimal_angle_part();
-	//test_sc_cut_point();
-	//test_sc_cut_point_simulate();	
-	//test_rs_cut_point();
-	//test_rs_cut_point_simulate();
-	//test_rs_cp_reid();
-
-	/////////////////////////////
-	//api test
-	//test_api_scion();	
-	//test_sc_batch();
-	//test_rs_batch();
-	//test_rs_batch_camera();
-	//test_rs_batch_reid();
-	//test_oa_batch();
-	test_api_batch();
-	//drawline_rs();
-	//drawline_sc();
-	//drawline_dist();
-
-
-	//system("pause");
-	return 0;
-}
-

+ 0 - 131
fork_rs.cpp

@@ -1,131 +0,0 @@
-#include "fork_rs.h"
-
-namespace graft_cv{
-
-	CForkDetectOptimal::CForkDetectOptimal()
-		:m_roi_width(0),m_roi_height(0)
-	{
-	}
-	CForkDetectOptimal::CForkDetectOptimal(int w,int h)
-		:m_roi_width(w),m_roi_height(h)
-	{
-	}
-	CForkDetectOptimal::~CForkDetectOptimal(){}
-	void CForkDetectOptimal::set_roi_size(int w,int h){
-		m_roi_width = w;
-		m_roi_height = h;
-	}
-	void CForkDetectOptimal::get_roi_size(int &w,int &h){
-		w = m_roi_width;
-		h = m_roi_height;
-	}
-
-	double CForkDetectOptimal::center_pt_index(
-		const cv::Mat& binimg,
-		cv::Point&cent,
-		double cut_angle //刀具切割角度
-		)
-	{
-		double ratio = 0.0;
-		cv::RotatedRect centers_rect = cv::RotatedRect(cv::Point2f(0,0), cv::Size2f(m_roi_width,m_roi_height), -cut_angle);//换算成顺时针角度
-		cv::Point2f vertices[4];
-		 centers_rect.points(vertices);
-
-		 cv::Point2f left_cent  = cv::Point2f(cent.x + vertices[0].x, cent.y + vertices[0].y);
-		 cv::Point2f right_cent = cv::Point2f(cent.x + vertices[1].x, cent.y + vertices[1].y);
-		 cv::RotatedRect left_rect = cv::RotatedRect(left_cent, cv::Size2f(m_roi_width,m_roi_height), -cut_angle);
-		 cv::RotatedRect right_rect = cv::RotatedRect(right_cent, cv::Size2f(m_roi_width,m_roi_height), -cut_angle);
-
-		 double left_cnt = roi_object_size(binimg, left_rect);
-		 double right_cnt = roi_object_size(binimg, right_rect);
-		 ratio = left_cnt* left_cnt/right_cnt/(m_roi_width*m_roi_height);
-
-		 //imshow
-		 cv::Mat tmp_img = binimg.clone();
-		 cv::Point2f vertices_left[4];
-		 cv::Point2f vertices_right[4];
-		 left_rect.points(vertices_left);
-		 right_rect.points(vertices_right);
-		 for (int i = 0; i < 4; i++){
-			 cv::line(tmp_img, vertices_left[i], vertices_left[(i+1)%4], cv::Scalar(128,255,0), 1);
-			 cv::line(tmp_img, vertices_right[i], vertices_right[(i+1)%4], cv::Scalar(200,255,0), 1);
-		 }
-		 circle(tmp_img,cent,5, cv::Scalar(128,0,0));
-
-		 return ratio;
-	}
-
-	double CForkDetectOptimal::roi_object_size(
-		const cv::Mat& binimg,
-		cv::RotatedRect &rrect)
-	{
-		double cnt = 1.0;
-		cv::Rect brect = rrect.boundingRect();
-		cv::Point2f vertices[4];
-		rrect.points(vertices);
-
-		//Mat tmp_img = Mat::zeros(binimg.rows,binimg.cols,CV_8UC1);
-		for(int r = brect.y; r<brect.y+brect.height;++r){
-			for(int c=brect.x; c<brect.x+brect.width;++c){
-				cv::Point2f ptf = cv::Point2f(c,r);
-				bool isin = is_in_rrect(vertices,ptf, rrect.angle);
-				if(isin){
-					//tmp_img.at<unsigned char>(r,c) = 255;
-					if(r<0||r>binimg.rows-1){continue;}
-					if(c<0||c>binimg.cols-1){continue;}
-					if(binimg.at<unsigned char>(r,c) >0){cnt+=1.0;}
-				}
-			}
-		}
-		return cnt;		 
-	}
-	bool CForkDetectOptimal::is_in_rrect(
-		cv::Point2f* ptf4,
-		cv::Point2f ptf,
-		float fAngle)
-	{
-		cv::Point2f ptf4Vector[4];
-		int nQuadrant[4] = {0};
-		fAngle *= CV_PI/180 *(-1);
-
-		for(int idx=0;idx<4;idx++){
-			float fDifx = float(ptf.x - ptf4[idx].x);
-			float fDify = float(ptf.y - ptf4[idx].y);
-			int nDifx = fDifx * cos(fAngle) - fDify * sin(fAngle);
-			int nDify = fDifx * sin(fAngle) + fDify * cos(fAngle);
-
-			if(nDifx >=0 && nDify >=0) nQuadrant[0]++;
-			if(nDifx < 0 && nDify >=0) nQuadrant[1]++;
-			if(nDifx < 0 && nDify < 0) nQuadrant[2]++;
-			if(nDifx > 0 && nDify < 0) nQuadrant[3]++;
-
-		}
-		int firstIdx = -1;
-		int secIdx = -1;
-		int countNum = 0;
-		for(int idx=0;idx<4;idx++){
-			if(nQuadrant[idx] !=0){
-				if(firstIdx == -1){
-					firstIdx = idx;
-				}
-				else{
-					if(secIdx == -1 && firstIdx != -1){
-						secIdx = idx;
-					}
-				}
-				countNum++;
-			}
-		}
-		if(countNum <= 2){
-			if(abs(firstIdx - secIdx)==1 || abs(firstIdx - secIdx)==3 ||
-				(countNum==1 && (firstIdx==-1 || secIdx==-1)))
-				{
-					return false;
-			}
-		}
-		return true;
-	}
-
-
-
-};

+ 0 - 31
fork_rs.h

@@ -1,31 +0,0 @@
-#pragma once
-
-#include <opencv2\imgproc\imgproc.hpp>
-
-//using namespace cv;
-
-namespace graft_cv{
-	// CForkDetectOptimal类实现优化
-	// 用于优化分叉点检测
-	// 要求:1)分叉点位于茎中心
-	//       2)通过分叉点的线能够实现有效切割
-	// 方法:通过茎中心线上的点,切割角度,找到不伤叶子的最优位置进行切割
-	//       采用虚拟切割线两侧区域前景对比的方法
-	class CForkDetectOptimal
-	{
-	public:
-		CForkDetectOptimal();
-		CForkDetectOptimal(int w, int h);
-		~CForkDetectOptimal();
-
-		double center_pt_index(const cv::Mat& binimg, cv::Point&cent, double cut_angle);
-		void set_roi_size(int w, int h);
-		void get_roi_size(int &w, int &h);
-	private:
-		int m_roi_width;
-		int m_roi_height;
-
-		double roi_object_size(const cv::Mat& binimg, cv::RotatedRect &rrect);
-		bool is_in_rrect(cv::Point2f* ptf4, cv::Point2f ptf, float fAngle);
-	};
-};

+ 15 - 89
gcv_conf.yml

@@ -1,115 +1,41 @@
 %YAML:1.0
 conf_parameters:
    image_show: 1
-   image_return: 1
-   image_row_grid: 20
-   image_col_grid: 100
-   self_camera: 0
-   timeout_proc: 100000
-   timeout_append: 150
+   image_return: 1   
    image_save: 1
    image_depository: "D:\\logs\\algo_img"
-   image_backup_days: 7
-   oa_y_flip: 0
-   oa_morph_radius: 1
-   oa_morph_iteration: 2
-   oa_min_leaf_area: 10000
-   #oa_min_hist_value: 5
-   #oa_morph_radius_base: 1
-   #oa_morph_iteration_base: 2
-   #oa_min_hist_value_base: 10
-   #oa_col_th_ratio: 6.9999999999999996e-001
-   #oa_row_th_ratio: 1.2000000000000000e+000
-   #oa_stem_x_padding: 40
-   #oa_stem_dia_min: 10
-   #oa_stem_fork_y_min: 10
-   #oa_stem_dia_mp: 9.0000000000000002e-001
-   #oa_clip_y_min: 245
-   #oa_clip_y_max: 385
-   rs_y_flip: 0
-   rs_col_th_ratio: 6.5e-001
-   rs_row_th_ratio: 1.1999999999999999e+000
-   rs_min_hist_value: 5
-   rs_stem_x_padding: 50
-   rs_stem_dia_min: 12
-   rs_stem_dia_mp: 9.6e-001
-   rs_stem_fork_y_min: 40
-   rs_stem_edge_detect_window: 5
-   rs_cand_corner_box_width_ratio: 3.
-   rs_cand_corner_box_xoffset_ratio: 7.5000000000000000e-001
-   rs_opt_corner_xoffset_ratio: 2.0000000000000001e-001
-   rs_opt_corner_yoffset_ratio: -5.0000000000000000e-001
-   rs_corner_mask_rad_ratio: 2.5000000000000000e-001
-   rs_morph_radius: 2
-   rs_morph_iteration: 5
-   rs_morph_iteration_gray: 5
-   rs_max_corner_num: 500
-   rs_corner_qaulity_level: 1.0000000000000001e-001
-   rs_corner_min_distance: 10.
-   rs_cut_angle: -60.
-   rs_cut_point_offset_ratio: 9.0000000000000000e-001
-   sc_y_flip: 0
-   sc_col_th_ratio: 6.9999999999999996e-001
-   sc_row_th_ratio: 2.000000000000000e+000
-   sc_stem_x_padding: 50
-   sc_stem_dia_min: 3
-   sc_clip_padding: 5
-   sc_stem_ymax_padding: 200
-   sc_default_cut_length: 20
-   sc_stem_edge_detect_window: 5
-   sc_r2_th: 1.0500000000000000e+000
-   sc_r2_window: 30
-   sc_average_window: 1
-   sc_morph_radius: 1
-   sc_morph_iteration: 2
-   rs_oa_pixel_ratio: 2.3333300000000001e-001
-   rs_cut_pixel_ratio: 5.8479999999999997e-002
-   sc_cut_pixel_ratio: 8.7499999999999994e-002
-   # rs_grab_xmin: -100
-   # rs_grab_xmax: 250
-   # rs_grab_ymin: -45
-   # rs_grab_ymax: 0
-   # rs_grab_zmin: 300
-   # rs_grab_zmax: 400
-   # rs_grab_stem_diameter: 5.0
-   # rs_grab_y_opt: -30
-   # rs_grab_seedling_dist: 40.0
-   # rs_grab_stem_min_pts: 50
-   # rs_grab_ror_ratio: 0.8
-   # rs_grab_offset: -5.0
+   image_backup_days: 7   
 
    rs_grab_xmin: -200
    rs_grab_xmax: 250
-   rs_grab_ymin: -30
-   rs_grab_ymax: 10
-   rs_grab_zmin: 300
-   rs_grab_zmax: 380
-   rs_grab_stem_diameter: 5.0
-   # rs_grab_y_opt: 30
+   rs_grab_ymin: -20
+   rs_grab_ymax: 30
+   rs_grab_zmin: 340
+   rs_grab_zmax: 420
+   rs_grab_stem_diameter: 5.0   
    rs_grab_seedling_dist: 40.0
    rs_grab_stem_min_pts: 50
+   rs_grab_seedling_min_pts: 2500
    rs_grab_ror_ratio: 0.85
-   rs_grab_offset: 0
-   rs_grab_fork_th: 1.5
+   rs_grab_offset: 0   
    rs_grab_fork_yup: 10
    rs_grab_fork_ybt: -10
-
+   rs_grab_read_history_root_positon: 1
 
    sc_grab_xmin: -200
    sc_grab_xmax: 220
    sc_grab_ymin: -30
    sc_grab_ymax: 10
    sc_grab_zmin: 300
-   sc_grab_zmax: 400
-   
-   sc_grab_stem_diameter: 5.0
-   # sc_grab_y_opt: 30
+   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_th: 1.5
+   sc_grab_offset: 0   
    sc_grab_fork_yup: 10
    sc_grab_fork_ybt: 0
+   sc_grab_read_history_root_positon: 1
    
 

+ 400 - 0
grab_occlusion.cpp

@@ -0,0 +1,400 @@
+#include <sstream>
+#include <opencv2\highgui\highgui.hpp>
+#include "grab_occlusion.h"
+
+
+namespace graft_cv {
+	CStemResultInfos::CStemResultInfos(double seedling_dist,std::string pcd_id, CGcvLogger*pLog)
+		: m_pLogger(pLog)
+		, m_seedling_dist(seedling_dist)
+		, m_append_counter(0)
+		, m_pcdId(pcd_id)	
+		, m_max_size(200)
+	{}
+	
+	CStemResultInfos::~CStemResultInfos()
+	{}
+
+	void CStemResultInfos::append(
+		CStemResult& sr
+	)
+	{
+		m_infos.insert(m_infos.begin(), sr);
+		if (m_infos.size() > m_max_size) {
+			m_infos.pop_back();
+		}
+		m_append_counter += 1;
+
+		if (m_append_counter % 10 == 0) {
+			//定期写入数据
+			_update_root_centers();
+			write_root_centers(m_json_filename);
+		}
+	}
+	void CStemResultInfos::clear()
+	{
+		m_infos.clear();
+	}
+	void CStemResultInfos::get_root_centers(
+		std::vector<CStemResult>&rst
+	)
+	{
+		//如果存在m_root_centers,就返回m_root_centers
+		//否则构建新的
+
+		//方法: 通过m_seedling_dist进行分类, 当m_append_counter数量增加10后就进行更新
+		if (m_root_centers.size() == 0) {
+			//用当前m_infos中的数据生成root_centers数据
+			_update_root_centers();
+			rst.clear();
+			for (auto& sr : m_root_centers) {
+				rst.push_back(sr);
+			}
+		}
+		else {
+			rst.clear();
+			for (auto& sr : m_root_centers) {
+				rst.push_back(sr);
+			}
+			
+		}
+	}
+
+
+	void CStemResultInfos::_update_root_centers() {
+		//依据m_infos中的数据,苗间距m_seedling_dist,聚类生成茎的平均位置,茎的点云平均数量
+		//更新m_root_centers
+
+		//以root_center为基础进行聚类,如果root_center是空的,因当前数据进行聚类
+		std::vector<CStemResult> root_centers;
+		double d1 = m_seedling_dist / 2.0;
+		double d2 = d1*1.75;
+		pcl::PointCloud<pcl::PointXYZ>::Ptr cloud2d_pos(new pcl::PointCloud < pcl::PointXYZ>);
+		for (auto&sr : m_infos) {
+			cloud2d_pos->points.push_back(pcl::PointXYZ((float)sr.root_x, 0.0, (float)sr.root_z));
+		}
+		cloud2d_pos->width = cloud2d_pos->points.size();
+		std::vector<pcl::PointXYZ>cluster_center;
+		std::vector<std::vector<int>> cluster_member;
+		euclidean_clustering_ttsas(cloud2d_pos, d1, d2, cluster_center, cluster_member);
+
+		for (size_t i = 0; i < cluster_center.size(); ++i) {
+			double x = (double)cluster_center.at(i).x;
+			double y = (double)cluster_center.at(i).y;
+			double z = (double)cluster_center.at(i).z;
+			int count = (int)cluster_member.at(i).size();
+			int pc_size = 0.0;
+			for (auto& idx : cluster_member.at(i)) {
+				pc_size += m_infos.at(idx).stem_size;
+			}
+			pc_size = (int)(pc_size / (float)count);
+
+			CStemResult sr = CStemResult(x, y, z, pc_size, std::string(""), count);
+			root_centers.push_back(sr);
+		}
+
+		if (m_root_centers.size() == 0) {
+			//如果没有历史数据,直接赋值
+			m_root_centers = root_centers;
+		}
+		else {
+			if (m_infos.size() > 50) {
+				//如果当前数据量较大,用当前的结果
+				m_root_centers = root_centers;
+			}
+			else {
+				//否则将当前结果合并到m_root_centers
+				//m_root_centers
+				for (auto& cent : root_centers) {					
+					double dist_min = d2;
+					int min_root_idx = 0;
+
+					for (int j = 0; j < m_root_centers.size();++j) {
+						CStemResult& root = m_root_centers.at(j);
+						double dist = root.calcluate_distance(cent);
+						if (dist < dist_min) {
+							dist_min = dist;
+							min_root_idx = j;
+						}
+					}
+					if (dist_min < d1) {
+						//merge
+						double mu_x, mu_y,mu_z;
+						CStemResult& min_root = m_root_centers.at(min_root_idx);
+						mu_x = (min_root.root_x * min_root.root_count +
+							cent.root_x * cent.root_count) / (double)(min_root.root_count + cent.root_count);
+
+						mu_y = (min_root.root_y * min_root.root_count +
+							cent.root_y * cent.root_count) / (double)(min_root.root_count + cent.root_count);
+
+						mu_z = (min_root.root_z * min_root.root_count +
+							cent.root_z * cent.root_count) / (double)(min_root.root_count + cent.root_count);
+
+						min_root.root_x = mu_x;
+						min_root.root_y = mu_y;
+						min_root.root_z = mu_z;
+						min_root.root_count += cent.root_count;
+					}
+					else {
+						//add root
+						m_root_centers.push_back(cent);
+					}
+				}
+			}
+		}
+		//m_root_centers 排序、剔除
+		std::sort(m_root_centers.begin(), m_root_centers.end(),
+			[](const CStemResult& sr1, const CStemResult& sr2) {return sr1.root_x < sr2.root_x; });
+		//nms		
+		_filter_root_centers(d1, d2);
+	}
+	void CStemResultInfos::_filter_root_centers(double d1, double d2)
+	{
+		//对生成的根中心m_root_centers进行过滤,剔除异常
+		//1 z值,通过中值,距离中值远的剔除
+
+		if (m_root_centers.size() > 3) {
+			std::vector<double>root_z;
+			for (auto&rc : m_root_centers) {
+				root_z.push_back(rc.root_z);
+			}
+			std::sort(root_z.begin(), root_z.end());
+			double mid_z = 0.0;
+			if (root_z.size() % 2 == 1) {
+				int idx = (m_root_centers.size() - 1) / 2;
+				mid_z = root_z.at(idx);
+			}
+			else {
+				int idx = root_z.size() / 2;
+				mid_z = 0.5 * (root_z.at(idx) + root_z.at(idx - 1));
+			}
+			std::vector<CStemResult> valid_root_centers;
+			for (auto&rc : m_root_centers) {
+				if (fabs(rc.root_z - mid_z) < d2) {
+					valid_root_centers.push_back(rc);
+				}
+			}
+			m_root_centers = valid_root_centers;
+		}
+
+		//2 按x做分组,排除权重小的
+		if (m_root_centers.size() > 3) {
+			std::vector<double> center_dist;
+			for (int i = 0; i < m_root_centers.size(); ++i) {
+				double x = m_root_centers.at(i).root_x;
+				double mod_sum = 0.0;
+				for (int j = 0; j < m_root_centers.size(); ++j) {
+					double dist = fabs(m_root_centers.at(j).root_x - x);
+					double mod = fmod(dist, m_seedling_dist);
+					double mod_inv = m_seedling_dist - mod;
+					mod = min(mod, mod_inv);
+					mod_sum += mod;
+				}
+				mod_sum /= (m_root_centers.size() - 1);
+				center_dist.push_back(mod_sum);
+			}
+
+			std::vector<CStemResult> valid_root_centers;
+			for (int i = 0; i < center_dist.size(); ++i) {
+				double dist = center_dist.at(i);
+				if (dist < d1) {
+					valid_root_centers.push_back(m_root_centers.at(i));
+				}
+			}
+			m_root_centers = valid_root_centers;
+		}
+		//3 数量少的剔除
+		int total_count = 0;
+		for (auto&rc : m_root_centers) {
+			total_count += rc.root_count;
+		}
+		if (total_count > 50) {
+			bool need_del = false;
+			for (auto& rc : m_root_centers) {
+				if (rc.root_count <= 2) {
+					need_del = true;
+					break;
+				}
+			}
+			if (need_del) {
+				std::vector<CStemResult> valid_root_centers;
+				for (int i = 0; i < m_root_centers.size(); ++i) {					
+					if (m_root_centers.at(i).root_count > 2) {
+						valid_root_centers.push_back(m_root_centers.at(i));
+					}
+				}
+				m_root_centers = valid_root_centers;
+			}
+			
+		}
+
+	}
+	void CStemResultInfos::set_json_filename(std::string& filename) {
+		m_json_filename = std::string(filename);
+	}
+	void CStemResultInfos::read_root_centers(
+		std::string& filename
+	) 
+	{
+		//读取历史数据,每次启动时,去取
+		m_json_filename = std::string(filename);
+		//1 文件是否存在
+		ifstream f(filename.c_str());
+		if (!f.good()) {
+			//文件不存在
+			if (m_pLogger) {
+				stringstream buff;
+				buff << m_pcdId << ": json file not exists:" << filename;
+				m_pLogger->INFO(buff.str());
+			}
+			return;
+		}	
+
+		cv::FileStorage fs(filename, cv::FileStorage::READ);
+		cv::FileNode root_centers = fs["root_centers"];
+		cv::FileNodeIterator it = root_centers.begin(), it_end = root_centers.end();
+		m_root_centers.clear();
+		for (; it != it_end; ++it) {
+			double x = (double)(*it)["x"];
+			double y = (double)(*it)["y"];
+			double z = (double)(*it)["z"];
+			int size = (int)(*it)["size"];
+			std::string bid = (std::string)(*it)["batch_id"];
+			int count = (int)(*it)["count"];
+			CStemResult sr = CStemResult(x,y,z,size, bid, count);
+			m_root_centers.push_back(sr);
+		}
+		fs.release();
+
+	}
+	void CStemResultInfos::write_root_centers(
+		std::string& filename
+	)
+	{
+		cv::FileStorage fs(filename, cv::FileStorage::WRITE);
+		fs << "root_centers" << "[";
+		for (auto& sr : m_root_centers) {		
+			fs << "{" << "x" << sr.root_x
+				<< "y" << sr.root_y
+				<< "z" << sr.root_z
+				<< "size" << sr.stem_size
+				<< "batch_id" << sr.batch_id	
+				<< "count" << sr.root_count
+				<< "}";
+		}
+		fs << "]";
+		fs.release();
+
+	}
+
+	void CStemResultInfos::euclidean_clustering_ttsas(
+		pcl::PointCloud<pcl::PointXYZ>::Ptr in_cloud,
+		double d1, double d2,
+		std::vector<pcl::PointXYZ>&cluster_center,
+		std::vector<std::vector<int>> &clustr_member
+	)
+	{
+		if (m_pLogger) {
+			stringstream buff;
+			buff << m_pcdId << ": root center estimate: euclidean_clustering_ttsas() begin...";
+			m_pLogger->INFO(buff.str());
+		}
+		std::vector<int> cluster_weight;
+		std::vector<int> data_stat;
+
+		std::vector<pcl::PointXYZ>cluster_center_raw;
+		std::vector<std::vector<int>> clustr_member_raw;
+
+		for (size_t i = 0; i < in_cloud->points.size(); ++i) { data_stat.push_back(0); }
+		size_t data_len = in_cloud->points.size();
+		int exists_change = 0;
+		int prev_change = 0;
+		int cur_change = 0;
+		int m = 0;
+		while (std::find(data_stat.begin(), data_stat.end(), 0) != data_stat.end()) {
+			bool new_while_first = true;
+			for (size_t i = 0; i < data_len; ++i) {
+				if (data_stat.at(i) == 0 && new_while_first && exists_change == 0) {
+					new_while_first = false;
+					std::vector<int> idx;
+					idx.push_back(i);
+					clustr_member_raw.push_back(idx);
+					pcl::PointXYZ center;
+					center.x = in_cloud->points.at(i).x;
+					center.y = in_cloud->points.at(i).y;
+					center.z = in_cloud->points.at(i).z;
+
+					cluster_center_raw.push_back(center);
+					data_stat.at(i) = 1;
+					cur_change += 1;
+					cluster_weight.push_back(1);
+					m += 1;
+				}
+				else if (data_stat[i] == 0) {
+					std::vector<float> distances;
+					for (size_t j = 0; j < clustr_member_raw.size(); ++j) {
+						std::vector<float> distances_sub;
+						for (size_t jj = 0; jj < clustr_member_raw.at(j).size(); ++jj) {
+							size_t ele_idx = clustr_member_raw.at(j).at(jj);
+							double d = sqrt(
+								(in_cloud->points.at(i).x - in_cloud->points.at(ele_idx).x) * (in_cloud->points.at(i).x - in_cloud->points.at(ele_idx).x) +
+								(in_cloud->points.at(i).y - in_cloud->points.at(ele_idx).y) * (in_cloud->points.at(i).y - in_cloud->points.at(ele_idx).y) +
+								(in_cloud->points.at(i).z - in_cloud->points.at(ele_idx).z) * (in_cloud->points.at(i).z - in_cloud->points.at(ele_idx).z));
+							distances_sub.push_back(d);
+						}
+						double min_dist = *std::min_element(distances_sub.begin(), distances_sub.end());
+						distances.push_back(min_dist);
+					}
+					int min_idx = std::min_element(distances.begin(), distances.end()) - distances.begin();
+					if (distances.at(min_idx) < d1) {
+						data_stat.at(i) = 1;
+						double w = cluster_weight.at(min_idx);
+						cluster_weight.at(min_idx) += 1;
+						clustr_member_raw.at(min_idx).push_back(i);
+						cluster_center_raw.at(min_idx).x = (cluster_center_raw.at(min_idx).x * w + in_cloud->points.at(i).x) / (w + 1);
+						cluster_center_raw.at(min_idx).y = (cluster_center_raw.at(min_idx).y * w + in_cloud->points.at(i).y) / (w + 1);
+						cluster_center_raw.at(min_idx).z = (cluster_center_raw.at(min_idx).z * w + in_cloud->points.at(i).z) / (w + 1);
+						cur_change += 1;
+					}
+					else if (distances.at(min_idx) > d2) {
+						std::vector<int> idx;
+						idx.push_back(i);
+						clustr_member_raw.push_back(idx);
+						pcl::PointXYZ center;
+						center.x = in_cloud->points.at(i).x;
+						center.y = in_cloud->points.at(i).y;
+						center.z = in_cloud->points.at(i).z;
+
+						cluster_center_raw.push_back(center);
+						data_stat.at(i) = 1;
+						cur_change += 1;
+						cluster_weight.push_back(1);
+						m += 1;
+					}
+
+				}
+				else if (data_stat.at(i) == 1) {
+					cur_change += 1;
+				}
+			}
+			exists_change = fabs(cur_change - prev_change);
+			prev_change = cur_change;
+			cur_change = 0;
+		}
+
+		// copy result
+		for (size_t i = 0; i < clustr_member_raw.size(); ++i) {
+			//if (clustr_member_raw.at(i).size() < 20) { continue; }
+			cluster_center.push_back(cluster_center_raw.at(i));
+			clustr_member.push_back(clustr_member_raw.at(i));
+		}
+		if (m_pLogger) {
+			stringstream buff;
+			buff << m_pcdId << ":  root center estimate: euclidean_clustering_ttsas() end";
+			m_pLogger->INFO(buff.str());
+		}
+	}
+
+
+
+}

+ 80 - 0
grab_occlusion.h

@@ -0,0 +1,80 @@
+#pragma once
+
+#include <vector>
+#include <string>
+#include <math.h>
+#include <pcl\point_types.h>
+#include <pcl\point_cloud.h>
+#include "logger.h"
+
+namespace graft_cv {
+	class CStemResult {
+	public:
+		CStemResult() :
+			root_x(0.0),
+			root_z(0.0),
+			stem_size(0),
+			batch_id(std::string("")),
+			root_count(0)			
+		{};
+		CStemResult(double x,double y, double z, int size, std::string& bid, int rcount)
+		{
+			
+			root_x = x;
+			root_y = y;
+			root_z = z;
+			stem_size = size;
+			batch_id = std::string(bid);
+			root_count = rcount;
+		};
+		double calcluate_distance(const CStemResult& sr) {
+			double dist = 0.0;
+			dist = sqrt((this->root_x - sr.root_x) *(this->root_x - sr.root_x) +
+				//(this->root_y - sr.root_y) *(this->root_y - sr.root_y) +
+				(this->root_z - sr.root_z) *(this->root_z - sr.root_z));
+			return dist;
+		};
+		double root_x;	//识别到的茎根x坐标
+		double root_y;
+		double root_z;	//识别到的茎根z坐标
+		int stem_size;	//识别到的茎根矩形邻域点云数量
+		std::string batch_id;	//识别到的茎批次(每一次处理,批次一致)
+		int root_count;	//统计root的累计个数
+
+	private:
+	};
+
+	class CStemResultInfos {
+	public:
+		CStemResultInfos(double seedling_dist,std::string pcd_id,  CGcvLogger*pLog=0);
+		~CStemResultInfos();
+		
+		void set_json_filename(std::string& filename);
+		void read_root_centers(std::string& filename);//读取历史数据,每次启动时,去取
+		void write_root_centers(std::string& filename);//保存当前数据,间隔一定时间保存一次
+
+		void append(CStemResult& sr);
+		void clear();
+		void get_root_centers(std::vector<CStemResult>&rst);
+
+
+	protected:
+		CGcvLogger * m_pLogger;
+		int m_max_size;	//m_infos最大长度		
+		std::vector<CStemResult> m_infos;
+		double m_seedling_dist;		//植株间距,毫米
+		std::vector<CStemResult> m_root_centers;	//茎根位置历史平均值
+		int m_append_counter;
+		std::string m_json_filename;
+		std::string m_pcdId;
+
+		void _update_root_centers();	//通过当前的数据生成茎中心位置,聚类
+		void _filter_root_centers(double d1, double d2);	//对生成的根中心m_root_centers进行过滤,剔除异常
+		void euclidean_clustering_ttsas(
+			pcl::PointCloud<pcl::PointXYZ>::Ptr in_cloud,
+			double d1, double d2,
+			std::vector<pcl::PointXYZ>&cluster_center,
+			std::vector<std::vector<int>> &clustr_member
+		);
+	};
+}

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 441 - 614
grab_point_rs.cpp


+ 33 - 36
grab_point_rs.h

@@ -7,6 +7,7 @@
 #include "data_def.h"
 #include "logger.h"
 #include "imstorage_manager.h"
+#include "grab_occlusion.h"
 
 namespace graft_cv {
 	class CRootStockGrabPoint {
@@ -24,6 +25,12 @@ namespace graft_cv {
 		int m_dtype;
 		string m_pcdId;
 
+		//历史植株位置信息
+		CStemResultInfos* m_pStemInfos;
+		std::string m_stem_info_file;
+		std::vector<CStemResult> m_root_centers;  //通过m_pStemInfos获取到历史根中心位置
+		std::vector<bool> m_root_center_with_seedling;	//m_root_centers位置上是否含有植株
+
 		//用于记录第一排z均值,用来辅助判别1、2排的苗
 		float m_1st_row_zmean_rs = -1.0;
 		float m_1st_row_zmean_sc = -1.0;
@@ -50,40 +57,7 @@ namespace graft_cv {
 			pcl::PointCloud<pcl::PointXYZ>::Ptr in_cloud, 
 			std::vector<int> &stem_cloud_idx
 			);
-		//////////////////////////////////////////////////////////////////////////////////////
-		//叶子剔除,通过形态学方法,腐蚀,得到叶子区域,将叶子区域内地的点云去掉
-		void leaf_filter_morph(
-			pcl::PointCloud<pcl::PointXYZ>::Ptr in_cloud,	//input 输入点云数据
-			std::vector<int> &stem_cloud_idx				//output, 过滤后的点云序号
-		);
-		//生成3d图像
-		void gen_3d_image(
-			pcl::PointCloud<pcl::PointXYZ>::Ptr in_cloud,	//input 输入点云数据
-			pcl::PointXYZ& min_pt,							//input 图像下限
-			pcl::PointXYZ& max_pt,							//input 图像上限
-			float step,										//input 图像像素间隔
-			cv::Mat& bin_3d_img,								//output, 生成的binary图像
-			std::map<int, std::vector<int>>& id2pcdidx
-			);
-		//3*3*3内的膨胀
-		void dilation_3d(
-			cv::Mat& in_3d_img,		//input, 输入图像
-			cv::Mat& out_3d_img		//output, 生成的图像
-		);
-		//3*3*3内的腐蚀
-		void erosion_3d(
-			cv::Mat& in_3d_img,
-			int th,				//阈值
-			cv::Mat& out_3d_img
-		);
-		//得到点云序号
-		void get_mass_obj_idx(
-			cv::Mat& open_3d_img,				//input, 开运算后的图像
-			std::map<int, std::vector<int>>& id2pcdidx, //input 保存的像素位置的点云序号
-			std::vector<int>& mass_idx			//output,
-		);
-		//////////////////////////////////////////////////////////////////////////////////////
-		//叶子剔除,通过形态学方法
+		
 		void leaf_filter_ror(
 			pcl::PointCloud<pcl::PointXYZ>::Ptr in_cloud,	//input 输入点云数据
 			std::vector<int> &stem_cloud_idx				//output, 过滤后的点云序号
@@ -175,8 +149,7 @@ namespace graft_cv {
 			pcl::PointCloud<pcl::PointXYZ>::Ptr in_line_cloud,	//input
 			pcl::ModelCoefficients::Ptr line_model,			//input
 			pcl::PointXYZ&pt,								//输出,
-			pcl::PointXYZ &pt_ref,							//输出,	返回点茎节的参考点
-			std::vector<int>& valid_line_index,				//输出,
+			pcl::PointXYZ &pt_ref,							//输出,	返回点茎节的参考点			
 			float& stem_width_mu,								//输出,茎宽度,直径
 			float& stem_deflection							//输出,茎的最大挠度,最大弯曲处的偏离直径轴心的距离,毫米
 		);
@@ -199,8 +172,32 @@ namespace graft_cv {
 			pcl::PointCloud<pcl::PointXYZ>::Ptr,	//输入,整体点云cloud_dowm_sampled, 
 			pcl::PointXYZ& selected_pt,				//输入,selected_pt, 
 			pcl::PointXYZ& selected_pt_ref,        //输入,selected_pt_ref,
+			const PositionInfo& posinfo,					//输入,
 			cv::Mat& rst_img						//输出,图片, 640*1280
 		);
+		//根据历史根的位置,计算对应位置点云数量,进而判断此位置是否有苗
+		void seedling_detect_by_point_cloud();
+		int get_point_count_inbox(const CStemResult& sr, //input
+			pcl::PointXYZ& aabb_min,	//output
+			pcl::PointXYZ& aabb_max);	//output
+		//没有检测到苗的情况,后处理
+		void no_seedling_detected_post_process(
+			int first_row_seedling_number,		//input
+			int& selected_idx,					//output, 选择root_center的序号
+			pcl::PointXYZ& selected_pt,			//output
+			pcl::PointXYZ& selected_pt_ref,		//output
+			PositionInfo& posinfo				//output
+		);
+		//检测到苗的情况,后处理
+		void had_seedling_detected_post_process(
+			int first_row_seedling_number,		//input
+			float stem_width_mu,				//input
+			float stem_deflection,				//input
+			int& selected_idx,					//output, 选择root_center的序号
+			pcl::PointXYZ& selected_pt,			//input-output
+			pcl::PointXYZ& selected_pt_ref,		//input-output
+			PositionInfo& posinfo				//output
+		);
 
 		void viewer_cloud(pcl::PointCloud<pcl::PointXYZ>::Ptr, std::string&winname);
 		void viewer_cloud(pcl::PointCloud<pcl::PointXYZRGB>::Ptr, std::string&winname);

+ 43 - 248
graft_cv_api.cpp

@@ -5,14 +5,9 @@
 #include "data_def.h"
 #include "data_def_api.h"
 #include "config.h"
-#include "optimal_angle.h"
-#include "cut_point_rs.h"
-#include "cut_point_sc.h"
 #include "logger.h"
 #include "utils.h"
 #include "imstorage_manager.h"
-#include "cut_point_rs_reid.h"
-
 #include "grab_point_rs.h"
 #include "chessboard_calibration.h"
 
@@ -20,7 +15,7 @@ extern CRITICAL_SECTION g_cs;
 namespace graft_cv
 {
 
-	char *g_version_str = "0.7.23";
+	char *g_version_str = "0.8.0";
 
 	//configure
 	string g_conf_file = "./gcv_conf.yml";	
@@ -36,28 +31,15 @@ namespace graft_cv
 
 	//image saver
 	
-	CImStoreManager* g_pImStore=0;
-
-	//implement
-	//COptimalAnglePart g_oa = COptimalAnglePart(g_cp,&g_logger);
-	CCotyledonAngle g_oa = CCotyledonAngle(g_cp,&g_logger);
-	CRootStockCutPoint g_rs_cp = CRootStockCutPoint(g_cp,&g_logger);
-	CRootStockCutPointReid g_rs_cp_reid = CRootStockCutPointReid(g_cp,&g_logger);
-	CScionCutPoint g_sc_cp = CScionCutPoint(g_cp,&g_logger);
-
+	CImStoreManager* g_pImStore=0;	
 	CRootStockGrabPoint g_sola_grab_rs(g_cp, &g_logger);
 	CRootStockGrabPoint g_sola_grab_sc(g_cp, &g_logger);
-
-	CSolaCutPointReid g_sola_reid_rs = CSolaCutPointReid(g_cp, 1, &g_logger);
-	CSolaCutPointReid g_sola_reid_sc = CSolaCutPointReid(g_cp, 0, &g_logger);
-
 	CChessboardCalibration g_chessboard = CChessboardCalibration(g_cp, &g_logger);
 
 	//??多线程有问题
-	map<string, cv::Mat> g_img_cache;
-	
+	map<string, cv::Mat> g_img_cache;	
 
-	//0 log path
+	//1 log path
 	int cv_set_logpath(char*lpath)
 	{	
 		try{
@@ -74,6 +56,12 @@ namespace graft_cv
 			g_logger_ofs<<tmp;
 			g_logger_ofs.flush();
 			cout<<tmp<<endl;
+
+			string pinfo = get_cparam_info(&g_cp);
+			g_logger.INFO(string("lib version: ") + string(g_version_str));
+			g_logger.INFO(string("load parameters:\n") + pinfo);
+
+
 			g_logger.setPath(string(lpath));
 			return 0;
 		}
@@ -82,7 +70,7 @@ namespace graft_cv
 			return 1;
 		}
 	}
-	// 0-debug, 1-info, 2-warning, 3-error
+	//2 set log level:  0-debug, 1-info, 2-warning, 3-error
 	int cv_set_loglevel(int lev)
 	{	
 		if(lev <0 || lev>3){
@@ -114,7 +102,7 @@ namespace graft_cv
 			return 1;
 		}
 	}
-
+	//3 初始化图片存储其
 	int cv_init_image_saver()
 	{		
 		if( g_cp.image_save){
@@ -141,28 +129,17 @@ namespace graft_cv
 				g_pImStore=0;
 			}			
 		}
-		g_oa.set_image_saver(&g_pImStore);
-		g_rs_cp.set_image_saver(&g_pImStore);
-		g_sc_cp.set_image_saver(&g_pImStore);
+		//g_oa.set_image_saver(&g_pImStore);
+		//g_rs_cp.set_image_saver(&g_pImStore);
+		//g_sc_cp.set_image_saver(&g_pImStore);
 		g_sola_grab_rs.set_image_saver(&g_pImStore);
 		g_sola_grab_sc.set_image_saver(&g_pImStore);
-		g_sola_reid_rs.set_image_saver(&g_pImStore);
-		g_sola_reid_sc.set_image_saver(&g_pImStore);	
+		//g_sola_reid_rs.set_image_saver(&g_pImStore);
+		//g_sola_reid_sc.set_image_saver(&g_pImStore);	
 		g_chessboard.set_image_saver(&g_pImStore);
 		return 0;
-	}
-
-	GCV_API int cv_release()
-	{
-		if(g_pImStore){
-			delete g_pImStore;
-			g_pImStore = 0;
-		}
-		//DeleteCriticalSection(&g_cs);
-		return 0;
-	}
-
-	//1
+	}	
+	//4
 	int cv_init(char*conf)
 	{
 		//InitializeCriticalSection(&g_cs);
@@ -200,7 +177,7 @@ namespace graft_cv
 		
 		return 0;
 	};
-	//2
+	//5
 	void cv_set_param(ConfigParam&cp)
 	{
 		g_cp = cp;	
@@ -229,7 +206,24 @@ namespace graft_cv
 		return 0;
 
 	}
-	//3
+
+	//6
+	int cv_release()
+	{
+		if (g_pImStore) {
+			delete g_pImStore;
+			g_pImStore = 0;
+		}
+		//DeleteCriticalSection(&g_cs);
+		return 0;
+	}
+
+	//7
+	void cv_get_conf_file(char*buff)
+	{
+		strcpy_s(buff, g_conf_file.size() + 1, g_conf_file.c_str());
+	};
+	//8
 	void cv_save_param(char* conf_file/*=0*/)
 	{
 		//save configures
@@ -254,54 +248,17 @@ namespace graft_cv
 			fs.release();	
 		}
 	}
-	//4
+	//9
 	void cv_get_param(ConfigParam&cp)
 	{
 		cp = g_cp;		
 	};
-	//5
+	//10
 	void get_version(char* buf)
 	{			
 		strcpy_s(buf, strlen(g_version_str)+1,g_version_str);
 	};
-	
-	//6
-	void cv_get_conf_file(char*buff)
-	{
-		strcpy_s(buff, g_conf_file.size()+1, g_conf_file.c_str());
-	};
-
-	//7
-	/*int rs_oa_init()
-	{
-		return g_oa.reset();		
-	};*/
-	//8
-	/*int rs_oa_append(
-		ImgInfo* imginfo,
-		PositionInfo& posinfo
-		)
-	{
-		memset(&posinfo,0,sizeof(PositionInfo));
-		try{
-			g_oa.append(imginfo, posinfo);			
-			
-		}
-		catch(std::exception &err){
-			g_logger.ERRORINFO(err.what());
-			return 1;
-		}
-		catch(string& msg){
-			g_logger.ERRORINFO(msg);
-			return 1;
-		}		
-		catch(...){
-			g_logger.ERRORINFO("unknown error");
-			return 1;
-		}
-		return 0;
-	};*/
-	//
+	//11
 	int sola_grab_point_rs(
 		float* points,
 		int pixel_size,
@@ -339,7 +296,7 @@ namespace graft_cv
 		return 0;
 
 	}
-
+	//12
 	int sola_grab_point_sc(
 		float* points,
 		int pixel_size,
@@ -377,7 +334,7 @@ namespace graft_cv
 		return 0;
 
 	}
-
+	//13
 	int chessboard_calibration(float* points, int pixel_size, int pt_size, PositionInfo& posinfo, const char* fn)
 	{
 		memset(&posinfo, 0, sizeof(PositionInfo));
@@ -408,166 +365,4 @@ namespace graft_cv
 		}
 		return 0;
 	 }
-
-
-	//9
-	int rs_oa_get_result(
-		ImgInfo* imginfo,
-		PositionInfo& posinfo
-		)
-	{
-		memset(&posinfo,0,sizeof(PositionInfo));
-		try{
-			double oa = g_oa.angle_recognize(imginfo, posinfo);
-			
-		}
-		catch(std::exception &err){
-			g_logger.ERRORINFO(err.what());
-			return 1;
-		}
-		catch(string& msg){
-			g_logger.ERRORINFO(msg);
-			return 1;
-		}		
-		catch(...){
-			g_logger.ERRORINFO("unknown error");
-			return 1;
-		}
-		return 0;
-		
-	}
-
-	//10
-	int rs_cut_point(
-		ImgInfo* imginfo, 
-		PositionInfo& posinfo
-		)		
-	{
-		memset(&posinfo,0,sizeof(PositionInfo));
-		try{
-			g_rs_cp.up_point_detect(
-				imginfo,
-				cv::Mat(),
-				posinfo, 
-				g_img_cache
-				);
-		}
-		catch(std::exception &err){
-			g_logger.ERRORINFO(err.what());
-			return 1;
-		}
-		catch(string& msg){
-			g_logger.ERRORINFO(msg);
-			return 1;
-		}		
-		catch(...){
-			g_logger.ERRORINFO("unknown error");
-			return 1;
-		}
-		return 0;
-		
-	}
-
-	//11
-	int rs_cut_point_reid(ImgInfo*imginfo , const char* pre_img_id, PositionInfo& posinfo)
-	{
-		memset(&posinfo,0,sizeof(PositionInfo));
-		try{
-			g_rs_cp_reid.cut_point_reid(
-				imginfo,
-				cv::Mat(),
-				pre_img_id,
-				posinfo,
-				g_img_cache
-				);
-		}
-		catch(std::exception &err){
-			g_logger.ERRORINFO(err.what());
-			return 1;
-		}
-		catch(string& msg){
-			g_logger.ERRORINFO(msg);
-			return 1;
-		}		
-		catch(...){
-			g_logger.ERRORINFO("unknown error");
-			return 1;
-		}
-		return 0;		
-	}
-
-	// 
-	int sola_cut_point_reid_rs(ImgInfo*imginfo, PositionInfo& posinfo)
-	{
-		memset(&posinfo, 0, sizeof(PositionInfo));
-		int sola_type = 1;
-		try {
-			g_sola_reid_rs.cut_point_reid(imginfo, cv::Mat(), posinfo);
-		}
-		catch (std::exception &err) {
-			g_logger.ERRORINFO(err.what());
-			return 1;
-		}
-		catch (string& msg) {
-			g_logger.ERRORINFO(msg);
-			return 1;
-		}
-		catch (...) {
-			g_logger.ERRORINFO("unknown error");
-			return 1;
-		}
-		return 0;
-	}
-
-	int sola_cut_point_reid_sc(ImgInfo*imginfo, PositionInfo& posinfo)
-	{
-		memset(&posinfo, 0, sizeof(PositionInfo));
-		int sola_type = 0;
-		try {
-			g_sola_reid_sc.cut_point_reid(imginfo, cv::Mat(), posinfo);
-		}
-		catch (std::exception &err) {
-			g_logger.ERRORINFO(err.what());
-			return 1;
-		}
-		catch (string& msg) {
-			g_logger.ERRORINFO(msg);
-			return 1;
-		}
-		catch (...) {
-			g_logger.ERRORINFO("unknown error");
-			return 1;
-		}
-		return 0;
-	}
-
-	//12
-	int sc_cut_point(
-		ImgInfo* imginfo, 
-		PositionInfo& posinfo
-		)
-	{
-		memset(&posinfo,0,sizeof(PositionInfo));
-		try{
-			g_sc_cp.up_point_detect(
-				imginfo,
-				cv::Mat(),
-				posinfo
-				);
-		}
-		catch(std::exception &err){
-			g_logger.ERRORINFO(err.what());
-			return 1;
-		}
-		catch(string& msg){
-			g_logger.ERRORINFO(msg);
-			return 1;
-		}		
-		catch(...){			
-			g_logger.ERRORINFO("unknown error");
-			return 1;
-		}
-		return 0;
-	}
-
 };

+ 31 - 97
graft_cv_api.h

@@ -63,113 +63,47 @@ GCV_API void cv_get_param(ConfigParam&);
 GCV_API void get_version(char* buf);
 
 
-//11 茄科上苗,找到抓取位置
-//
+//11 茄科上苗,基于3d点云,找到抓取位置, 砧木
+//  
 //  输入: points ---      输入, 指向点云的指针,点云为3值一组,结构:[pt0.x, pt0.y, pt0.z, pt1.x, pt1.y,pt1.z], 有时是4值一组(视采集设备数据情况)
 //         pixel_size ---  输入,一个点云的维度(一般3或4)
 //         pt_size-------- 输入, 点云数量,上例中数量为2
-//         dtype  -------- 输入,穗苗--0, 砧木--1
-//
 //         posinfo ------- 输出
+//				double rs_grab_x;		//砧木上苗抓取位置x,毫米
+//				double rs_grab_y;		//砧木上苗抓取位置y,毫米
+//				double rs_grab_z;		//砧木上苗抓取位置z,毫米
+//				double rs_width;		//茎的宽度(直径),毫米
+//				double rs_tortuosity;	//弯曲度,离茎中心轴线最大距离,毫米
+//				double rs_count;		//当前第一排共有多少株
+//              ImgInfo* pp_images[5];  //返回的处理结果图片
+//
 //         fn ------------ 输入, points指向0,且fn可用时,读取文件中的数据(用于测试),仅支持ply格式
-//				posinfo.rs_pre_x;
-//				posinfo.rs_pre_y;
-//				posinfo.rs_pre_z;
-//				其余数据为0
+//
 //  返回: 0- 正常; 其他- 失败
-GCV_API int sola_grab_point_rs(float* points, int pixel_size, int pt_size, PositionInfo& posinfo, const char* fn=0);
-GCV_API int sola_grab_point_sc(float* points, int pixel_size, int pt_size, PositionInfo& posinfo, const char* fn = 0);
-
-GCV_API int chessboard_calibration(float* points, int pixel_size, int pt_size, PositionInfo& posinfo, const char* fn = 0);
+GCV_API int sola_grab_point_rs(float* points, int pixel_size, int pt_size, PositionInfo& posinfo, const char* fn = 0);
 
-//12  砧木最优角度识别,追加图像,要求图像的角度按顺序,第一帧图像角度为0,最后一帧图像角度为180
-//   每次追加图片,通过posinfo返回:
-//            1)叶展宽度posinfo.rs_oa_width;
-//            2) 基质宽度posinfo.rs_oa_width_base
-//            3) 茎分叉点y posinfo.rs_oa_stem_y_fork;//茎分叉点y,毫米
-//	          4) 茎可视下端y posinfo.rs_oa_clamp_y_end;//茎可视下端y,毫米
-//            5)2帧图像:posinfo.pp_images[0]--砧木分割二值图像 (return image 为 true时)
-//                        posinfo.pp_images[1]--基质分割二值图像
-//   返回: 0- 正常; 1- 失败
-//GCV_API int rs_oa_append(ImgInfo*, PositionInfo& posinfo);
-
-//13 获取砧木最优角度
-//  ImgInfo* 为输出顶部拍照的图片
-//  返回posinfo.rs_oa, 需要旋转的角度,逆时针为正方向
-
-//   返回: 0- 正常; 1- 失败
-GCV_API int rs_oa_get_result(ImgInfo*, PositionInfo& posinfo);
-
-//14 砧木切割点识别,返回
-//       posinfo.rs_img_id
-//		 posinfo.rs_cut_upoint_x
-//		 posinfo.rs_cut_upoint_y
-//		 posinfo.rs_stem_diameter
-//       posinfo.rs_cut_lpoint_x 
-//	     posinfo.rs_cut_lpoint_y
-//  	 posinfo.pp_images   (return image 为 true时)
-//               返回3张图片:图0:二值图像,含茎x-range,茎分叉点右侧边缘坐标(circle中心)
-//                            图1: 灰度图,候选角点(circle),候选框,参考点(茎分叉点右侧边缘坐标)
-//                            图2:灰度图,上切割点,候选框,参考点,下切点(circle中心),根点(circle中心)
-//   返回: 0- 正常; 1- 失败
-GCV_API int rs_cut_point(ImgInfo*, PositionInfo& posinfo);
-
-
-//15 砧木切割点切后识别,返回
-//		posinfo.rs_becut_upoint_x
-//   	posinfo.rs_becut_upoint_y
-//  	 posinfo.pp_images   (return image 为 true时)
-//               返回1张图片:图0:二值图像,含茎x-range,上切点(circle中心),下切点(circle中心),根点(circle中心)
-//                            
-//   返回: 0- 正常; 1- 失败
-GCV_API int rs_cut_point_reid(ImgInfo*, const char* pre_img_id, PositionInfo& posinfo);
-
-//16 茄科切割点切后识别
-//  input:
-//       ImgInfo*  --- 输入图像
-//       sola_type --- 0---穗苗; 1--砧木
-//       posinfo---- 返回信息
+//12 茄科上苗,基于3d点云,找到抓取位置, 穗苗
+//  
+//  输入: points ---      输入, 指向点云的指针,点云为3值一组,结构:[pt0.x, pt0.y, pt0.z, pt1.x, pt1.y,pt1.z], 有时是4值一组(视采集设备数据情况)
+//         pixel_size ---  输入,一个点云的维度(一般3或4)
+//         pt_size-------- 输入, 点云数量,上例中数量为2
+//         posinfo ------- 输出
+//				double sc_grab_x;		//穗苗上苗抓取位置x,毫米
+//				double sc_grab_y;		//穗苗上苗抓取位置y,毫米
+//				double sc_grab_z;		//穗苗上苗抓取位置z,毫米
+//				double sc_width;		//茎的宽度(直径),毫米
+//				double sc_tortuosity;	//弯曲度,离茎中心轴线最大距离,毫米
+//				double sc_count;		//当前第一排共有多少株
+//              ImgInfo* pp_images[5];  //返回的处理结果图片
+//
+//         fn ------------ 输入, points指向0,且fn可用时,读取文件中的数据(用于测试),仅支持ply格式
 //
-// 返回
-//		上切点,中切点,下切点
-//      //砧木,坐标左下角位0点
-//      posinfo.rs_reid_sola_upoint_x;			//base_y, 夹爪基面的y像素坐标, 砧木在下方(夹爪的上沿),接穗在上方(夹爪的下沿)
-//      posinfo.rs_reid_sola_upoint_y;			//上切割点y像素坐标与base_y的像素距离
-//      posinfo.rs_reid_sola_cpoint_x;			//--------------------无意义(目标框x)
-//      posinfo.rs_reid_sola_cpoint_y;			//中切割点y像素坐标与base_y的像素距离
-//      posinfo.rs_reid_sola_lpoint_x;			//--------------------无意义(目标框x)
-//      posinfo.rs_reid_sola_lpoint_y;			//下切割点y像素坐标与base_y的像素距离
-//   	
-//      //接穗,坐标左上角位0点
-//      posinfo.sc_reid_sola_upoint_x;			//base_y, 夹爪基面的y像素坐标, 砧木在下方(夹爪的上沿),接穗在上方(夹爪的下沿)
-//      posinfo.sc_reid_sola_upoint_y;			//上切割点y像素坐标与base_y的像素距离
-//      posinfo.sc_reid_sola_cpoint_x;			//--------------------无意义(目标框x)
-//      posinfo.sc_reid_sola_cpoint_y;			//中切割点y像素坐标与base_y的像素距离
-//      posinfo.sc_reid_sola_lpoint_x;			//--------------------无意义(目标框x)
-//      posinfo.sc_reid_sola_lpoint_y;			//下切割点y像素坐标与base_y的像素距离
-//   	
-//  	 posinfo.pp_images   (return image 为 true时)
-//               返回2张图片:图0:二值图像
-//                           图1: 灰度图像,拟合椭圆
-//                            
-//   返回: 0- 正常; 1- 失败
-GCV_API int sola_cut_point_reid_rs(ImgInfo*, PositionInfo& posinfo);
-GCV_API int sola_cut_point_reid_sc(ImgInfo*, PositionInfo& posinfo);
-
-
-
-//17 穗苗上切割点识别,返回
-//		 posinfo.sc_cut_upoint_x;
-//		 posinfo.sc_cut_upoint_y;
-//		 posinfo.sc_cut_cpoint_x;
-//       posinfo.sc_cut_cpoint_y;
-//  	 posinfo.pp_images      (return image 为 true时)
-//               返回1张图片:图0:二值图像,含茎x-range,茎分叉点水平线,尖点水平线,上切点(circle中心),中切点(circle中心)
-//                
-//   返回: 0- 正常; 1- 失败
-GCV_API int sc_cut_point(ImgInfo*, PositionInfo& posinfo);
+//  返回: 0- 正常; 其他- 失败
+GCV_API int sola_grab_point_sc(float* points, int pixel_size, int pt_size, PositionInfo& posinfo, const char* fn = 0);
 
 
+//13 3d点云棋盘格标定功能,通过输入的点云(棋盘格点云),识别点云上的交叉点,并输出交叉点坐标
+GCV_API int chessboard_calibration(float* points, int pixel_size, int pt_size, PositionInfo& posinfo, const char* fn = 0);
 
 };//namespace graft_cv
 

+ 0 - 1207
optimal_angle.cpp

@@ -1,1207 +0,0 @@
-//#include "StdAfx.h"
-#include <opencv2\imgproc\imgproc.hpp>
-#include "optimal_angle.h"
-#include "utils.h"
-#include <string.h>
-
-namespace graft_cv{
-
-//COptimalAngle::COptimalAngle(ConfigParam&cp, CGcvLogger* pLog)
-//	:m_cparam(cp),
-//	m_pLogger(pLog),
-//	m_pImginfo(0),
-//	m_pImginfoBase(0),
-//	m_height(0),
-//	m_width(0),
-//	m_patch_id(""),
-//	m_imgIndex(0),
-//	m_imgId(""),
-//	m_ppImgSaver(0)
-//{
-//}
-//COptimalAngle::~COptimalAngle(void)
-//{
-//	this->clear_imginfo();
-//}
-//void COptimalAngle::clear_imginfo(){
-//	if (m_pImginfo){
-//		imginfo_release(&m_pImginfo);
-//		m_pImginfo=0;
-//	}
-//	if (m_pImginfoBase){
-//		imginfo_release(&m_pImginfoBase);
-//		m_pImginfoBase=0;
-//	}
-//}
-//int COptimalAngle::reset()
-//{
-//	if(m_pLogger){
-//		m_pLogger->DEBUG("optimal angle reset begin.");
-//	}
-//	m_fork_ys.clear();
-//	m_end_ys.clear();
-//	m_widths.clear();
-//	m_an2width.clear();
-//	m_an2widthBase.clear();
-//	m_width=0;
-//	m_height=0;
-//	m_patch_id="";
-//	m_imgIndex=0;
-//	if(m_pLogger){
-//		m_pLogger->DEBUG("optimal angle reset finished.");
-//	}
-//	return 0;
-//}
-//
-//int COptimalAngle::append(
-//	ImgInfo* imginfo,
-//	PositionInfo& posinfo	
-//	)
-//{	
-//	//clear opencv windows
-//	if(m_cparam.image_show){destroyAllWindows();}
-//
-//	clock_t t;
-//	clock_t t0 = clock();
-//	if(m_imgIndex==0){
-//		//new patch
-//		m_patch_id = getImgId(img_type::oa);	
-//	}
-//	m_imgId = getImgIdOa(m_patch_id,m_imgIndex);	
-//	m_imgIndex+=1;
-//
-//	if(m_pLogger){
-//		m_pLogger->INFO(m_imgId + " append image begin.");
-//	}	
-//	if(!isvalid(imginfo)){
-//		throw_msg(m_imgId+" invalid input image");
-//	}
-//	if(m_width==0 || m_height==0){
-//		m_width = imginfo->width;
-//		m_height = imginfo->height;
-//	}
-//	int angle = imginfo->angle;
-//	if(m_pLogger){
-//		stringstream buff;
-//		buff<<m_imgId<<" append image, angle="<<angle
-//			<<"\twidth="<<imginfo->width
-//			<<"\theight="<<imginfo->height;
-//		m_pLogger->INFO(buff.str());
-//	}
-//	Mat img = imginfo2mat(imginfo);	
-//	
-//	//imshow_wait("src", img);
-//	if(m_cparam.self_camera){
-//		image_set_bottom(img,20,8);
-//		if(m_pLogger){				
-//			m_pLogger->DEBUG(m_imgId+" oa_append image set bottom with pixel value 20.");				
-//		}
-//	}
-//	if(m_cparam.oa_y_flip){
-//		flip(img,img,0);
-//		if(m_pLogger){				
-//			m_pLogger->DEBUG(m_imgId+" oa_append image y fliped.");				
-//		}
-//	}
-//	if(m_ppImgSaver && *m_ppImgSaver){
-//		(*m_ppImgSaver)->saveImage(img, m_imgId);
-//		if(m_pLogger){				
-//			m_pLogger->DEBUG(m_imgId+" oa_append after image save.");				
-//		}
-//	}
-//	if(m_cparam.image_show){
-//		Mat tmp_b = img.clone();
-//		cv::line(tmp_b,Point(0,m_cparam.oa_clip_y_min), Point(tmp_b.cols,m_cparam.oa_clip_y_min),Scalar(200),3);
-//		cv::line(tmp_b,Point(0,m_cparam.oa_clip_y_max), Point(tmp_b.cols,m_cparam.oa_clip_y_max),Scalar(200),3);			
-//		imshow_wait("oa_sub_image_range", tmp_b);
-//	}
-//
-//	Rect rect_rs(Point(0,0),Point(img.cols,m_cparam.oa_clip_y_min));
-//	//Rect rect_base(Point(0,m_cparam.oa_clip_y_max),Point(img.cols,img.rows));
-//
-//	Mat rs_img = img(rect_rs);
-//	//Mat bs_img = img(rect_base);
-//
-//	
-//	// 1 rootstock image processing 
-//	// 1.1 calculate the image, get binary image and get object width
-//	int min_idx, max_idx;
-//	vector<int> hist_col;
-//	int width = imgproc(rs_img, hist_col, min_idx, max_idx);
-//	m_an2width.insert(make_pair<int,int>(angle, width));
-//	posinfo.rs_oa_width=width;
-//
-//	if(m_cparam.image_show){			
-//		Mat hist_col_img;
-//		hist2image(hist_col,hist_col_img,1,m_cparam.image_col_grid,m_cparam.image_row_grid);
-//		imshow_wait("oa_hist_col", hist_col_img);			
-//	}
-//
-//	if(m_pLogger){
-//		stringstream buff;
-//		buff<<m_imgId<<" append image, rootstock width="<<width;
-//		m_pLogger->INFO(buff.str());
-//	}
-//
-//	if(!m_cparam.image_show){
-//		t = clock();		
-//		if(1000.0*((float)(t-t0))/CLOCKS_PER_SEC>(float)m_cparam.timeout_append){
-//			throw_msg(m_imgId+" time out");
-//		}
-//	}
-//
-//	//1.2 茎粗计算
-//	//1.2.1 茎x方向位置:x方向位置范围	
-//	int r0,r1;
-//	r0=r1=-1;	
-//	std::vector<int>hist_row_leaf;
-//	mat_histogram(m_binImg,hist_row_leaf,1);
-//	for(size_t i=0;i<hist_row_leaf.size();++i){
-//		if(hist_row_leaf[i]>=m_cparam.oa_min_hist_value && r0<0){r0=i;}
-//		if(hist_row_leaf[i]>=m_cparam.oa_min_hist_value){r1=i;}
-//	}
-//	if(r0<0 || r1<0){throw_msg(string(m_imgId+" invalid image, with no object in binary image"));}
-//		
-//	vector<int> hist_col_yfork;
-//	mat_histogram_yfork(m_binImg,hist_col_yfork,r0,r1);
-//	if(m_cparam.image_show){			
-//		Mat tmp;
-//		hist2image(hist_col_yfork,tmp,1,m_cparam.image_col_grid,m_cparam.image_row_grid);
-//		imshow_wait("oa_hist_col_yfork", tmp);			
-//	}	
-//
-//	int x0,x1,stem_x0, stem_x1;
-//	int centx = (int)((min_idx+ max_idx)/2.0);
-//	get_stem_x_range_oa(
-//		hist_col_yfork,
-//		m_cparam.oa_col_th_ratio,
-//		m_cparam.oa_stem_x_padding,
-//		centx,
-//		width,
-//		x0,
-//		x1,
-//		stem_x0,
-//		stem_x1);
-//
-//	if(m_pLogger){
-//		stringstream buff;
-//		buff<<m_imgId<<" append image, x0="<<x0
-//			<<"\tx1="<<x1
-//			<<"\tstem_x0="<<stem_x0
-//			<<"\tstem_x1="<<stem_x1;
-//		m_pLogger->INFO(buff.str());
-//	}
-//
-//	if(m_cparam.image_show){
-//		Mat tmp_b = m_binImg.clone();
-//		cv::line(tmp_b,Point(x0,0), Point(x0,tmp_b.rows),Scalar(200),3);
-//		cv::line(tmp_b,Point(x1,0), Point(x1,tmp_b.rows),Scalar(200),3);			
-//		imshow_wait("oa_x_range", tmp_b);
-//	}
-//
-//	if(!m_cparam.image_show){
-//		t = clock();
-//		if(1000.0*((float)(t-t0))/CLOCKS_PER_SEC>(float)m_cparam.timeout_append){
-//			throw_msg(m_imgId+" time out");
-//		}		
-//	}
-//
-//	vector<int> hist_row;
-//	mat_histogram(m_binImg,hist_row,1,-1,-1,x0,x1+1);
-//
-//	if(m_cparam.image_show){		
-//		Mat hist_row_img;
-//		hist2image(hist_row,hist_row_img, 0,m_cparam.image_col_grid,m_cparam.image_row_grid);		
-//		imshow_wait("oa_hist_row", hist_row_img);			
-//	}
-//	// 1.2.2 茎分叉点检测,y方向检测
-//	int stem_fork_y=-1,stem_end_y=-1, stem_dia=-1;
-//	get_stem_y_fork(
-//		hist_row,
-//		m_cparam.oa_row_th_ratio,
-//		m_cparam.oa_stem_dia_min,
-//		m_cparam.oa_stem_fork_y_min,
-//		m_cparam.oa_stem_dia_mp,
-//		stem_fork_y,
-//		stem_end_y,
-//		stem_dia);
-//	if(m_pLogger){
-//		stringstream buff;
-//		buff<<m_imgId<<" append image, stem_fork_y="<<stem_fork_y
-//			<<"\tstem_end_y="<<stem_end_y
-//			<<"\tstem_dia="<<stem_dia;
-//		m_pLogger->INFO(buff.str());
-//	}
-//	
-//
-//	if(m_cparam.image_show){
-//		Mat tmp_bin = m_binImg.clone();
-//		cv::line(tmp_bin,Point(min_idx,0), Point(min_idx,tmp_bin.rows),Scalar(200),3);
-//		cv::line(tmp_bin,Point(max_idx,0), Point(max_idx,tmp_bin.rows),Scalar(200),3);		
-//		cv::line(tmp_bin,Point(x0,stem_fork_y), Point(x1,stem_fork_y),Scalar(200),3);
-//		cv::line(tmp_bin,Point(x0,stem_end_y), Point(x1,stem_end_y),Scalar(200),3);
-//		imshow_wait("oa_result", tmp_bin);
-//	}
-//	
-//	m_fork_ys.push_back(stem_fork_y);
-//	m_end_ys.push_back(stem_end_y);
-//	m_widths.push_back(width);
-//
-//
-//	//2 基质图像处理
-//	//int min_idx_base, max_idx_base;
-//	//vector<int> hist_col_base;
-//	//int width_base = imgprocBase(bs_img, hist_col_base, min_idx_base, max_idx_base);
-//	//m_an2widthBase.insert(make_pair<int,int>(angle, width_base));
-//	//posinfo.rs_oa_width_base = width_base;
-//
-//	//if(m_pLogger){
-//	//	stringstream buff;
-//	//	buff<<m_imgId<<" append image, base width="<<width_base;
-//	//	m_pLogger->INFO(buff.str());
-//	//
-//
-//	// 3 返回结果
-//	double fork_y = (double)stem_fork_y;
-//	double end_y = (double)stem_end_y;
-//
-//	fork_y = ((double)m_height/2.0 - fork_y)*m_cparam.rs_oa_pixel_ratio;
-//	end_y =  ((double)m_height/2.0 - end_y)*m_cparam.rs_oa_pixel_ratio;
-//	posinfo.rs_oa_stem_y_fork=fork_y;
-//    posinfo.rs_oa_clamp_y_end=end_y;
-//	if(m_pLogger){
-//		stringstream buff;
-//		buff<<m_imgId<<" append image, stem_fork_y(mm)="<<fork_y
-//			<<"\tstem_end_y(mm)="<<end_y;
-//		m_pLogger->INFO(buff.str());
-//	}
-//	//4 返回图像
-//	if(m_cparam.image_return){
-//		this->clear_imginfo();
-//		cv::line(m_binImg,Point(min_idx,0), Point(min_idx,rs_img.rows),Scalar(200),3);
-//		cv::line(m_binImg,Point(max_idx,0), Point(max_idx,rs_img.rows),Scalar(200),3);
-//
-//		cv::line(m_binImg,Point(x0,stem_fork_y), Point(x1,stem_fork_y),Scalar(200),3);
-//		cv::line(m_binImg,Point(x0,stem_end_y), Point(x1,stem_end_y),Scalar(200),3);
-//
-//		clear_imginfo();
-//		m_pImginfo = mat2imginfo(m_binImg);
-//		//m_pImginfoBase = mat2imginfo(m_binImgBase);
-//		posinfo.pp_images[0]=m_pImginfo;
-//		//posinfo.pp_images[1]=m_pImginfoBase;
-//
-//		if(m_ppImgSaver && *m_ppImgSaver){
-//			(*m_ppImgSaver)->saveImage(m_binImg, m_imgId+"_rst_0");			
-//		}
-//	}
-//	if(m_pLogger){
-//		m_pLogger->INFO(m_imgId + " append image finished.");
-//	}	
-//	return 0;
-//}
-//
-//double COptimalAngle::infer(PositionInfo& posinfo){
-//	
-//	if(m_pLogger){
-//		m_pLogger->INFO(m_patch_id + " optimal angle infer begin.");
-//	}	
-//	double oa = this->angle_fit(this->m_an2width);
-//	//double oa_base = 0.0;
-//	//try{
-//	//	oa_base = this->angle_fit_base(this->m_an2widthBase);
-//	//}
-//	//catch(...){
-//	//	if(m_pLogger){		
-//	//		m_pLogger->WARNING("angle_fit_base() error");
-//	//	}
-//	//}
-//	posinfo.rs_oa = oa;
-//	//posinfo.rs_oa_base=oa_base;
-//
-//	if(m_fork_ys.size()==0 ||m_end_ys.size()==0){
-//		throw_msg(m_patch_id+ " empty fork_ys or end_ys, NEED append image");
-//	}
-//	vector<size_t>des_idx = sort_indexes_e(m_widths,false);	
-//	int e_idx = (int)((float)m_end_ys.size() * 0.5);	
-//	sort(m_end_ys.begin(), m_end_ys.end());
-//	double fork_y = ((m_fork_ys[des_idx[0]] +  m_fork_ys[des_idx[1]])/2.0);
-//	double end_y = m_end_ys[e_idx];
-//	if(m_pLogger){
-//		stringstream buff;
-//		buff<<m_patch_id<<" angle fit result, stem_fork_y(pixel)="<<(int)(fork_y)
-//			<<"\tstem_end_y(pixel)="<<(int)(end_y);
-//		m_pLogger->INFO(buff.str());
-//	}
-//
-//	fork_y = ((double)m_height/2.0 - fork_y)*m_cparam.rs_oa_pixel_ratio;
-//	end_y =  ((double)m_height/2.0 - end_y)*m_cparam.rs_oa_pixel_ratio;
-//	posinfo.rs_oa_stem_y_fork=fork_y;
-//    posinfo.rs_oa_clamp_y_end=end_y;
-//	if(m_pLogger){
-//		stringstream buff;
-//		buff<<m_patch_id<<" angle fit result, stem_fork_y(mm)="<<fork_y
-//			<<"\tstem_end_y(mm)="<<end_y;
-//		m_pLogger->INFO(buff.str());
-//	
-//		m_pLogger->INFO(m_patch_id + " optimal angle infer finished.");
-//	}	
-//	return oa;
-//}
-//
-//int COptimalAngle::imgproc(
-//	Mat& img, 
-//	vector<int>& hist,
-//	int& min_idx, 
-//	int& max_idx
-//	)
-//{
-//	//int morph_size = 1;
-//	//int min_hist_value = 10;
-//	hist.clear();
-//
-//	Mat b_img;
-//	double th = threshold(
-//		img, 
-//		b_img, 
-//		255,
-//		255,
-//		THRESH_OTSU);//+THRESH_BINARY_INV
-//
-//	Mat kernel = getStructuringElement(
-//		MORPH_RECT, 
-//		Size( 2*m_cparam.oa_morph_radius+1, 2*m_cparam.oa_morph_radius+1), 
-//		Point( m_cparam.oa_morph_radius, m_cparam.oa_morph_radius)
-//		);
-//    
-//    morphologyEx(
-//		b_img, 
-//		m_binImg, 
-//		MORPH_CLOSE,
-//		kernel,
-//		Point(-1,-1),
-//		m_cparam.oa_morph_iteration);
-//
-//	
-//	
-//	mat_histogram(m_binImg, hist, 0);		
-//
-//	/*int min_idx, max_idx;*/
-//	min_idx = hist.size();
-//	max_idx = 0;
-//	vector<int>::const_iterator it0 = hist.begin();
-//	for(vector<int>::const_iterator it = hist.begin();it!=hist.end();++it){
-//		if(*it>=m_cparam.oa_min_hist_value){
-//			int idx = it - it0;
-//			if(idx<min_idx){min_idx = idx;}
-//			if(idx > max_idx) {max_idx = idx;}
-//		}
-//	}
-//	if(max_idx<=min_idx){
-//		throw_msg(m_imgId+" invalid binary image, not exist valid objects");		
-//	}
-//	if(m_cparam.image_show){		
-//		Mat tmp = m_binImg.clone();
-//		cv::line(tmp,Point(min_idx,0), Point(min_idx,tmp.rows),Scalar(156),3);
-//		cv::line(tmp,Point(max_idx,0), Point(max_idx,tmp.rows),Scalar(156),3);
-//		imshow_wait("oa_bin", tmp);		
-//	}
-//    int width = max_idx-min_idx+1;	
-//	return width;
-//}
-//
-//int COptimalAngle::imgprocBase(
-//	Mat& img, 
-//	vector<int>& hist,
-//	int& min_idx, 
-//	int& max_idx
-//	)
-//{
-//	//int morph_size = 1;
-//	//int min_hist_value = 10;
-//	hist.clear();
-//
-//	Mat b_img;
-//	double th = threshold(
-//		img, 
-//		b_img, 
-//		255,
-//		255,
-//		THRESH_OTSU+THRESH_BINARY_INV);
-//
-//	Mat kernel = getStructuringElement(
-//		MORPH_RECT, 
-//		Size( 2*m_cparam.oa_morph_radius_base+1, 2*m_cparam.oa_morph_radius_base+1), 
-//		Point( m_cparam.oa_morph_radius_base, m_cparam.oa_morph_radius_base)
-//		);
-//    
-//    morphologyEx(
-//		b_img, 
-//		m_binImgBase, 
-//		MORPH_OPEN,
-//		kernel,
-//		Point(-1,-1),
-//		m_cparam.oa_morph_iteration_base);
-//
-//	if(m_cparam.image_show){	
-//		destroyAllWindows();
-//		imshow_wait("oa_bin_base", m_binImgBase);		
-//	}
-//	
-//	mat_histogram(m_binImgBase, hist, 0);	
-//
-//	/*int min_idx, max_idx;*/
-//	min_idx = hist.size();
-//	max_idx = 0;
-//	vector<int>::const_iterator it0 = hist.begin();
-//	for(vector<int>::const_iterator it = hist.begin()+5;it!=hist.end();++it){
-//		if(*it>=m_cparam.oa_min_hist_value_base){
-//			int idx = it - it0;
-//			if(idx<min_idx){min_idx = idx;}
-//			if(idx > max_idx) {max_idx = idx;}
-//		}
-//	}
-//	if(max_idx<=min_idx){
-//		throw_msg(m_imgId+" invalid binary image, not exist valid objects");		
-//	}
-//    int width = max_idx-min_idx+1;	
-//	return width;
-//}
-////angle_fit()方法
-////append()加载的图片,满足下述条件:0-180度采样,其中0和180度都有数值
-//double COptimalAngle::angle_fit(map<int,int>& an2width,bool is_base)
-//{
-//	if(an2width.size()<3){
-//		throw_msg(m_patch_id+" not enough valid images, NEED append image");
-//	}
-//	double oa = 0.0;
-//	std::vector<double> x;//angle
-//	std::vector<double> y;//width
-//
-//	map<int,int>::iterator it = an2width.begin();
-//	for(it=an2width.begin(); it!=an2width.end(); ++it)
-//	{
-//		x.push_back((double)(it->first));
-//		y.push_back((double)(it->second));
-//	}
-//	//mean value of first and latest y
-//	double y_mu = 0.5*(y[0]+ y[y.size()-1]);
-//	y[0] = y[y.size()-1] = y_mu;
-//	size_t ap_times = x.size()-1;
-//	for (size_t i=0; i<ap_times;++i)
-//	{
-//		x.push_back(x[i+1]+180.0);
-//		y.push_back(y[i+1]);
-//	}
-//	vector<double>::iterator smallest = min_element(begin(y), end(y));
-//	size_t min_idx, max_idx;
-//	min_idx = distance(y.begin(), smallest);
-//
-//	for(size_t i = min_idx+1;i<y.size();++i){
-//		if(fabs(y[i]-*smallest)<0.1){
-//			max_idx = i;
-//			break;
-//		}
-//	}
-//
-//	// slice x and y the convex segment
-//	vector<double>xx;
-//	vector<double>yy;
-//	for(size_t i=min_idx;i<=max_idx;++i){
-//		xx.push_back(x[i]);
-//		yy.push_back(y[i]);
-//	}
-//
-//	// fit quadratic function with opencv
-//	Mat A = cv::Mat::zeros(cv::Size(3,xx.size()), CV_64FC1);
-//	for(int i=0; i<xx.size();++i){
-//		A.at<double>(i,0) = 1;
-//		A.at<double>(i,1) = xx[i];
-//		A.at<double>(i,2) = xx[i] * xx[i];
-//	}
-//
-//	Mat b = cv::Mat::zeros(cv::Size(1,yy.size()), CV_64FC1);
-//	for(int i = 0; i<yy.size(); ++i){
-//		b.at<double>(i,0) = yy[i];
-//	}
-//	Mat c, d;
-//	c = A.t() * A;
-//	d = A.t() * b;
-//	Mat result = cv::Mat::zeros(cv::Size(1,3),CV_64FC1);
-//	cv::solve(c,d,result);
-//	
-//
-//	double a0 = result.at<double>(0, 0);
-//    double a1 = result.at<double>(1, 0);
-//    double a2 = result.at<double>(2, 0);
-//	if(fabs(a2)<1.0e-6){
-//		throw_msg(m_patch_id+" a2 = 0 in solver");
-//	}
-//	oa = -a1 / a2 / 2;
-//	if(oa >180.0){oa -= 180.0;}
-//	return oa;
-//}
-//double COptimalAngle::angle_fit_base(map<int, int>&){
-//	return 0.0;
-//}
-//
-/////////////////////////////////////////////////////////////////////////////////
-//COptimalAnglePart::COptimalAnglePart(ConfigParam&cp, CGcvLogger* pLog)
-//	:COptimalAngle(cp,pLog)
-//{
-//}
-//COptimalAnglePart::~COptimalAnglePart()
-//{
-//	COptimalAngle::clear_imginfo();
-//}
-//// append()加载的图片,满足不是0-180度采样,但保证部分采样中一定存在最大值,
-//// 直接利用这些数值进行二次函数的拟合
-//double COptimalAnglePart::angle_fit(map<int,int>& an2width,bool is_base)
-//{ 
-//	
-//	double oa = 0.0;
-//	std::vector<double> xx;//angle
-//	std::vector<double> yy;//width
-//
-//	map<int,int>::iterator it = an2width.begin();
-//	for(it=an2width.begin(); it!=an2width.end(); ++it)
-//	{
-//		xx.push_back((double)(it->first));
-//		yy.push_back((double)(it->second));
-//	}
-//	//sort 
-//	for(size_t i =0;i<xx.size()-1;++i){
-//		for(size_t j = i+1; j<xx.size();++j){
-//			if(xx[j]<xx[i]){
-//				double tmp = xx[i];
-//				xx[i]=xx[j];
-//				xx[j]=tmp;
-//				tmp = yy[i];
-//				yy[i]=yy[j];
-//				yy[j]=tmp;
-//			}
-//		}
-//	}
-//
-//	if(m_pLogger){			
-//		stringstream buff;
-//		buff<<m_patch_id;
-//		if(is_base){
-//			buff<<" rootstock_base ";
-//		}
-//		else{
-//			buff<<" rootstock_leaf ";
-//		}
-//		buff<<"opt-angle, (xi,yi): ";
-//		for(size_t i=0;i<xx.size();++i){
-//			buff<<"("<<xx[i]<<","<<yy[i]<<"), ";
-//		}		
-//		m_pLogger->INFO(buff.str());
-//	}
-//
-//	if(an2width.size()<3){
-//		throw_msg(m_patch_id+" not enough valid images, NEED append image");
-//	}
-//	// angle field check
-//	if((xx.back()-xx.front())<90){
-//		if(m_pLogger){			
-//			stringstream buff;
-//			buff<<m_patch_id<<" x_end="<<xx.back()<<" x_front="<<xx.front();				
-//			buff<<" not enough angle field, small than 90 degree.";
-//			m_pLogger->ERRORINFO(buff.str());
-//		}
-//		throw_msg(m_patch_id+" not enough angle field, small than 90 degree");
-//	}
-//	oa = opt_angle_part_impl(xx,yy,is_base);
-//	if(m_pLogger){
-//		stringstream buff;
-//		buff<<m_patch_id;
-//		if(is_base){
-//			buff<<" rootstock_base ";
-//		}
-//		else{
-//			buff<<" rootstock_leaf ";
-//		}
-//        buff<<" opt-angle: "<<oa;
-//		m_pLogger->INFO(buff.str());
-//	}
-//	return oa;	
-//}
-//double COptimalAnglePart::angle_fit_base(map<int, int>& an2width){
-//	
-//	double oa = 0.0;
-//	//find the maximun angle
-//	oa = angle_fit(an2width,true);
-//
-//	//get the minimum angle
-//	if(oa>45.0){oa -= 45.0;}
-//	else{oa +=45.0;}
-//	return oa;	
-//}
-//void COptimalAnglePart::zero_cross_detect(
-//	vector<int>&d_sign, //input
-//	bool& is_local_max, // whether exists local max 
-//	int& local_limit_idx // local limit index of original vector
-//)
-//{
-//	int min_zc_idx = -1;
-//    int max_zc_idx = -1;
-//	bool b_local_min =false;
-//	bool b_local_max =false;
-//    bool is_all_down=true;
-//    bool is_all_up = true;
-//    for (size_t i=0; i<d_sign.size();++i){
-//		if (d_sign[i] >0){is_all_down=false;}
-//		if (d_sign[i] <0){is_all_up=false;}
-//		if (i == d_sign.size()-1){continue;}
-//
-//        if (d_sign[i] >=0 && d_sign[i+1] <=0){
-//			//is_local_max=true;
-//			max_zc_idx = i+1;
-//			b_local_max=true;
-//            
-//		}
-//        if (d_sign[i] <=0 && d_sign[i+1] >=0){
-//			//is_local_max=false;
-//            min_zc_idx=i+1;
-//			b_local_min=true;
-//		}
-//	}
-//    if(b_local_min){
-//		is_local_max=false;
-//        local_limit_idx = min_zc_idx;
-//		return;
-//	}
-//	if(b_local_max){
-//		is_local_max=true;
-//        local_limit_idx = max_zc_idx;
-//		return;
-//	}
-//    if (is_all_down){
-//		is_local_max=true;
-//        local_limit_idx=0;
-//        return;
-//	}
-//    if( is_all_up){
-//		is_local_max=true;
-//        local_limit_idx=d_sign.size();
-//        return;        
-//	}
-//	is_local_max=true;
-//    local_limit_idx=-1;
-//    return;
-//}
-//double COptimalAnglePart::limit_min_angle(
-//		vector<double>&x, //sorted, ascending
-//		vector<double>&y,
-//		size_t min_idx
-//		)
-//{
-//	size_t i = min_idx;
-//	if(fabs(x[i+1]-x[i])<1.0e-6 || fabs(x[i]-x[i-1])<1.0e-6){
-//	 throw_msg(m_patch_id+" limit_min_angle, diff_x < 1.0e-6");
-//	}
-//    double k_r = (y[i+1]-y[i])/(x[i+1]-x[i]);
-//    double k_l = (y[i]-y[i-1])/(x[i]-x[i-1]);
-//    double oa = 0.0;
-//	double b_r = 0.0;
-//	double b_l = 0.0;
-//	double cross_x = 0;
-//    if (fabs(k_r) > fabs(k_l)){
-//        // right line
-//        b_r = y[i]-k_r*x[i];
-//        b_l = y[i-1] + k_r*x[i-1];
-//        cross_x = line_cross(k_r,b_r,-k_r,b_l);
-//        oa = cross_x;
-//	}
-//    else{
-//        //# left line
-//        b_l = y[i]-k_l*x[i];
-//        b_r =  y[i+1] + k_l*x[i+1];
-//        cross_x = line_cross(k_l,b_l,-k_l,b_r);
-//        oa = cross_x;
-//	}
-//    return oa;
-//}
-//
-//double COptimalAnglePart::line_cross(double k1,double b1,double k2,double b2)
-//{
-//	double x = (b2-b1) / (k1-k2);
-//    return x;
-//}
-//
-//double COptimalAnglePart::opt_angle_part_impl(
-//		vector<double>&x, //sorted, ascending
-//		vector<double>&y,
-//		bool is_base)
-//{
-//	// sign of difference of y
-//	vector<int> dy_sign;
-//	for(size_t i=1; i<y.size();++i){
-//		double dd = y[i] - y[i-1];
-//		if(dd>0){
-//			dy_sign.push_back(1);
-//		}
-//		else{
-//			if(dd<0){dy_sign.push_back(-1);}
-//			else{dy_sign.push_back(0);}
-//		}
-//	}
-//	//local limit search
-//	bool is_local_max = false; 
-//	int local_limit_idx = -1;
-//	zero_cross_detect(dy_sign,is_local_max,local_limit_idx);
-//	if(local_limit_idx<0){
-//	    throw_msg(m_patch_id+" not found local limit");
-//	}
-//	// optimal angle calculation
-//	vector<double> xx;
-//	vector<double> yy;
-//	double oa=0.0;
-//	if(is_local_max){
-//		//存在局部最大
-//        if( local_limit_idx == 0 || local_limit_idx==y.size()-1){
-//            //#单调  
-//			oa = x[local_limit_idx];
-//			//if (local_limit_idx == 0){				
-//			//	for(size_t i=0;i<3;++i){
-//			///		xx.push_back(x[i]);
-//			//		yy.push_back(y[i]);
-//			//	}
-//			//}
-//			//else	{
-//			//	for(size_t i=y.size()-3;i<y.size();++i){
-//			//		xx.push_back(x[i]);
-//			//		yy.push_back(y[i]);
-//			//	}
-//			//}             
-//			//oa = qua_fitting(xx,yy); 
-//			if(m_pLogger){				
-//				m_pLogger->INFO(m_patch_id+ " angle fit -- signle --- max_angle");
-//			}
-//			
-//		}
-//        else{
-//            // 极大值        
-//			for(size_t i=local_limit_idx-1;i<local_limit_idx+2;++i){
-//					xx.push_back(x[i]);
-//					yy.push_back(-y[i]);
-//				}
-//			oa = limit_min_angle(xx,yy,1);  
-//			if(m_pLogger){				
-//				m_pLogger->INFO(m_patch_id+" angle fit -- local max --- 3p insert");
-//			}
-//		}
-//	}
-//    else{
-//		// 极小值   
-//        oa = limit_min_angle(x,y,local_limit_idx);
-//		if(is_base){
-//			//for base, offset 45 degree
-//			if(oa >45){oa = oa-45.0;}
-//			else{oa = oa+45.0;}  
-//		}
-//		else{  
-//			// for rootstock, offset 90 degree
-//			if(oa >90){oa = oa-90.0;}
-//			else{oa = oa+90.0;}   
-//		}
-//		if(m_pLogger){				
-//			m_pLogger->INFO(m_patch_id+" angle fit -- local min --- 3p insert");
-//		}
-//	}
-//    return oa;
-//}
-
-CCotyledonAngle::CCotyledonAngle(ConfigParam&cp, CGcvLogger* pLog)
-	:m_cparam(cp),
-	m_pLogger(pLog),	
-	m_imgId(""),
-	m_ppImgSaver(0),
-	m_height(0),
-	m_width(0)
-{
-}
-
-CCotyledonAngle::~CCotyledonAngle(void)
-{	
-}
-
-void CCotyledonAngle::clear_imginfo(){
-	if (m_pImginfoOpen){
-		imginfo_release(&m_pImginfoOpen);
-		m_pImginfoOpen=0;
-	}
-	if (m_pImginfoAngle){
-		imginfo_release(&m_pImginfoAngle);
-		m_pImginfoAngle=0;
-	}
-}
-int CCotyledonAngle::angle_recognize(
-	ImgInfo* imginfo,
-	PositionInfo& posinfo	
-	)
-{
-	//clear opencv windows
-	if(m_cparam.image_show){ cv::destroyAllWindows();}
-
-	clock_t t;
-	clock_t t0 = clock();	
-	m_imgId = getImgId(img_type::oa);	
-
-	if(m_pLogger){
-		m_pLogger->INFO(m_imgId + " cotyledon angle recognize begin.");
-	}	
-	if(!isvalid(imginfo)){
-		throw_msg(m_imgId+" invalid input image");
-	}
-	if(m_width==0 || m_height==0){
-		m_width = imginfo->width;
-		m_height = imginfo->height;
-	}	
-	if(m_pLogger){
-		stringstream buff;
-		buff<<m_imgId<<" load image\twidth="<<imginfo->width
-			<<"\theight="<<imginfo->height;
-		m_pLogger->INFO(buff.str());
-	}
-	cv::Mat img = imginfo2mat(imginfo);
-
-
-
-	//for DEBUG
-	//Mat img = *(Mat*)(imginfo);
-	//m_width = img.cols/2;
-	//m_height = img.rows/2;
-	//cv::resize(img, img, cv::Size(m_width,m_height ));
-	//end DEBUG
-
-
-	//imshow_wait("src", img);
-	if(m_cparam.self_camera){
-		image_set_bottom(img,20,8);
-		if(m_pLogger){				
-			m_pLogger->DEBUG(m_imgId+" oa_recognize image set bottom with pixel value 20.");				
-		}
-	}
-	if(m_cparam.oa_y_flip){
-		cv::flip(img,img,0);
-		if(m_pLogger){				
-			m_pLogger->DEBUG(m_imgId+" oa_recognize image y fliped.");				
-		}
-	}
-	if(m_ppImgSaver && *m_ppImgSaver){
-		(*m_ppImgSaver)->saveImage(img, m_imgId);
-		if(m_pLogger){				
-			m_pLogger->DEBUG(m_imgId+" oa_recognize after image save.");				
-		}
-	}
-	if(m_cparam.image_show){
-		cv::Mat tmp_b = img.clone();
-		imshow_wait("oa_image", tmp_b);
-	}
-
-	//1图像分割
-	this->img_segment(img);
-	if(m_cparam.image_show){					
-		imshow_wait("oa_image_bin", m_binImg);
-	}
-	cv::Mat img_median, img_base, img_open, img_xor;
-	cv::medianBlur(m_binImg,img_median, 5);	
-
-	cv::Mat kernel = cv::getStructuringElement(
-		cv::MORPH_ELLIPSE,
-		cv::Size( 2*m_cparam.oa_morph_radius + 1, 2*m_cparam.oa_morph_radius+1),
-		cv::Point( m_cparam.oa_morph_radius, m_cparam.oa_morph_radius)
-			);  
-	cv::morphologyEx(
-		img_median,
-		img_base,
-		cv::MORPH_CLOSE,
-		kernel,
-		cv::Point(-1,-1),
-		1);
-
-	if(m_cparam.image_show){					
-		imshow_wait("img_base", img_base);
-	}
-
-	//2 找到2片叶子,计算各自重心,主方向,面积,横纵比,椭圆度,选择最优,计算需要旋转角度
-	int iter_step = 3;
-	int iter_open = 10;
-	
-	double leaf_area_th = (double)m_cparam.oa_min_leaf_area;
-	vector<vector<cv::Point>> contours;
-	vector<cv::Vec4i> hierarchy;
-	vector<t_leaf> leafs;
-
-	while( iter_open >0 && iter_open < 50){
-
-		cv::morphologyEx(
-			img_base,
-			img_open,
-			cv::MORPH_OPEN,
-			kernel,
-			cv::Point(-1,-1),
-			iter_open);
-		if(m_cparam.image_show){
-			imshow_wait("img_base", img_base);
-			imshow_wait("img_open", img_open);
-		}
-		m_openImg = img_open.clone();
-	
-		contours.clear();
-		hierarchy.clear();
-		leafs.clear();
-		findContours(img_open,contours,hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
-		for(int i=0;i<contours.size();++i){
-			double area = contourArea(contours[i]);
-			if (area < leaf_area_th){continue;}			
-			cv::RotatedRect minrect_ellips = fitEllipse(contours[i]);
-			cv::Moments moment = moments(contours[i]);
-			double centx = moment.m10 / moment.m00;
-			double centy = moment.m01 / moment.m00;
-
-			t_leaf leaf;
-			leaf.area = area;
-			leaf.centx = centx;
-			leaf.centy = centy;			
-			leaf.minrect_ellips = minrect_ellips;
-			leaf.contours = contours[i];
-
-			leafs.push_back(leaf);
-		}	
-
-		if(leafs.size()<2){
-			iter_open += iter_step;
-		}
-		if(leafs.size()>2){
-			iter_open -= iter_step;
-		}
-		if(leafs.size()==2){
-			break;
-		}
-
-	}
-	if(leafs.size()!=2){
-		throw_msg(m_imgId+" leafs detect failed");
-	}
-
-	//select one leaf for angle detection
-	double min_err = 1.0e16;
-	int min_err_idx = -1;
-	for(size_t i =0; i<leafs.size();++i){		
-		double err = fit_error_ellipse(leafs[i].minrect_ellips, leafs[i].contours);
-		if(err<min_err){
-			min_err = err;
-			min_err_idx = i;
-		}
-	}
-	if(min_err_idx<0){
-		throw_msg(m_imgId+" no normal leaf");
-	}
-
-	//计算旋转角度
-	double all_area = leafs[0].area+leafs[1].area;
-    double r0 = leafs[0].area/all_area;
-    double all_centx = leafs[0].centx * r0 + leafs[1].centx * (1-r0);
-    double all_centy = leafs[0].centy * r0 + leafs[1].centy * (1 - r0);
-
-	float tar_angle1 = 90 + leafs[min_err_idx].minrect_ellips.angle;//长轴与x轴的夹角(图像坐标系下),90-270间
-	float tar_angle2 =  leafs[min_err_idx].minrect_ellips.angle - 90;//-90 ~ 90
-	if(tar_angle2<0){
-		tar_angle2+=360;
-	}
-	//叶尖方向(相对于两个叶片中心)
-	float leaf_apex_angle = atan2(leafs[min_err_idx].centy - all_centy, leafs[min_err_idx].centx - all_centx) * 180 / CV_PI;
-	if(leaf_apex_angle<0){
-		leaf_apex_angle += 360;
-	}
-
-	float diff1 = fabs(leaf_apex_angle - tar_angle1);
-	if(diff1>180){
-		diff1 = 360 - diff1;
-	}
-	float diff2 = fabs(leaf_apex_angle - tar_angle2);
-	if(diff2>180){
-		diff2 = 360 - diff2;
-	}
-	float rot_angle = tar_angle1;
-	if(diff2 < diff1){
-		rot_angle = tar_angle2;
-	}
-
-	rot_angle -= 180;//需要旋转的角度
-
-	//draw image
-	cv::Mat ellipse_img = m_openImg.clone();
-	for(size_t j=0; j<leafs.size(); ++j){
-		stringstream buff;
-		buff<<"wa="<<(float)((int)(leafs[j].minrect_ellips.angle*10.0)/10.0);	
-		cv::Scalar color = cv::Scalar(100);
-		if(j == min_err_idx){
-			color[0] = 180;
-			buff<<",rot="<<(float)((int)(rot_angle*10.0)/10.0);
-		}
-			
-		cv::Point2f vertices[4];
-		leafs[j].minrect_ellips.points(vertices);
-		for (int i = 0; i < 4; i++)
-			line(ellipse_img, vertices[i], vertices[(i+1)%4], color);
-					
-		putText(ellipse_img,buff.str(),leafs[j].minrect_ellips.center, 0,0.5,color);
-			
-	}
-	if(m_cparam.image_show){		
-		imshow_wait("ellipse_img", ellipse_img);			
-	}
-
-	// 3 返回结果	
-	posinfo.rs_oa=(double)rot_angle;
-    
-	if(m_pLogger){
-		stringstream buff;
-		buff<<m_imgId<<" detect rotat angle "<<posinfo.rs_oa;
-		m_pLogger->INFO(buff.str());
-	}
-	//4 返回图像
-	if(m_cparam.image_return){
-		this->clear_imginfo();
-		m_pImginfoOpen = mat2imginfo(m_openImg);
-		m_pImginfoAngle = mat2imginfo(ellipse_img);
-		posinfo.pp_images[0]=m_pImginfoOpen;
-		posinfo.pp_images[1]=m_pImginfoAngle;
-
-		if(m_ppImgSaver && *m_ppImgSaver){
-			(*m_ppImgSaver)->saveImage(m_binImg, m_imgId+"_rst_0");	
-			(*m_ppImgSaver)->saveImage(ellipse_img, m_imgId+"_rst_1");
-			if(!m_grayImg.empty()){
-				(*m_ppImgSaver)->saveImage(m_grayImg, m_imgId+"_rst_2");
-			}
-		}
-	}
-	
-	if(m_pLogger){
-		m_pLogger->INFO(m_imgId + " oa_recognize image finished.");
-	}	
-	return 0;
-}
-double CCotyledonAngle::fit_error_ellipse(
-	cv::RotatedRect& ellipse_rect,
-	vector<cv::Point>& pts)
-{
-	/*
-	  ref:https://blog.csdn.net/fangyan90617/article/details/89486331
-	  ellipse common function: A * x^2 + B * x*y + C * y^2 + D * x + E * y + F = 0
-	  reformed function: 
-	              A * x'^2 + B * x'*y' + C * y'^2 + F = 0
-				  x' = x - x0
-				  y' = y - y0
-	  from ellipse_rect, calculate A,B,C,F
-
-	*/
-	if(pts.size()==0){
-		return 1.0e6;
-	}
-	float A, B,C, F;
-	get_ellipse_param(ellipse_rect, A, B,C, F);
-	double mean_err = 0.0;
-	double x,y,err;
-	for(size_t i=0; i<pts.size(); ++i){
-		x = (double)pts[i].x - ellipse_rect.center.x;
-		y = (double)pts[i].y - ellipse_rect.center.y;
-		err = A * x * x + B * x * y + C * y * y + F;
-		mean_err += err*err;
-	}
-	mean_err /= (double)pts.size();
-	mean_err = sqrt(mean_err);
-	return mean_err;	
-}
-void CCotyledonAngle::get_ellipse_param(
-	cv::RotatedRect&ellipse_rect,
-	float&A, 
-	float&B, 
-	float&C, 
-	float&F)
-{
-	float theta = ellipse_rect.angle * CV_PI / 180.0;
-	float a = ellipse_rect.size.width / 2.0;
-	float b = ellipse_rect.size.height / 2.0;
-	A = a * a * sin(theta) * sin(theta) + b * b * cos(theta) * cos(theta);
-	B = (-2.0) * (a * a - b * b) * sin(theta) * cos(theta);
-	C = a * a * cos(theta) * cos(theta) + b * b * sin(theta) * sin(theta);
-    F = (-1.0) * a * a * b * b;
-}
-void CCotyledonAngle::img_segment(cv::Mat&img)
-{
-	if(img.channels()!=1){
-		//color image ,bgr, for testing
-		/*Mat img_gray,b_img;
-		cvtColor(img,img_gray,COLOR_BGR2GRAY);
-		double th = threshold(
-			img_gray,
-			b_img,
-			255,
-			255,
-			THRESH_OTSU
-			);
-	
-		b_img/= 255;*/
-
-		cv::Mat img_hsv, b_img_hsv;
-		cv::cvtColor(
-			img, 
-			img_hsv,
-			cv::COLOR_BGR2HSV
-			);
-
-		cv::inRange(
-			img_hsv,
-			cv::Scalar(30 , 30, 30),
-			cv::Scalar(75, 255, 255),
-			b_img_hsv
-			);
-
-		/*imshow_wait("oa_image_range", b_img_hsv);
-		b_img_hsv/=255;
-		b_img = b_img.mul(b_img_hsv);	*/
-
-		//int morph_size = 1;
-		cv::Mat kernel = getStructuringElement(
-			cv::MORPH_RECT,
-			cv::Size( 2*m_cparam.oa_morph_radius + 1, 2*m_cparam.oa_morph_radius+1),
-			cv::Point( m_cparam.oa_morph_radius, m_cparam.oa_morph_radius)
-			);  
-		cv::morphologyEx(
-			b_img_hsv,
-			m_binImg,
-			cv::MORPH_CLOSE,
-			kernel,
-			cv::Point(-1,-1),
-			m_cparam.oa_morph_iteration);
-		
-	}
-	else{
-		//from imginfo image, gray image 
-		//int morph_size = 1;	
-
-		cv::Mat b_img;
-		m_grayImg = img.clone();
-		double th = threshold(img, b_img, 255, 255, cv::THRESH_OTSU);
-		cv::Mat kernel = getStructuringElement(
-			cv::MORPH_RECT,
-			cv::Size( 2*m_cparam.oa_morph_radius + 1, 2*m_cparam.oa_morph_radius+1 ),
-			cv::Point( m_cparam.oa_morph_radius, m_cparam.oa_morph_radius)
-			);    
-		cv::morphologyEx(
-			b_img, 
-			m_binImg, 
-			cv::MORPH_OPEN,
-			kernel,
-			cv::Point(-1,-1),
-			m_cparam.oa_morph_iteration
-			);
-	}	
-}
-
-
-};

+ 0 - 180
optimal_angle.h

@@ -1,180 +0,0 @@
-#pragma once
-#include <opencv.hpp>
-#include <map>
-#include <opencv2\imgproc\imgproc.hpp>
-#include "data_def_api.h"
-#include "logger.h"
-#include "imstorage_manager.h"
-
-using namespace std;
-//using namespace cv;
-
-namespace graft_cv{
-
-// class COptimalAngle
-// 1. find the max angle 
-// 2. find the clamp position
-// 条件:图像0度到180度间,并第一帧为0度时刻,最后一帧为180时刻
-// 采用的方法:拼接数据(360度范围),通过找到两个最小点,此两点间的数据用
-//             二次曲线拟合,得到对称轴x坐标,即为最优角度
-//class COptimalAngle
-//{
-//public:
-//	COptimalAngle(ConfigParam&, CGcvLogger* pLog=0);
-//	virtual ~COptimalAngle(void);
-//	int reset();
-//	int append(ImgInfo*, 
-//		PositionInfo& posinfo
-//		);
-//	double infer(PositionInfo& posinfo);// calculate the optimal angle
-//
-//	//fit optimal angle based m_an2width
-//	virtual double angle_fit(map<int, int>&,bool is_base=false);
-//	virtual double angle_fit_base(map<int, int>&);// for base matter
-//	void set_image_saver(CImStoreManager** ppis)
-//	{
-//		m_ppImgSaver=ppis;
-//	}
-//protected:
-//	//global configure parameters
-//	ConfigParam& m_cparam;
-//	CGcvLogger* m_pLogger;
-//	string m_patch_id;
-//	CImStoreManager** m_ppImgSaver;
-//	int m_imgIndex;
-//	string m_imgId;
-//   
-//	// binary image
-//	Mat m_binImg;
-//	Mat m_binImgBase;
-//
-//	//返回图片,用于调试
-//	ImgInfo* m_pImginfo;
-//	ImgInfo* m_pImginfoBase;
-//
-//	// 角度-叶展宽度(像素)
-//	map<int, int> m_an2width;
-//	map<int, int> m_an2widthBase;
-//	// 图像处理函数
-//	// 返回min_idx左侧x,max_idx右侧x
-//	int imgproc(
-//		Mat&,  
-//		vector<int>& hist, 
-//		int& min_idx, 
-//		int& max_idx);
-//	int imgprocBase(
-//		Mat&,  
-//		vector<int>& hist, 
-//		int& min_idx, 
-//		int& max_idx);
-//
-//	// 清理释放m_pImginfo
-//	void clear_imginfo();
-//	    
-//	//茎分叉点y值系列
-//	vector<int> m_fork_ys;
-//	
-//	//茎最低点y值系列
-//	vector<int> m_end_ys;
-//
-//	//叶展宽度系列
-//	vector<int>m_widths;
-//
-//	//all image size
-//	int m_width;
-//	int m_height;	
-//};
-
-
-//COptimalAnglePart, 继承自COptimalAngle
-//条件:图像0度到90度间,并保证>=90度范围
-//方法:0-90度范围必然存在最大值或最小值,通过最大最小值局部数据
-//      插值(二次曲线拟合)得到最大角度计算
-//class COptimalAnglePart: public COptimalAngle{
-//public:
-//	COptimalAnglePart(ConfigParam&, CGcvLogger*pLog=0);
-//	virtual ~COptimalAnglePart();
-//	//fit optimal angle based m_an2width
-//	double angle_fit(map<int, int>&,bool is_base=false);
-//	double angle_fit_base(map<int, int>&);// for base matter
-//protected:
-//	//zero_cross_detect()
-//	//过零点检测,用于确定是否单调(增或减),局部最小,局部最大,
-//	//并返回局部极值index
-//	void zero_cross_detect(
-//		vector<int>&d_sign, //input
-//		bool& is_local_max, // whether exists local max 
-//		int& local_limit_idx // local limit index of original vector
-//		);  
-//	double limit_min_angle(
-//		vector<double>&x, //sorted, ascending
-//		vector<double>&y,
-//		size_t min_idx
-//		);
-//
-//	// 计算y = k1*x + b1和y = k2*x + b2两条直线相交交点,x坐标
-//	double line_cross(
-//		double k1,
-//		double b1,
-//		double k2,
-//		double b2);
-//	//
-//	double opt_angle_part_impl(
-//		vector<double>&x, //sorted, ascending
-//		vector<double>&y,
-//		bool is_base=false);
-//};
-
-// CCotyledonAngle
-// 顶部拍照砧木,通过子叶角度识别,提供机构旋转角度
-class CCotyledonAngle{
-public:
-
-	CCotyledonAngle(ConfigParam&, CGcvLogger* pLog=0);
-	virtual ~CCotyledonAngle();
-	int angle_recognize(ImgInfo*, 
-		PositionInfo& posinfo
-		);
-	void set_image_saver(CImStoreManager** ppis)
-	{
-		m_ppImgSaver=ppis;
-	}
-
-protected:
-	//global configure parameters
-	ConfigParam& m_cparam;
-	CGcvLogger* m_pLogger;
-
-	string m_imgId;
-	CImStoreManager** m_ppImgSaver;
-
-
-	//all image size
-	cv::Mat m_grayImg;
-	cv::Mat m_binImg;
-	int m_width;
-	int m_height;
-	cv::Mat m_openImg; // for save	
-
-	//返回图片,用于调试
-	ImgInfo* m_pImginfoOpen;//fork-y, right-x
-	ImgInfo* m_pImginfoAngle;//corners, reference-point, candidate box
-	
-
-	//
-	typedef struct {
-		double area;
-		double centx;
-		double centy;		
-		cv::RotatedRect minrect_ellips;
-		vector<cv::Point> contours;
-	} t_leaf;
-
-	void img_segment(cv::Mat&img);
-	double fit_error_ellipse(cv::RotatedRect&ellipse_rect,vector<cv::Point>& pts);
-	void get_ellipse_param(cv::RotatedRect&ellipse_rect,   //input
-		float&A, float&B, float&C, float&F); //output
-	void clear_imginfo();
-};
-
-};

+ 0 - 41
test.cpp

@@ -1,41 +0,0 @@
-#include "stdafx.h"
-#include <iostream>
-#include <strstream>
-#include <time.h>
-
-#include "imstorage_manager.h"
-//using namespace graft_cv;
-
-void test_file_storeage()
-{
-	///*extern CRITICAL_SECTION g_cs;
-	//InitializeCriticalSection(&g_cs);*/
-	
-	CImStoreManager ism = CImStoreManager();
-	//ism.setStoreDays(1);
-	string path = "D:\\logs\\img_depo";
-	ism.setStoreDir(path);	
-
-	for(size_t i=0;i<7;++i){
-		stringstream buff,bid;
-		buff <<"D:\\private\\grafting_robot\\samples\\rootstlock_pumpkin\\000\\"<<i<<".jpg";
-		bid<<time(NULL)<<"_"<<i;
-		string fn = buff.str();
-		string fid = bid.str();
-		Mat img = imread(fn);
-		ism.saveImage(img,fid);
-
-	}
-	 
-	Sleep(5000);
-	
-
-	//DeleteCriticalSection(&g_cs);
-
-}
-//int _tmain(int argc, _TCHAR* argv[])
-//{		
-//	test_file_storeage();
-//	
-//	return 0;
-//}

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott