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

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

    • [0. 前言](#0. 前言)
    • [1. DNN 模块使用指南](#1. DNN 模块使用指南)
      • [1.1 实现过程](#1.1 实现过程)
      • [1.2 优化思路](#1.2 优化思路)
    • [2. YOLO 实时检测](#2. YOLO 实时检测)
      • [2.1 实现过程](#2.1 实现过程)
      • [2.2 优化思路](#2.2 优化思路)
    • [3. 图像风格迁移](#3. 图像风格迁移)
      • [3.1 实现过程](#3.1 实现过程)
      • [3.2 优化思路](#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 个类别即可
python 复制代码
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 利用率
python 复制代码
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) 剔除重叠过多的框
    • 绘制剩余边界框和标签
python 复制代码
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

    # 构建输入 blob
    blob = 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: break

cap.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 信息,便于性能调优
python 复制代码
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:break

cap.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]
python 复制代码
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 后端,加速风格迁移推理
python 复制代码
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: break
    h,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) & 0xFF
    if key==ord('1'): curr='mosaic'
    elif key==ord('2'): curr='candy'
    elif key==ord('3'): curr='udnie'
    elif key==27: break

    net = 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)------深度学习与卷积神经网络

相关推荐
hixiong1236 小时前
C# OpencvSharp使用lpd_yunet进行车牌检测
开发语言·opencv·计算机视觉·c#
闻缺陷则喜何志丹6 小时前
【超音速专利 CN118134841A】一种光伏产品缺陷检测AI深度学习算法
人工智能·深度学习·算法·专利·光伏·超音速
Coovally AI模型快速验证7 小时前
超越传统3D生成:OccScene实现感知与生成的跨任务共赢
人工智能·深度学习·机器学习·计算机视觉·3d·目标跟踪
rengang667 小时前
14-循环神经网络(RNN):分析RNN在序列数据中的表现和特点
人工智能·rnn·深度学习
CV实验室8 小时前
CV论文速递: 覆盖医学影像分析、视频理解与生成、3D场景理解与定位等方向! (10.27-10.31)
人工智能·计算机视觉·3d·音视频
PixelMind8 小时前
【LUT技术专题】SVDLUT: 基于SVD优化的3DLUT
图像处理·深度学习·lut
LabVIEW开发8 小时前
LabVIEW用直线边缘检测实现液位测量
数码相机·计算机视觉·labview·labview知识·labview功能·labview程序
吃鱼不卡次8 小时前
RT-DETR解码模块(Decoder)
人工智能·深度学习·cross attention·rt-detr·匈牙利匹配·self attention·对比去噪训练
zhan1145148 小时前
解析平面卷积/pytorch的nn.Conv2d的计算步骤,in_channels与out_channels如何计算而来
人工智能·pytorch·深度学习·cnn·卷积神经网络