工作记录——7

Time :2020.01.23

这是假期前修改的程序。记忆中修改的部分是将激光雷达和相机检测到的障碍物的位置、速度、角度做加权处理并输出,此外还输出了相机检测到障碍物的类别、长、宽。

#include "ros/ros.h"
#include <std_msgs/String.h>
#include <package/talker1.h>                   //自定义头文件
#include <package/talker2.h>                   //自定义头文件
#include <message_filters/subscriber.h>
#include <message_filters/sync_policies/approximate_time.h>//相近对齐
#include <message_filters/time_synchronizer.h>//区别
#include <message_filters/synchronizer.h>//区别
#include <cstdio>
#include <stdlib.h>
#include <string>
#include <sstream>
#include <algorithm>
using namespace std;
using namespace message_filters;

typedef sync_policies::ApproximateTime<package::talker1,package::talker2> MySyncPolicy;  
//匈牙利算法用到的
#define MAXN 990                  //MAXN表示X集合和Y集合顶点个数的最大值

class Listener{
	public:
	Listener(ros::NodeHandle _nh);//在构造函数中传入节点句柄,并调用 定义订阅节点函数
	~Listener(){};
	void callback(const package::talker1ConstPtr& msg1,const package::talker2ConstPtr& msg2);
	int path(int u);
	int maxMatch();
	
	private:
	ros::NodeHandle nh;
	int length,width,s,v,q,length1,width1,s1,v1,q1,s2,v2,q2,n1,n2;
	string type,type1,type2;
	double Result;
	int g[MAXN][MAXN];                //邻接矩阵,g[i][j]=1表示有连接 
	int cx[MAXN],cy[MAXN];            //cx[i],表示最终求得的最大匹配中,与x集合中元素Xi匹配的集合Y中顶点的索引//cy[i],表示最终求得的最大匹配中,与y集合中元素Yi匹配的集合X中顶点的索引
	int mk[MAXN];                     //DFS算法中记录顶点访问状态的数据mk[i]=0表示未访问过,为1表示访问过,标记的永远是二分图右边的顶点。
	//定义消息同步机制和成员变量
	message_filters::Subscriber<package::talker1>* sub1 ;  // topic1 输入
	message_filters::Subscriber<package::talker2>* sub2;   // topic2 输入
	message_filters::Synchronizer<MySyncPolicy>* sync;
};

Listener::Listener(ros::NodeHandle _nh)
{
//类构造函数中开辟空间new
	nh=_nh;
	sub1 = new message_filters::Subscriber<package::talker1>(nh, "message1", 1000);
    sub2 = new message_filters::Subscriber<package::talker2>(nh, "message2", 1000);
    sync = new  message_filters::Synchronizer<MySyncPolicy>(MySyncPolicy(10), *sub1, *sub2);
    sync->registerCallback(boost::bind(&Listener::callback,this, _1, _2));
}

