对opencv MeanShift 融合矩形框的改进

OPENCV 中的代码改进,当然要根据自己的实际情况来,OPENCV 中行人检测有两种矩形框的融合算法,这里只对meanshift 方法做改进

如果有更好的方法,希望可以跟我讲下。

对于去除重合部分,我也写了改进,看懂了可以加到自己程序中。

为什么要做局部MeanShift?

图1.全局MeanShift

如图所示:两幅图像距离较近且有多个矩形框,全局MeanShift融合后可能会造成这种结果

而如果用局部融合就能避免这种情况。

/*----------------------------------分数判定:begin--------------------------------------------------*/
		//////////////将感兴趣区域归一化后计算HOG特征--begin////////////////////
		 cvSetImageROI(imageOrigin,r);
		 IplImage *test=cvCreateImage(cvGetSize(imageOrigin),8,3);
		 cvCopyImage(imageOrigin,test);
		 cvResetImageROI(imageOrigin);
		 IplImage* testTempImg=cvCreateImage(cvSize(40,40),8,3);
		 cvZero(testTempImg);
		 cvResize(test,testTempImg);
		 hog->compute(testTempImg, descriptors,Size(1,1), Size(0,0)); //Hog特征计算
		 Mat another(descriptors);
		 descriptors.clear();
		////////////将感兴趣区域归一化后计算HOG特征--end///////////////
		 double ret = 0;
		  ret = ssvm.get_calc_liner(vec_count,var_count,a,another,results,alpha,0)-rho; //计算SVM分数
		 ////////////////////////////
		 cvReleaseImage(&test);
		 cvReleaseImage(&testTempImg);
		 ////////////////////////////
		  if(ret <0)
		 {
			continue;  //去掉SVM 分值小于0的图像
		 }

		 rc_.push_back(rcc);
		 weights.push_back(ret);
		 double rate = max(rcc.width*1.0/40,rcc.height*1.0/40);
		 //选取长宽最大值,作为尺度,考虑还不够周到,这里改变,Meanshift 全部都要改
		 //这里还可以改进
		 foundScales.push_back(rate);
/*----------------------------------分数判定:end--------------------------------------------------*/
//////////上述应该是一个循环,加入多个点//////////////

   /////////////////////////融合过程-begin////////////////////////////
	//vector<Rect> rc_;//矩形框
	//	vector<double> weights;//权重,score
	//	vector<double> foundScales;//放缩尺度
	groupRectangles_meanshift1(rc_, weights, foundScales, 0.3, Size(40,40)); //框出来的矩形框进行融合
	//groupRectangles_meanshift1该函数在最后定义//
	 ///////////////////////融合过程-end///////////////////////////

	//////////////////重合去重第一步:计算融合后的分值//////////////////
	for( i = 0; i < rc_.size(); i++ )

		{
		//加入矩形框
		Rect r = rc_[i];
		found_filtered.push_back(r);
		}
		vector<float> found_score(found_filtered.size()); //矩形框的分数
	for( i = 0; i < found_filtered.size(); i++ )

		{

		Rect r = found_filtered[i];

		//////////////////////////////////
		cvSetImageROI(imageOrigin,r);
		IplImage *test=cvCreateImage(cvGetSize(imageOrigin),8,3);
		cvCopyImage(imageOrigin,test);
		cvResetImageROI(imageOrigin);
		IplImage* testTempImg=cvCreateImage(cvSize(40,40),8,3);
		cvZero(testTempImg);
		cvResize(test,testTempImg);
		hog->compute(testTempImg, descriptors,Size(1,1), Size(0,0)); //Hog特征计算
		Mat another(descriptors);
		descriptors.clear();
		double ret = 0;
		ret= ssvm.get_calc_liner(vec_count,var_count,a,another,results,alpha,0)-rho;
		cvReleaseImage(&test);
		cvReleaseImage(&testTempImg);
		found_score[i]=ret;
		////////////////////////////
		}
	  ////////重合去重第二步:矩形框内的部分,取分值最大的/////
