用 OpenCV 的 DNN 模块玩转图像分类

你是不是也想快速实现图像分类,却不想费劲搭建复杂的深度学习框架?今天就给大家分享一个超实用的技巧 ------ 用 OpenCV 的 DNN 模块直接调用训练好的模型,不管是单张图片还是批量图片,都能轻松完成分类任务,小白也能快速上手!

一、核心原理:DNN 模块到底能干啥?

简单来说,OpenCV 的 DNN 模块就像一个 "模型中转站"。它支持加载 Caffe、TensorFlow、PyTorch 等主流框架训练好的模型,不用我们再去手写网络结构、调参训练。

我们只需要做两件事:

  1. 准备好模型配置文件权重文件
  2. 把输入图像处理成模型能 "看懂" 的样子
  3. 丢给模型就能直接出分类结果

这次我们用的是经典的 GoogLeNet 模型,它是基于 ImageNet 数据集训练的,可以识别 1000 种常见物体。

二、实战步骤:从单张图片到批量预测

话不多说,直接上代码和讲解,每一步都给你掰扯明白。

1. 前期准备

先把需要的工具包导入,再处理好标签文件。这个标签文件对应了 ImageNet 的 1000 个分类,能把模型输出的数字索引转换成我们能看懂的物体名称。

python 复制代码
# 导入工具包
import utils_paths
import numpy as np
import cv2

# 标签文件处理:把每行的标签提取出来,方便后续对应结果
rows = open("synset_words.txt").read().strip().split("\n")
classes = [r[r.find(" ") + 1:].split(",")[0] for r in rows]

2. 加载预训练模型

这里我们加载基于 Caffe 框架训练的 GoogLeNet 模型,需要两个文件:.prototxt是模型的配置文件,定义了网络结构;.caffemodel是训练好的权重文件,存着网络里的参数。

python 复制代码
# Caffe所需配置文件:加载模型结构和权重
net = cv2.dnn.readNetFromCaffe("bvlc_googlenet.prototxt",
	"bvlc_googlenet.caffemodel")

3. 单张图片预测:一步一步来

这是最基础的操作,核心就是把图片转换成模型需要的blob格式,再传入模型得到结果。

python 复制代码
# 获取图像路径
imagePaths = sorted(list(utils_paths.list_images("images/")))

# 读取并预处理单张图片
image = cv2.imread(imagePaths[0])
# 第一步:调整尺寸。模型训练时用的是224×224,测试也得统一尺寸
resized = cv2.resize(image, (224, 224))
# 第二步:转换成blob。1是缩放因子,(104,117,123)是ImageNet的三通道均值
blob = cv2.dnn.blobFromImage(resized, 1, (224, 224), (104, 117, 123))
print("First Blob: {}".format(blob.shape))  # 输出blob形状,方便检查

# 传入模型做预测
net.setInput(blob)
preds = net.forward()  # 前向传播,得到1000个分类的概率值

# 找出概率最大的分类
idx = np.argsort(preds[0])[::-1][0]  # 排序后取第一个(概率最大)
# 生成结果文本:分类名称 + 概率百分比
text = "Label: {}, {:.2f}%".format(classes[idx],preds[0][idx] * 100)
# 把结果画到图片上
cv2.putText(image, text, (5, 25),  cv2.FONT_HERSHEY_SIMPLEX,0.7, (0, 0, 255), 2)

# 显示结果
cv2.imshow("Image", image)
cv2.waitKey(0)

这里要注意两个关键点:

  • 图片尺寸必须和训练时一致,不然模型会 "看不懂"
  • 减均值是为了消除光照的影响,让分类更准确,这个均值是 ImageNet 数据集统计出来的,直接用就行

4. 批量图片预测:效率翻倍

如果有一堆图片要分类,一个个预测太麻烦,用blobFromImages函数(注意比单张多了个s)就能批量处理,速度更快。

python 复制代码
# Batch数据制作:批量处理剩下的图片
images = []
for p in imagePaths[1:]:
	image = cv2.imread(p)
	image = cv2.resize(image, (224, 224))
	images.append(image)

# 转换成批量blob,参数和单张一样
blob = cv2.dnn.blobFromImages(images, 1, (224, 224), (104, 117, 123))
print("Second Blob: {}".format(blob.shape))

# 批量预测
net.setInput(blob)
preds = net.forward()