void Listener::callback(const package::talker1ConstPtr& msg1,const package::talker2ConstPtr& msg2)
{
//类成员函数回调处理
//输出相机检测到几个障碍物:
	 n1=msg1->s;
//输出激光雷达检测到几个障碍物:
	 n2=msg2->s;	
/*************************************************************************************************************************************
											定义二位数组,将多传感器的输出信息传入各自数组中,方便后续计算
*************************************************************************************************************************************/
//相机的检测到的障碍物的位置、角度、速度等依次输出(放到一个矩阵中(n1*6)):
	int m=0,n=0;
	double array[n2];
	vector<vector<double>> msg1vector(n1,vector<double>(6));
	for(int i=0;i<n1;i++){
		for(int j=0;j<6;j++){
			msg1vector[i][j]=msg1->array.data[m];//把相机检测到的每个障碍物的特征信息放到矩阵中:
			//cout<<msg1vector[i][j]<<endl;
			m=m+1;
		 }			
	}
	vector<vector<double>> msg2vector(n2,vector<double>(3));//定义存放激光雷达检测到的障碍物信息的矩阵(n2*3):
	for(int i=0;i<n2;i++){
		for(int j=0;j<3;j++){
			msg2vector[i][j]=msg2->array.data[n];//把激光雷达检测到的每个障碍物的特征信息放到矩阵中:
			//cout<<msg2vector[i][j]<<endl;
			n=n+1;
		 }	
	}

/*************************************************************************************************************************************
													     欧式距离
*************************************************************************************************************************************/
/*
//欧式距离
//定义一个矩阵存放欧式距离计算结果、msg1中有4个障碍物,msg2中有5个障碍物,那么矩阵的维数是4*5,即n1*n2(矩阵1的行数×矩阵2的行数);
 	vector<vector<double>> distanceresultV(n1,vector<double>(n2));	
	
	for(int i=0;i<n1;i++){
    	for(int j=0;j<n2;j++){
		double d=0.0;	     //需要注意d的位置
        	for(int k=0;k<3;k++){//数组a与数组b的列是一样的,因此k代表他们的列数。
        		d+=(msg1vector[i][k]-msg2vector[j][k])*(msg1vector[i][k]-msg2vector[j][k]);   //注意此处是msg1vector-msg2vector
				Result=sqrt(d);
        	}
        	distanceresultV[i][j]=Result;
        	cout<<"distanceresultV"<<i<<"."<<j<<"     "<<distanceresultV[i][j]<<endl; 
    	}
	}
 */
/*************************************************************************************************************************************
													   标准欧式距离
*************************************************************************************************************************************/
//判断分母是否为零
//定义一个矩阵存放欧式距离计算结果、msg1中有4个障碍物,msg2中有5个障碍物,那么矩阵的维数是4*5,即n1*n2(矩阵1的行数×矩阵2的行数);
//////////////////////////////////////////////////////////////////////////////////////////
double U[3]={0,0,0};
double u1[3]={0,0,0};
double u2[3]={0,0,0};//定义存放均值的参数;u1、u2分别存放msg1vector、msg2vector;U存放最终的数据;//必须要初始化,不然会计算错误
double S[3]={0,0,0};
double s1[3]={0,0,0};
double s2[3]={0,0,0};//定义存放均方根的参数;s1、s2分别存放msg1vector、msg2vector每列的数据;S[3]存放最终的数据;

	for(int i=0;i<3;i++){
		for(int j=0;j<n1;j++){
			u1[i]+=msg1vector[j][i];//u1[0]存放的是第一组的 第一列,u1[1]存放的是第二列,u1[2]存放的是第三列;
		}
		//cout<<"u1"<<i<<"     "<<u1[i]<<endl;
	}
	for(int i=0;i<3;i++){
		for(int j=0;j<n2;j++){
			u2[i]+=msg2vector[j][i];//u2[0]存放的是第二组的 第一列,u2[1]存放的是第二列,u2[2]存放的是第三列;
			//cout<<"u2"<<i<<"     "<<u2[i]<<endl;			
		}
	}
//求数组中每一列的均值
	for(int i=0;i<3;i++){
		U[i]=(u1[i]+u2[i])/(n1+n2);//U[0]存放的是第一列的均值,U[1]存放的是第二列的均值,U[2]存放的是第三列的均值;
		//cout<<"U"<<i<<"     "<<U[i]<<endl;
	}
//MSG1VECTOR第一列数据、第二列数据、第三列数据
	for(int i=0;i<3;i++){
		for(int j=0;j<n1;j++){
			s1[i]+=(msg1vector[j][i]-U[i])*(msg1vector[j][i]-U[i]);//s1[0]存放的是第一列,s1[1]存放的是第二列,s1[2]存放的是第三列;
		}
	}
//MSG2VECTOR第一列数据、第二列数据、第三列数据
	for(int i=0;i<3;i++){
		for(int j=0;j<n2;j++){
			s2[i]+=(msg2vector[j][i]-U[i])*(msg2vector[j][i]-U[i]);//s1[0]存放的是第一列,s1[1]存放的是第二列,s1[2]存放的是第三列;
		}
	}
//求数组中每一列的均方根
	for(int i=0;i<3;i++){
		S[i]=(s1[i]+s2[i])/(n1+n2);//U[0]存放的是第一列的均值,U[1]存放的是第二列的均值,U[2]存放的是第三列的均值;
		//cout<<"S"<<i<<"     "<<S[i]<<endl;
	}
vector<vector<double>> distanceresultV(n1,vector<double>(n2));
	for(int i=0;i<n1;i++){
    	for(int j=0;j<n2;j++){
        	double d=0.0;
			for(int k=0;k<3;k++){//数组a与数组b的列是一样的,因此k代表他们的列数。
				//判断分母是否为零:
				if(S[k]){
				d+=(msg1vector[i][k]-msg2vector[j][k])*(msg1vector[i][k]-msg2vector[j][k])/S[k];   //计算标准欧式距离的关键步骤
				Result=sqrt(d);
				}
    		}
        distanceresultV[i][j]=Result;
        //cout<<"distanceresultV"<<i<<"."<<j<<"     "<<distanceresultV[i][j]<<endl; //输出第一组数据和第二组数据之间的距离
		}//distanceresultV[i][j]矩阵就是接下来要处理的数据
	}

/*************************************************************************************************************************************

													编写错误的标准欧式距离

*************************************************************************************************************************************/

  /*	vector<vector<double>> distanceresultV(n1,vector<double>(n2));
	for(int i=0;i<n1;i++){
    	for(int j=0;j<n2;j++){
        	double d=0.0;
        	for(int k=0;k<3;k++){//数组a与数组b的列是一样的,因此k代表他们的列数。
				double u[3],s[3];
				u[k]=(msg1vector[i][k]+msg2vector[j][k])/2;//计算平均值
				s[k]=(msg1vector[i][k]-u[k])*(msg1vector[i][k]-u[k]);//计算分母
				//判断分母是否为零:
				if(s[k]){
				d+=(msg1vector[i][k]-msg2vector[j][k])*(msg1vector[i][k]-msg2vector[j][k])/s[k];   //计算标准欧式距离的关键步骤
				Result=sqrt(d);
				}
        	}
        	distanceresultV[i][j]=Result;
        	cout<<"distanceresultV"<<i<<"."<<j<<"     "<<distanceresultV[i][j]<<endl; 
    	}
	}//distanceresultV[i][j]矩阵就是接下来要处理的数据
	*/

 
 // 找到每行的最小值及次小值,并将其置为1,其余值置为0

 /*************************************************************************************************************************************
													处理存储几何距离的数组(将最小的两个置1,其余的置0)
						     		××××××××××最好再根据最小值和次小值的差距确定保留一个、两个或者多个匹配对象××××××××××××
*************************************************************************************************************************************/
   for(int i=0;i<n1;i++){
        for(int j=0;j<n2;j++){
            array[j]=distanceresultV[i][j];//先取出来距离矩阵的第一行
        }
        double m1,m2;//存储两个最小值
        m1=9999;
        m2=9999;
        for(int k=0;k<n2;k++){
            if(array[k]<m1){
                m2=m1;
                m1=array[k];
            }
            else if(array[k]<m2){
                m2=array[k];
            }
        }
//2020.01.21
		double m3=m2-m1;                                                              //给出一个阈值判断,防止最小值和次小值差距太大,但仍将次小值视为匹配对象;
		//cout<<"m1: "<<m1<<"m2: "<<m2<<"m3: "<<m3<<endl;
		if(m3<=0.8){                                                                  //更改阈值大小可以决定匹配准确程度,阈值越小,搜索范围越小;
       		for(int l=0;l<n2;l++){
           		if(array[l]==m1){
               	g[i][l]=1;
           		}
           		else if(array[l]==m2){
               	g[i][l]=1;
           		}
           		else{
               	g[i][l]=0;
           		}
       		}
		}
		else{
			for(int l=0;l<n2;l++){
           		if(array[l]==m1){
               	g[i][l]=1;
           		}
           		else{
               	g[i][l]=0;
           		}
       		}
		}
	}
 	//输出处理结果
	for(int m=0;m<n1;m++){
        for(int n=0;n<n2;n++){
            cout<<"g["<<m<<"]"<<"["<<n<<"]"<<g[m][n]<<endl;
        }
    } 
/*************************************************************************************************************************************
													在回调函数中调用类外的匈牙利匹配算法
*************************************************************************************************************************************/
	int num= Listener::maxMatch();//调用匈牙利算法最核心的步骤//输出了有多少组匹配的障碍物
    cout<<"num="<<num<<endl;//输出匹配成功了多少组
	//比较n1、n2大小;
	//需要修改算法
	//int t=n1>n2?n1:n2;
	vector<vector<double>> Result1(n1,vector<double>(6));
	vector<vector<double>> Result2(n1,vector<double>(3));
	vector<vector<double>> Result(n1,vector<double>(6));
	for(int i=0;i<n1;++i){                                ////////此处的n1应该是num吧,即匹配的个数
        cout<<"cx["<<i+1<<"] --> "<<cx[i]+1<<endl;
		int q=cx[i];                                    //q也是与i相关的数据 //相机的第i个目标与激光雷达的第cx[i](第q)个对象相对应

         /***************************************************************************************************************
												  对相机中的第i个目标与激光雷达中的第q个目标的前三列做加权处理
													      (至于后面采用什么样的加权算法还需要确定)
													        输出相机检测到的目标的长、宽及类别信息
         ************************************************************************************************ ***************/
//给相机和激光雷达的速度、方向以及距离的测量值分别附一个权重 输出(msg1和msg2均参与计算);输出障碍物的类别、长、宽(输出msg1相对应的. 就可以了)		 
//假设相机的检测结果赋权重是{0.3,0.45,0.5,1,1,1} 列向量p1
//假设激光雷达的检测结果赋权重是{0.7,0.55,0.5} 列向量p1
		double p1[6]={0.3,0.45,0.5,1,1,1};
		double p2[3]={0.7,0.55,0.5};

//存放msg1vector乘上权重后的数据
		for(int k=0;k<6;k++){
		Result1[i][k]=(msg1vector[i][k])*p1[k];
		Result[i][k]=Result1[i][k];//把Result1直接赋值给Result,这样Result1后边的三列数据就会给Result,后边直接将这两组矩阵的前三列相加即可
		//cout<<"计算结果1是 : "<<Result1[i][k]<<endl;
		}
//计算msg2vector乘上权重后的数据	
		for(int k=0;k<3;k++){
		Result2[i][k]=(msg2vector[q][k])*p2[k];
		//cout<<"计算结果2是 : "<<Result2[i][k]<<endl;
		}
		for(int k=0;k<3;k++){
		Result[i][k]=Result1[i][k]+Result2[i][k];
		}
		
		/*****************************************************************************************************************
															输出类别
		******************************************************************************************************************/
		int ii = Result[i][5];//这个是5,不是6
    	/*stringstream stream;                    //这个是将int类型转换成string类型;switch类型的表达式需要整形或者枚举型,所以不需要该部分
    	string result;
    	int ii = Result[i][5];//这个是5,不是6
		cout<<"Result[i][6]"<<Result[i][6]<<endl; //
    	stream<<ii; //将int输入流
    	stream>>result; //从stream中抽取前面插入的int值
    	cout<<result<<endl; //
		stream.clear();*/

		switch(ii){//switch语句中的expression必须是一个整型或枚举类型,或者是一个class类型,其中class有一个单一的转换函数将其转换为整型或枚举类型。
   		case 0://当是整型数据时,直接case int类型,不需要  case 'A' :
      	cout<<"障碍物"<<i<<"的类型是: 卡车" << endl; 
      	break;
   		case 1:
		cout<<"障碍物"<<i<<"的类型是: 汽车" << endl; 
		break;   
   		case 2:
      	cout<<"障碍物"<<i<<"的类型是: 非机动车" << endl;
      	break;
   		case 3:
      	cout<<"障碍物"<<i<<"的类型是: 行人" << endl;
      	break;
   		default:
      	cout<<"障碍物"<<i<<"的类型是: 无效的目标" << endl;
   		}
		/*****************************************************************************************************************
															输出障碍物的位置、速度、方向、长和宽
		******************************************************************************************************************/
		cout<<"障碍物"<<i<<"的位置是 : "<<Result[i][0]<<"m"<<endl;
		cout<<"障碍物"<<i<<"的速度是 : "<<Result[i][1]<<"km/h"<<endl;
		cout<<"障碍物"<<i<<"的角度是 : "<<Result[i][2]<<"°"<<endl;
		cout<<"障碍物"<<i<<"的长是 : "<<Result[i][3]<<"m"<<endl;
		cout<<"障碍物"<<i<<"的宽是 : "<<Result[i][4]<<"m"<<endl;

	}

}//callback的末尾括号