//////////////////////found_filtered为融合后的矩形框//////////////////////////
	for( i = 0; i < found_filtered.size(); i++ )

		    {
				//进行了重合去除,选取附近分值最大矩形框
		         Rect r = found_filtered[i];

		         for( j = 0; j < rc_.size(); j++ )

					 if( j != i && (r & found_filtered[j]).area() == r.area())
					{//这里是将重叠的部分,分值小的矩形框的权重设为-1,为了取最大值
		                if(found_score[i]>found_score[j])
						{
							found_score[j]=-1;
							break;
						}
						 else
						{
							 found_score[i]=-1;
							 break;
						}
					}

		    }
	   ////////重合去重第三步:重叠部分,取分值最大的/////
 //////////////////////////////////////////////////////////////////
	for( i = 0; i < found_filtered.size(); i++ )

		    {
				//进行了重合去除
		         Rect r = found_filtered[i];

		         for( j = 0; j < rc_.size(); j++ )
					//判定重合是否大于相较面积的70%(这个比例有待测试)
					//判定都为上一步过滤后的结果,可能存在部分相较,但不包含的情况
					 if( j != i && (r & found_filtered[j]).area() >= r.area()*0.7 &&found_score[j]!=-1&&found_score[i]!=-1)
					{//这里是将重叠的部分,分值小的矩形框的权重设为-1
		                		 if(found_score[i]>found_score[j])
						{
								 found_score[j]=-1;
								break;
						}

						 else
						{
							 found_score[i]=-1;
							 break;
						}
					}

		    }
		for(int i=0;i<found_filtered.size();i++)
			{
			  if (found_score[i]==-1)//将分值等于-1的过滤掉
			  {
				continue;
			  }
			 Rect r = found_filtered[i];

			r.x -= cvRound(r.width*0.05);

			r.width = cvRound(r.width*1.05);

			r.y -= cvRound(r.height*0.05);

			r.height = cvRound(r.height*1.05);

			rectangle(img_dst, r.tl(), r.br(), cv::Scalar(0,255,0), 2);	//在图像上画矩形框
			}

/*-----------------------MeanShift做局部的(源程序是对全局)------------------------*/
//meanshift 融合
class MeanshiftGrouping
{
public:
	//	 MeanshiftGrouping msGrouping(smothing, hits,rectList, hitWeights, 1e-5, 100);//得到
	///////////////////////////////////////////////////////////////////////
	//	 msGrouping.getModes(resultHits, resultWeights, 1);
	//////////////////////////////////////////////////////////////////////
	MeanshiftGrouping(const Point3d& densKer, const vector<Point3d>& posV,const vector<Rect>&list,
		const vector<double>& wV, double eps, int maxIter = 20)
		{
		densityKernel = densKer;
		weightsV = wV;
		positionsV = posV;
		positionsCount = (int)posV.size();
		meanshiftV.resize(positionsCount);
		distanceV.resize(positionsCount);
		iterMax = maxIter;
		modeEps = eps;

		for (unsigned i = 0; i<positionsV.size(); i++)
			{
			meanshiftV[i] = getNewValue(positionsV[i],list[i],list);//positionV 只有中点坐标没有长宽。
			distanceV[i] = moveToMode(meanshiftV[i],list[i],list);//做最大为iterMax次循环//均值漂移后的值
			meanshiftV[i] -= positionsV[i];//这一步后面没用到
			}
		}
	void getModes(vector<Point3d>& modesV, vector<double>& resWeightsV, const double eps)
		{
		for (size_t i=0; i <distanceV.size(); i++)
			{
			bool is_found = false;
			for(size_t j=0; j<modesV.size(); j++)
				{
				if ( getDistance(distanceV[i], modesV[j]) < eps)//欧式距离小于阈值
					{
					is_found=true;
					break;
					}
				}
			if (!is_found)
				{
				modesV.push_back(distanceV[i]);//添加距离较大的点,也就是说两个点距离较大,不是同一个矩形框
				}
			}

		resWeightsV.resize(modesV.size());

		for (size_t i=0; i<modesV.size(); i++)
			{
			resWeightsV[i] = getResultWeight(modesV[i]);//得到点的权值
			}
		}

protected:
	vector<Point3d> positionsV;
	vector<double> weightsV;