# 遍历每个预测结果,画到图片上并显示
for (i, p) in enumerate(imagePaths[1:]):
	image = cv2.imread(p)
	idx = np.argsort(preds[i])[::-1][0]
	text = "Label: {}, {:.2f}%".format(classes[idx],preds[i][idx] * 100)
	cv2.putText(image, text, (5, 25),  cv2.FONT_HERSHEY_SIMPLEX,0.7, (0, 0, 255), 2)
	cv2.imshow("Image", image)
	cv2.waitKey(0)

三、小技巧和注意事项

  1. 预处理要一致:训练时对图片做了啥操作(缩放、减均值、裁剪等),测试时必须一模一样,不然结果会跑偏。
  2. 框架选择灵活 :除了 Caffe,OpenCV 还支持readNetFromTensorflowreadNetFromTorch等,换个函数就能加载其他框架的模型。
  3. 批量预测更高效:处理大量图片时,批量预测比单张循环快很多,推荐优先使用。

完整代码

python 复制代码
# 导入工具包
import utils_paths
import numpy as np
import cv2

# 标签文件处理
rows = open("synset_words.txt").read().strip().split("\n")
classes = [r[r.find(" ") + 1:].split(",")[0] for r in rows]

# Caffe所需配置文件
net = cv2.dnn.readNetFromCaffe("bvlc_googlenet.prototxt",
	"bvlc_googlenet.caffemodel")

# 图像路径
imagePaths = sorted(list(utils_paths.list_images("images/")))

# 图像数据预处理
image = cv2.imread(imagePaths[0])
resized = cv2.resize(image, (224, 224))
# image scalefactor size mean swapRB 
blob = cv2.dnn.blobFromImage(resized, 1, (224, 224), (104, 117, 123))
print("First Blob: {}".format(blob.shape))

# 得到预测结果
net.setInput(blob)
preds = net.forward()

# 排序,取分类可能性最大的
idx = np.argsort(preds[0])[::-1][0]
text = "Label: {}, {:.2f}%".format(classes[idx],
	preds[0][idx] * 100)
cv2.putText(image, text, (5, 25),  cv2.FONT_HERSHEY_SIMPLEX,
	0.7, (0, 0, 255), 2)

# 显示
cv2.imshow("Image", image)
cv2.waitKey(0)

# Batch数据制作
images = []

# 方法一样,数据是一个batch
for p in imagePaths[1:]:
	image = cv2.imread(p)
	image = cv2.resize(image, (224, 224))
	images.append(image)

# blobFromImages函数,注意有s
blob = cv2.dnn.blobFromImages(images, 1, (224, 224), (104, 117, 123))
print("Second Blob: {}".format(blob.shape))

# 获取预测结果
net.setInput(blob)
preds = net.forward()
for (i, p) in enumerate(imagePaths[1:]):
	image = cv2.imread(p)
	idx = np.argsort(preds[i])[::-1][0]
	text = "Label: {}, {:.2f}%".format(classes[idx],
		preds[i][idx] * 100)
	cv2.putText(image, text, (5, 25),  cv2.FONT_HERSHEY_SIMPLEX,
		0.7, (0, 0, 255), 2)
	cv2.imshow("Image", image)
	cv2.waitKey(0)
相关推荐
管牛牛4 小时前
图像的几何变换
人工智能·opencv·计算机视觉
sali-tec5 小时前
C# 基于OpenCv的视觉工作流-章11-高斯滤波
图像处理·人工智能·opencv·算法·计算机视觉
hudawei9967 小时前
google.mlkit:face-detection和 opencv的人脸识别有什么区别
人工智能·opencv·计算机视觉·google·人脸识别·mlkit·face-detection
格林威7 小时前
多光源条件下图像一致性校正:消除阴影与高光干扰的 6 个核心策略,附 OpenCV+Halcon 实战代码!
人工智能·数码相机·opencv·算法·计算机视觉·分类·视觉检测
2501_941507947 小时前
【深度学习】YOLOv3实现鸡蛋缺陷检测与分类_1
深度学习·yolo·分类
Suahi8 小时前
【HuggingFace LLM】经典NLP微调任务之分类
人工智能·自然语言处理·分类
乐园游梦记8 小时前
工业视觉(尤其是 3D/2.5D 相机场景)中针对不同数据类型、精度、用途设计的保存格式
数码相机·opencv·3d·c#
roman_日积跬步-终至千里8 小时前
【深度学习-实验】花卉识别:用少量数据构建多分类系统的设计思路
人工智能·深度学习·分类
AAD555888998 小时前
【电力设备检测】YOLO11-LQEHead绝缘子缺陷检测与分类系统实现
人工智能·分类·数据挖掘