如果把索贝尔(Sobel)和拉普拉斯(Laplacian)比作"挖掘机",那 Canny 边缘检测 就是整个工程队的**"总指挥官"**。
它不是一个单一的算子,而是一套**"组合拳"。它诞生于 1986 年,至今仍是计算机视觉领域的"黄金标准"**。为什么?因为它最聪明,能帮你把那些乱七八糟的噪点过滤掉,只留下最真实、最连贯的边缘。
Canny 的工作逻辑非常严密,就像工厂里的四道质检工序,缺一不可。
🏭 Canny 的"四步走"流水线
第一步:大扫除(高斯滤波)
"先别急着找边缘,把地扫干净。"
还记得我们之前聊的高斯噪点吗?边缘检测最怕噪点,因为噪点也是灰度突变,很容易被误认为是边缘。
- 动作 :Canny 首先会用高斯滤波把图片"磨皮"一下。
- 目的:把那些细小的噪点抹平,防止后面误判。
第二步:找坡度(计算梯度)
"看看哪里是上坡,哪里是下坡。"
这一步就是请出我们刚才聊的索贝尔算子(Sobel)。
- 动作 :计算每个像素点的梯度幅值 (坡度有多陡)和梯度方向(坡往哪边上)。
- 结果 :此时我们得到了一张充满了"坡度信息"的图,但这时候的边缘通常比较粗,像是一条条宽带子,而不是细线。
第三步:瘦身(非极大值抑制)
"把粗宽的边缘,修成细细的线。"
这是 Canny 最核心的独门绝技!
- 问题:刚才索贝尔找到的边缘往往有好几个像素宽(像一座山的山脊)。
- 动作 :Canny 会沿着"坡度方向"检查,只保留坡度最陡的那个点(山顶),把旁边的"山坡"全部削掉(置为 0)。
- 结果 :原本粗粗的边缘带,瞬间变成了一条单像素宽的细线。
第四步:严筛选(双阈值检测)
"谁是真边缘,谁是假边缘?"
这时候图上还有很多杂乱的细线,哪些是我们要的物体轮廓,哪些是干扰?Canny 用了两把尺子来量:高阈值 和低阈值。
- 强边缘(肯定保留) :
- 梯度值 > 高阈值。
- 比如:物体的主轮廓,非常清晰,直接留下。
- 非边缘(直接扔掉) :
- 梯度值 < 低阈值。
- 比如:残留的噪点,直接删掉。
- 弱边缘(看情况) :
- 低阈值 < 梯度值 < 高阈值。
- 比如:光线暗的地方的轮廓,或者是纹理。
- 智能判断 :如果这个"弱边缘"连着"强边缘",说明它是物体的一部分,保留!如果它孤零零的,说明是噪点,扔掉!
📌 为什么 Canny 是"黄金标准"?
因为它完美解决了三个矛盾:
- 低错误率:该找到的边缘都找到了(没漏掉),不是边缘的没乱找(没误判)。
- 高定位精度:找到的边缘位置非常准,就在物体的真实边界上(得益于"瘦身"步骤)。
- 单边缘响应:一个边缘只画一条线,不会画出重影(也得益于"瘦身")。
🆚 索贝尔 vs. Canny
| 特性 | 索贝尔 (Sobel) | Canny |
|---|---|---|
| 身份 | 一个算子 | 一套完整的算法流程 |
| 结果 | 边缘比较粗,容易有噪点 | 边缘是细线,干净、连贯 |
| 复杂度 | 简单,计算快 | 复杂,计算慢 |
| 用途 | 简单的方向检测 | 需要精准轮廓的高级任务 |
一句话总结:
如果你只是想简单看看图片哪里变化了,用索贝尔;如果你需要精准、干净、连贯 的物体轮廓(比如要识别车牌、人脸),Canny 是永远的神。
在 Canny 边缘检测的流程中,"像素强度"指的其实是梯度幅值。
简单来说,它计算的是**"这个像素点和周围邻居相比,颜色(灰度)变化得有多剧烈"**。变化越剧烈,数值越大,就越像是边缘。
这个计算过程主要分三步走:
1. 找变化(计算 GxG_xGx 和 GyG_yGy)
首先,我们要看这个像素在横向 和纵向 上分别变化了多少。通常使用索贝尔算子来完成。
- GxG_xGx(横向变化) :用右边的像素减去左边的像素(加权)。如果左右差别大,说明有垂直边缘。
- GyG_yGy(纵向变化) :用下边的像素减去上边的像素(加权)。如果上下差别大,说明有水平边缘。
通俗理解:
- GxG_xGx 是"左右坡度"。
- GyG_yGy 是"上下坡度"。
2. 算总强度(合成梯度幅值)
有了横向和纵向的变化量,怎么算出总的"强度"呢?这就用到了勾股定理。
公式如下:
强度=Gx2+Gy2 \text{强度} = \sqrt{G_x^2 + G_y^2} 强度=Gx2+Gy2
也就是:强度的平方 = 横向变化的平方 + 纵向变化的平方。
3. 举个栗子(算一算)
假设有一个像素点 PPP,经过索贝尔算子计算后:
- 它左边的像素很暗,右边很亮,算出横向变化 Gx=30G_x = 30Gx=30。
- 它上下的像素亮度差不多,算出纵向变化 Gy=10G_y = 10Gy=10。
那么,这个像素点的最终强度就是:
强度=302+102=900+100=1000≈31.6 \text{强度} = \sqrt{30^2 + 10^2} = \sqrt{900 + 100} = \sqrt{1000} \approx 31.6 强度=302+102 =900+100 =1000 ≈31.6
📌 总结
这个算出来的 31.6,就是你在上一个问题里问的**"像素强度"**。
接下来,Canny 就会拿这个 31.6 去和你的 minVal 和 maxVal 做比较:
- 如果
maxVal是 50,31.6 < 50,那它就不是"强边缘"。 - 如果
minVal是 20,31.6 > 20,那它就是"弱边缘"(待定区),需要看它有没有连着强边缘。