	Point3d densityKernel;
	int positionsCount;

	vector<Point3d> meanshiftV;
	vector<Point3d> distanceV;
	int iterMax;
	double modeEps;

	Point3d getNewValue(const Point3d& inPt ,const Rect inR ,const vector<Rect>list) const
		{//inPt 输入三维坐标 、inR 为输入的矩形  list为所有矩形
		Point3d resPoint(.0);
		Point3d ratPoint(.0);
		int value=20;//只考虑矩形框四个角差值小于20的点,这个可以自己设定
		for (size_t i=0; i<positionsV.size(); i++)
			{
			Point3d aPt= positionsV[i];
			// double rate = exp(aPt.z);
			if(inR.x -list[i].x>value||inR.y -list[i].y>value||inR.width -list[i].width>value||inR.height -list[i].height>value)
				continue;//局部判断,如果不是同一个矩形附近,将排除附近矩形的影响

			Point3d bPt = inPt;
			Point3d sPt = densityKernel;//核

			////////////////////////////////////////
			sPt.x *= exp(aPt.z);//Z为尺度
			sPt.y *= exp(aPt.z);

			aPt.x /= sPt.x;
			aPt.y /= sPt.y;
			aPt.z /= sPt.z;

			bPt.x /= sPt.x;
			bPt.y /= sPt.y;
			bPt.z /= sPt.z;
			///映射到对应尺度的图片的坐标/////////sPt为scale//反归一化
			////////////////////////////////////////////

			double w = (weightsV[i])*std::exp(-((aPt-bPt).dot(aPt-bPt))/2)/std::sqrt(sPt.dot(Point3d(1,1,1)));
			//重新计算的权重,原权重weightsV[i]为线性SVM的得分
			resPoint += w*aPt;//根据中心点的距离加相应的权值,距离越近,权值越大

			ratPoint.x += w/sPt.x;//这边除以权重值,使得放缩后的图像权重变小
			ratPoint.y += w/sPt.y;
			ratPoint.z += w/sPt.z;

			}
		resPoint.x /= ratPoint.x;
		resPoint.y /= ratPoint.y;
		resPoint.z /= ratPoint.z;
		return resPoint;//返回被周围点影响后的值
		}

	double getResultWeight(const Point3d& inPt) const
		{
		double sumW=0;//最终返回的值
		int num=0;
		size_t aa=positionsV.size();//位置点的个数
		int len = int(aa);//位置点的个数
		for (size_t i=0; i<aa; i++)
			{
			Point3d aPt = positionsV[i];
			Point3d sPt = densityKernel;

			sPt.x *= exp(aPt.z);
			sPt.y *= exp(aPt.z);

			aPt -= inPt;//讲个坐标之差

			aPt.x /= sPt.x;
			aPt.y /= sPt.y;
			aPt.z /= sPt.z;
			/*-----------------这块还可以优化,策略的考虑,权重的选取--begin-----------------*/
			if(aa>10)//考虑如果aa的数量过小时
				{
				double mm = aPt.dot(aPt);

				if(aPt.dot(aPt)<=0.5)//两个点的欧式距离
					{

					if(weightsV[i]>0.6)//weightsV[i] 为svm的权值
						{
						sumW+=0.35;
						}
					else if(weightsV[i]>0.3)
						{
						sumW+=0.3;
						}
					continue;
					}
				//////////////////////////原始///////////
				sumW+=(weightsV[i])*std::exp(-(aPt.dot(aPt))/2)/std::sqrt(sPt.dot(Point3d(1,1,1)));
				/////////////////////////////////////////
				}
			else
				{
				//sumW+=weightsV[i];
				sumW+=(weightsV[i])*std::exp(-(aPt.dot(aPt))/2)*2.8;

				}
			/*---------待优化部分-----------------*/
			/*------这块还可以优化,策略的考虑,权重的选取--end------*/

			return sumW;//计算最后的权值
			}

		Point3d moveToMode(Point3d aPt ,Rect inR, const vector<Rect>list) const
			{//均值漂移后的位置
			Point3d bPt;
			for (int i = 0; i<iterMax; i++)
				{
				bPt = aPt;
				aPt = getNewValue(bPt,inR,list);
				if ( getDistance(aPt, bPt) <= modeEps )//小于阈值时返回,说明达到稳定状态
					{
					break;
					}
				}
			return aPt;//返回稳定状态的值
			}

		double getDistance(Point3d p1, Point3d p2) const
			{//计算欧式距离
			Point3d ns = densityKernel;
			ns.x *= exp(p2.z);
			ns.y *= exp(p2.z);
			p2 -= p1;
			p2.x /= ns.x;
			p2.y /= ns.y;
			p2.z /= ns.z;
			return p2.dot(p2);
			}
		};

