云计算百科
云计算领域专业知识百科平台

OpenCV基础入门4:轮廓检测与模板匹配

一、轮廓检测基础

1.1 什么是轮廓?

轮廓可以简单理解为连续的点组成的曲线,这些点具有相同的颜色或灰度值。在计算机视觉中,轮廓是形状分析和物体检测与识别的关键基础。通过轮廓分析,我们可以识别物体的形状、计算其面积和周长,并进行进一步的图像处理。

1.2 核心API:cv2.findContours()

image, contours, hierarchy = cv2.findContours(img, mode, method)

参数详解:

参数说明
img 需要检测的原图(必须是二值图像)
mode 轮廓检索模式
method 轮廓近似方法

mode(检索模式)对比:

模式说明
cv2.RETR_EXTERNAL 只检测外轮廓,忽略所有子轮廓
cv2.RETR_LIST 不建立等级关系,所有轮廓同属一级
cv2.RETR_CCOMP 建立两级组织结构(外轮廓为1级,内孔为2级)
cv2.RETR_TREE 建立完整的树形组织结构(最常用)

method(近似方法)对比:

方法说明
cv2.CHAIN_APPROX_NONE 存储所有轮廓点
cv2.CHAIN_APPROX_SIMPLE 压缩存储,只保留关键点(如矩形只存4个点)

返回值说明:

  • image:处理后的原图
  • contours:所有轮廓的列表,每个轮廓以numpy数组存储边界点坐标
  • hierarchy:轮廓层次结构 [Next, Previous, First Child, Parent]

1.3 完整示例:轮廓检测与绘制

在绘制轮廓之前,我们先了解 cv2.drawContours() 函数的详细参数:

cv2.drawContours(image, contours, contourIdx, color, thickness=None,
lineType=None, hierarchy=None, maxLevel=None, offset=None)

参数详解:

参数说明
image 要在其上绘制轮廓的输入图像
contours 轮廓列表,通常由 cv2.findContours() 函数返回
contourIdx 要绘制的轮廓的索引。如果为负数(如 -1),则绘制所有轮廓
color 轮廓的颜色,以 BGR 格式表示。例如,(0, 255, 0) 表示绿色
thickness 轮廓线的粗细。默认值为 1
lineType 轮廓线的类型。默认值为 cv2.LINE_8
hierarchy 轮廓层次结构。通常由 cv2.findContours() 函数返回
maxLevel 绘制的最大轮廓层级。默认值为 None,表示绘制所有层级
offset 轮廓点的偏移量。默认值为 None

完整示例代码:

import cv2

# 1. 读取图片并转为灰度图
phone = cv2.imread('phone.png')
phone_gray = cv2.cvtColor(phone, cv2.COLOR_BGR2GRAY)

# 2. 二值化处理(关键步骤!)
ret, phone_binary = cv2.threshold(phone_gray, 120, 255, cv2.THRESH_BINARY)

