OpenCV函数解读之groupRectangles

本文详细解释了OpenCV中的groupRectangles函数,包括其参数、作用以及内部执行流程,特别关注了如何通过组合阈值和相似性计算进行窗口的合并和分类,以及meanshift用于进一步的聚类过程。
摘要由CSDN通过智能技术生成

不管新版本的CascadeClassifier,还是老版本的HAAR检测函数cvHaarDetectObjects,都使用了groupRectangles函数进行窗口的组合,其函数原型有以下几个:

CV_EXPORTS void groupRectangles(CV_OUT CV_IN_OUT vector& rectList, int groupThreshold, double eps=0.2);

CV_EXPORTS_W void groupRectangles(CV_OUT CV_IN_OUT vector& rectList, CV_OUT vector& weights, int groupThreshold, double eps=0.2);

CV_EXPORTS void groupRectangles( vector& rectList, int groupThreshold, double eps, vector* weights, vector* levelWeights );

CV_EXPORTS void groupRectangles(vector& rectList, vector& rejectLevels,

vector& levelWeights, int groupThreshold, double eps=0.2);

CV_EXPORTS void groupRectangles_meanshift(vector& rectList, vector& foundWeights, vector& 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 labels;

int nclasses = partition(rectList, labels, SimilarRects(eps));

其中nclasses表示组合类别,labels表示每个rect属于哪个类别的,相似度计算使用SimilarRects类

关于partition函数简介: http://docs.opencv.org/modules/core/doc/clustering.html#partition,实现不相交集合数据结构的类别

值得一提的是,该函数的调用必须输入不相交的计算方法,在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(r.x*s),

saturate_cast(r.y*s),

saturate_cast(r.width*s),

saturate_cast(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( r2.width * eps );

int dy = saturate_cast( 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);

}

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值