凸壳求解convex hull

        给定二维平面上一组点集P,寻找它的凸壳 ,可以采用Graham's scan (O(nlgn) 或者Jarvis's march (O(nh), h是凸壳的顶点数。)。

       Graham's scan采用一个stack S, 从y值最小的点开始,逆时针扫描所有点,将其依次入栈S, 如果next-to-top(S), top(S), Pi 形成一个nonleft turn, 说明top(s)在凸壳内部,应该 pop掉。

    1:寻找y值最小点P0.

    2:以P0为极坐标原点,将P中所有点按逆时针方向排序。

    3:push(P0, P1, P2);

    4:FOR i = 3 to n-1

          {

                  while ( next-to-top(S), top(S), Pi 形成一个开口向右的角 )

                   { 

                           pop(S);

                   }

                  push(Pi);

          }                   

### ConvexHull 算法原理详解 ConvexHull包)是计算几何中的一个基础问题,其目标是找到一个最小的多边形,使得给定点集中所有的点都位于该多边形的边界上或内部。包算法广泛应用于计算机视觉、图形学、机器人路径规划等领域。 #### 1. 包的基本定义 对于一个二维平面上的点集 $ Q $,其包是一个最小的多边形,满足 $ Q $ 中的每个点都在多边形的边界上或内部。包通常用 $ CH(Q) $ 表示,即 Convex Hull of $ Q $ [^2]。 #### 2. 包算法的常见类型 包的求解算法有很多种,常见的包括: - **Graham 扫描法**:首先选择一个极点(通常是最左下角的点),然后按照其余点相对于该极点的极角排序,最后依次扫描并维护一个栈,确保每一步都保持性。 - **Andrew 算法(上下包法)**:将点集按 $ x $ 坐标排序,然后分别构造上包和下包。 - **分治算法**:将点集分成两部分,分别求解包,再合并两个包。 - **快速包算法(QuickHull)**:类似于快速排序的思想,通过递归划分点集并构建包。 #### 3. Graham 扫描法的详细原理 Graham 扫描法是求解包的经典算法之一,其时间复杂度为 $ O(n \log n) $,主要步骤如下: - **步骤 1:选择基准点** 选择一个极点,通常是点集中 $ y $ 坐标最小的点,如果有多个点具有相同的 $ y $ 坐标,则选择 $ x $ 坐标最小的点。 - **步骤 2:按极角排序** 以基准点为原点,计算其余点相对于基准点的极角,并按极角从小到大排序。 - **步骤 3:扫描并维护包** 使用一个栈来维护当前的包顶点。每次将新点加入栈时,检查是否满足性条件。如果不满足,则弹出栈顶的点,直到满足条件后再将新点压入栈中。 具体来说,假设当前栈中有两个点 $ b $ 和 $ c $,新加入的点为 $ d $。如果向量 $ \vec{bc} $ 到 $ \vec{cd} $ 的逆时针角度小于 180 度,则说明点 $ c $ 不属于包,应将其弹出栈。 #### 4. Andrew 算法的详细原理 Andrew 算法通过将点集按 $ x $ 坐标排序后,分别构建上包和下包,最终合并得到完整的包。其时间复杂度也为 $ O(n \log n) $,具体步骤如下: - **步骤 1:按 $ x $ 坐标排序** 将所有点按 $ x $ 坐标从小到大排序,如果 $ x $ 坐标相同,则按 $ y $ 坐标排序。 - **步骤 2:构建下包** 从左到右扫描点集,维护一个栈,确保每次加入新点后,包的边界仍然保持性。 - **步骤 3:构建上包** 从右到左扫描点集,同样维护一个栈,确保性。 - **步骤 4:合并包** 将下包和上包合并,并去除重复点,得到最终的包。 #### 5. 包算法的时间复杂度下界 包问题的时间复杂度下界为 $ \Omega(n \log n) $,因为任何比较排序问题都可以归约到包问题。因此,Graham 扫描法和 Andrew 算法的时间复杂度已经达到理论下界,是高效的算法 。 #### 6. OpenCV 中的 convexHull() 函数 OpenCV 提供了 `convexHull()` 函数用于计算图像中点集的包,其函数定义如下: ```cpp void cv::convexHull(InputArray points, OutputArray hull, bool clockwise = false, bool returnPoints = true) ``` - `points`:输入的二维点集。 - `hull`:输出的包顶点。 - `clockwise`:指定包的方向,`true` 表示顺时针方向,`false` 表示逆时针方向。 - `returnPoints`:指定输出形式,`true` 表示输出顶点坐标,`false` 表示输出点索引 [^1]。 #### 7. 实际应用中的注意事项 - **输入点集的预处理**:通常需要对点集进行去噪和排序,以提高算法效率。 - **边界情况处理**:当点集中的点共线或重复时,需特别处理以避免算法失败。 - **性能优化**:在大规模点集中,可以采用分治策略或随机化算法提高效率。 ### 示例代码 以下是一个使用 Python 和 OpenCV 计算包的简单示例: ```python import cv2 import numpy as np # 读取图像并转为灰度图 image = cv2.imread('input.jpg') gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 二值化处理 _, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 寻找轮廓 contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 计算包 for cnt in contours: hull = cv2.convexHull(cnt) # 绘制包 cv2.drawContours(image, [hull], 0, (0, 255, 0), 2) # 显示结果 cv2.imshow('Convex Hull', image) cv2.waitKey(0) cv2.destroyAllWindows() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值