Quellcode durchsuchen

v0.6.0 更新角度识别接口、砧木切前切割点识别、切割点重识别(没有完全实现),提供debug版dll测试

chenhongjiang vor 2 Jahren
Ursprung
Commit
dc7d3a822e
9 geänderte Dateien mit 1310 neuen und 1284 gelöschten Zeilen
  1. 7 7
      config.cpp
  2. 13 11
      cut_point_rs.cpp
  3. 14 6
      cut_point_rs_reid.cpp
  4. 22 17
      data_def_api.h
  5. 331 320
      demo.cpp
  6. 12 12
      gcv_conf.yml
  7. 5 5
      graft_cv_api.h
  8. 805 805
      optimal_angle.cpp
  9. 101 101
      optimal_angle.h

+ 7 - 7
config.cpp

@@ -36,7 +36,7 @@ namespace graft_cv{
 			<< "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
-			<< "oa_min_hist_value"<< m_cparam->oa_min_hist_value
+			/*<< "oa_min_hist_value"<< m_cparam->oa_min_hist_value
 			<< "oa_morph_radius_base"<<  m_cparam->oa_morph_radius_base	
 			<< "oa_morph_iteration_base" << m_cparam->oa_morph_iteration_base
 			<< "oa_min_hist_value_base"<< m_cparam->oa_min_hist_value_base
@@ -49,7 +49,7 @@ namespace graft_cv{
 			<< "oa_stem_dia_mp"<< m_cparam->oa_stem_dia_mp
 
 			<< "oa_clip_y_min"<< m_cparam->oa_clip_y_min
-			<< "oa_clip_y_max"<<m_cparam->oa_clip_y_max
+			<< "oa_clip_y_max"<<m_cparam->oa_clip_y_max*/
 
 
 			<< "rs_y_flip"<<  m_cparam->rs_y_flip 	
@@ -112,11 +112,11 @@ namespace graft_cv{
 		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->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->oa_min_hist_value = (int)node["oa_min_hist_value"];
+		/*m_cparam->oa_min_hist_value = (int)node["oa_min_hist_value"];
 		m_cparam->oa_morph_radius_base = (int)node["oa_morph_radius_base"];
 		m_cparam->oa_morph_iteration_base  = (int)node["oa_morph_iteration_base"];
 		m_cparam->oa_min_hist_value_base = (int)node["oa_min_hist_value_base"];
@@ -128,7 +128,7 @@ namespace graft_cv{
 		m_cparam->oa_stem_fork_y_min  = (int)node["oa_stem_fork_y_min"];
 		m_cparam->oa_stem_dia_mp = (double)node["oa_stem_dia_mp"];
 		m_cparam->oa_clip_y_min = (int)node["oa_clip_y_min"];
-		m_cparam->oa_clip_y_max = (int)node["oa_clip_y_max"];
+		m_cparam->oa_clip_y_max = (int)node["oa_clip_y_max"];*/
 
 		m_cparam->rs_y_flip = (bool)(int)node["rs_y_flip"];
 		m_cparam->rs_col_th_ratio  = (double)node["rs_col_th_ratio"];
@@ -196,7 +196,7 @@ namespace graft_cv{
 			<< "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
-			<< "oa_min_hist_value:\t"<< m_cparam->oa_min_hist_value<<endl
+			/*<< "oa_min_hist_value:\t"<< m_cparam->oa_min_hist_value<<endl
 			<< "oa_morph_radius_base:\t"<<  m_cparam->oa_morph_radius_base	 << endl
 			<< "oa_morph_iteration_base:\t" << m_cparam->oa_morph_iteration_base << endl
 			<< "oa_min_hist_value_base:\t"<< m_cparam->oa_min_hist_value_base << endl
@@ -209,7 +209,7 @@ namespace graft_cv{
 			<< "oa_stem_dia_mp:\t"<< m_cparam->oa_stem_dia_mp << endl
 
 			<< "oa_clip_y_min:\t"<< m_cparam->oa_clip_y_min << endl
-			<< "oa_clip_y_max:\t"<<m_cparam->oa_clip_y_max << endl
+			<< "oa_clip_y_max:\t"<<m_cparam->oa_clip_y_max << endl*/
 
 
 			<< "rs_y_flip:\t"<<  m_cparam->rs_y_flip 	 << endl

+ 13 - 11
cut_point_rs.cpp

@@ -131,8 +131,9 @@ int CRootStockCutPoint::up_point_detect(
 	///////////////////////////////////////////////////////
 	// image segment
 	this->img_segment(img);
-	// image save to cache
-	img_cache.insert(make_pair<string, Mat>(m_imgId, m_grayImg));
+	// image save to cache, clear first
+	img_cache.clear();
+	img_cache.insert(make_pair<string, Mat>(m_imgId, m_grayImg.clone()));
 
     if(m_pLogger){	
 		m_pLogger->DEBUG(m_imgId+" after image segment.");				
@@ -362,22 +363,23 @@ int CRootStockCutPoint::up_point_detect(
 	///////////////////////////////////////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;
+	//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;
+	//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 * 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;
+	//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;
+	//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;

+ 14 - 6
cut_point_rs_reid.cpp

@@ -175,12 +175,20 @@ int CRootStockCutPointReid::cut_point_reid(
 	BFMatcher matcher(NORM_L2);
 	std::vector< DMatch > matches;
 	matcher.match( descriptors_pre, descriptors_cur, matches );
-	//-- Draw matches
-	Mat img_matches;
-	drawMatches( m_preGrayImg, keypoints_pre, m_grayImg, keypoints_cur, matches, img_matches );
-	//-- Show detected matches
-	imshow("Matches", img_matches );
-	waitKey(-1);
+	if(m_cparam.image_show){
+		//-- Draw matches
+		Mat img_matches;
+		drawMatches( m_preGrayImg, keypoints_pre, m_grayImg, keypoints_cur, matches, img_matches );
+		//-- Show detected matches
+		imshow("Matches", img_matches );
+		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;

+ 22 - 17
data_def_api.h

@@ -33,20 +33,20 @@ typedef struct{
 	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 
+	//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 
+	//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值
+	//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)
@@ -109,11 +109,11 @@ typedef struct
 {
 	//以下涉及到位置均为实际位置,毫米
 	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_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位置,毫米
@@ -121,6 +121,11 @@ typedef struct
 	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 sc_cut_upoint_x;//穗苗上切割点x位置,毫米
 	double sc_cut_upoint_y;//穗苗上切割点y位置,毫米

+ 331 - 320
demo.cpp

@@ -50,7 +50,7 @@ void test_init_cp(ConfigParam&cp){
 	cp.oa_y_flip=true;
 	cp.oa_morph_radius = 1;
 	cp.oa_morph_iteration=2; 
-	cp.oa_min_hist_value=10;
+	/*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;
@@ -62,7 +62,7 @@ void test_init_cp(ConfigParam&cp){
     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.oa_clip_y_max = 355;*/
 
 	cp.rs_y_flip=false;
 	cp.rs_col_th_ratio= 0.7; 	                      
@@ -158,7 +158,7 @@ void test_camconfig_read()
 	ConfigParam cp0, cp1;
 	memset(&cp1, 0, sizeof(ConfigParam));
 	cp0 = cp1;
-	cp0.oa_min_hist_value = 100;
+	//cp0.oa_min_hist_value = 100;
 	cout<<&cp0<<endl;
 
 	CGCvConfig cam0 = CGCvConfig();
@@ -206,309 +206,309 @@ void test_anglefit_readdata(vector<map<int,int>>& data){
 		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_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()
 {
 
@@ -1250,7 +1250,7 @@ void test_oa_batch(){
 	//cv_set_param(cp_ret);
 	//namedWindow("pic", CV_WINDOW_NORMAL);
 	
-	string work_folder = "E:\\projects\\grafting_robot\\samples\\20220831\\top";
+	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);			
@@ -1259,11 +1259,11 @@ void test_oa_batch(){
 			if(filename.find(".rst_")!=string::npos){continue;}
 			//if(filename.find("\\249.bmp")==string::npos){continue;}
 			PositionInfo posinfo;
-			Mat img = imread(filename, cv::IMREAD_COLOR);//IMREAD_GRAYSCALE
+			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* imginfo = mat2imginfo(img);
+			//ImgInfo* imginfo = (ImgInfo*)(&img);
 			//imginfo->angle = j*30;
 			try{
 				//rs_oa_init();
@@ -1407,7 +1407,7 @@ void test_api_batch(){
 	cv_init_image_saver();
 	namedWindow("pic", CV_WINDOW_NORMAL);
 	
-	string work_folder = "E:\\projects\\grafting_robot\\samples\\20220105\\batch";
+	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){
@@ -1416,7 +1416,7 @@ void test_api_batch(){
 		//buff<<work_folder<<"\\"<<"0-4-489.bmp";
 		string batch_folder = buff.str();
 		PositionInfo posinfo;
-
+		PositionInfo posinfo_cut;
 		///////////////////////////////////////////////////////
 		// 1 optimal angle
 		/*rs_oa_init();		
@@ -1453,23 +1453,34 @@ void test_api_batch(){
 		//////////////////////////////////////////////////////////////////
 		// 2 rootstock cut point
 		//if(!(i==4 || i==6 ||i==8 || i==12 || i==15) ){continue;}
-		//if(i!=12){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);		
+		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);
+			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){
@@ -1608,9 +1619,9 @@ int _tmain(int argc, _TCHAR* argv[])
 	//test_sc_batch();
 	//test_rs_batch();
 	//test_rs_batch_camera();
-	test_rs_batch_reid();
+	//test_rs_batch_reid();
 	//test_oa_batch();
-	//test_api_batch();
+	test_api_batch();
 	//drawline_rs();
 	//drawline_sc();
 	//drawline_dist();

+ 12 - 12
gcv_conf.yml

@@ -14,18 +14,18 @@ conf_parameters:
    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
+   #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

+ 5 - 5
graft_cv_api.h

@@ -79,18 +79,18 @@ GCV_API void get_version(char* buf);
 
 //13 获取砧木最优角度
 //  ImgInfo* 为输出顶部拍照的图片
-//  返回posinfo.rs_oa,
-//      posinfo.rs_oa_base
-//      posinfo.rs_oa_stem_y_fork,
-//      posinfo.rs_oa_clamp_y_end,
+//  返回posinfo.rs_oa, 需要旋转的角度,逆时针为正方向
+
 //   返回: 0- 正常; 1- 失败
 GCV_API int rs_oa_get_result(ImgInfo*, PositionInfo& posinfo);
 
 //14 砧木切割点识别,返回
-//       posinfo.rs_cut_edge_length
+//       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),候选框,参考点(茎分叉点右侧边缘坐标)

Datei-Diff unterdrückt, da er zu groß ist
+ 805 - 805
optimal_angle.cpp


+ 101 - 101
optimal_angle.h

@@ -17,113 +17,113 @@ namespace graft_cv{
 // 条件:图像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;	
-};
+//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);
-};
+//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
 // 顶部拍照砧木,通过子叶角度识别,提供机构旋转角度

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.