Opencv(十八) : 图像凸包检测

编程达人挑战赛·第5期 10w+人浏览 277人参与

一、凸包是什么?

凸包就是包含某一点集所有点的最小凸多边形,特点是完全凸起、没有凹处。简单说,就像用一根橡皮筋紧紧围住所有点,松手后橡皮筋自然形成的轮廓——所有点要么在轮廓上,要么在轮廓内。

它的核心价值是简化物体形态,保留关键边界特征,常用在物体识别、手势识别、边界检测等场景。

二、4种核心凸包算法

1. 穷举法

  • 核心逻辑:把点集中所有点两两配对连线,检查其他所有点是否都在这条直线的同一侧。如果是,这两个配对点就是凸包点。
  • 优点:原理简单,不用复杂逻辑;
  • 缺点:效率极低,仅适合极少数点的场景(比如少于50个点),实际用得少。

2. Graham扫描法

步骤
  1. 将纵坐标最小的点记为P0,且以该点为原点构建二维坐标系,那么P0就一定是一个凸包点。
  2. 计算各个点对于P0的角度,按照从小到大的顺序进行排序(逆时针顺序),当角度相同时,与P0较近的点排在前面。那么角度最大的点和角度最小的点一定是凸包点。
  3. 用栈来记录已知的凸包点,先将P0和P1放入栈中,然后去求下一个凸包点。
  4. 入栈下一个点,将栈顶的两个点相连,得到一条直线。看下一个点在直线的右侧还是左侧,如果
    是右侧就执行步骤5,如果在左侧或在直线上就执行步骤6。
  5. 如果在右侧,说明栈顶的那个点不是凸包点,将栈顶元素出栈并执行步骤4。
  6. 如果在左侧或直线上,说明该点是凸包点,就将其保存。
  7. 检查栈顶的点是不是步骤2中角度值最大的那个点,如果是就结束了,如果不是就将当前点的下个
    点作为要计算的对象,执行步骤4,直到栈顶元素就是步骤2中角度值最大的点,那么循环结束。

3. Andrew扫描链法

步骤
  1. 对所有点按坐标x为第一关键字、y为第二关键字排序,第1个和最后一个
    肯定在凸包上。
  2. 先顺序遍历所有点,通过三个点所构建的两个向量的叉积来判断是不是凸
    包点,这样就可以构建出下凸包。
  3. 然后逆序遍历所有点,按照相同的方式就可以构建出上凸包,最后将上凸
    包和下凸包连接即可。
  • 优点:实现最简单、稳定性最高,是工程里最常用的算法;
  • 适用:几乎所有场景,从几百个点到几万个点都能高效处理。

4. QuickHull法

  • 核心步骤(3步搞定):
    1. 找横坐标最小的P1和最大的P2,连线后把点集分成“上包”(直线上方)和“下包”(直线下方);
    2. 以上包为例,找距离P1P2直线最远的点P3,连线P1P3和P2P3,再筛选出新的候选点集;
    3. 对新的点集重复步骤2,直到没有可添加的点,下包同理处理。
  • 优点:平均效率极高,适合大规模点集(比如几万个点);
  • 缺点:极端情况(比如所有点共线)效率会下降。

三、代码实现凸包检测

# 导入opencv的库(计算机视觉处理核心库)
import cv2

# 1.读取图片(BGR格式,OpenCV默认读取方式)
image_np = cv2.imread('./picture.png')  # 替换为自己的图片路径

# 2.灰度化(降维:3通道彩色图→1通道灰度图,减少计算量)
image_gray = cv2.cvtColor(image_np,cv2.COLOR_BGR2GRAY)

# 3.二值化(黑白分割:将灰度图转为只有0/255的黑白图,突出轮廓)
ret,image_thresh = cv2.threshold(image_gray,127,255,cv2.THRESH_BINARY)

# 4.获取轮廓点的坐标(提取物体边界的关键步骤)
contours,hierarchy = cv2.findContours(image_thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

# 5.寻找凸包(核心:从轮廓点中筛选出凸包点)
# cv2.convexHull(points,hull,clockwise,returnPoints)
cnt = contours[0]  # 取第一个轮廓(假设图片只有一个物体)
hull = cv2.convexHull(cnt)  # 计算该轮廓的凸包
print(type(hull))  # 输出:<class 'numpy.ndarray'>,凸包点是多维数组

# 6.绘制凸包(把凸包轮廓画在原图上)
# polylines(img,pts,isClosed,color,thickness,lineType,shift)
image_poly = cv2.polylines(image_np,[hull],True,(0,0,255),2)  # 红色、线宽2

# 7.结果显示(弹出窗口展示图片)
cv2.imshow('image_np',image_np)  # 原图+凸包
cv2.imshow('image_poly',image_poly)  # 同image_np(因为polylines直接修改原图)
cv2.waitKey(0)  # 等待按键关闭窗口
cv2.destroyAllWindows()  # 补充:建议加这行,避免窗口残留

输出结果为:
在这里插入图片描述
在这里插入图片描述

四、核心总结

  1. 凸包的核心作用:简化形态、保留边界,为后续识别/检测提供基础;
  2. 算法选择优先级:Andrew扫描链法(首选,简单稳定)→ Graham扫描法(中大规模点集)→ QuickHull法(超大点集)→ 穷举法(仅学习用);
  3. 关键共性:所有算法都是通过“筛选最外层点”实现,核心是判断点与直线的位置关系(左侧/右侧/共线)。
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mrliu__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值