用java实现均值偏移(Mean-Shift)算法

20 篇文章 0 订阅
18 篇文章 0 订阅

我们首先了解一下什么是均值偏移(Mean-Shift)算法,如下:

均值偏移(mean shift,也叫均值漂移或均值平移)这个概念最早是由Fukunaga等人于1975年在《The estimation of the gradient of a density function with application in pattern recognitioin》这篇关于概率密度梯度函数的估计中提出来的,其最初含义正如其名,就是偏移的均值向量。 它是一种无参估计算法,沿着概率梯度的上升方向寻找分布的峰值。

然而在以后的很长一段时间内mean shift并没有引起人们的注意,直到20年以后,也就是1995年,另外一篇关于Mean shift的重要文献《Mean shift analysis and application》才发表。在这篇重要的文献中,Yizong cheng对基本Mean shift算法在以下两个方面做了推广,首先定义了一族核函数,使得随着样本与被偏移点的距离不同,其偏移量对均值偏移向量的贡献也不同,其次设定了一个权重系数,使得不同的样本点重要性不一样,这大大扩大了Mean shift的适用范围。直到1998年Bradski将MeanShift算法用于人脸的跟踪才使得此算法的优势在目标跟踪领域体现出来。

MeanShift算法是一种无参概率密度估计法,算法利用像素特征点概率密度函数的梯度推导而得, MeanShift算法通过迭代运算收敛于概率密度函数的局部最大值,实现目标定位和跟踪,也能对可变形状目标实时跟踪,对目标的变形,旋转等运动也有较强的鲁棒性。MeanShift算法是一种自动迭代跟踪算法,由 MeanShift补偿向量不断沿着密度函数的梯度方向移动。在一定条件下,MeanShift算法能收敛到局部最优点,从而实现对运动体准确地定位。

均值平移算法是一种非参数的统计迭代算法。

该算法可以使用在运动跟踪方面上。

我们现在开始用java实现,如下:

首先是计算欧式距离

//计算欧式距离
	private static double countDistance(double[] p1,double[] p2) {
		
		double sum=0;
		
		for(int i=0;i<p1.length;i++)
			sum+=Math.pow(p1[i]-p2[i],2);
		
		return Math.sqrt(sum);
	}

然后是随机抽取向量

//随机抽取向量
	private static double[] randomVector(DenseMatrix64F src) {
		
		double[] rs = new double[src.numCols];
		
		Random r=new Random();
		
		int inx = r.nextInt(src.numRows);
		
		for(int i=0;i<src.numCols;i++) {
			rs[i] = src.get(inx,i);
		}
		
		
		return rs;
	}

然后是筛选指定向量指定半径内的所有向量

private static DenseMatrix64F findDatasInCircle(DenseMatrix64F src,double[] p,double r) {
		
		DenseMatrix64F rs = new DenseMatrix64F(0,src.numCols);
		
		for(int i=0;i<src.numRows;i++) {
			
			double[] tmp = new double[src.numCols];
			
			for(int j=0;j<src.numCols;j++)
				tmp[j]=src.get(i, j);
			
			if(countDistance(p,tmp) <= r) {
				rs.reshape(rs.numRows+1, src.numCols, true);
				for(int j=0;j<src.numCols;j++)
					rs.set(rs.numRows-1, j, src.get(i, j));
			}
		}
		
		return rs;
	}

然后是计算新的向量叠加

private static double[] countVectorSuperposition(DenseMatrix64F src) {
		
		double[] rs = new double[src.numCols];
		
		for(int i=0;i<src.numCols;i++) {
			
			double tmp = 0;
			
			for(int j=0;j<src.numRows;j++)
				tmp+=src.get(j,i);
			
			rs[i] = tmp;
			
		}
		
		return rs;
	}

然后是主方法

public static double[] meanShift(DenseMatrix64F dataSet,double r) {
		
		
		//随机选取向量
		double[] rs = randomVector(dataSet);
		
		double diff = Double.MAX_VALUE;
		
		double change = Double.MAX_VALUE;
	
		
		//开始迭代
		while(diff > 0 && change != 0) {
			
			//筛选半径内所有向量
			DenseMatrix64F subVectors = findDatasInCircle(dataSet,rs,r);
			
			//计算向量叠加
			double[] sumVectors  = countVectorSuperposition(subVectors);
			
			
			//计算目标向量
			double vCount = countDistance(rs,sumVectors);
			
			change = vCount-diff;
			
			diff = vCount;
			
			System.out.println("diff :"+diff);
			
			//更新圆心向量
			rs = sumVectors;
		}
		
		
		
		return rs;
		

	}

ok现在开始测试

List<String> list = new ArrayList<String>();
        try{
            BufferedReader br = new BufferedReader(new FileReader("D:\\test.txt"));
            String s = null;
            while((s = br.readLine())!=null){
            	list.add(s);
            }
            br.close();    
        }catch(Exception e){
            e.printStackTrace();
        }
        
        DenseMatrix64F dataMatIn = new DenseMatrix64F(list.size(),2);

        for(int i=0;i<list.size();i++) {
        	
        	String[] items = list.get(i).split("	");
        	dataMatIn.set(i, 0, Double.parseDouble(items[0]));
        	dataMatIn.set(i,1, Double.parseDouble(items[1]));
        }
        
        System.out.println(meanShift(dataMatIn,2));

测试结果如下:

向量最终不再变化

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路边草随风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值