在计算机视觉领域,边缘检测与轮廓查找是图像分析的核心技术。本文将结合OpenCV库(cv2模块),从理论原理到代码实战,系统讲解如何通过Python实现这两个关键操作。
边缘是图像中灰度/颜色发生剧烈变化的区域,其数学本质是图像梯度的局部最大值。常见应用场景包括:
轮廓是图像中连续边缘点的集合,代表物体的形状信息。与边缘检测不同,轮廓查找更关注闭合区域的完整描述,常用于:
pip install opencv-python numpy matplotlib
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 读取图像(建议使用灰度模式)
img = cv2.imread('test.jpg', cv2.IMREAD_GRAYSCALE)
# 1. 预处理(降噪)
blurred = cv2.GaussianBlur(img, (5,5), 0)
# 2. 边缘检测
edges = cv2.Canny(blurred, threshold1=50, threshold2=150)
# 3. 轮廓查找
contours, hierarchy = cv2.findContours(
edges,
cv2.RETR_EXTERNAL, # 检索模式
cv2.CHAIN_APPROX_SIMPLE # 近似方法
)
# 4. 结果可视化
result = cv2.drawContours(img.copy(), contours, -1, (0,255,0), 2)
plt.imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
plt.show()
Canny算法参数优化技巧:
threshold1/threshold2
:双阈值策略,建议保持2:1~3:1比例median = np.median(img)
sigma = 0.33
lower = int(max(0, (1.0 - sigma) * median))
upper = int(min(255, (1.0 + sigma) * median))
参数 | 选项 | 适用场景 |
---|---|---|
检索模式 | RETR_EXTERNAL RETR_TREE |
仅外层轮廓 完整层级结构 |
近似方法 | CHAIN_APPROX_NONE CHAIN_APPROX_SIMPLE |
保留所有点 压缩冗余点 |
for cnt in contours:
# 面积过滤
area = cv2.contourArea(cnt)
if area < 100: continue
# 最小外接矩形
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
# 轮廓近似(多边形逼近)
epsilon = 0.02 * cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True)
def document_scanner(img_path):
# 预处理
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5,5), 0)
# 自适应阈值处理
thresh = cv2.adaptiveThreshold(
blurred, 255,
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY_INV, 11, 2
)
# 轮廓查找
contours, _ = cv2.findContours(
thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
)
# 筛选最大轮廓(假设文档为最大区域)
max_cnt = max(contours, key=cv2.contourArea)
# 透视变换
rect = cv2.minAreaRect(max_cnt)
box = cv2.boxPoints(rect)
box = np.int0(box)
# 获取变换矩阵
width = int(rect[1][0])
height = int(rect[1][1])
src_pts = box.astype("float32")
dst_pts = np.array([[0, height-1],
[0, 0],
[width-1, 0],
[width-1, height-1]], dtype="float32")
M = cv2.getPerspectiveTransform(src_pts, dst_pts)
# 应用变换
warped = cv2.warpPerspective(img, M, (width, height))
return warped
# 形态学闭运算
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
closed = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)
# 面积过滤+长宽比筛选
valid_contours = []
for cnt in contours:
area = cv2.contourArea(cnt)
if area < 500: continue
x,y,w,h = cv2.boundingRect(cnt)
aspect_ratio = w / float(h)
if 0.8 < aspect_ratio < 1.2:
valid_contours.append(cnt)
cv2.setNumThreads()
加速轮廓查找通过本文的学习,您已掌握从基础边缘检测到复杂轮廓分析的全流程技术。建议通过实际项目(如车牌识别、文档扫描)巩固知识,重点关注参数调优与异常处理能力。完整代码已上传至GitHub(链接),欢迎Star与Issue交流。