当前位置: 首页 > news >正文

OpenCV计算机视觉实战(28)——深度学习初体验

OpenCV计算机视觉实战(28)——深度学习初体验

    • 0. 前言
    • 1. DNN 模块使用指南
      • 1.1 实现过程
      • 1.2 优化思路
    • 2. YOLO 实时检测
      • 2.1 实现过程
      • 2.2 优化思路
    • 3. 图像风格迁移
      • 3.1 实现过程
      • 3.2 优化思路
    • 小结
    • 系列链接

0. 前言

深度学习已彻底改变了计算机视觉领域,从图像分类到目标检测,再到艺术风格迁移,强大的预训练模型让我们在几行代码内就能实现昔日难以企及的效果。本文将首先演示如何无缝加载 CaffeONNXTorch 等多种模型格式并进行高效批量推理;接着用 YOLOv3 在进行实时多尺度目标检测,并通过类别配色、非极大值抑制与 FPS 统计,打造实用的检测流程;最后,加载多款风格迁移网络,轻松为视频流添加艺术特效。

1. DNN 模块使用指南

OpenCVcv2.dnn 模块支持加载各种主流深度学习框架导出的模型( CaffeTensorFlowONNXTorch 等),并在 CPU/GPU 上高效推理,接下来,展示如何加载 Caffe 模型进行前向推理。

1.1 实现过程

  • 加载模型
    • 使用 cv2.dnn.readNetFromCaffe 加载 Caffe 导出的 .prototxt.caffemodel,同时支持 GPU 加速(需调用 net.setPreferableBackend)
  • 输入预处理
    • blobFromImageH × W × C 图像转换为 NCHW 格式,并进行缩放、均值减除、通道交换等操作,符合网络训练时的输入规范
    • scalefactor:像素缩放系数
    • mean:对每个通道减去的均值
  • 前向推理
    • net.setInput(blob):将预处理后的 blob 传入网络
    • net.forward():执行一次完整的前向传播,返回输出多维数组
  • 结果解析
    • 对分类输出做 argsort,取概率最高的前 5 个类别即可
import cv2
import numpy as np# 功能:演示 DNN 模块加载 Caffe 模型并进行分类推理
# 1. 加载网络结构与预训练权重
net = cv2.dnn.readNetFromCaffe('bvlc_googlenet.prototxt', 'bvlc_googlenet.caffemodel'
)# 2. 读取并预处理输入图像
img = cv2.imread('2.jpeg')
blob = cv2.dnn.blobFromImage(img, scalefactor=1.0, size=(224,224), mean=(104,117,123), swapRB=False, crop=False
)# 3. 设置网络输入,执行前向推理
net.setInput(blob)
preds = net.forward()# 4. 解析输出(取 top-5 类别)
idxs = np.argsort(preds.flatten())[::-1][:5]
for i in idxs:print(f'ClassID: {i}, Score: {preds[0,i]:.4f}')

关键函数解析:

  • cv2.dnn.readNetFromCaffe(proto,model):加载 Caffe 模型(结构 & 权重)
  • cv2.dnn.blobFromImage(img, ...):对输入图像执行缩放、均值减除、通道交换、NCHW 排序
  • net.setInput(blob):将预处理后的数据设置为网络输入
  • net.forward():执行前向推理并返回输出

1.2 优化思路

  • 多模型格式支持:除了 Caffe,还可用 readNetFromTensorflowreadNetFromONNX 加载 TensorFlowONNX 模型
  • 后端与目标设备:可通过 setPreferableBackend/Target 切换 OpenVINOCUDAHalide 等加速方案
  • 批量推理:用 blobFromImages 实现批量输入,提高 GPU 利用率
import cv2
import numpy as np# 功能:同时支持 ONNX 与 Caffe,演示 CPU/GPU 加速与批量推理
# 选择模型格式
use_onnx = True
if use_onnx:net = cv2.dnn.readNetFromONNX('resnet50.onnx')
else:net = cv2.dnn.readNetFromCaffe('deploy.prototxt', 'resnet50.caffemodel')# 切换到 CUDA(若可用)或 OpenVINO
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)
net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA_FP16)# 批量加载多张图
imgs = [cv2.imread(p) for p in ['img1.jpg','img2.jpg','img3.jpg']]
blobs = cv2.dnn.blobFromImages(imgs,scalefactor=1/255.0,size=(224,224),mean=(0.485,0.456,0.406),swapRB=True,crop=False
)
# 归一化到 ImageNet 标准
blobs /= np.array([0.229,0.224,0.225]).reshape(3,1,1)net.setInput(blobs)
outs = net.forward()  # 3×1000 分类得分# 解析每张图的 top1
for i, out in enumerate(outs):idx = out.argmax()score = out[idx]print(f'Image {i}: Class {idx}, Score {score:.3f}')

