OPENCV学习笔记(二) 聚合函数
class CV_EXPORTS SimilarRects
// This function splits the input sequence or set into one or more equivalence classes and // returns the vector of labels - 0-based class indexes for each element.// predicate(a,b) returns true if the two sequence elements certainly belong to the same class. // // The algorithm is described in "Introduction to Algorithms" // by Cormen,Leiserson and Rivest,the chapter "Data structures for disjoint sets" template<typename _Tp,class _EqPredicate> int partition( const vector<_Tp>& _vec,vector<int>& labels, _EqPredicate predicate=_EqPredicate()) { int i,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 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 if( nodes[root][RANK] >= 0 ) nodes[root][RANK] = ~nclasses++; labels[i] = ~nodes[root][RANK]; } return nclasses; }
首先说下并查集,主要功能是就是将相似的元素分为一类,有点像聚类,但是聚类没有具体的相似测试.如果我们有{1,1,3,4,5,6,6},直接可以看出来这个可以分成{{1,1},{3,3},{4,4},{5,5},{6,6}}.当然这个前提是两个元素相似等于相等.普通的可以这样做,先排序再相连的两个元素比较,如相等,再往后移动,具体可以看http://www.haskell.org/haskellwiki/99_questions/1_to_10第9题. 这个是在一维的情况下,但是如果到了二维呢,(x1,y1)是不可以排序的的,就像实数点是可以排序,但是复数却不可以一样.这个时候可以定义`相似`,可以这样仍为如果(x1,y1),(x2,y2)的欧式距离小于某个值就认为相似.这个时候再分类就可以了. 相似是两个元素的比较操作,在代码中体现为 '_EqPredicate predicate=_EqPredicate()'可以作为参数传给它的. 并查集的基本结构可以是这样的.
(截图来自<数据结构与算法分析-C语言版>) 每个元素有一个指向父亲指针,如果2个元素相同就可以把其中一个元素的父亲指向另一个.如下 当然由于元素的结构简单,可以直接使用数组代替,数组的位置为元素的value,数组的值为它爹的地址.如 {0,2,4} 可以认为0,3是单元素,第4个它爹是3,第5个元素它爹是4 可以看成{0,3<-4<-5}.所以上面的图可以写成 当然图中指向0认为是单个元素. 在OpenCV代码中表现为 for(i = 0; i < N; i++) { nodes[i][PARENT]=-1; nodes[i][RANK] = 0; } // find root while( nodes[root][PARENT] >= 0 ) root = nodes[root][PARENT]; while( nodes[root2][PARENT] >= 0 ) root2 = nodes[root2][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; } // 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; }
after. 部分代码如下. 1 struct PointLike{ 2 PointLike(int thresh){ 3 this->thresh = thresh; 4 } 5 bool operator()(cv::Point p1,cv::Point p2){ 6 int x = p1.x - p2.x; 7 int y = p1.y - p2.y; 8 return x*x+y*y <=thresh*thresh; 9 } 10 int thresh; 11 }; 12 13 PointLike plike(20); 14 std::vector<int> labels; 15 int count; 16 count = cv::partition(pts_v,plike); 17 18 for(size_t i = 0;i<pts_v.size();i++) 19 { 20 cv::circle(after,pts_v[i],2,colorTab[labels[i]]); 21 } 2.合并重叠的矩形.(人脸识别里用的) 相似条件(重叠面积占小矩形面基的75%) before: after: 部分代码如下: struct RectLike{
2 RectLike(double p){
this->p = p;
operator()(cv::Rect r1,cv::Rect r2){
int area1 = r1.area();
int area2 = r2.area();
//相交Rect面积
9 int area = overlap_rect_area(r1,r2);
10 return area1<area2?area>=p*area1:area>=p*area2;
11 }
12 double p;
13 };
14
15 RectLike rLike(0.75);
16 std::vector<17 18 count = cv::partition(rects_v,rLike);
19
20 0;i<rects_v.size();i++)
21 {
22 cv::rectangle(after,rects_v[i],128); line-height:1.5!important">23 }
参考:
1.http://www.cnblogs.com/zhuangzhuang1988/archive/2012/07/13/2589856.html 2.opencv源码。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |