不管新版本的CascadeClassifier,还是老版本的HAAR检测函数cvHaarDetectObjects,都使用了groupRectangles函数进行窗口的组合,其函数原型有以下几个:
CV_EXPORTS void groupRectangles(CV_OUT CV_IN_OUT vector<Rect>& rectList, int groupThreshold, double eps=0.2);
CV_EXPORTS_W void groupRectangles(CV_OUT CV_IN_OUT vector<Rect>& rectList, CV_OUT vector<int>& weights, int groupThreshold, double eps=0.2);
CV_EXPORTS void groupRectangles( vector<Rect>& rectList, int groupThreshold, double eps, vector<int>* weights, vector<double>* levelWeights );
CV_EXPORTS void groupRectangles(vector<Rect>& rectList, vector<int>& rejectLevels,
vector<double>& levelWeights, int groupThreshold, double eps=0.2);
CV_EXPORTS void groupRectangles_meanshift(vector<Rect>& rectList, vector<double>& foundWeights, vector<double>& foundScales,
double detectThreshold = 0.0, Size winDetSize = Size(64, 128));
最后一个函数添加mean shift进行组合聚类,下面针对groupRectangles函数进行说明(前三个函数都调用了参数最多的第四个函数实现):
rectList:带组合的窗口,即作为输入又作为输出
rejectLevels:通过分类器的stage数,一般不小于stage总数-4,也就是weights
levelWeights:通过上述stage数的输出权重,也就是通过的stage数的所有node之和,里面即包含left_val又right_val,同一个node只包含其中的一个
groupThreshold:组合阈值,当没有输入rejectLevels的时候,当待合并的窗口数大于该阈值的时候才可能进行合并,否则放弃;当输入rejectLevels的时候,当前组合下通过检测的stage最大值数大于该阈值的时候才可能进行合并,否则放弃
eps:待合并的两个窗口的相关性,从矩形所在位置的像素差值考虑,当eps为0的时候不进行合并,直接返回
该函数的内部执行流程
1) 当组合阈值groupThreshold小于等于0的时候,如果输出weights,则weights中返回与rectList同样个数个1,函数直接返回,不进行合并操作
2) 调用partition函数对rectList中的矩形进行分类
vector<int> labels;
int nclasses = partition(rectList, labels, SimilarRects(eps));
其中nclasses表示组合类别,labels表示每个rect属于哪个类别的,相似度计算使用SimilarRects类
值得一提的是,该函数的调用必须输入不相交的计算方法,在groupRectangles函数中使用SimilarRects计算相似度,输入参数为eps,相似的矩形是要被分为同一类的
SimilarRect中计算相似度的方法:
inline bool operator()(const Rect& r1, const Rect& r2) const
{
// delta为最小长宽的eps倍
double delta = eps*(std::min(r1.width, r2.width) + std::min(r1.height, r2.height))*0.5;
// 如果矩形的四个顶点的位置差别都小于delta,则表示相似的矩形
return std::abs(r1.x - r2.x) <= delta &&
std::abs(r1.y - r2.y) <= delta &&
std::abs(r1.x + r1.width - r2.x - r2.width) <= delta &&
std::abs(r1.y + r1.height - r2.y - r2.height) <= delta;
}
3) 组合分到同一类别的矩形并保存当前类别下通过stage的最大值以及最大的权重
for( i = 0; i < nlabels; i++ )
{
int cls = labels[i];
rrects[cls].x += rectList[i].x;
rrects[cls].y += rectList[i].y;
rrects[cls].width += rectList[i].width;
rrects[cls].height += rectList[i].height;
rweights[cls]++;
}
for( i = 0; i < nclasses; i++ )
{
Rect r = rrects[i];
float s = 1.f/rweights[i];
rrects[i] = Rect(saturate_cast<int>(r.x*s),
saturate_cast<int>(r.y*s),
saturate_cast<int>(r.width*s),
saturate_cast<int>(r.height*s));
}
for( i = 0; i < nlabels; i++ )
{
int cls = labels[i];
if( (*weights)[i] > rejectLevels[cls] )
{
rejectLevels[cls] = (*weights)[i];
rejectWeights[cls] = (*levelWeights)[i];
}
else if( ( (*weights)[i] == rejectLevels[cls] ) && ( (*levelWeights)[i] > rejectWeights[cls] ) )
rejectWeights[cls] = (*levelWeights)[i];
}
4) 按照groupThreshold合并规则,以及是否存在包含关系输出合并后的矩形
for( i = 0; i < nclasses; i++ )
{
Rect r1 = rrects[i];
int n1 = levelWeights ? rejectLevels[i] : rweights[i];
double w1 = rejectWeights[i];
// 合并的矩形数小于等于组合阈值不进行输出
if( n1 <= groupThreshold )
continue;
// filter out small face rectangles inside large rectangles
for( j = 0; j < nclasses; j++ )
{
int n2 = rweights[j];
if( j == i || n2 <= groupThreshold )
continue;
Rect r2 = rrects[j];
int dx = saturate_cast<int>( r2.width * eps );
int dy = saturate_cast<int>( r2.height * eps );
// 当r1在r2的内部的时候,停止
if( i != j &&
r1.x >= r2.x - dx &&
r1.y >= r2.y - dy &&
r1.x + r1.width <= r2.x + r2.width + dx &&
r1.y + r1.height <= r2.y + r2.height + dy &&
(n2 > std::max(3, n1) || n1 < 3) )
break;
}
// r1不在r2的内部时j才可能等于nclasses
if( j == nclasses )
{
rectList.push_back(r1);
if( weights )
weights->push_back(n1);
if( levelWeights )
levelWeights->push_back(w1);
}
}
感谢:http://blog.csdn.net/xidianzhimeng/article/details/40107763
- OpenCV原则解读HAAR+Adaboost
因为人脸检测项目.用途OpenCV在旧分类中的训练效果.因此该检测方法中所使用的分类归纳.加上自己的一些理解.重印一些好文章记录. 文章http://www.61ic.com/Article/DaVi ...
- csharp通过dll调用opencv函数,图片作为参数
[blog 项目实战派]csharp通过dll调用opencv函数,图片作为参数 一直想做着方面的研究,但是因为这个方面的知识过于小众,也是由于自己找资料的能力比较弱,知道今天才找 ...
- matlab调用opencv函数的配置
环境: VS2010 活动解决方案平台x64 WIN 8.1 Opencv 2.4.3 Matlab 2012a 1. 首先保证vs2010能正确调用opencv函数, 2. Matlab中选择编 ...
- OpenCv函数学习(一)
Intel Image Processing Library (IPL) typedef struct _IplImage { int nSize; /* IplImage大小 */ int ID; ...
- 一些常用的opencv函数
分配图像空间: IplImage* cvCreateImage(CvSize size, int depth, int channels); size: cvSize(width,hei ...
- 常用的OpenCV函数速查
常用的OpenCV函数速查 1.cvLoadImage:将图像文件加载至内存: 2.cvNamedWindow:在屏幕上创建一个窗口: 3.cvShowImage:在一个已创建好的窗口中显示图像: 4 ...
- [转] matlab调用opencv函数的配置
原文地址百度账户 aleasa123 方式1 1. 首先保证vs2010能正确调用opencv函数, 2. Matlab中选择编译器,操作如下: 打开matlab2012,输入mex –setup ...
- OpenCV2学习笔记(十五):利用Cmake高速查找OpenCV函数源代码
在使用OpenCV时,在对一个函数的调用不是非常了解的情况下,通常希望查到该函数的官方声明.而假设想进一步研究OpenCV的函数,则必须深入到源码. 在VS中我们能够选中想要查看的OpenCV函数,点 ...
- OpenCV函数:提取轮廓相关函数使用方法
opencv中提供findContours()函数来寻找图像中物体的轮廓,并结合drawContours()函数将找到的轮廓绘制出.首先看一下findContours(),opencv中提供了两种定义 ...
随机推荐
- 百度编辑器 无法获取post过去的值
如果你的,表单form是套用 table的话,请一下,要把 form 放在table的最外面.否则获取不到post值
- robot API笔记4
robot.htmldata包 包编写HTML格式的输出文件. 这个包被认为是稳定的但不是公共API的一部分. robot.htmldata.htmlfilewriter module classro ...
- Ubuntu 修复windows启动项
打开终端输入命令sudo gedit /etc/default/grub修改GRUB_TIMEOUT="10"然后在终端中输入sudo update-grubupdate 命令会自 ...
- js 继承inheritance/extends
主要就是<javascript语言精粹>语言精粹中的内容 5.1伪类 Function.prototype.method = function(name,func){ this.proto ...
- 你不知道的JavaScript--面向对象高级程序设计
转载http://blog.csdn.net/i10630226/article/details/51088841 1. JS是基于原型的程序 建立一个简单的面向对象的类.有属性,有方法. funct ...
- web开发必须知道的javascripat工具
1,JavaScript compressor and comparison tool 有许多工具可以帮助你压缩JavaScript代码,但是这个过程比较耗时,并且,对于某个特定的场景来说,很难分析出 ...
- IO流 总结二
流只能操作数据. File 类 用来将文件或者文件夹封装成对象. 方便文件与文件夹进行操作 File对象可以作为参数传递给流的构造函数. 可以将已有的和已出现的文件或者文件夹封装成对象 File a ...
- 166. Fraction to Recurring Decimal -- 将除法的商表示成字符串(循环节用括号表示)
Given two integers representing the numerator and denominator of a fraction, return the fraction in ...
- 给Eclipse中hibernate.cfg.xml配置文件加提示
在hibernate框架需要的jar包中找到hibernate3.jar,并用压缩软件打开,如图: 2 选择org文件夹--打开下一级文件夹 3 点击类型,方便找到dtd文件,下拉查看dtd文件,有两 ...
- 10个必备的移动UI设计资源站(转)
创建移动设计模式是非常重要的一步,记住!这是为移动设备设计而不是web.不仅仅是移动屏幕远小于普通的电脑屏幕,关键是鼠标和键盘已经被手指替代了! 当然还有更重要的,说起来很苦逼,我们再也不能使用一种模 ...