关键函数解析:

  • readNetFromONNX(path):加载 ONNX 标准模型
  • setPreferableBackend/Target():切换计算后端,常见后端有 CUDAOpenVINOHalide
  • blobFromImages(list, ...):一次构造多图的批量输入 Blob,减少多次数据上传开销

2. YOLO 实时检测

使用 Darknet 格式的 YOLOv3 模型,在摄像头或视频帧上实时检测常见物体。YOLO 将整张图分成网格,一次前向计算即可输出所有边界框与类别。

2.1 实现过程

  • 加载 Darknet 模型
    • readNetFromDarknet 支持 .cfg + .weights
    • 调用 setPreferableBackend/Target 可开启 GPUOpenVINO 加速
  • 获取输出层
    • getUnconnectedOutLayers 返回需手动 forward 的层索引,用于提取检测结果
  • 输入预处理
    • 图像缩放到 416 × 416,像素值归一化到 [0, 1],并交换 RB 通道
  • 后处理
    • 根据置信度过滤检测框
    • NMS (NMSBoxes) 剔除重叠过多的框
    • 绘制剩余边界框和标签
import cv2
import numpy as np# 功能:载入 YOLOv3 模型并在摄像头实时检测
net = cv2.dnn.readNetFromDarknet('yolov3.cfg', 'yolov3.weights')# 获取输出层名称
layer_names = net.getLayerNames()
out_layers_indices = net.getUnconnectedOutLayers()
out_layers = [layer_names[i-1] for i in out_layers_indices]cap = cv2.VideoCapture(0)
while True:ret, frame = cap.read()if not ret: break# 构建输入 blobblob = cv2.dnn.blobFromImage(frame, 1/255.0, (416,416), swapRB=True, crop=False)net.setInput(blob)outs = net.forward(out_layers)h, w = frame.shape[:2]boxes, confidences, classIDs = [], [], []for out in outs:for det in out:scores = det[5:]cid = np.argmax(scores)conf = scores[cid]if conf > 0.5:cx, cy, bw, bh = (det[0:4] * [w, h, w, h]).astype(int)x, y = int(cx - bw/2), int(cy - bh/2)boxes.append([x,y,int(bw),int(bh)])confidences.append(float(conf))classIDs.append(cid)# 非极大值抑制idxs = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4)if len(idxs):for i in idxs.flatten():x,y,bw,bh = boxes[i]cv2.rectangle(frame, (x,y), (x+bw,y+bh), (0,255,0), 2)cv2.putText(frame, f'{classIDs[i]}:{confidences[i]:.2f}',(x,y-5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0),1)cv2.imshow('YOLOv3 Detection', frame)if cv2.waitKey(1)==27: breakcap.release()
cv2.destroyAllWindows()

检测结果

关键函数解析:

  • cv2.dnn.readNetFromDarknet(cfg,weights):加载 YOLO Darknet 模型
  • net.getUnconnectedOutLayers():获取输出层索引
  • blobFromImage(frame,1/255,size,swapRB):构建适用于 YOLO 的输入 blob
  • cv2.dnn.NMSBoxes(boxes,confs,thr,nt):非极大值抑制,过滤重叠冗余检测框

2.2 优化思路

  • 多尺度检测:用多次不同尺寸的 blobFromImage 检测小物体更准确,再合并结果
  • 类别名称与配色:加载 coco.names 并为每个类别分配固定颜色,提高可读性
  • FPS 统计:实时计算并叠加 FPS 信息,便于性能调优
import cv2
import numpy as np
import time# 功能:YOLOv3 多尺度检测 + 类名 + FPS 统计
net = cv2.dnn.readNetFromDarknet('yolov3.cfg','yolov3.weights')
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)
net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)# 载入类别
with open('coco.names') as f:classes = [line.strip() for line in f]
colors = np.random.randint(0,255,(len(classes),3))# 输出层
ln = [net.getLayerNames()[i-1] for i in net.getUnconnectedOutLayers().flatten()]# cap = cv2.VideoCapture(0)
cap = cv2.VideoCapture('r2.mp4')
for i in range(1440):ret, frame = cap.read()
prev = time.time()
while True:ret, frame = cap.read()if not ret: break# 多尺度输入outs = []for scale in [320, 416, 608]:blob = cv2.dnn.blobFromImage(frame,1/255.0,(scale,scale),swapRB=True, crop=False)net.setInput(blob)outs += net.forward(ln)# 后处理h, w = frame.shape[:2]boxes,confs,ids = [],[],[]for det in outs:for d in det:scores = d[5:]; cid = np.argmax(scores); conf = scores[cid]if conf>0.5:cx,cy,bw,bh = (d[0:4]*[w,h,w,h]).astype(int)x,y = int(cx-bw/2), int(cy-bh/2)boxes.append([x,y,bw,bh]); confs.append(float(conf)); ids.append(cid)idxs = cv2.dnn.NMSBoxes(boxes,confs,0.5,0.4)# 绘制for i in idxs.flatten():x,y,bw,bh = boxes[i]; cid = ids[i]color = [int(c) for c in colors[cid]]cv2.rectangle(frame,(x,y),(x+bw,y+bh),color,2)cv2.putText(frame,f'{classes[cid]}:{confs[i]:.2f}',(x,y-5),cv2.FONT_HERSHEY_SIMPLEX,0.5,color,1)# FPS 叠加fps = 1/(time.time()-prev); prev=time.time()cv2.putText(frame,f'FPS: {fps:.1f}',(10,20),cv2.FONT_HERSHEY_SIMPLEX,0.6,(0,0,255),2)cv2.imshow('YOLO Multi-Scale', frame)if cv2.waitKey(1)==27:breakcap.release(); cv2.destroyAllWindows()

