做了一下在线测试,在匆忙中没把凸包代码很好的完善,下面给出源码和效果。
#ifndef _GRAHAM_H_
#define _GRAHAM_H_
#include <cstdlib>
#include <iostream>
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#include<Math.h>
using namespace std;
#define MINUM 65536
const float val=3.1415926;
typedef float FPoint;
typedef struct
{
FPoint x;
FPoint y;
}p2d;
typedef struct
{
float x;
float y;
float angle;
}SPoint;
void Swap(SPoint **m_Point,int i,int j);
int _Partition(SPoint* TPoint,int left,int right);
void Quick_Sort(SPoint* TPoint,int left,int right);
int Find_Minumy_Point(SPoint *m_Point,int nLen);
void Compute_Angles(SPoint *m_Point,SPoint *T_Point,int nLen,int index);
float distance(SPoint *T_Point,SPoint pt,int flag);
void sort_by_distance(SPoint *T_Point,SPoint pt,int start,int end);
void Adjustment(SPoint *T_Point,SPoint pt,int nLen);
int GraHam(SPoint *m_Point,SPoint *T_Point,p2d* CS,int nLen);
#endif
#include"Graham.h"
void Swap(SPoint **m_Point,int i,int j)
{
SPoint temp;
temp.x=(*m_Point)[i].x;
temp.y=(*m_Point)[i].y;
temp.angle=(*m_Point)[i].angle;
(*m_Point)[i].x=(*m_Point)[j].x;
(*m_Point)[i].y=(*m_Point)[j].y;
(*m_Point)[i].angle=(*m_Point)[j].angle;
(*m_Point)[j].x=temp.x;
(*m_Point)[j].y=temp.y;
(*m_Point)[j].angle=temp.angle;
}
int _Partition(SPoint* TPoint,int left,int right)
{
int pivot=left;
int i=left+1;
int j=right;
while(1)
{
while(TPoint[i].angle<TPoint[pivot].angle&&i<=right) {i=i+1;}
while(TPoint[j].angle>TPoint[pivot].angle&&j>left) {j=j-1;}
if(i<j) { Swap(&TPoint,i,j); }
else break;
}
Swap(&TPoint,pivot,j);
return j;
}
void Quick_Sort(SPoint* TPoint,int left,int right)
{
if(left<right)
{
int Partition=_Partition(TPoint,left,right);
Quick_Sort(TPoint,left,Partition-1);
Quick_Sort(TPoint,Partition+1,right);
}
}
int Find_Minumy_Point(SPoint *m_Point,int nLen)
{
int mid=(nLen-1)/2;
float minumy=(float)MINUM;
int res=-1;
for(int i=0;i<=mid;i++)
{
if(m_Point[i].y<m_Point[nLen-1-i].y)
{
if(m_Point[i].y<minumy)
{
minumy=m_Point[i].y;
res=i;
}
else
{
if(m_Point[i].y==minumy&&res!=-1)
{
if(m_Point[i].x<=m_Point[res].x)
{
minumy=m_Point[i].y;
res=i;
}
}
}
}
else
{
if(m_Point[nLen-i-1].y<minumy)
{
minumy=m_Point[nLen-1-i].y;
res=nLen-1-i;
}
else
{
if(m_Point[nLen-i-1].y==minumy&&res!=-1)
{
if(m_Point[nLen-1-i].x<=m_Point[res].x)
{
minumy=m_Point[nLen-1-i].y;
res=nLen-1-i;
}
}
}
}
}
return res;
}
void Compute_Angles(SPoint *m_Point,SPoint *T_Point,int nLen,int index)
{
float m_tan,x,y;
Swap(&m_Point,0,index);
for(int i=1;i<nLen;i++)
{
x=m_Point[i].x-m_Point[0].x;
y=m_Point[i].y-m_Point[0].y;
if(x>0&&y>0) m_tan=atan(y/x);
if(x>=0&&y==0)m_tan=0;
if(x>0&&y<0) m_tan=2*val-atan((-y)/x);
if(x<0&&y==0)m_tan=-val;
if(x<0&&y>0) m_tan=val-atan(y/(-x));
if(x<0&&y<0) m_tan=val+atan((-y)/x);
if(x==0&&y>0)m_tan=0.5*val;
if(x==0&&y<0)m_tan=1.5*val;
//m_Tan=atan2f(y,x);
T_Point[i-1].x=m_Point[i].x;
T_Point[i-1].y=m_Point[i].y;
T_Point[i-1].angle=m_tan;
}
for(int i=0;i<nLen-1;i++)
printf("%f,%f,%f\n",T_Point[i].x,T_Point[i].y,T_Point[i].angle);
printf("\n\n\n");
Quick_Sort(T_Point,0,nLen-2);
}
float distance(SPoint *T_Point,SPoint pt,int flag)
{
float dis=(T_Point[flag].x-pt.x)*(T_Point[flag].x-pt.x)+(T_Point[flag].y-pt.y)*(T_Point[flag].y-pt.y);
dis=sqrtf(dis);
return dis;
}
void sort_by_distance(SPoint *T_Point,SPoint pt,int start,int end)
{
float dis1,dis2;
for(int m=start;m<end;m++)
{
for(int n=m+1;n<end;n++)
{
dis1=distance(T_Point,pt,m);
dis2=distance(T_Point,pt,n);
if(dis1>dis2) Swap(&T_Point,m,n);
}
}
}
void Adjustment(SPoint *T_Point,SPoint pt,int nLen)
{
int p=0,q;
int dis1,dis2;
while(p<nLen)
{
q=p+1;
if(q>=nLen) break;
else
{
while(T_Point[p].angle==T_Point[q].angle&&q<nLen)
{
q=q+1;
}
if(p+1==q)
{
p=p+1;
}
else
{
sort_by_distance(T_Point,pt,p,q-1);
}
}
}
}
int GraHam(SPoint *m_Point,SPoint *T_Point,p2d* CS,int nLen)
{
int index=Find_Minumy_Point(m_Point,nLen);
printf("The point x=%f,y=%f has minumy\n",m_Point[index].x,m_Point[index].y);
Compute_Angles(m_Point,T_Point,nLen,index);
Adjustment(T_Point,m_Point[0],nLen-1);
for(int i=0;i<nLen-1;i++)
printf("%f,%f,%f\n",T_Point[i].x,T_Point[i].y,T_Point[i].angle);
CS[0].x=T_Point[nLen-2].x;
CS[0].y=T_Point[nLen-2].y;
CS[1].x=m_Point[0].x;
CS[1].y=m_Point[0].y;
int sp=1;
int k=0;
float D;
while(k<nLen-1)
{
//栈顶两点以及扫描线上一点所构成的三角区符号
//D=CS[sp-1].x*CS[sp].y+CS[sp].x*T_Point[k].y+T_Point[k].x*CS[sp-1].y
//-CS[sp-1].y*CS[sp].x-CS[sp].y*T_Point[k].x-T_Point[k].y*CS[sp-1].x;
D=(T_Point[k].x-CS[sp].x)*(CS[sp-1].y-CS[sp].y)-(CS[sp-1].x-CS[sp].x)*(T_Point[k].y-CS[sp].y);
if(D>=0)
{
sp=sp+1;
CS[sp].x=T_Point[k].x;
CS[sp].y=T_Point[k].y;
k=k+1;
}
else
{
sp=sp-1;
/*if(sp==0)
{
CS[sp].x=T_Point[k].x;
CS[sp].y=T_Point[k].y;
}*/
}
}
return (sp+1);
}
/**************************************************************
***Mail:zhjkobe2013@live.com
***Author: zhang jie
***Function: Graham algorithms
***cpp:main.cpp
***Create time:2015-04-10 12:26
***Last Modify Time: 2015-04-10
***************************************************************/
#include "Graham.h"
//凸壳问题的格雷厄姆
#define WIDTH 640
#define HEIGHT 480
#define N 10
const char* win_name="GraHam";
int nCount=0;
int re=0;
void Record_Point_CallBack(int event,int x,int y,int flags,void* param);
CvPoint pt;
int main(int argc, char *argv[])
{
IplImage* Img=cvCreateImage(cvSize(WIDTH,HEIGHT),IPL_DEPTH_8U,3);
cvZero(Img);
cvNamedWindow(win_name);
CvPoint* m_Point=new CvPoint[N];
char c;
cvSetMouseCallback(win_name,Record_Point_CallBack,(void*)Img);
loop:
while(1)
{
if(nCount>=1&&nCount<=N)
{
m_Point[nCount-1].x=pt.x;
m_Point[nCount-1].y=pt.y;
}
//printf("nCount=%d\n",nCount);
cvShowImage(win_name,Img);
c=cvWaitKey(100);
if(c=='r') { nCount=0; cvZero(Img); }
if(nCount==N+1) break;
}
SPoint *p_Point=new SPoint[N];
SPoint *T_Point=new SPoint[N-1];
p2d* CS=new p2d[N+1];
for(int i=0;i<N;i++)
{
p_Point[i].x=(float)m_Point[i].x;
p_Point[i].y=(float)m_Point[i].y;
p_Point[i].angle=0.0;
printf("x=%d,y=%d\n",m_Point[i].x,m_Point[i].y);
}
printf("start\n");
int nIndex=GraHam(p_Point,T_Point,CS,N);
printf("nIndex=%d\n",nIndex);
CvPoint pt1,pt2;
for(int i=0;i<nIndex;i++)
{
pt1.x=(int)CS[i%nIndex].x;
pt1.y=(int)CS[i%nIndex].y;
pt2.x=(int)CS[(i+1)%nIndex].x;
pt2.y=(int)CS[(i+1)%nIndex].y;
printf("cs[%d].x=%f,cs[%d].y=%f\n",i,CS[i].x,i,CS[i].y);
cvLine(Img,pt1,pt2,cvScalar(0,0,255),1,8,0);
}
printf("Finish\n");
cvShowImage(win_name,Img);
re=re+1;
if(re==3)
cvSaveImage("res.bmp",Img);
nCount=0;
printf("nCount=%d,re=%d\n",nCount,re);
goto loop;
cvWaitKey(0);
cvDestroyAllWindows();
cvReleaseImage(&Img);
if(p_Point) delete[] p_Point;
if(m_Point) delete[] m_Point;
if(CS) delete[] CS;
system("PAUSE");
return EXIT_SUCCESS;
}
void Record_Point_CallBack(int event,int x,int y,int flags,void* param)
{
IplImage* pImg=(IplImage*)param;
switch(event)
{
case CV_EVENT_LBUTTONDOWN:
{
pt.x=x;
pt.y=y;
if(nCount<N) cvCircle(pImg,cvPoint(pt.x,pt.y),1,cvScalar(255,0,0),1,8,0);
nCount+=1;
}
break;
case CV_EVENT_RBUTTONDOWN:
{
nCount=-1;
cvZero(pImg);
}
break;
default: break;
}
}