第6篇|OpenCV边缘检测✂️捕捉目标轮廓
上一篇我们讲解了阈值处理,实现了目标与背景的分离,这是图像识别的基础。
但要真正“识别”一个目标,需要捕捉它的边缘——边缘是目标与背景的分界线,也是目标形状、轮廓的关键特征(比如人脸的轮廓、文字的笔画边缘、物体的轮廓)。
今天我们就来讲讲OpenCV中最核心的边缘检测技术。
📌 什么是边缘?如何检测边缘?
首先我们明白一个核心概念:图像中的“边缘”,本质是像素值发生剧烈变化的区域。
比如一张黑色背景上的白色方块,方块的边缘处,像素值从0(黑色)瞬间变为255(白色),这种剧烈的灰度变化,就是边缘的特征。
边缘检测的逻辑,就是识别出像素值迅速变化的区域,具体大概两步:
降噪处理: 图像中通常存在噪声(比如轻微的杂点),噪声会导致边缘误检测,因此第一步需要对图像进行模糊降噪,让真实边缘更加明显;
边缘检测: 通过算法计算像素值的变化幅度,或说梯度。梯度越大,说明像素值变化越剧烈,越可能是边缘,再通过设定阈值,保留梯度大的区域,即得到了边缘。
OpenCV提供了多种常用的边缘检测算法,适用于不同场景,我们重点讲解最常用的Canny算法,以及Sobel、Laplacian两种补充算法。
🔧 三种常用边缘检测算法
我们以“物体轮廓图像”为例,分别演示三种算法的边缘检测效果。
1. Canny边缘检测
Canny算法是目前最常用的边缘检测算法,抗噪声能力强,检测出的边缘更细腻、更精准。它能有效去除虚假边缘,保留真实边缘,适用于大多数场景。
函数调用:
cv2.Canny(image, threshold1, threshold2, apertureSize, L2gradient)
参数(重点在前3个):
image: 需要检测的图像矩阵(灰度图最佳,彩色图也可);
threshold1: 低阈值(用于过滤弱边缘,常用50-100);
threshold2: 高阈值(用于确定强边缘,常用100-200);
补充:高阈值和低阈值的比例通常为2:1或3:1,高于高阈值的是强边缘,低于低阈值的是弱边缘,介于两者之间的,若与强边缘相连,则保留,否则去除。
import cv2# 读取图像并转换为灰度图img = cv2.imread("test.png")img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 高斯模糊降噪(Canny算法内置降噪,但额外降噪效果通常能更好)img_blur = cv2.GaussianBlur(img_gray, (3, 3), 0) # (3,3)是模糊核大小# Canny边缘检测(低阈值50,高阈值100)canny_edges = cv2.Canny(img_blur, 50, 100)cv2.imshow("original", img)cv2.imshow("Canny edges", canny_edges)cv2.waitKey(0)cv2.destroyAllWindows()
2. Sobel边缘检测
Sobel算法的核心是“通过梯度计算,分别检测水平方向和垂直方向的边缘”,抗噪声能力强,计算速度快,但检测出的边缘较粗,不够细腻,适合对边缘精度要求不高的场景。
函数调用:
cv2.Sobel(src, ddepth, dx, dy, ksize)
参数说明:
ddepth:输出图像的深度(通常设为cv2.CV_64F,避免梯度计算时数字溢出);
dx:水平方向梯度(1表示检测水平边缘,0表示不检测);
dy:垂直方向梯度(1表示检测垂直边缘,0表示不检测);
ksize: Sobel核的大小(常用3、5、7,值越大,则边缘越粗)。
import cv2import numpy as npimport matplotlib.pyplot as pltimg = cv2.imread("test.png")img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 检测水平方向边缘(dx=1,dy=0)sobel_x = cv2.Sobel(img_gray, cv2.CV_64F, 1, 0, ksize=3)# 检测垂直方向边缘(dx=0,dy=1)sobel_y = cv2.Sobel(img_gray, cv2.CV_64F, 0, 1, ksize=3)# 处理梯度负值(将负值转为正值,避免边缘丢失)sobel_x = cv2.convertScaleAbs(sobel_x)sobel_y = cv2.convertScaleAbs(sobel_y)# 合并水平和垂直边缘sobel_edges = cv2.addWeighted(sobel_x, 0.5, sobel_y, 0.5, 0)plt.subplot(2, 2, 1)plt.imshow(img_gray, cmap="gray")plt.title("Original Gray")plt.subplot(2, 2, 2)plt.imshow(sobel_x, cmap="gray")plt.title("Horizontal Edge")plt.subplot(2, 2, 3)plt.imshow(sobel_y, cmap="gray")plt.title("Vertical Edge")plt.subplot(2, 2, 4)plt.imshow(sobel_edges, cmap="gray")plt.title("Sobel Combined Edge")plt.show()
3. Laplacian边缘检测
Laplacian算法是“检测所有方向的边缘”(不需要分别检测水平和垂直),检测速度快,但抗噪声能力弱,容易检测出虚假边缘,适合“噪声少、边缘清晰”的场景。
函数调用:
cv2.Laplacian(src, ddepth, ksize)
参数说明:与Sobel算法类似,ddepth设为cv2.CV_64F,ksize为奇数(3、5、7)。
import cv2import numpy as npimg = cv2.imread("test.png")img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 高斯模糊降噪(Laplacian抗噪声弱,须先降噪)img_blur = cv2.GaussianBlur(img_gray, (3, 3), 0)# Laplacian边缘检测laplacian_edges = cv2.Laplacian(img_blur, cv2.CV_64F, ksize=3)# 处理梯度负值,转为正值laplacian_edges = cv2.convertScaleAbs(laplacian_edges)cv2.imshow("Original Image", img)cv2.imshow("Laplacian Edge Detection", laplacian_edges)cv2.waitKey(0)cv2.destroyAllWindows()
📊 三种算法对比
Canny算法:效果最好、抗噪声强、边缘细腻,适合大多数场景(首选);
Sobel算法:抗噪声强、速度快、边缘较粗,适合粗轮廓检测、工业场景;
Laplacian算法:检测所有方向边缘、速度快,抗噪声弱,适合噪声少、简单场景。
💡 小贴士
边缘模糊问题 先做高斯模糊降噪,尤其是Laplacian算法,降噪很关键。
Canny算法阈值选择 低阈值和高阈值比例2:1或3:1;若边缘太少,降低低阈值;若虚假边缘太多,提高高阈值。
📌 小结+预告
本篇我们介绍了三种常用的边缘检测算法——Canny、Sobel、Laplacian,了解了算法的原理、优缺点和适用场景。
下篇我们将学习“轮廓检测与形状分析”,基于边缘检测的结果,提取目标的完整轮廓,再通过轮廓分析,判断目标的形状(比如圆形、矩形、三角形)、计算轮廓的面积和周长等等。
往期回顾:
字符串str的操作|Python自学成才(番外篇1)
用OpenCV提取图像中的目标区域 | Part.5
OpenCV在处理图像时的颜色异常问题 | Part.4
改个文件的后缀名,然后在文件里藏点好东西
你知不知道计算机是如何识别一个文件的类型
用OpenCV对图片进行简单的几何操作 | OpenCV-Part.3