检测结果

3. 图像风格迁移

借助 OpenCV DNN 支持的预训练风格迁移模型,将普通图片转换为特定艺术风格。

3.1 实现过程

  • 加载 Torch 模型
    • readNetFromTorch 支持加载 .t7 格式的风格迁移网络
  • 输入预处理
    • Caffe 类似,需减去训练时的通道均值 (103.939,116.779,123.680)
    • 不交换通道,因为模型期望 BGR 顺序
  • 前向推理与后处理
    • forward 得到形状为 (1,3,H,W) 的输出
    • 去批次维度、加回均值,并转置为 H × W × 3,最后裁剪到 [0,255]
import cv2
import numpy as np# 功能:使用 OpenCV DNN 风格迁移模型,将图像转换为油画风格
net = cv2.dnn.readNetFromTorch('model/the_wave.t7')img = cv2.imread('2.jpeg')
(h, w) = img.shape[:2]
# 将图片缩小以加快处理速度
newW = 600
newH = int(h * newW / w)
resized = cv2.resize(img, (newW, newH))# 构建输入 blob 并前向传播
blob = cv2.dnn.blobFromImage(resized, 1.0, (newW, newH),(103.939, 116.779, 123.680), swapRB=False, crop=False)
net.setInput(blob)
output = net.forward()# 还原输出图像
out = output.reshape(3, newH, newW)
out[0] += 103.939; out[1] += 116.779; out[2] += 123.680
out = out.transpose(1,2,0)
out = np.clip(out, 0, 255).astype('uint8')cv2.imshow('Styled Image', out)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

关键函数解析:

  • cv2.dnn.readNetFromTorch(model):加载 Torch 导出的风格迁移模型
  • blobFromImage(img,1.0,size,mean,swapRB):构建符合模型输入的 blob,包含均值减除和尺寸调整
  • net.forward():执行前向推理,输出风格迁移后的特征图

3.2 优化思路

  • 多风格模型切换:同时加载多种 .t7 模型,按键实时切换风格
  • 原图融合:用 addWeighted 将原图与风格图按比例混合,获得“浅度风格化”效果
  • GPU 加速支持:在 DNN 模块中设置 CUDA 后端,加速风格迁移推理
import cv2
import numpy as np# 功能:多个风格模型切换 + 原图混合 + CUDA 加速
styles = {'mosaic': 'model/mosaic.t7','candy':  'model/candy.t7','udnie':  'model/feathers.t7'
}
nets = {k: cv2.dnn.readNetFromTorch(v) for k,v in styles.items()}
for net in nets.values():net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA_FP16)
curr = 'mosaic'cap = cv2.VideoCapture(0)
alpha = 0.6  # 原图融合比例while True:ret, frame = cap.read()if not ret: breakh,w = frame.shape[:2]inp = cv2.dnn.blobFromImage(frame,1.0,(w,h),(103.939,116.779,123.680),swapRB=False,crop=False)# 按键切换风格key = cv2.waitKey(1) & 0xFFif key==ord('1'): curr='mosaic'elif key==ord('2'): curr='candy'elif key==ord('3'): curr='udnie'elif key==27: breaknet = nets[curr]net.setInput(inp)out = net.forward()[0]out = out.reshape(3,h,w).transpose(1,2,0)out += np.array((103.939,116.779,123.680))out = np.clip(out,0,255).astype('uint8')# 原图融合blended = cv2.addWeighted(frame,1-alpha,out,alpha,0)cv2.putText(blended, f'Style: {curr}', (10,30),cv2.FONT_HERSHEY_SIMPLEX,1,(255,255,255),2)cv2.imshow('Neural Style Transfer', blended)cap.release(); cv2.destroyAllWindows()

运行结果

