(OpenCV)函數cv::partition解析

本文地址:http://blog.csdn.net/mounty_fsc/article/details/51085072

1. 簡介

  • 功能:爲一個模板函數,把數據類型爲_Tp的一組集合進行聚類,分成若干個類別。
  • 思想:該算法爲《算法導論》(Introduction to Algorythms)中Data structures for disjoint sets章節描述的不相交集的實現,算法思想見博文(Algorithm)不相交集(Disjoint-set)
  • 該算法爲聚類算法,屬於層次聚類算法(Hierarchical Clustering),思想上符合AGNES (Agglomerative Nesting),一種從底向上聚類的算法。但實現上還有有些區別。

2. 源代碼

源代碼註釋寫的非常詳細了,要註釋的內容不多。

/** @brief Splits an element set into equivalency classes.  
@param _vec Set of elements stored as a vector.  
@param labels Output vector of labels. It contains as many elements as vec. 
Each label labels[i] is a 0-based cluster index of `vec[i]`.  
@param predicate Equivalence predicate (pointer to a boolean function of two arguments or an
instance of the class that has the method bool operator()(const _Tp& a, const _Tp& b) ). The
predicate returns true when the elements are certainly in the same class, and returns false 
if they may or may not be in the same class. 
*/
template<typename _Tp, class _EqPredicate> int
partition( const vector<_Tp>& _vec, vector<int>& labels,
           _EqPredicate predicate=_EqPredicate())
{
    int i, j, N = (int)_vec.size();
    const _Tp* vec = &_vec[0];

    const int PARENT=0;
    const int RANK=1;

    vector<int> _nodes(N*2);
    int (*nodes)[2] = (int(*)[2])&_nodes[0];

    // The first O(N) pass: create N single-vertex trees
    for(i = 0; i < N; i++)
    {
        nodes[i][PARENT]=-1;
        nodes[i][RANK] = 0;
    }
    // The main O(N^2) pass: merge connected components
    // 注意:
    // root表示i的根節點
    // root2表示j的根節點
    // 在執行predicate時是i,j節點而不是root,root2節點,這樣就保證了
    // 原始的N個基本元素間互相都做了比較
    for( i = 0; i < N; i++ )
    {
        int root = i;

        // find root
        while( nodes[root][PARENT] >= 0 )
            root = nodes[root][PARENT];

        for( j = 0; j < N; j++ )
        {
            if( i == j || !predicate(vec[i], vec[j]))
                continue;
            int root2 = j;

            while( nodes[root2][PARENT] >= 0 )
                root2 = nodes[root2][PARENT];

            if( root2 != root )
            {
                // unite both trees
                int rank = nodes[root][RANK], rank2 = nodes[root2][RANK];
                if( rank > rank2 )
                    nodes[root2][PARENT] = root;
                else
                {
                    nodes[root][PARENT] = root2;
                    nodes[root2][RANK] += rank == rank2;
                    root = root2;
                }
                assert( nodes[root][PARENT] < 0 );

                int k = j, parent;

                // compress the path from node2 to root
                while( (parent = nodes[k][PARENT]) >= 0 )
                {
                    nodes[k][PARENT] = root;
                    k = parent;
                }

                // compress the path from node to root
                k = i;
                while( (parent = nodes[k][PARENT]) >= 0 )
                {
                    nodes[k][PARENT] = root;
                    k = parent;
                }
            }
        }
    }

    // Final O(N) pass: enumerate classes
    labels.resize(N);
    int nclasses = 0;

    for( i = 0; i < N; i++ )
    {
        int root = i;
        while( nodes[root][PARENT] >= 0 )
            root = nodes[root][PARENT];
        // re-use the rank as the class label
        // 這部分代碼寫的很漂亮、巧妙
        // 把i所在類的根節點的秩賦值爲類別值
        // 但做了取反得到對應的負數,下一次if就不用執行了
        if( nodes[root][RANK] >= 0 )
            nodes[root][RANK] = ~nclasses++;
        labels[i] = ~nodes[root][RANK];
    }
    return nclasses;
}

3. 應用

在去除物體檢測中,常常需要對重複的bounding box刪除,需要使用groupRectangles函數,該函數則是對partition的一層封裝。在gropRectangels中,計算矩形間相似度的_EqPredicate爲SimilarRects,其定義如下,幾何上來說,如果矩陣r1,r2在空間上是比較接近的,則返回true,否則false。但是值得注意的是,如果r1包含r2,則不一定會判定爲r1與r2很接近,所以在HOG中的,gropRectangels還進行了一層去除包含關係的操作。

class CV_EXPORTS SimilarRects
{
public:
    SimilarRects(double _eps) : eps(_eps) {}
    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;
    }
    double eps;
};
發佈了32 篇原創文章 · 獲贊 51 · 訪問量 26萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章