/*************************************************************************************************************************************
													    匈牙利算法类外实现
*************************************************************************************************************************************/

//从集合X中的定顶点u出发,用深度有限的策略寻找增广路
//这种增广路只能是当前的匹配数增加1
int Listener::path(int u){                    //传入的是左侧的顶点
    for(int v=0;v<n2;++v){          //考虑所有右侧顶点,从第一个开始扫描,依次向下
        if(g[u][v] && !mk[v]){      //如果左侧有右侧某顶点相连接,并且这个右侧顶点没有被此时的左侧顶点访问过
            mk[v]=1;                //标记右侧顶点,访问v
            	//接下来,判断这个右侧顶点。
            	//如果v没有匹配,则直接将v匹配给u。或者,如果v已经匹配了,但是从cy[v],也就是从v之前已经匹配的x出发,找到一条增广路,但是这里记住这里v已经记录访问过了
            	//如果第一个条件成立,则不会递归调用
            if(cy[v]==-1 || path(cy[v])){     //path()函数的返回值是1或者0;
            	//如果满足上述条件,更新cx cy
                cx[u]=v;            //把Y中v匹配给X中u
                cy[v]=u;            //把X中u匹配给Y中v
                return 1;           //找到左侧点的匹配值,那么将返回1
            }
        }
    }
    return 0;                        //如果不存在从u出发的增广路,则返回0
    //具体的说:如果左侧点找不到一个匹配点,那么将会返回0,此时path(cy[v])=0,就不会将右侧点与之前匹配的点拆散,而是左侧点重新依次向下寻找右侧链接顶点
}

int Listener::maxMatch(){                       //求二分图最大匹配的匈牙利算法;
    int res=0;
   	memset(cx,-1,sizeof(cx));         //从0匹配开始增广,将cx和xy各元素都初始化为-1;
    memset(cy,-1,sizeof(cy));
    for(int i=0;i<n1;++i){            //开始依次从左侧顶点匹配;
        if(cx[i]==-1){                //从X集合中每个没有匹配的点出发开始寻找增广路;
            memset(mk,0,sizeof(mk));  //每个左侧顶点匹配之前都要初始化;
            res+=Listener::path(i);             //输出匹配成功个数,或者if(path(i)) res++   
        }
    }
    	return res;
}


/*************************************************************************************************************************************
													        主函数
*************************************************************************************************************************************/

int main(int argc, char **argv)
{
    ros::init(argc, argv, "listener");
	ros::NodeHandle nh;
	Listener listener(nh);
	ros::spin();
    return 0;
}
工作记录——7工作记录——7 罗宾酱 发布了11 篇原创文章 · 获赞 6 · 访问量 391 私信 关注
上一篇:【论文推荐】滤波嫁接 + 语义分割动态路由 + 基于对抗训练的自监督


下一篇:Linux网络服务