关键函数解析:

  • 键盘事件:用 waitKey 获取按键,动态切换风格模型
  • cv2.addWeighted(src1,alpha,src2,beta,gamma):原图与风格图按 alpha:beta 比例线性融合
  • CUDA 后端:显著提升风格迁移帧率,实现实时特效

小结

在本文中,我们深入探索了 OpenCVDNN 模块如何助力深度学习模型的高效部署与推理。首先,借助 cv2.dnn 对多种主流模型格式(如 CaffeONNXTorch) 进行了加载与分类推理,掌握了图像预处理、前向传播及结果解析等关键流程,并介绍了批量推理与 GPU 加速等优化手段。随后,结合 YOLOv3 模型实现了实时多尺度目标检测,展示了如何提取输出层、进行后处理、绘制检测框及计算帧率等技巧。最后,我们使用风格迁移模型对图像进行了艺术化处理,轻松实现油画风格转换。

系列链接

OpenCV计算机视觉实战(1)——计算机视觉简介
OpenCV计算机视觉实战(2)——环境搭建与OpenCV简介
OpenCV计算机视觉实战(3)——计算机图像处理基础
OpenCV计算机视觉实战(4)——计算机视觉核心技术全解析
OpenCV计算机视觉实战(5)——图像基础操作全解析
OpenCV计算机视觉实战(6)——经典计算机视觉算法
OpenCV计算机视觉实战(7)——色彩空间详解
OpenCV计算机视觉实战(8)——图像滤波详解
OpenCV计算机视觉实战(9)——阈值化技术详解
OpenCV计算机视觉实战(10)——形态学操作详解
OpenCV计算机视觉实战(11)——边缘检测详解
OpenCV计算机视觉实战(12)——图像金字塔与特征缩放
OpenCV计算机视觉实战(13)——轮廓检测详解
OpenCV计算机视觉实战(14)——直方图均衡化
OpenCV计算机视觉实战(15)——霍夫变换详解
OpenCV计算机视觉实战(16)——图像分割技术
OpenCV计算机视觉实战(17)——特征点检测详解
OpenCV计算机视觉实战(18)——视频处理详解
OpenCV计算机视觉实战(19)——特征描述符详解
OpenCV计算机视觉实战(20)——光流法运动分析
OpenCV计算机视觉实战(21)——模板匹配详解
OpenCV计算机视觉实战(22)——图像拼接详解
OpenCV计算机视觉实战(23)——目标检测详解
OpenCV计算机视觉实战(24)——目标追踪算法
OpenCV计算机视觉实战(25)——立体视觉详解
OpenCV计算机视觉实战(26)——OpenCV与机器学习
OpenCV计算机视觉实战(27)——深度学习与卷积神经网络

http://www.dtcms.com/a/565268.html

相关文章:

  • 统计局网站集约化建设方案网站数据库有哪些
  • 自己动手写深度学习框架(快速学习python和关联库)
  • 从“算法思维”到“算子思维”:我在昇腾AI开发中的认知跃迁
  • 全球优秀企业网站工程公司资质等级
  • Hello epoll!
  • 泰安哪里做网站wordpress 男扮女
  • Linux】 性能调优实战:内核参数优化技巧
  • 网站建设厘金手指排名二一伊春网站制作
  • 做公众号关注网站网页安全防护怎么关闭
  • 【运维✨】云服务器公网 IP 迷雾:为什么本机看不到那个地址?
  • Swift 6.2 列传(第一篇):主线 Actor 的 “独尊令”
  • 基于AI大模型智能硬件--小智 AI 聊天机器人项目介绍
  • mybatis-plus SQL 注入漏洞导致版本升级引发的问题
  • 低空经济爆发期 遥感影像识别如何破解数据安全与效率困局
  • 哈尔滨做平台网站平台公司哪家好南通启益建设集团有限公司网站
  • 可以做婚礼视频的网站有哪些免费域名注册可解析
  • 网络抓包教学
  • Input getevent记录和InputReader,InputDispatcher启动
  • ESP01s通过blinker云端进行远程控制开关灯
  • 前端面试高频题解析
  • 模板网站修改教程南宁cms建站系统
  • 中天建设集团网站WordPress好像微博一样插件
  • 果蔬检测数据集VOC+YOLO格式16099张72类别
  • 电子沙盘数字沙盘智能吸附工具栏:高效作战新利器7
  • 关于asp sql网站开发的书籍微梦网站建设
  • 突破局域网限制!EMQX 结合 cpolar 实现 MQTT 远程通信全攻略
  • 【经典书籍】《人月神话》第八章“胸有成竹”精华讲解
  • 升级mybatis-plus导致项目启动报错: net.sf.jsqlparser.statement.select.SelectBody
  • 线性代数 - 线性方程组的原始解法(高斯消元法)
  • 深入 Lua 环境机制:全局变量的 “容器” 与 “隔离术”