# 3. 检测轮廓
contours = cv2.findContours(phone_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[2]
print(f"检测到 {len(contours)} 个轮廓")

# 4. 绘制轮廓
image_copy = phone.copy()
cv2.drawContours(
image=image_copy,
contours=contours,
contourIdx=1, # -1 表示绘制所有轮廓
color=(0, 255, 0), # BGR格式,绿色
thickness=2
)
cv2.imshow('Contours', image_copy)
cv2.waitKey(0)

二、轮廓特征分析

2.1 轮廓面积与周长

# 计算面积
area = cv2.contourArea(contours[0])
print(f"面积: {area}")

# 计算周长(closed=True 表示闭合)
perimeter = cv2.arcLength(contours[0], closed=True)
print(f"周长: {perimeter}")

2.2 根据面积筛选轮廓

# 筛选面积大于10000的轮廓
large_contours = []
for c in contours:
if cv2.contourArea(c) > 10000:
large_contours.append(c)

# 按面积排序,取最大的
sorted_contours = sorted(contours, key=cv2.contourArea, reverse=True)
largest_contour = sorted_contours[0]

2.3 外接矩形与最小外接圆

cnt = contours[6] # 取第7个轮廓

# 外接矩形
x, y, w, h = cv2.boundingRect(cnt)
cv2.rectangle(phone, (x, y), (x+w, y+h), (0, 255, 0), 2)

# 最小外接圆
(x, y), radius = cv2.minEnclosingCircle(cnt)
cv2.circle(phone, (int(x), int(y)), int(radius), (0, 255, 0), 2)

三、轮廓近似

轮廓近似是多边形拟合的过程,用更少的点来表示轮廓,对于形状识别和压缩非常有用。

3.1 核心API:cv2.approxPolyDP()

approx = cv2.approxPolyDP(curve, epsilon, closed)

参数说明:

  • curve:输入轮廓
  • epsilon:近似精度(越小越接近原轮廓,越大越粗糙)
  • closed:是否闭合

3.2 完整示例

import cv2

phone = cv2.imread('phone.png')
phone_gray = cv2.cvtColor(phone, cv2.COLOR_BGR2GRAY)
ret, phone_thresh = cv2.threshold(phone_gray, 120, 255, cv2.THRESH_BINARY)
contours = cv2.findContours(phone_thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[2]

# epsilon = 0.0001 * 轮廓周长(精度非常高)
epsilon = 0.0001 * cv2.arcLength(contours[0], True)
approx = cv2.approxPolyDP(contours[0], epsilon, True)

print(f"原始轮廓点数: {contours[0].shape}")
print(f"近似后轮廓点数: {approx.shape}")

# 绘制近似轮廓(绿色)
phone_new = phone.copy()
cv2.drawContours(phone_new, [approx], 1, (0, 255, 0), 3)
cv2.imshow('Approx', phone_new)
cv2.waitKey(0)

四、实战案例:花朵轮廓检测与近似

4.1 作业要求

给定图片 hua.png,在同一窗口内完成:

  • 用红色画出花的外部轮廓
  • 用绿色画出其近似轮廓(ε = 0.005 × 周长)

4.2 代码实现

import cv2

# 读取并转为灰度图
hua = cv2.imread('hua.png')
hua_gray = cv2.cvtColor(hua, cv2.COLOR_BGR2GRAY)

# 二值化处理(注意使用 THRESH_TOZERO_INV)
ret, hua_binary = cv2.threshold(hua_gray, 240, 255, cv2.THRESH_TOZERO_INV)
cv2.imshow('Binary', hua_binary)
cv2.waitKey(0)

# 轮廓检测(只检测外轮廓)
contours = cv2.findContours(hua_binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[2]
print(f"检测到 {len(contours)} 个轮廓")

# 近似处理
epsilon = 0.005 * cv2.arcLength(contours[0], True)
approx = cv2.approxPolyDP(contours[0], epsilon, True)

# 绘制结果
image_copy = hua.copy()
cv2.drawContours(image_copy, contours, 1, (0, 0, 255), 2) # 红色 – 原始轮廓
cv2.drawContours(image_copy, [approx], 1, (0, 255, 0), 3) # 绿色 – 近似轮廓

cv2.imshow('Final Result', image_copy)
cv2.waitKey(0)
cv2.destroyAllWindows()

五、模板匹配

模板匹配是一种在图像中寻找与模板最相似区域的技术。

5.1 核心API:cv2.matchTemplate()

result = cv2.matchTemplate(image, templ, method)

匹配方法对比:
TM_SQDIFF_NORMED:归一化平方差匹配法,匹配越好,值越小;匹配越差,值越大。
TM_CCORR_NORMED :归一化相关匹配法,数值越大表明匹配程度越好。
TM_CCOEFF_NORMED :归一化相关系数匹配法,数值越大表明匹配程度越好。

方法数值含义最佳匹配
TM_SQDIFF / TM_SQDIFF_NORMED 平方差 值最小
TM_CCORR / TM_CCORR_NORMED 相关性 值最大
TM_CCOEFF / TM_CCOEFF_NORMED 相关系数 值最大

5.2 完整示例

import cv2

kele = cv2.imread('kele.png')
template = cv2.imread('template.png')
h, w = template.shape[:2]

# 模板匹配(使用归一化相关系数)
res = cv2.matchTemplate(kele, template, cv2.TM_CCOEFF_NORMED)

# 获取最佳匹配位置
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)

# 绘制矩形框
cv2.rectangle(kele, top_left, bottom_right, (0, 255, 0), 2)
cv2.imshow('Result', kele)
cv2.waitKey(0)

六、物体追踪(实时)

基于CSRT追踪器的实时物体追踪示例:

import cv2

# 创建CSRT追踪器
track = cv2.TrackerCSRT_create()
tracking = False

cap = cv2.VideoCapture(0)

while True:
ret, frame = cap.read()
frame = cv2.flip(frame, 1) # 水平翻转,更自然

if not ret:
break

# 按 's' 键选择追踪目标
if cv2.waitKey(1) == ord('s'):
tracking = True
roi = cv2.selectROI('Tracking', frame, showCrosshair=False)
track.init(frame, roi)

if tracking:
success, box = track.update(frame)
if success:
x, y, w, h = [int(v) for v in box]
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)

cv2.imshow('Tracking', frame)

if cv2.waitKey(1) == ord('q'):
break

cap.release()
cv2.destroyAllWindows()

七、总结

本文详细介绍了OpenCV中轮廓检测与模板匹配的核心技术,包括:

  • 轮廓检测基础:理解轮廓概念,掌握cv2.findContours()的使用方法
  • 轮廓特征分析:计算面积、周长,筛选轮廓,绘制外接矩形和最小外接圆
  • 轮廓近似:使用cv2.approxPolyDP()进行多边形拟合
  • 实战案例:花朵轮廓检测与近似处理
  • 模板匹配:在图像中寻找与模板相似区域
  • 实时物体追踪:基于CSRT追踪器实现实时目标跟踪
  • 这些技术是计算机视觉和图像处理的基础,广泛应用于物体识别、形状分析、目标跟踪等领域。建议读者结合实际项目多加练习,深入理解每个参数的含义和适用场景。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » OpenCV基础入门4:轮廓检测与模板匹配
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!