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

假设有更好的方法。希望能够跟我讲下。

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

为什么要做局部MeanShift?

图1.全局MeanShift

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

而假设用局部融合就能避免这样的情况。

  1. /*----------------------------------分数判定:begin--------------------------------------------------*/
  2. //////////////将感兴趣区域归一化后计算HOG特征--begin////////////////////
  3. cvSetImageROI(imageOrigin,r);
  4. IplImage *test=cvCreateImage(cvGetSize(imageOrigin),8,3);
  5. cvCopyImage(imageOrigin,test);
  6. cvResetImageROI(imageOrigin);
  7. IplImage* testTempImg=cvCreateImage(cvSize(40,40),8,3);
  8. cvZero(testTempImg);
  9. cvResize(test,testTempImg);
  10. hog->compute(testTempImg, descriptors,Size(1,1), Size(0,0)); //Hog特征计算
  11. Mat another(descriptors);
  12. descriptors.clear();
  13. ////////////将感兴趣区域归一化后计算HOG特征--end///////////////
  14. double ret = 0;
  15. ret = ssvm.get_calc_liner(vec_count,var_count,a,another,results,alpha,0)-rho; //计算SVM分数
  16. ////////////////////////////
  17. cvReleaseImage(&test);
  18. cvReleaseImage(&testTempImg);
  19. ////////////////////////////
  20. if(ret <0)
  21. {
  22. continue; //去掉SVM 分值小于0的图像
  23. }
  24.  
  25. rc_.push_back(rcc);
  26. weights.push_back(ret);
  27. double rate = max(rcc.width*1.0/40,rcc.height*1.0/40);
  28. //选取长宽最大值,作为尺度,考虑还不够周到,这里改变。Meanshift 所有都要改
  29. //这里还能够改进
  30. foundScales.push_back(rate);
  31. /*----------------------------------分数判定:end--------------------------------------------------*/
  32. //////////上述应该是一个循环,增加多个点//////////////
  33.  
  34. /////////////////////////融合过程-begin////////////////////////////
  35. //vector<Rect> rc_;//矩形框
  36. // vector<double> weights;//权重,score
  37. // vector<double> foundScales;//放缩尺度
  38. groupRectangles_meanshift1(rc_, weights, foundScales, 0.3, Size(40,40)); //框出来的矩形框进行融合
  39. //groupRectangles_meanshift1该函数在最后定义//
  40. ///////////////////////融合过程-end///////////////////////////
  41.  
  42. //////////////////重合去重第一步:计算融合后的分值//////////////////
  43. for( i = 0; i < rc_.size(); i++ )
  44.  
  45. {
  46. //增加矩形框
  47. Rect r = rc_[i];
  48. found_filtered.push_back(r);
  49. }
  50. vector<float> found_score(found_filtered.size()); //矩形框的分数
  51. for( i = 0; i < found_filtered.size(); i++ )
  52.  
  53. {
  54.  
  55. Rect r = found_filtered[i];
  56.  
  57. //////////////////////////////////
  58. cvSetImageROI(imageOrigin,r);
  59. IplImage *test=cvCreateImage(cvGetSize(imageOrigin),8,3);
  60. cvCopyImage(imageOrigin,test);
  61. cvResetImageROI(imageOrigin);
  62. IplImage* testTempImg=cvCreateImage(cvSize(40,40),8,3);
  63. cvZero(testTempImg);
  64. cvResize(test,testTempImg);
  65. hog->compute(testTempImg, descriptors,Size(1,1), Size(0,0)); //Hog特征计算
  66. Mat another(descriptors);
  67. descriptors.clear();
  68. double ret = 0;
  69. ret= ssvm.get_calc_liner(vec_count,var_count,a,another,results,alpha,0)-rho;
  70. cvReleaseImage(&test);
  71. cvReleaseImage(&testTempImg);
  72. found_score[i]=ret;
  73. ////////////////////////////
  74. }
  75. ////////重合去重第二步:矩形框内的部分。取分值最大的/////
  76. //////////////////////found_filtered为融合后的矩形框//////////////////////////
  77. for( i = 0; i < found_filtered.size(); i++ )
  78.  
  79. {
  80. //进行了重合去除,选取附近分值最大矩形框
  81. Rect r = found_filtered[i];
  82.  
  83. for( j = 0; j < rc_.size(); j++ )
  84.  
  85. if( j != i && (r & found_filtered[j]).area() == r.area())
  86. {//这里是将重叠的部分,分值小的矩形框的权重设为-1,为了取最大值
  87. if(found_score[i]>found_score[j])
  88. {
  89. found_score[j]=-1;
  90. break;
  91. }
  92. else
  93. {
  94. found_score[i]=-1;
  95. break;
  96. }
  97. }
  98.  
  99. }
  100. ////////重合去重第三步:重叠部分。取分值最大的/////
  101. //////////////////////////////////////////////////////////////////
  102. for( i = 0; i < found_filtered.size(); i++ )
  103.  
  104. {
  105. //进行了重合去除
  106. Rect r = found_filtered[i];
  107.  
  108. for( j = 0; j < rc_.size(); j++ )
  109. //判定重合是否大于相较面积的70%(这个比例有待測试)
  110. //判定都为上一步过滤后的结果,可能存在部分相较。但不包括的情况
  111. if( j != i && (r & found_filtered[j]).area() >= r.area()*0.7 &&found_score[j]!=-1&&found_score[i]!=-1)
  112. {//这里是将重叠的部分,分值小的矩形框的权重设为-1
  113. if(found_score[i]>found_score[j])
  114. {
  115. found_score[j]=-1;
  116. break;
  117. }
  118.  
  119. else
  120. {
  121. found_score[i]=-1;
  122. break;
  123. }
  124. }
  125.  
  126. }
  127. for(int i=0;i<found_filtered.size();i++)
  128. {
  129. if (found_score[i]==-1)//将分值等于-1的过滤掉
  130. {
  131. continue;
  132. }
  133. Rect r = found_filtered[i];
  134.  
  135. r.x -= cvRound(r.width*0.05);
  136.  
  137. r.width = cvRound(r.width*1.05);
  138.  
  139. r.y -= cvRound(r.height*0.05);
  140.  
  141. r.height = cvRound(r.height*1.05);
  142.  
  143. rectangle(img_dst, r.tl(), r.br(), cv::Scalar(0,255,0), 2); //在图像上画矩形框
  144. }
  145.  
  146. /*-----------------------MeanShift做局部的(源程序是对全局)------------------------*/
  147. //meanshift 融合
  148. class MeanshiftGrouping
  149. {
  150. public:
  151. // MeanshiftGrouping msGrouping(smothing, hits,rectList, hitWeights, 1e-5, 100);//得到
  152. ///////////////////////////////////////////////////////////////////////
  153. // msGrouping.getModes(resultHits, resultWeights, 1);
  154. //////////////////////////////////////////////////////////////////////
  155. MeanshiftGrouping(const Point3d& densKer, const vector<Point3d>& posV,const vector<Rect>&list,
  156. const vector<double>& wV, double eps, int maxIter = 20)
  157. {
  158. densityKernel = densKer;
  159. weightsV = wV;
  160. positionsV = posV;
  161. positionsCount = (int)posV.size();
  162. meanshiftV.resize(positionsCount);
  163. distanceV.resize(positionsCount);
  164. iterMax = maxIter;
  165. modeEps = eps;
  166.  
  167. for (unsigned i = 0; i<positionsV.size(); i++)
  168. {
  169. meanshiftV[i] = getNewValue(positionsV[i],list[i],list);//positionV 仅仅有中点坐标没有长宽。
  170.  
  171. distanceV[i] = moveToMode(meanshiftV[i],list[i],list);//做最大为iterMax次循环//均值漂移后的值
  172. meanshiftV[i] -= positionsV[i];//这一步后面没用到
  173. }
  174. }
  175. void getModes(vector<Point3d>& modesV, vector<double>& resWeightsV, const double eps)
  176. {
  177. for (size_t i=0; i <distanceV.size(); i++)
  178. {
  179. bool is_found = false;
  180. for(size_t j=0; j<modesV.size(); j++)
  181. {
  182. if ( getDistance(distanceV[i], modesV[j]) < eps)//欧式距离小于阈值
  183. {
  184. is_found=true;
  185. break;
  186. }
  187. }
  188. if (!is_found)
  189. {
  190. modesV.push_back(distanceV[i]);//增加距离较大的点,也就是说两个点距离较大。不是同一个矩形框
  191. }
  192. }
  193.  
  194. resWeightsV.resize(modesV.size());
  195.  
  196. for (size_t i=0; i<modesV.size(); i++)
  197. {
  198. resWeightsV[i] = getResultWeight(modesV[i]);//得到点的权值
  199. }
  200. }
  201.  
  202. protected:
  203. vector<Point3d> positionsV;
  204. vector<double> weightsV;
  205.  
  206. Point3d densityKernel;
  207. int positionsCount;
  208.  
  209. vector<Point3d> meanshiftV;
  210. vector<Point3d> distanceV;
  211. int iterMax;
  212. double modeEps;
  213.  
  214. Point3d getNewValue(const Point3d& inPt ,const Rect inR ,const vector<Rect>list) const
  215. {//inPt 输入三维坐标 、inR 为输入的矩形 list为所有矩形
  216. Point3d resPoint(.0);
  217. Point3d ratPoint(.0);
  218. int value=20;//仅仅考虑矩形框四个角差值小于20的点。这个能够自己设定
  219. for (size_t i=0; i<positionsV.size(); i++)
  220. {
  221. Point3d aPt= positionsV[i];
  222. // double rate = exp(aPt.z);
  223. 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)
  224. continue;//局部推断,假设不是同一个矩形附近,将排除附近矩形的影响
  225.  
  226. Point3d bPt = inPt;
  227. Point3d sPt = densityKernel;//核
  228.  
  229. ////////////////////////////////////////
  230. sPt.x *= exp(aPt.z);//Z为尺度
  231. sPt.y *= exp(aPt.z);
  232.  
  233. aPt.x /= sPt.x;
  234. aPt.y /= sPt.y;
  235. aPt.z /= sPt.z;
  236.  
  237. bPt.x /= sPt.x;
  238. bPt.y /= sPt.y;
  239. bPt.z /= sPt.z;
  240. ///映射到相应尺度的图片的坐标/////////sPt为scale//反归一化
  241. ////////////////////////////////////////////
  242.  
  243. double w = (weightsV[i])*std::exp(-((aPt-bPt).dot(aPt-bPt))/2)/std::sqrt(sPt.dot(Point3d(1,1,1)));
  244. //又一次计算的权重,原权重weightsV[i]为线性SVM的得分
  245. resPoint += w*aPt;//依据中心点的距离加相应的权值,距离越近,权值越大
  246.  
  247. ratPoint.x += w/sPt.x;//这边除以权重值,使得放缩后的图像权重变小
  248. ratPoint.y += w/sPt.y;
  249. ratPoint.z += w/sPt.z;
  250.  
  251. }
  252. resPoint.x /= ratPoint.x;
  253. resPoint.y /= ratPoint.y;
  254. resPoint.z /= ratPoint.z;
  255. return resPoint;//返回被周围点影响后的值
  256. }
  257.  
  258. double getResultWeight(const Point3d& inPt) const
  259. {
  260. double sumW=0;//终于返回的值
  261. int num=0;
  262. size_t aa=positionsV.size();//位置点的个数
  263. int len = int(aa);//位置点的个数
  264. for (size_t i=0; i<aa; i++)
  265. {
  266. Point3d aPt = positionsV[i];
  267. Point3d sPt = densityKernel;
  268.  
  269. sPt.x *= exp(aPt.z);
  270. sPt.y *= exp(aPt.z);
  271.  
  272. aPt -= inPt;//讲个坐标之差
  273.  
  274. aPt.x /= sPt.x;
  275. aPt.y /= sPt.y;
  276. aPt.z /= sPt.z;
  277. /*-----------------这块还能够优化,策略的考虑,权重的选取--begin-----------------*/
  278. if(aa>10)//考虑假设aa的数量过小时
  279. {
  280. double mm = aPt.dot(aPt);
  281.  
  282. if(aPt.dot(aPt)<=0.5)//两个点的欧式距离
  283. {
  284.  
  285. if(weightsV[i]>0.6)//weightsV[i] 为svm的权值
  286. {
  287. sumW+=0.35;
  288. }
  289. else if(weightsV[i]>0.3)
  290. {
  291. sumW+=0.3;
  292. }
  293. continue;
  294. }
  295. //////////////////////////原始///////////
  296. sumW+=(weightsV[i])*std::exp(-(aPt.dot(aPt))/2)/std::sqrt(sPt.dot(Point3d(1,1,1)));
  297. /////////////////////////////////////////
  298. }
  299. else
  300. {
  301. //sumW+=weightsV[i];
  302. sumW+=(weightsV[i])*std::exp(-(aPt.dot(aPt))/2)*2.8;
  303.  
  304. }
  305. /*---------待优化部分-----------------*/
  306. /*------这块还能够优化。策略的考虑,权重的选取--end------*/
  307.  
  308. return sumW;//计算最后的权值
  309. }
  310.  
  311. Point3d moveToMode(Point3d aPt ,Rect inR, const vector<Rect>list) const
  312. {//均值漂移后的位置
  313. Point3d bPt;
  314. for (int i = 0; i<iterMax; i++)
  315. {
  316. bPt = aPt;
  317. aPt = getNewValue(bPt,inR,list);
  318. if ( getDistance(aPt, bPt) <= modeEps )//小于阈值时返回,说明达到稳定状态
  319. {
  320. break;
  321. }
  322. }
  323. return aPt;//返回稳定状态的值
  324. }
  325.  
  326. double getDistance(Point3d p1, Point3d p2) const
  327. {//计算欧式距离
  328. Point3d ns = densityKernel;
  329. ns.x *= exp(p2.z);
  330. ns.y *= exp(p2.z);
  331. p2 -= p1;
  332. p2.x /= ns.x;
  333. p2.y /= ns.y;
  334. p2.z /= ns.z;
  335. return p2.dot(p2);
  336. }
  337. };
  338.  
  339. void groupRectangles_meanshift2(vector<Rect>& rectList, double detectThreshold, vector<double>* foundWeights,
  340. vector<double>& scales, Size winDetSize)
  341. //被groupRectangles_meanshift1调用
  342. {
  343. int detectionCount = (int)rectList.size();//矩形的个数
  344. vector<Point3d> hits(detectionCount), resultHits;
  345. vector<double> hitWeights(detectionCount), resultWeights;
  346. Point2d hitCenter;
  347.  
  348. for (int i=0; i < detectionCount; i++)
  349. {
  350. hitWeights[i] = (*foundWeights)[i];
  351. hitCenter = (rectList[i].tl() + rectList[i].br())*(0.5); //center of rectangles
  352. hits[i] = Point3d(hitCenter.x, hitCenter.y, std::log(scales[i]));//中心坐标x、y、log(scale)
  353. }
  354.  
  355. if (foundWeights)
  356. foundWeights->clear();
  357.  
  358. double logZ = std::log(1.3);
  359. Point3d smothing(8, 16, logZ);
  360.  
  361. MeanshiftGrouping msGrouping(smothing, hits,rectList, hitWeights, 1e-5, 100);//得到
  362. ///////////////////////////////////////////////////////////////////////
  363. msGrouping.getModes(resultHits, resultWeights, 1);
  364. //////////////////////////////////////////////////////////////////////
  365.  
  366. rectList.clear();
  367. for (unsigned i=0; i < resultHits.size(); ++i)
  368. {
  369.  
  370. double scale = exp(resultHits[i].z);//还原尺度
  371. hitCenter.x = resultHits[i].x;//中心坐标
  372. hitCenter.y = resultHits[i].y;
  373. Size s( int(winDetSize.width*scale), int(winDetSize.height*scale) );//还原窗的大小
  374. Rect resultRect( int(hitCenter.x-s.width/2), int(hitCenter.y-s.height/2),
  375. int(s.width), int(s.height) );//还原窗的位置
  376.  
  377. if (resultWeights[i] > detectThreshold)//detectThreshold 大于阈值的权重值输出
  378. {//返回矩形框 和 权值
  379. rectList.push_back(resultRect);
  380. foundWeights->push_back(resultWeights[i]);
  381. }
  382. }
  383. }
  384.  
  385. void groupRectangles_meanshift1(vector<Rect>& rectList, vector<double>& foundWeights,
  386. vector<double>& foundScales, double detectThreshold, Size winDetSize)
  387. {
  388. groupRectangles_meanshift2(rectList, detectThreshold, &foundWeights, foundScales, winDetSize);
  389. //rectList矩形列表, detectThreshold阈值, foundWeights得分, foundScales尺度, winDetSize窗体大小
  390. }

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

  1. Opencv在视频中静态、动态方式绘制矩形框ROI

    Opencv视频处理中的目标跟踪经常用到要在视频上画一个矩形框ROI,标注出要跟踪的物体,这里介绍两种在视频中绘制矩形框的方法,一种是"静态的",一种是"动态的" ...

  2. OpenCV—Python 轮廓检测 绘出矩形框(findContours\ boundingRect\rectangle

    千万注意opencv的轮廓检测和边缘检测是两码事 本文链接:https://blog.csdn.net/wsp_1138886114/article/details/82945328 1 获取轮廓 O ...

  3. C# GDI绘制矩形框,鼠标左键拖动可移动矩形框,滚轮放大缩小矩形框

    最近工作需要,要做一个矩形框,并且 用鼠标左键拖动矩形框移动其位置.网上查了一些感觉他们做的挺复杂的.我自己研究一天,做了一个比较简单的,发表出来供大家参考一下.如觉得简单,可路过,谢谢.哈哈. 先大 ...

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

    工具采用PIL:Python Imaging Library,图像处理标准库.PIL功能非常强大,但API却非常简单易用. 安装PIL 在Debian/Ubuntu Linux下直接通过apt安装 $ ...

  5. 如何用 matlab 在图片上绘制矩形框 和 添加文字 ?

    如何给图像添加矩形框?以及添加想要输入的文字 ? 案例程序,如下所示: clc; close all; clear all;image = imread('/home/wangxiao/Picture ...

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

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

  7. c#在pictureBox控件上绘制多个矩形框及删除绘制的矩形框

    在pictureBox上每次只绘制一个矩形框,绘制下一个矩形框时上次绘制的矩形框取消,代码如链接:https://www.cnblogs.com/luxiao/p/5625196.html 在绘制矩形 ...

  8. WPF 矩形框8个控制点伸缩及拖拽

    最近在研发图片控件矩形框8个控制点进行控制边框的大小.位置等信息,之前查阅了相关的信息,比如别人整合的类:ControlResizer 这个类虽然是好,但是很大程度上是有限制,换句话说,它需要你二次更 ...

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

    Torch 两个矩形框重叠面积的计算 (IoU between tow bounding box) function DecideOberlap(BBox_x1, BBox_y1, BBox_x2, ...

随机推荐

  1. C++STL源代码学习(之slist篇)

    ///stl_slist.h ///list为双向循环链表,slist为单向链表.某些操作效率更高 ///slist是SGI额外提供的单向链表,不属于C++标准 struct _Slist_node_ ...

  2. transform,transition,animation 的混合使用——进阶

    今天我们来讲述css3能够做成动画的最小独立单元,并且讲述如何使用这些独立的单元来构成一个‘高大尚’的组合动画. 这是我在网上找的一个案例,修改后的效果图,虽说不是特别的‘高大尚’,但我认为这也跟高大 ...

  3. .Net高级技术——垃圾收集器

    垃圾收集器概述 大排档和学校食堂.一个是别人帮你收拾盘子,一个是自己收拾盘子. 垃圾收集GC(Garbage Collection).内存的分配.回收不需要程序员操心,程序员只要需要的时候new就可以 ...

  4. java zxing实现二维码生成和解析zxing实现二维码生成和解析

    原文:https://www.cnblogs.com/zhangzhen894095789/p/6623041.html zxing实现二维码生成和解析   二维码 zxing   二维码的生成与解析 ...

  5. python笔记28-lxml.etree爬取html内容

    前言 本篇继续lxml.etree学习,在线访问接口,通过接口返回的html,解析出想要的text文本内容 环境准备: python 3.6 lxml requets 定位目标 爬取我的博客首页htt ...

  6. 单点登录 之 OAuth

    OAuth2.0是什么 OAuth2.0是什么——豆瓣和QQ的故事 OAuth简单说就是一种授权的协议,只要授权方和被授权方遵守这个协议去写代码提供服务,那双方就是实现了OAuth模式. 举个例子,你 ...

  7. [runtime] iOS-Runtime-Headers

    Dynamically Generated iOS Headers https://github.com/nst/iOS-Runtime-Headers Here are iOS Objective- ...

  8. tomcat sso 配置

    源: http://www.oecp.cn/hi/single/blog/349 为了实现单点登录,做了个CAS SSO单点登录实例,经过反复的琢磨和修改终于成功了,现将CAS SSO单点登录实例详细 ...

  9. java单个方法达到了65536字节的限制

    可以使方法更小的一件事是关闭调试.打开调试时,每一行(带代码)都有一个标记该行的语句. 不.重构代码.没有方法应该那么久.永远. Write small methods! 说真的:任何IDE都会指导您 ...

  10. GeoHash核心原理解析及java代码实现(转)

    原文链接:http://blog.jobbole.com/80633/ 引子 机机是个好动又好学的孩子,平日里就喜欢拿着手机地图点点按按来查询一些好玩的东西.某一天机机到北海公园游玩,肚肚饿了,于是乎 ...