	void groupRectangles_meanshift2(vector<Rect>& rectList, double detectThreshold, vector<double>* foundWeights,
		vector<double>& scales, Size winDetSize)
		//被groupRectangles_meanshift1调用
		{
		int detectionCount = (int)rectList.size();//矩形的个数
		vector<Point3d> hits(detectionCount), resultHits;
		vector<double> hitWeights(detectionCount), resultWeights;
		Point2d hitCenter;

		for (int i=0; i < detectionCount; i++)
			{
			hitWeights[i] = (*foundWeights)[i];
			hitCenter = (rectList[i].tl() + rectList[i].br())*(0.5); //center of rectangles
			hits[i] = Point3d(hitCenter.x, hitCenter.y, std::log(scales[i]));//中心坐标x、y、log(scale)
			}

		if (foundWeights)
			foundWeights->clear();

		double logZ = std::log(1.3);
		Point3d smothing(8, 16, logZ);

		MeanshiftGrouping msGrouping(smothing, hits,rectList, hitWeights, 1e-5, 100);//得到
		///////////////////////////////////////////////////////////////////////
		msGrouping.getModes(resultHits, resultWeights, 1);
		//////////////////////////////////////////////////////////////////////

		rectList.clear();
		for (unsigned i=0; i < resultHits.size(); ++i)
			{

			double scale = exp(resultHits[i].z);//还原尺度
			hitCenter.x = resultHits[i].x;//中心坐标
			hitCenter.y = resultHits[i].y;
			Size s( int(winDetSize.width*scale), int(winDetSize.height*scale) );//还原窗的大小
			Rect resultRect( int(hitCenter.x-s.width/2), int(hitCenter.y-s.height/2),
				int(s.width), int(s.height) );//还原窗的位置

			if (resultWeights[i] > detectThreshold)//detectThreshold 大于阈值的权重值输出
				{//返回矩形框  和  权值
				rectList.push_back(resultRect);
				foundWeights->push_back(resultWeights[i]);
				}
			}
		}

	void groupRectangles_meanshift1(vector<Rect>& rectList, vector<double>& foundWeights,
		vector<double>& foundScales, double detectThreshold, Size winDetSize)
		{
		groupRectangles_meanshift2(rectList, detectThreshold, &foundWeights, foundScales, winDetSize);
		//rectList矩形列表, detectThreshold阈值, foundWeights得分, foundScales尺度, winDetSize窗口大小
		}

对opencv MeanShift 融合矩形框的改进,布布扣,bubuko.com

时间: 2024-10-13 10:21:00

对opencv MeanShift 融合矩形框的改进的相关文章

vector&lt;Rect&gt;矩形框聚合拟合

groupRectangle函数实现矩形框聚合.原因:多尺度检测后,获取的矩形之间会存在重合.重叠和包含关系.因尺度缩放,可能导致同一个目标在多个尺度上被检测出来,故有必要进行融合.OpenCV中实现的融合有两种:1)按权重合并:2)使用Meanshift算法进行合并. 下面是简单的合并,其直接按照位置和大小关系进行合并. 其实现主要为:1)多所有矩形按照大小位置合并成不同的类别: 2)将同类别中的矩形合并成一个矩形,当不满足给出阈值条件时,矩形被舍弃,否则留下. partition函数详解 t

