二維凸包convex hull之C++及OpenCV實現
打算接下來好好研究下演算法(很明顯,演算法才是王道啊),然後儘量用直觀的方式輸出,於是用OpenCV畫圖成了不二首選,各位看官接下來看到一堆“XXX之C++及OpenCV實現”之類的標題就別見怪了~
另外還有個打算,看到自己寫的東西被別人拿去佔為己有,不爽,開始貼版權了^_^。
本文出處:http://blog.csdn.net/xizhibei
============================================================
今天就是二維凸包,演算法導論中文版584頁說的就是凸包,現在,讓我們來實現它。
話說,凸包在很多地方有著重要的作用,如手勢識別,需要識別出手的輪廓的凸包,二維或者三維區域的邊界等等。
而對於凸包演算法,其中最有名的莫過於Graham掃描演算法,它的複雜度為nlog(n),過程很優美,相信你看過執行過程你就會同樣覺得了。
簡單來說,這個演算法的過程就是這樣:
1.計算求得輸入點x座標最小(如果x相等,則比較y是不是最小)的點,作為第一個點
2.其它的點按照極角按順時針排列,如果有共線的,取最近的那一個
3.依次將0,1,2三個座標壓入棧
4.對於剩餘的點,i依次從3到最後,看次棧頂,棧頂,以及當前的i對應的點,如果是非左轉動,那麼彈棧
5.將i對應的點壓棧,轉到3
好了,現在開始實現:
下面是一些標頭檔案/定義以及簡單函式實現
其中值得一提的便是叉積,二維向量A和B的叉積就是A.x * B.y - A.y *B.x ,結果為正就表明A經過順時針到達B(當然,小於180),反之則逆時針,憑藉這種演算法,就可以按極角排序了。
- #include <cv.h>
- #include <cxcore.h>
- #include <highgui.h>
- #define POINT_NUM 100
- #define WIDTH 800
- #define HEIGHT 800
- #define zero 1e-12
- #define DIS(a,b) sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y))
-
#define SGN(x) (fabs(x)<zero?0:(x>0?1:-1))
- #define CROSS(a,b,c) ((b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x))//叉積,用來判斷旋轉方向
- #define CMP(a,b) (a.x < b.x || SGN(a.x - b.x)==0 && a.y < b.y)//座標的比較
- #define RAND (rand() % 100000 / 100000.0)//產生0-1之間的浮點數
- CvPoint p[POINT_NUM];
- CvPoint* hull_p = new CvPoint[POINT_NUM];//用來儲存凸包上的點
- int hull_size = 0;
- IplImage* img;
- //下面簡單實現了棧操作
- inlinevoid push(CvPoint* S,CvPoint pt)
- {
- S[hull_size++] = pt;
- }
- inline CvPoint pop(CvPoint* S)
- {
- return S[--hull_size];
- }
- inlinevoid swap(int x,int y)
- {
- CvPoint pt = p[x];
- p[x] = p[y];
- p[y] = pt;
- }
- inlinebool compare(CvPoint a,CvPoint b,CvPoint c)
- {
- int tmp = SGN(CROSS(a,b,c));
- if(tmp != 0)
- return tmp > 0;
- else//如果兩點共線的話,就需要比較遠近了
- return DIS(a,b) < DIS(a,b);
- }
- //快排,極角的排序
- void sort(int l,int r)
- {
- CvPoint tmp = p[(l + r) / 2];
- int i = l;
- int j = r;
- do
- {
- while(compare(p[0],p[i],tmp))i++;
- while(compare(p[0],tmp,p[j]))j--;
- if(i <= j)
- {
- swap(i,j);
- i++;
- j--;
- }
- }while(i <=j);
- if(i < r)sort(i,r);
- if(j > l)sort(l,j);
- }
這裡也跟上篇文章一樣,為了看清執行過程,加上了畫線函式,還有100微秒的延時,這樣就能看清了
[cpp]view plaincopyprint?- void draw_hull()
- {
- int min = -1;
- for(int j = 0;j < POINT_NUM;j++)//找出x座標最小的,作為起始點
- {
- if(min == -1 || CMP(p[j],p[min]))
- min = j;
- }
- if(min != 0)
- swap(0,min);
- sort(1,POINT_NUM - 1);//其他點排序
- push(hull_p,p[0]);
- push(hull_p,p[1]);
- push(hull_p,p[2]);
- for(int i = 3;i < POINT_NUM;i++)
- {
- while(CROSS(hull_p[hull_size - 2],hull_p[hull_size - 1],p[i]) < 0)//非左轉
- {
- pop(hull_p);
- cvLine(img,hull_p[hull_size - 1],p[i],cvScalar(255,0,255));//為了看清執行過程而加的
- cvShowImage("Image",img);
- cvWaitKey(100);
- }
- cvLine(img,hull_p[hull_size - 1],p[i],cvScalar(255,0,255));
- push(hull_p,p[i]);
- }
- cvPolyLine(img,&hull_p,&hull_size,1,1,cvScalar(0,0,255),2);//最終畫出凸包
- }
顯示圖片: [cpp]view plaincopyprint?
- void show_outcome()
- {
- cvSet(img,cvScalar(255,255,255));
- CvScalar color = cvScalar(0,0,0);
- for(int i = 0;i < POINT_NUM;i++)//畫出每個點,十字
- {
- int x = p[i].x;
- int y = p[i].y;
- cvLine(img,cvPoint(x - 5,y),cvPoint(x + 5,y),color,2);
- cvLine(img,cvPoint(x,y - 5),cvPoint(x,y + 5),color,2);
- }
- draw_hull();
- cvShowImage("Image",img);
- cvWaitKey(0);
- }
然後是主函式,這次的隨機點生成換了個方式,點隨機分佈在左邊的橢圓以及右邊的圓上,不再象上次那樣隨機產生在矩形區域內了: [cpp]view plaincopyprint?
- int main()
- {
- img = cvCreateImage(cvSize(WIDTH,HEIGHT),IPL_DEPTH_8U,3);
- srand((unsigned)time(NULL));
- double phase = RAND * CV_PI * 2.0;
-
相關推薦
二維凸包convex hull之C++及OpenCV實現
打算接下來好好研究下演算法(很明顯,演算法才是王道啊),然後儘量用直觀的方式輸出,於是用OpenCV畫圖成了不二首選,各位看官接下來看到一堆“XXX之C++及OpenCV實現”之類的標題就別見怪了~ 另外還有個打算,看到自己寫的東西被別人拿去佔為己有,不爽,開始貼版權
P2742 【模板】二維凸包 / [USACO5.1]圈奶牛Fencing the Cows
href sin const int can cross pri fin 二維 傳送門 二維凸包的板子 //minamoto #include<bits/stdc++.h> #define rint register int #define inf 0x3f3f
快速和改進的二維凸包演算法及其在O(n log h)中的實現(實現部分)
此篇接上一篇部落格http://blog.csdn.net/firstchange/article/details/78588669 實施選擇 陣列與列表 “List”類是一個C#集合,它使用一個數組作為其底層容器。使用“列表”而不是陣列應該有類似的效能。測試證實,
快速和改進的二維凸包演算法及其在O(n log h)中的實現(理論部分)
在國外某知名網站上瀏覽資訊時發現了一篇非常好的論文,因為是英文的,自己翻譯、整理了一下,如果想看原始的可以去以下連結:https://www.codeproject.com/Articles/1210225/Fast-and-improved-D-Convex-Hull-algorithm-
計算幾何 二維凸包問題 Andrew演算法
凸包:把給定點包圍在內部的、面積最小的凸多邊形。 Andrew演算法是Graham演算法的變種,速度更快穩定性也更好。 首先把所有點排序,按照第一關鍵字x第二關鍵字y從小到大排序,刪除重複點後得到點序列P1...Pn。 1)把P1,P2放入凸包中,凸包中的點使用棧儲存 2)從p3開始
分治法求二維凸包問題java
https://blog.csdn.net/bone_ace/article/details/46239187 見解法2。 有一點需要說明的是,如果有多個到直線p1 pn的距離都最大的點,找pmax使的∠pmax p1 pn最大 下面為java程式碼 package fd; impo
二維凸包求解(Andrew演算法 )
Andrew演算法是Graham演算法的變種。 其主要思想為把凸包上的點依次放入棧中, 如果發現形成了凹多邊形(叉積為負值) 就刪除一些點,使得又能夠維持凸的形態。 這時就會發現,處理各個點需要按照x從左往右的順序,排序即可 當然,這只是處理了下凸的一個凸殼,倒
二維凸包的板子
二維凸包的板子 感覺沒什麼可說的,碼風抄的孔老師的。 #include <cstdio> #include <algorithm> #include <cmath> const int N=1e4+10; #define Point Vector const doubl
USACO FC,二維凸包
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> const int maxn=10000+10; using namespace std; struct
P2742-二維凸包/圈奶牛Fencing the Cows【凸包】
正題 題目連結:https://www.luogu.org/recordnew/lists?uid=SSL_WYC_zombieeeeee&pid=P2742&status=&sort=0 題目大意 求凸包總長度 解題思路 求凸包
【洛谷P2742】【模板】二維凸包/[USACO5.1]圈奶牛【凸包】
題目大意: 題目連結:https://www.luogu.org/problemnew/show/P2742 求二維平面上的凸包。 思路: 二維凸包模板題。在這裡就不講述凸包的概念和做法了。需要的話可以看本題題解。 採用的是
【模板】二維凸包 / [USACO5.1]圈奶牛Fencing the Cows
坐標系 sca printf can || The cows 模板 get Problem surface 戳我 Meaning 坐標系內有若幹個點,問把這些點都圈起來的最小凸包周長。 這道題就是一道凸包的模板題啊,只要求出凸包後在計算就好了,給出幾個註意點 記得檢查是否
尋找凸包 convex hull(一)
今天學習OpenCV2中的ConvecHull函式連線如下:http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/shapedescriptors/hull/hull.html#hu
【洛谷 P3187】 [HNOI2007]最小矩形覆蓋 (二維凸包,旋轉卡殼)
ref scanf const 維護 math int() 一個 數據 pre 題目鏈接 嗯,毒瘤題。 首先有一個結論,就是最小矩形一定有條邊和凸包重合。腦補一下就好了。 然後枚舉凸包的邊,用旋轉卡殼維護上頂點、左端點、右端點就好了。 上頂點用叉積,叉積越大三角形面積越大,
凸包問題的分治演算法及python實現
利用分治思想處理凸包問題。 劃分:將點集S中的資料按橫座標排序,選出橫座標最小的點A和縱座標最小的點B,AB的連線將S劃分為兩個子集,位於(AB) 上方的集合S1和位於(BA) 上方的集合S2。 遞迴求解:遞迴呼叫演算法求S1的凸包和S2的凸包,遞迴演算
hdu3662 3D Convex Hull(三維凸包【三維計算幾何基本操作)
題目連線 分析: 三維凸包模板 瞧好了基本操作 三維和二維簡直不是一個級別的。。。orz #include<bits/stdc++.h> using namespace std; const double eps=1e-8; con
計算幾何_三維凸包(3d convex hull)
const double eps = 1e-8; typedef list<int>::iterator liit; inline int sign(double d){ if(d < -eps) return -1; return (d > e
bzoj1964: hull 三維凸包
typename opera ifdef ide esp urn print family www 傳送門 二維平面四個點求凸包面積->任選三個點面積之和/2 三維平面五個點求凸包體積->任選四個點體積之和/2 二維平面三個點面積->二個二維向量行列式
D - FATE HDU-2159 FATE 二維背包
text panel ret sub lin printf print %d tdi D - FATE Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Sub
HDU-2159 二維背包
裝備 urn 背包 stdio.h namespace logs set style bre 最近xhd正在玩一款叫做FATE的遊戲,為了得到極品裝備,xhd在不停的殺怪做任務。久而久之xhd開始對殺怪產生的厭惡感,但又不得不通過殺怪來升完這最後一級。現在的問題是,xhd