前言
在计算机视觉领域,OpenCV 是最常用的开源库之一。本文将通过三个实战案例,详细讲解 OpenCV 中的核心功能:轮廓检测与近似 、模板匹配 以及argparse 命令行参数解析。每个案例都配有完整代码和逐行解释,适合初学者快速上手。
目录
[1. 案例一:轮廓检测与轮廓近似](#1. 案例一:轮廓检测与轮廓近似)
[1.1 功能说明](#1.1 功能说明)
[1.2 完整代码](#1.2 完整代码)
[1.3 关键函数详解](#1.3 关键函数详解)
[1.4 效果说明](#1.4 效果说明)
[2. 案例二:模板匹配](#2. 案例二:模板匹配)
[2.1 功能说明](#2.1 功能说明)
[2.2 完整代码](#2.2 完整代码)
[2.3 匹配方法对比](#2.3 匹配方法对比)
[2.4 注意事项](#2.4 注意事项)
[3. 案例三:argparse 命令行参数解析](#3. 案例三:argparse 命令行参数解析)
[3.1 功能说明](#3.1 功能说明)
[3.2 完整代码](#3.2 完整代码)
[3.3 命令行使用方法](#3.3 命令行使用方法)
[3.4 add_argument 常用参数](#3.4 add_argument 常用参数)
[4. 总结](#4. 总结)
[✅ 核心知识点回顾](#✅ 核心知识点回顾)
[🎯 学习建议](#🎯 学习建议)
1. 案例一:轮廓检测与轮廓近似
1.1 功能说明
轮廓检测是图像处理中非常基础且重要的操作,用于提取物体的边缘轮廓。而轮廓近似(Douglas-Peucker 算法)可以在保留轮廓基本形状的前提下,大幅减少轮廓的顶点数量,实现轮廓 "瘦身"。
作业要求:
- 用红色画出花的外部轮廓
- 用绿色画出其近似轮廓(ε 设置为轮廓周长的 0.005)
1.2 完整代码
import cv2
import numpy as np
# 1. 图像预处理:灰度化+反向二值化
img = cv2.imread('flower.png')
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 反向二值化:白色背景变黑色,花朵变白色
# thresh=245:像素值大于245的(接近白色)设为0(黑色),其余设为255(白色)
ret, img_thresh = cv2.threshold(img_gray, thresh=245, maxval=255, type=cv2.THRESH_BINARY_INV)
cv2.imshow('binary', img_thresh)
# 2. 轮廓检测
# RETR_EXTERNAL:只检测最外层轮廓
# CHAIN_APPROX_NONE:存储所有轮廓点
contours = cv2.findContours(img_thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2]
# 只保留面积最大的轮廓(过滤噪声)
max_contour = max(contours, key=cv2.contourArea)
# 3. 设置近似精度(epsilon)
# epsilon = 轮廓周长的0.5%,值越大近似程度越高
epsilon = 0.005 * cv2.arcLength(max_contour, closed=True)
# 4. 轮廓近似 - Douglas-Peucker算法
approx = cv2.approxPolyDP(max_contour, epsilon, closed=True)
# 5. 对比原轮廓与近似轮廓的顶点数量
print("原轮廓顶点数量:", max_contour.shape)
print("近似轮廓顶点数量:", approx.shape)
# 6. 绘制并显示结果
img_new = img.copy()
# 红色绘制原始轮廓 (BGR格式:(0, 0, 255) = 红色)
cv2.drawContours(img_new, contours=[max_contour], contourIdx=-1, color=(0, 0, 255), thickness=2)
# 绿色绘制近似轮廓 (BGR格式:(0, 255, 0) = 绿色)
cv2.drawContours(img_new, contours=[approx], contourIdx=-1, color=(0, 255, 0), thickness=2)
# 同一窗口显示最终结果
cv2.imshow('flower_contour', img_new)
cv2.waitKey(0)
cv2.destroyAllWindows()
1.3 关键函数详解
表格
| 函数 | 作用 | 重要参数 |
|---|---|---|
cv2.threshold() |
图像二值化 | THRESH_BINARY_INV 反向二值化 |
cv2.findContours() |
轮廓检测 | RETR_EXTERNAL 只检测外轮廓 |
cv2.contourArea() |
计算轮廓面积 | 用于筛选最大轮廓 |
cv2.arcLength() |
计算轮廓周长 | 用于设置 epsilon |
cv2.approxPolyDP() |
轮廓近似 | epsilon 控制近似精度 |
cv2.drawContours() |
绘制轮廓 | thickness 线条粗细 |
1.4 效果说明
- 红色线条:原始轮廓,顶点数量多,细节丰富
- 绿色线条:近似轮廓,顶点数量大幅减少,但基本形状保持不变
- 通过调整
epsilon系数(0.001~0.05)可以控制近似程度
2. 案例二:模板匹配
2.1 功能说明
模板匹配是在一幅图像中寻找与模板图像最相似的区域,类似于 "找不同" 的逆操作 ------"找相同"。常用于目标检测、物体定位等场景。
2.2 完整代码
python
运行
import cv2
import numpy as np
# 读取原图和模板图
sweetsnow = cv2.imread('kele.png') # 大图(待搜索图)
template = cv2.imread('111.png') # 小图(模板图)
# 先显示原图和模板,确认加载成功
cv2.imshow('kele', sweetsnow)
cv2.imshow('template', template)
cv2.waitKey(0)
# 获取模板的高度和宽度
h, w = template.shape[:2]
# 执行模板匹配
# TM_CCOEFF_NORMED:归一化相关系数匹配法,值越接近1匹配度越高
res = cv2.matchTemplate(sweetsnow, template, cv2.TM_CCOEFF_NORMED)
# 获取匹配结果中的最大值和对应位置
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
print(f"最佳匹配度:{max_val:.4f}")
print(f"匹配位置左上角:{max_loc}")
# 计算矩形框右下角坐标
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
# 在原图上绘制矩形框标记匹配区域(青色)
peach_template = cv2.rectangle(sweetsnow, top_left, bottom_right, (255, 255, 0), 2)
# 缩放显示(避免图片太大)
peach_template = cv2.resize(peach_template, (0, 0), fx=0.5, fy=0.5)
cv2.imshow('template_match_result', peach_template)
cv2.waitKey(0)
cv2.destroyAllWindows()
2.3 匹配方法对比
OpenCV 提供了 6 种模板匹配方法:
表格
| 方法 | 说明 | 最佳值 |
|---|---|---|
TM_SQDIFF |
平方差匹配 | 最小值(0) |
TM_SQDIFF_NORMED |
归一化平方差匹配 | 最小值(0) |
TM_CCORR |
相关匹配 | 最大值 |
TM_CCORR_NORMED |
归一化相关匹配 | 最大值(1) |
TM_CCOEFF |
相关系数匹配 | 最大值 |
TM_CCOEFF_NORMED |
归一化相关系数匹配 | 最大值(1)⭐推荐 |
💡 推荐使用
TM_CCOEFF_NORMED:归一化后结果在 -1,1 之间,阈值设置更直观,通常 > 0.8 就是很好的匹配。
2.4 注意事项
- 模板尺寸:模板必须小于原图
- 多目标匹配 :阈值法(如
np.where(res > 0.8))可检测多个匹配 - 旋转缩放:传统模板匹配不支持旋转和缩放,需要多尺度金字塔
3. 案例三:argparse 命令行参数解析
3.1 功能说明
argparse是 Python 标准库,用于解析命令行参数。在实际项目中,我们经常需要通过命令行传入参数(如串口号、阈值、置信度等),而不是硬编码在代码中。
3.2 完整代码
python
运行
import argparse
# 1. 创建参数解析器对象
parser = argparse.ArgumentParser(description='这是一个参数解析演示程序')
# 2. 添加各种类型的参数
# 字符串类型参数:串口号
parser.add_argument("--SERIAL_PORT1",
type=str,
default='COM5',
help='第一个报警器的串口号')
# 整数类型参数:面积阈值
parser.add_argument("--area_threshold",
type=int,
default=1600,
help='物体面积的阈值')
# 浮点类型参数:置信度
parser.add_argument("--confid_level",
type=float,
default=0.8,
help='识别的置信度')
# 简单整数参数(长参数名)
parser.add_argument("--aa",
type=int,
default=10)
# 同时支持短参数名和长参数名:-b 或 --bbb
parser.add_argument('-b', "--bbb",
type=int,
default=120)
# 3. 解析命令行参数
opt = parser.parse_args()
# 4. 使用参数
a = opt.aa
b = opt.bbb
print(f"a + b = {a + b}")
# 打印所有参数
print("\n=== 所有参数 ===")
print(f"串口号:{opt.SERIAL_PORT1}")
print(f"面积阈值:{opt.area_threshold}")
print(f"置信度:{opt.confid_level}")
print(f"aa:{opt.aa}")
print(f"bbb:{opt.bbb}")
3.3 命令行使用方法
bash
运行
# 使用默认参数运行
python demo.py
# 自定义参数运行
python demo.py --aa 50 --bbb 100
# 使用短参数名
python demo.py -b 200
# 查看帮助
python demo.py -h
python demo.py --help
3.4 add_argument 常用参数
表格
| 参数 | 说明 | 示例 |
|---|---|---|
type |
参数类型 | int, float, str |
default |
默认值 | default=0.8 |
help |
参数说明文字 | help='置信度阈值' |
required |
是否必填 | required=True |
choices |
可选值列表 | choices=[0.5, 0.8, 0.95] |
action |
特殊动作 | action='store_true'(布尔开关) |
4. 总结
本文通过三个实战案例,系统学习了 OpenCV 图像处理的核心技能:
✅ 核心知识点回顾
-
轮廓检测与近似
- 二值化预处理是关键
cv2.approxPolyDP()实现轮廓简化- epsilon 值控制近似精度
-
模板匹配
cv2.matchTemplate()+cv2.minMaxLoc()组合使用- 推荐
TM_CCOEFF_NORMED归一化匹配方法 - 阈值 > 0.8 通常为可靠匹配
-
argparse 参数解析
- 让程序更灵活,避免硬编码
- 支持多种数据类型
- 长短参数名提升易用性
🎯 学习建议
- 这三个功能经常组合使用:先用 argparse 传入图片路径→模板匹配定位→轮廓检测提取形状
- 多调整参数观察效果变化(如 epsilon、匹配方法、阈值等)
- 实际项目中记得添加异常处理(图片读取失败、参数非法等)