一、凸包

凸包(convex hull)是一个计算几何的概念,通俗的来说就是在一个二维的平面中有n 个点,我们可通过在外面的点画出一个多边型使得所以的点都在这个多边形里面,如下所示

二、Graham扫描法

思路:先找到一个最左边同时最下面的点作为起始点,然后从这个点开始按照逆时针逐个找凸包上的点,实际上就是进行极角排序依次放入栈中,同时对栈进行操作,排除点那些不非顶点的点。

步骤:

  1. 把所有点放在二维坐标系中,那么y方向最小的一定是一个顶点,如果这样的点有两个以上那么可以选择x方向最小的那个点,这样的话就可以找到第一个顶点了。如图中的p0。
  2. p0 作为原点,建立一个坐标系;
  3. 以p0为顶点,计算剩下几个点的角度,如p1的角度为∠Ap0P1=α,p2点的角度为∠Ap0P2=α1,根据图像的这些调度的大小进行排序,像p2和p3这样的点角度是一样的∠Ap0P2=∠Ap0P3,我们将计算x方向的大小,将小的点放到前面,如p2-->p3;
  4. 我们先找到了p0 p1,将其按顺序入栈,然后找第上面已经排序的后一个未入栈的点(待入栈点),这一步主要是判断已经入栈的栈顶元素是不是凸包的顶点,需要的工具是已经排序的下一个入栈的点。此时我们可以 连接原点和栈顶的那个点成一条直线L,判断那个待入栈点的位置,有两种可能性     a: 该点在直线L的上方,如:
  5.       如上图所示,p2 在直线L的上方,p1是凸包上的顶点,那么我们可以将p2入栈,此时栈里面的原始依次是p0、p1、p2,如上图所示。      b:在直线的直线上或者下方那么这个栈顶的元素就不是凸包上的顶点,例如判断待判断点p3:此时栈顶元素是p1。综合a、b两种情况循环判断凸包顶点。

5、重复步骤4,直到最后一个点(补充一下,步骤四中,点不会出现在那条直线的下方,因为在第三步中已经根据角度排序了,我看了好几个博客第四步的分类是有问题的,这是我个人的理解,如有问题请不吝指出,谢谢)

 最后,栈中的元素就是凸包上的点了。

图像如下:

 在实际写代码的时候看到了下面的方法,这个方法比直线的更加方便,让人容易理解,前面的三步都是一样的,就是后面的第四步有所区别

补充:浅谈叉积的意义:

a=AC=(C-A)=(0-0,2-0)=(0,2);

b=AB=(B-A)=(1-0,1-0)=(1,1)

同理:若 a(x1,y1), b(x2,y2),则:

记作result=a×b=AC×AB=x1y2-y1x2;

result>0  ----->AC 在AB 的左边

result=0  ----->AC AB 共线,这里就要查方向了

result<0  ----->AC 在AB 的右边

代码实现