实现在矩形框中输入文字,可以显示剩余字数的功能

如下图: 要实现上面的功能,需要做到三点: 1.实现矩形框布局 思路就是矩形框作为整个布局的一个background,在drawable中创建一个shap.xml样式文件 <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"     android:shape="r

GreenOpenPaint的实现(五)矩形框

想显示一副图片相对来说比较容易.但是想在SDI中显示一个可以拖拽的矩形框,并且在滚动和缩放下都不变形,是很困难的. MFC应该说在这个方面提供了强大的支持,但是也有一些是由于历史的原因需要去除的地方,特别是在缩放的这个地方还存在一些问题. 我认为关键是形成知识的框架,这样面对未来的需求就能够灵活应变. 这里,我结合GreenOpenPaint的具体实现进行总结. 我总结了一下,有几点: 1.肯定是要为这个矩形生成专门的类.这个类的实现,需要在DOC中,因为DOC就是用来管理所有的模型的:那么注意

Torch 两个矩形框重叠面积的计算 (IoU between tow bounding box)

Torch 两个矩形框重叠面积的计算 (IoU between tow bounding box) 1 function DecideOberlap(BBox_x1, BBox_y1, BBox_x2, BBox_y2, BBox_gt_x1, BBox_gt_y1, BBox_gt_x2, BBox_gt_y2) 2 3 x1 = BBox_x1; 4 y1 = BBox_y1; 5 width1 = BBox_x2 - BBox_x1; 6 height1 = BBox_y2 - BBox_

HDU 3265 Posters(线段树扫描线&#183;矩形框面积并)

题意  把一些矩形海报挖去一部分小矩形贴在指定位置  问最后海报覆盖的面积 一个矩形框可以分割成4个独立的小矩形  然后就能用扫描线求面积并了 #include <cstdio> #include <algorithm> using namespace std; const int N = 100005, M = N << 2; typedef long long ll; struct SLine { int x, y1, y2, flag; SLine() {}; S

Skyline实现橡皮筋效果绘制矩形框

这种类似于框选的效果用的比较普遍,一般三维平台和GIS平台都提供了支持接口,可是Skyline就是这么傲娇! 思路是这样的:绘制出的矩形框应该是一直与屏幕边框平行的,也就是矩形框的实际旋转角度是等于摄像机的偏移角YAW值的,这样我们只要知道矩形的宽度,用矩形的两个对角点沿摄像机方向或者沿摄像机反方向延长一个宽度的距离就能得到矩形的另外两个点了.这个宽度利用两个对角点的距离和摄像机偏移角度很容易就能算出来,就不赘叙了. 最核心的代码就是正确计算矩形对角线与水平方向的夹角了: 1 //计算矩形对角点

用canvas实现鼠标拖动绘制矩形框

需要用到jCanvas插件和jQuery. jCanvas下载:https://raw.githubusercontent.com/caleb531/jcanvas/master/jcanvas.min.js 代码如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>鼠标拖动绘制矩形框(canvas)</ti

【python】PIL 批量绘制图片矩形框工具

工具采用PIL:Python Imaging Library,图像处理标准库.PIL功能非常强大,但API却非常简单易用. 安装PIL 在Debian/Ubuntu Linux下直接通过apt安装 $ sudo apt-get install python-imaging Windows平台直接通过pip安装 pip install pillow 批量工具脚本 默认执行方式为:              执行脚本命令 python drawline.py           1.获取当前路径下的

Android摄像头:只拍摄SurfaceView预览界面特定区域内容(矩形框)---完整(原理:底层SurfaceView+上层绘制ImageView)

Android摄像头:只拍摄SurfaceView预览界面特定区域内容(矩形框)---完整实现(原理:底层SurfaceView+上层绘制ImageView) 分类: Android开发 Android UI2013-05-23 15:04 1600人阅读 评论(1) 收藏 举报 目录(?)[+] http://blog.csdn.net/yanzi1225627/article/details/8580034 最近一直在审视以前做过的东西,关于android摄像头预览,预览界面上呈现矩形框,在