热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

理解Graham扫描算法查找凸包

参考https:muthu.counderstanding-graham-scan-algorithm-for-finding-the-convex-hull-of-a-set-o

参考

 

https://muthu.co/understanding-graham-scan-algorithm-for-finding-the-convex-hull-of-a-set-of-points/

 

 

 

Convex Hull is one of the fundamental algorithms in Computational geometry used in many computer vision applications like Collision avoidance in Self Driving Cars, Shape analysis and Hand Gesture-recognition, etc.

By Definition, A Convex Hull is the smallest convex set that encloses a given set of points. For Example, Given a set of points P in 2D or 3D space, a subset of points in P which fully encloses all points is called the Convex Hull. Take a look at the below figure.

技术分享图片

There are a number of algorithms[1] proposed for computing the convex hull of a finite set of points with various computational complexities. One such algorithm is the Graham Scan algorithm with a worst case complexity of O(nlogn) which is going to be the topic of my discussion in this post.

Before we get into the algorithm we must understand a few basics upon which the Graham scan is built upon because once you understand them, convex hull would become fairly easy to implement.


Convex vs Concave

技术分享图片

Every polygon is either Convex or Concave. A polygon is said to be Convex if all its internal angles are less than 180° as you can see in the figure above. It’s Concave if the polygon has angles greater than 180°.

There is another way to define a Convex Polygon. If every point on every line segment between two points inside or on the boundary of the polygon remains inside or on the boundary then the polygon is said to be Convex. Take a look at the below image to understand the above statement.

技术分享图片


 


Counterclockwise turns

技术分享图片

There are many ways to determine if the tuple of 3 points forms a clockwise turn or a counterclockwise turn or if they are collinear. One of the ways is by finding the determinant of the matrix formed by the three points. If the determinant is positive, then a->b->c is counterclockwise; if the determinant is negative, then a->b->c is clockwise; if the determinant is zero then a->b->c are collinear.

技术分享图片

The determinant is not the most efficient way to identify the turn because of the complexity of multiplication and addition operations. There is a more efficient way which uses the slope of the lines formed by the points.

技术分享图片

Slope of line segment (A, B): σ = (y2 – y1)/(x2 – x1)
Slope of line segment (B, C): τ = (y3 – y2)/(x3 – x2)

If σ > τ, the orientation is clockwise (right turn)

Using above values of σ and τ, we can conclude that,
the orientation depends on sign of below expression:

(y2 – y1)*(x3 – x2) – (y3 – y2)*(x2 – x1)

The above expression is negative when σ <τ, i.e., counterclockwise

The python code we will be using later on for determining the CCW is as below:




  • def ccw(a, b, c):

  • return (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1])



Polar Angle

In the plane, the polar angle theta is the counterclockwise angle from the x-axis at which a point in the xy-plane lies. [2]

技术分享图片

We use a special function in math library atan2 to find the angle in radians.




  • from math import atan2


  • def polar_angle(p0, p1):

  • y_span=p0[1]-p1[1]

  • x_span=p0[0]-p1[0]

  • return atan2(y_span,x_span)



Graham Scan Algorithm

With the basics in place, we are ready to understand the Graham Scan Convex Hull algorithm. The steps in the algorithm are:



  1. Given a set of points on the plane, find a point with the lowest Y coordinate value, if there are more than one, then select the one with the lower X coordinate value. Call this point an Anchor point.

  2. Sort all the points based on the polar angle they make with the anchor point. If two points make the same angle with Anchor Point P, then sort it by distance from P

  3. Initialize the convex hull array with the anchor point and the first element in the sorted array.

  4. Iterate over each point in the sorted array and see if traversing to a point from the previous two points makes a clockwise or a counter-clockwise direction. If clockwise then reject the point and move on to the next point. Continue this till the end of the sorted array.

Take a look at the below simulation to understand the Graham Scan process.

技术分享图片

The complete notebook with the steps is given here.

https://github.com/muthuspark/ml_research/blob/master/Construction%20of%20Convex%20Hull%20using%20Graham%20Scan.ipynb


Step 1: Given a set of points on the plane, find a point with the lowest Y coordinate value, if there are more than one, then select the one with the lower X coordinate value. Call this point an Anchor point.

技术分享图片




  • anchor_point = datapoints[0]

  • for _, point in enumerate(datapoints):

  • if point[1] [1]:

  • anchor_point = point

  • elif point[1] == anchor_point[1] and point[0] [0]:

  • anchor_point = point

  • print(anchor_point)



Step 2: Sort all the points based on the polar angle they make with the anchor point. If two points make the same angle with Anchor Point P, then sort it by distance from P




  • from math import atan2


  • def polar_angle(p0, p1):

  • y_span=p0[1]-p1[1]

  • x_span=p0[0]-p1[0]

  • return atan2(y_span,x_span)


  • # find the angle

  • datapoints_angles = []

  • origin = [0,0]

  • for _, point in enumerate(datapoints):

  • datapoints_angles.append([point[0],point[1], polar_angle(anchor_point, point)])


  • datapoints_angles = np.array(datapoints_angles)

  • datapoints_angles = datapoints_angles[datapoints_angles[:,2].argsort()]

  • sorted_datapoints = datapoints_angles[:,(0,1)]



Step 3: Initialize the convex hull array with the anchor point and the first element in the sorted array.




  • convex_hull = [anchor_point, sorted_datapoints[0]]



Step 4: Iterate over each point in the sorted array and see if traversing to a point from the previous two points makes a clockwise or a counter-clockwise direction. If clockwise then reject the point and move on to the next point. Continue this till the end of the sorted array.




  • def ccw(a, b, c):

  • return (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1])


  • for point in sorted_datapoints[1:]:

  • while ccw(convex_hull[-2],convex_hull[-1], point)<=0:

  • del convex_hull[-1] # backtrack

  • convex_hull.append(point)


That’s all!

PS: Code I wrote for sorting the array at step 2 doesn’t sort the array if there are duplicate angles. I have to update the code.

References:



    1. https://en.wikipedia.org/wiki/Convex_hull_algorithms

    2. http://mathworld.wolfram.com/PolarAngle.html


推荐阅读
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • 本文介绍了Oracle存储过程的基本语法和写法示例,同时还介绍了已命名的系统异常的产生原因。 ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • Webmin远程命令执行漏洞复现及防护方法
    本文介绍了Webmin远程命令执行漏洞CVE-2019-15107的漏洞详情和复现方法,同时提供了防护方法。漏洞存在于Webmin的找回密码页面中,攻击者无需权限即可注入命令并执行任意系统命令。文章还提供了相关参考链接和搭建靶场的步骤。此外,还指出了参考链接中的数据包不准确的问题,并解释了漏洞触发的条件。最后,给出了防护方法以避免受到该漏洞的攻击。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
author-avatar
能然然520
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有