Mat src(800, 800, CV_8UC3);
vector<Point> points;
vector<Point> statk_points;
Point  firstPoint = {0,0}; // 找到的第一个点,也就是最下面,最左边的点//在图像上随机生成点  找到第一个点
void createPoints()
{RNG rng = theRNG();int count = (unsigned)rng % 100 + 21;for (int i = 0; i < count; ++i){Point p;p.x = rng.uniform(100, 600);p.y = rng.uniform(100, 600);points.push_back(p);}int n = points.size();// 寻找所有点中的最左边和左下面的点for (int i = 0; i < n; i++){if (points[i].y> firstPoint.y||(points[i].y == firstPoint.y&& points[i].x == firstPoint.x)){firstPoint = points[i];}}printf("%d    %d\n", firstPoint.x, firstPoint.y);for (int  i = 0; i < n; i++){if (firstPoint == points[i]){statk_points.push_back(points[i]);circle(src, points[i], 5, Scalar(0, 0, 255), -1);}else {circle(src, points[i], 2, Scalar(0, 0, 0), -1);}}}// 计算两个点之间的距离
double distance(Point p1, Point p2)
{return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}//计算叉积,小于0说明p1在p2的逆时针方向(右边),即p0p1的极角大于p0p2的极角
//a×b,公式:若a = (x1, y1),b = (x2, y2),则
//AC×AB = x1y2 - x2y1=b
double cross_product(Point p0, Point p1, Point p2)
{return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}// com
bool  com(Point& p1,  Point& p2)
{double temp = cross_product(firstPoint, p1, p2);if (fabs(temp) < 1e-6)//极角相等按照距离从小到大排序{return distance(firstPoint, p1) < distance(firstPoint, p2);}else{return temp > 0;}
}
vector<Point> Graham_Scan()
{// 1、生产点 并找出第一个点createPoints();int top = 2;printf("%d\n", points.size());// 2、极坐标排序sort(points.begin() + 1, points.end(), com);statk_points.push_back(points[1]);statk_points.push_back(points[2]);imshow("生产点-第一个点", src);for (int i = 3; i < points.size(); ++i){while (top > 0 && cross_product(statk_points[top - 1], points[i], statk_points[top]) >= 0){--top;statk_points.pop_back();}statk_points.push_back(points[i]);++top;}return  statk_points;
}int main()
{vector<Point> p=Graham_Scan();int count = p.size();Mat newimgage = src.clone();for (int i = 0; i < count-1; ++i){line(newimgage, p[i], p[i+1], Scalar(0, 0, 255),1,8,0);}line(newimgage, p[count - 1], p[0], Scalar(0, 0, 255), 1, 8, 0);imshow("凸包", newimgage);waitKey(0);return 0;}

 

Opencv 笔记7 凸包算法-Graham扫描法相关推荐

  1. 凸包算法Graham扫描法

    凸包算法(Graham扫描法) 转载自 SZUhg https://www.cnblogs.com/wpbing/p/9456240.html 叉乘与线段相交 判断一个点是否在一条线段的左边还是右边, ...

  2. 凸包算法-------Graham扫描法

    在网络上关于凸包解法多种多样,讲的也非常的不错,可以参考一下这篇博客,但是还是想用自己的话去描述一遍,以加深一下印象. 常见的解法有: 穷举法(蛮力法) 分治法 Jarvis步进法 Graham扫描法 ...

  3. 凸包(Graham扫描法构建)

    凸包(Graham扫描法构建) PS:我的妈呀,心态爆炸,好像也不太难,看各种模板看的云里雾里的,真的还是自己动手敲来的好,几乎没多久就懂的差不多了.... 一个本该寒假就该掌握的知识,居然熬了我几个 ...

  4. 凸包问题 —— Graham扫描法

    凸包问题 -- Graham扫描法: (1)找出点集p[]中最左下的点p1,把p1同点集中其他各点用线段连接,并计算这些线段与水平线的夹角,然后按夹角从小到大和按到p1的距离从近到远排序(夹角范围为 ...

  5. CGAL笔记之凸包算法—3D凸包

    CGAL笔记之凸包算法-3D凸包 1 介绍 2 静态凸壳结构 2.1 特性类 2.1.1 示例 2.1.2 低维结果示例 2.2 极值点 2.3 半空间交集 2.3.1 例子 2.4 凸性检查 3 动 ...

  6. 【opencv学习笔记】030 之 凸包之Graham扫描法与Jarvis步进法详解

    目录 一.前言 二.凸包 1.概念 2.凸包查找算法 1.Graham扫描法 2.Jarvis步进法 3.凸包API 4.代码展示 5.执行结果 一.前言 继续更新有关于opencv的基础博客,即将更 ...

  7. 凸包与Graham扫描法求凸包

    前置芝士 凸多边形 凸多边形指的是所有内角都在 (0,π](0,\pi](0,π] 范围内的多边形. 凸包 对于一个平面上的一个给定的点集,他们对应的凸包就是能把他们全部包含的最小凸多边形. 如果形象 ...

  8. 寻找凸包的graham 扫描法

    1,点集Q的凸包(convex hull)是指一个最小凸多边形,满足Q中的点或者在多边形边上或者在其内.  2,凸包最常用的凸包算法是Graham扫描法和Jarvis步进法.  3,Graham扫描法 ...

  9. c语言凸包算法,基于C语言的凸包算法实现

    基于C语言的凸包算法实现 非计算机专业,代码有些的不好的地方,大佬轻喷^ _ ^ 根据要求,需要使用C语言实现凸包算法--Graham扫描法,本文将从算法理解.实现思路.遇到的问题及其解决方案三个方面 ...

最新文章

  1. (转)如何修改maven的默认jdk版本
  2. Zynq UltraScale + MPSoC示例设计 - 在64位Linux上执行32位应用程序
  3. Hyper-V 2016 系列教程48 Windows Server Backup 一次性备份操作
  4. Python:执行精确的浮点数运算
  5. Socket.io 深入理解
  6. 深度学习算法简要综述(下)
  7. No valid Qt version set. Set one in Tools/Options 问题(QT)
  8. Frame中添加一个黄色的panel
  9. rem + vw 布局
  10. spring之httpclient doget请求
  11. mysql可视化工具
  12. Unity 安卓打包
  13. 电子电路设计中的脉冲电路详解
  14. Java实现 蓝桥杯算法提高金明的预算方案
  15. bde oracle 商友的流程_BorlandC++使用BDE访问Oracle的方法
  16. 2020主流室内定位技术对比
  17. 计算机考研11408总分418上岸攻略
  18. 【空指针异常,也不全是。】
  19. SN74AHCT541PWR缓冲器 非反向1Element 8 Bit per Element 三态 Output 20-TSSOP
  20. Java 报错 restartedMain] o.s.boot.SpringApplication : Application run failed

热门文章

  1. the win16 subsystem was unable to enter protected mode,DOSX.EXE must be in your AUTOEXEC.NT and pres
  2. Thinkphp内核自动挂机阅读文章系统源码
  3. python xlrd导入后怎么保存_pythonxlrd导入.xslx模板,使用Openpyxl编辑并重新保存.xslx-Fi...
  4. 关于含税单价和不含税单价的关系记录
  5. Python爬虫练习:爬取猫眼电影实时票房
  6. 人人5功盖世时候,我在支持国产
  7. 优化算法之引力搜索算法
  8. MD5 标准算法详解
  9. PHP 将两个数组合并,保持原有key,并保持在同一个维度
  10. android在framework层增加自己的service仿照GPS