对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 融合矩形框的改进的更多相关文章
- Opencv在视频中静态、动态方式绘制矩形框ROI
Opencv视频处理中的目标跟踪经常用到要在视频上画一个矩形框ROI,标注出要跟踪的物体,这里介绍两种在视频中绘制矩形框的方法,一种是"静态的",一种是"动态的" ...
- OpenCV—Python 轮廓检测 绘出矩形框(findContours\ boundingRect\rectangle
千万注意opencv的轮廓检测和边缘检测是两码事 本文链接:https://blog.csdn.net/wsp_1138886114/article/details/82945328 1 获取轮廓 O ...
- C# GDI绘制矩形框,鼠标左键拖动可移动矩形框,滚轮放大缩小矩形框
最近工作需要,要做一个矩形框,并且 用鼠标左键拖动矩形框移动其位置.网上查了一些感觉他们做的挺复杂的.我自己研究一天,做了一个比较简单的,发表出来供大家参考一下.如觉得简单,可路过,谢谢.哈哈. 先大 ...
- 【python】PIL 批量绘制图片矩形框工具
工具采用PIL:Python Imaging Library,图像处理标准库.PIL功能非常强大,但API却非常简单易用. 安装PIL 在Debian/Ubuntu Linux下直接通过apt安装 $ ...
- 如何用 matlab 在图片上绘制矩形框 和 添加文字 ?
如何给图像添加矩形框?以及添加想要输入的文字 ? 案例程序,如下所示: clc; close all; clear all;image = imread('/home/wangxiao/Picture ...
- Android摄像头:只拍摄SurfaceView预览界面特定区域内容(矩形框)---完整(原理:底层SurfaceView+上层绘制ImageView)
Android摄像头:只拍摄SurfaceView预览界面特定区域内容(矩形框)---完整实现(原理:底层SurfaceView+上层绘制ImageView) 分类: Android开发 Androi ...
- c#在pictureBox控件上绘制多个矩形框及删除绘制的矩形框
在pictureBox上每次只绘制一个矩形框,绘制下一个矩形框时上次绘制的矩形框取消,代码如链接:https://www.cnblogs.com/luxiao/p/5625196.html 在绘制矩形 ...
- WPF 矩形框8个控制点伸缩及拖拽
最近在研发图片控件矩形框8个控制点进行控制边框的大小.位置等信息,之前查阅了相关的信息,比如别人整合的类:ControlResizer 这个类虽然是好,但是很大程度上是有限制,换句话说,它需要你二次更 ...
- Torch 两个矩形框重叠面积的计算 (IoU between tow bounding box)
Torch 两个矩形框重叠面积的计算 (IoU between tow bounding box) function DecideOberlap(BBox_x1, BBox_y1, BBox_x2, ...
随机推荐
- 线程系列08,实现线程锁的各种方式,使用lock,Montor,Mutex,Semaphore以及线程死锁
当涉及到多线程共享数据,需要数据同步的时候,就可以考虑使用线程锁了.本篇体验线程锁的各种用法以及线程死锁.主要包括: ※ 使用lock处理数据同步※ 使用Monitor.Enter和Monitor.E ...
- 实现观察者模式(Observer Pattern)的2种方式
在观察者模式中有2个要素:一个是被观察对象,另一个是观察者.但被观察对象的状态发生改变会通知观察者. 举例:把订阅报纸的人看作是观察者,把报纸看作被观察对象.每当有新的新闻就要通知订阅报纸的人.本篇分 ...
- https跳转到http的过程在IE6中存在BUG(Bea-090475)
前段时间做OA系统的https的安全登录功能(以前登录是采用的一般的http方式,后因为安全性考虑需要改成https的方式)在本机测试完全通过. 可是近期同事发现在测试环境下用IE6访问会出现不能访问 ...
- ubuntu下如何查看自己的外网IP
1.1 安装使用curl命令实现 sudo apt-get install curl1.2 输入命令 curl ifconfig.me
- 关于JAVA多线程并发synchronized的测试与合理使用
在项目开发中, 或许会碰到JAVA的多线程处理, 为保证业务数据的正常, 必须加上锁机制, 常用的处理方法一般是加上synchronized关键字, 目前JDK版本对synchronized已经做了 ...
- 【BZOJ】【2595】【WC2008】游览计划
Orz zky神犇http://blog.csdn.net/iamzky/article/details/42029921 spfa的灵活应用!(好像是求了一个叫做斯坦纳树的东西……) o(︶︿︶)o ...
- BZOJ 4145 [AMPPZ2014] The Prices 解题报告
感觉也是一个小清新题.. 我们考虑设立状态 $Dp[i][s]$ 表示考虑了前 $i$ 个商店后,购买状态为 $s$ 的最小花费. 转移的话就枚举每个商店 $i$,首先令: $$Dp[i][s] = ...
- CenoOS下如何对mysql编码进行配置
1 修改/etc/mysql/my.cnf配置文件 增加default-character-set=utf8 配置文件如下 [client] port = 3306 socket = /var/run ...
- [4] 圆锥(Cone)图形的生成算法
顶点数据的生成 bool YfBuildConeVertices ( Yreal radius, Yreal height, Yuint slices, YeOriginPose originPose ...
- evaluate-division
https://leetcode.com/problems/evaluate-division/ public class Solution { private Map mp; private cla ...