vector<Rect>矩形框聚合拟合

时间:2019-09-19
本文章向大家介绍vector<Rect>矩形框聚合拟合,主要包括vector<Rect>矩形框聚合拟合使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

groupRectangle函数实现矩形框聚合。原因:多尺度检测后,获取的矩形之间会存在重合、重叠和包含关系。因尺度缩放,可能导致同一个目标在多个尺度上被检测出来,故有必要进行融合。OpenCV中实现的融合有两种:1)按权重合并;2)使用Meanshift算法进行合并。

下面是简单的合并,其直接按照位置和大小关系进行合并。

其实现主要为:1)多所有矩形按照大小位置合并成不同的类别;

2)将同类别中的矩形合并成一个矩形,当不满足给出阈值条件时,矩形被舍弃,否则留下。

void groupRectangles(std::vector<Rect>& rectList, int groupThreshold, double eps,
                     std::vector<int>* weights, std::vector<double>* levelWeights)
{
    if( groupThreshold <= 0 || rectList.empty() )
    {
        if( weights )
        {
            size_t i, sz = rectList.size();
            weights->resize(sz);
            for( i = 0; i < sz; i++ )
                (*weights)[i] = 1;
        }
        return;
    }
 
    std::vector<int> labels;
    // 调用partition函数,将所有的矩形框初步分为几类,其中labels为每个矩形框对应的类别编号,eps为判断两个矩形框是否属于
    // 同一类的控制参数。如果两个矩形框的四个相应顶点的差值的绝对值都在deta范围内,则认为属于同一类,否则是不同类。
    int nclasses = partition(rectList, labels, SimilarRects(eps));
 
    std::vector<Rect> rrects(nclasses);
    std::vector<int> rweights(nclasses, 0);
    std::vector<int> rejectLevels(nclasses, 0);
    std::vector<double> rejectWeights(nclasses, DBL_MIN);
    int i, j, nlabels = (int)labels.size();
    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]++;
    }
 
    bool useDefaultWeights = false;
 
    if ( levelWeights && weights && !weights->empty() && !levelWeights->empty() )
    {
        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];
        }
    }
    else
        useDefaultWeights = true;
    // 计算每一类别的平均矩形框位置,即每一个类别最终对应一个矩形框
    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));
    }
 
    rectList.clear();
    if( weights )
        weights->clear();
    if( levelWeights )
        levelWeights->clear();
    // 再次过滤上面分类中得到的所有矩形框
    for( i = 0; i < nclasses; i++ )
    {
        Rect r1 = rrects[i];
        int n1 = rweights[i];
        double w1 = rejectWeights[i];
        int l1 = rejectLevels[i];
 
        // filter out rectangles which don't have enough similar rectangles
        // 将每一类别中矩形框个数较少的类别过滤掉。
        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 );
 
            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;
        }
 
        if( j == nclasses )
        {
            rectList.push_back(r1);
            if( weights )
                weights->push_back(useDefaultWeights ? n1 : l1);
            if( levelWeights )
                levelWeights->push_back(w1);
        }
    }
}

原文地址:https://www.cnblogs.com/lx17746071609/p/11549862.html