最小包围凸包

最近看了最小凸包绘制,官方代码没看,常见的有Graham's scan算法

其实原理比较简单,先将点集排序,之后根据左转进行栈扫描。

1.点集排序:一般取x坐标最小的,并且尽量y大的,靠左下角的点作为起始点。然后连接起始点P0与其他点,计算连线与竖直向下方向的夹角,按照大小顺序排列。

2.然后根据排序之后的点,依次判定该点是否左转,若是左转,入栈,否则,取下一点。判断左转可以根据矢量面积法:

S(P1,P2,P3)=|y1 y2 y3|= (x1-x3)*(y2-y3)-(y1-y3)*(x2-x3)  第一点为P1,向量方向为P1P2,判断P3点,若S为正,P3在向量P1P2的左侧。

1.点集排序:

void sort(vector& pss)
{
    //pss是装着原本的点
    //bound是排好序的点
    //首先排序

    int count = pss.size();
    int first_Point = 0;
    float* Aangle = new float[count]; //动态数组存放角度
    int Min_x = pss[0].x ;
    int Max_y = pss[0].y ;
    for(int i=0;iMax_y)))
        {
            Min_x = pss[i].x;
            Max_y = pss[i].y;
            first_Point = i;  
        } 
    }
    Point temp = pss[0];       //将起始点放到首位置
    pss[0] = pss[first_Point];
    pss[first_Point]= temp;

//计算连线与竖直方向夹角

    for(int i=0;i

2.栈扫描

void scan(vector& pss,vector& bound)
{
    int i = 1;//记录拐点索引
    int pop_count= 0;//记录弹出次数
    
    bound.push_back(pss[0]);
    bound.push_back(pss[1]);
    bound.push_back(pss[2]);
    //根据已排好序列的点连接线段
    do 
    {
        //计算夹角
        float angle = ((bound[i].y - bound[i+1].y)*(bound[i-1].x - bound[i+1].x) - (bound[i-1].y - bound[i+1].y)*(bound[i].x - bound[i+1].x));
        if(angle<=0.0)//左转
        {
            bound.push_back(pss[(i+2+pop_count)%pss.size()]);// 压栈
            i++;//索引加1
        }
        else//右转
        {
            bound.erase(bound.end()-2);//弹出倒数第二个点
            pop_count++;//弹出次数加1 
            i--;.//索引减1
        }

    } while (pss[0] != *bound.rbegin() );//回到起始点
}

测试:

void test(vector point)

{

       vector bound;

      sort(point);

      scan(point,bound);

      for (int i =0;i

结果:最小包围凸包_第1张图片

你可能感兴趣的:(opencv)