计算机视觉入门:从像素到理解的旅程

发布于:2025-04-02 ⋅ 阅读:(26) ⋅ 点赞:(0)

在这里插入图片描述
在这里插入图片描述

计算机视觉入门:从像素到理解的旅程,计算机视觉是人工智能领域的核心方向之一,旨在让计算机具备理解和解释视觉信息的能力。本文以系统化的知识框架,结合 Python 代码与经典案例,带您从像素级操作逐步掌握计算机视觉核心技术。涵盖图像处理、特征工程、传统机器学习到深度学习模型,助您构建从基础到进阶的完整能力体系。

在这里插入图片描述

前言

        计算机视觉是一门研究如何使机器“看”的科学,更进一步的说,就是是指用摄影机和电脑代替人眼对目标进行识别、跟踪和测量等机器视觉,并进一步做图形处理,使电脑处理成为更适合人眼观察或传送给仪器检测的图像。作为一个科学学科,计算机视觉研究相关的理论和技术,试图建立能够从图像或者多维数据中获取‘信息’的人工智能系统。这里所指的信息指Shannon定义的,可以用来帮助做一个“决定”的信息。因为感知可以看作是从感官信号中提取信息,所以计算机视觉也可以看作是研究如何使人工系统从图像或多维数据中“感知”的科学。


👉👉👉 🥇 点击进入计算机视觉专栏,计算机视觉(CV)是人工智能的重要分支,致力于让机器通过数字图像或视频获取、处理和分析视觉信息,并模拟人类视觉的认知能力。本专栏涵盖基础概念、技术应用、前沿研究和实战案例等方向。

👉👉👉 🥇 点击进入计算机网络技术专栏,本专栏旨在深入探讨计算机网络的核心概念、关键技术、协议标准以及最新发展趋势,帮助读者全面理解网络通信的原理与实践。

👉👉👉 🥇 点击进入网络安全知识专栏,本专栏详细介绍了网络安全入门:理解基本概念和术语,网络安全的五大核心领域:防护、检测、响应、恢复与治理,常见的网络攻击类型及防范技巧,网络安全防护层次:从物理到应用的多重保障,企业网络安全的十大挑战及解决方案等。

一、计算机视觉基础​

1.1 学科核心挑战​

    计算机视觉旨在让计算机理解图像与视频中的内容,将视觉感知转化为有意义的信息,这一目标面临着诸多复杂挑战。​

    从二维到三维的信息损失,是计算机视觉中的深度感知难题。在现实世界里,物体以三维形式存在,可当它们被拍摄成图像或视频时,就转化成了二维形式,这一过程中深度信息大量丢失 。以自动驾驶为例,汽车的视觉系统需精准感知前方车辆、行人的距离,若深度信息缺失或不准确,就极易引发交通事故。像双目视觉技术,虽模拟人类双眼视差原理来计算深度,但在远距离或纹理特征不明显的场景下,效果会大打折扣。​

    视角与光照变化带来了图像差异的不变性问题。同一物体,因拍摄视角、光照条件的不同,呈现出的图像会有很大差异。在安防监控里,不同时段的光照变化,如白天强光、夜晚弱光,以及不同角度的监控画面,都会给目标识别带来困难。传统的特征提取方法,像尺度不变特征变换(SIFT),虽对尺度、旋转有一定不变性,可对光照变化的鲁棒性仍有待提升。​

    遮挡与类内多样性构成了复杂场景下的鲁棒性挑战。实际场景里,物体常被其他物体遮挡,部分信息难以获取,不同个体间的类内差异也很大。在人群密集的场景中,行人相互遮挡,给行人检测与跟踪增加了难度;不同品种的狗,外貌特征差异明显,这对图像分类算法的泛化能力是个考验。基于深度学习的目标检测算法,如 Faster R-CNN,虽能处理部分遮挡情况,但面对严重遮挡和复杂类内多样性时,性能依旧会下降。​

1.2 技术发展里程碑​

    计算机视觉技术的发展历经多个关键阶段,每个阶段都带来了重大突破。​

    20 世纪 60 年代,边缘检测算法萌芽,这是计算机视觉发展的开端。当时,研究人员开始探索用计算机处理图像,边缘检测算法应运而生,它能提取图像中的边缘信息,为后续的形状分析等任务奠定基础,不过处理的图像相对简单,对复杂场景的适应性差。​

    到了 80 年代,特征匹配技术取得突破,研究人员开发出更复杂的计算机视觉算法,如边缘检测、线段检测、形状检测等,基于知识的专家系统也开始用于处理图像。例如,利用特征点匹配进行目标识别,提高了识别的准确性和鲁棒性,但这些算法计算量大,对硬件要求高。​

    21 世纪初,SIFT、SURF 等特征被广泛应用,这些特征对尺度、旋转、光照变化有一定不变性,在目标识别、图像拼接等领域得到大量应用,推动了计算机视觉在工业自动化、医学诊断、安全监控等领域的应用,但在复杂场景下,其性能仍需进一步提升。​

    2012 年,AlexNet 在 ImageNet 挑战赛中夺冠,引发了深度学习革命。它证明了深度卷积神经网络在大规模图像分类任务中的强大能力,开启了深度学习在计算机视觉领域的广泛应用。此后,基于深度学习的目标检测、图像分割、语义理解等算法不断涌现,性能大幅提升。​

    2020 年以后,多模态大模型与轻量化部署成为趋势。多模态大模型融合图像、文本、语音等多种信息,提升了计算机视觉系统的理解能力;轻量化部署则让计算机视觉技术能在移动端、嵌入式设备上运行,拓宽了应用场景,如智能安防摄像头、移动设备上的图像识别应用等 。​

二、图像数字化与预处理​

2.1 图像读取与存储​

    在计算机视觉中,图像的读取与存储是基础操作,OpenCV 库提供了强大的工具来实现这一过程。使用 OpenCV 读取图像时,默认以 BGR 格式存储,而 Matplotlib 等可视化库通常使用 RGB 格式,因此常需进行格式转换。​

import cv2​
import matplotlib.pyplot as plt​
​
# 读取图像​
image = cv2.imread('test.jpg')​
​
# BGR转RGB​
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)​
​
# 显示图像​
plt.imshow(image_rgb)​
plt.axis('off')​
plt.show()


    通过 Matplotlib 的imshow函数,我们可以直观地展示图像。同时,还可以查看图像的像素矩阵,了解图像的基本信息。​

print(image_rgb.shape)  # 输出图像尺寸​
print(image_rgb[0, 0])  # 输出图像左上角像素值​


    这能帮助我们深入理解图像的数字化表示,为后续处理提供基础。​

2.2 几何变换实战​

2.2.1 透视变换​

    透视变换是一种重要的几何变换,它能将图像从一个视角转换到另一个视角,在文档扫描、图像校正等领域应用广泛。在 Python 中,使用 OpenCV 库可以方便地实现透视变换。假设我们有一张包含矩形物体的图像,想要将其选定的矩形区域拉伸为正方形,可以按照以下步骤进行操作:​

import cv2​
import numpy as np​
​
​
def perspective_transformation():# 读取图像​
    img = cv2.imread('example.jpg')​
​
    # 定义原始图像上的四个点坐标(假设为矩形的四个角点)​
    pts1 = np.float32([[100, 100], [300, 100], [100, 300], [300, 300]])​
​
    # 定义目标图像上的四个点坐标(拉伸为正方形)​
    width, height = 200, 200​
    pts2 = np.float32([[0, 0], [width, 0], [0, height], [width, height]])​
​
    # 计算透视变换矩阵​
    matrix = cv2.getPerspectiveTransform(pts1, pts2)​
​
    # 应用透视变换​
    img_output = cv2.warpPerspective(img, matrix, (width, height))​
​
    # 展示原始图像和变换后的图像​
    cv2.imshow('Original Image', img)​
    cv2.imshow('Transformed Image', img_output)​
​
    # 等待用户按键后退出​
    cv2.waitKey(0)​
    cv2.destroyAllWindows()​
​
​
if __name__ == '__main__':​
    perspective_transformation()

    在上述代码中,cv2.getPerspectiveTransform函数根据原始图像和目标图像上的四个对应点计算透视变换矩阵,cv2.warpPerspective函数则应用该矩阵对原始图像进行透视变换。这种变换在文档扫描场景中尤为重要,当文档拍摄角度倾斜时,通过透视变换可以将其校正为正视角度,方便后续的文字识别等处理。​

三、传统特征工程实践​

3.1 SIFT 特征检测​

    尺度不变特征变换(SIFT)是一种强大的局部特征检测与描述算法,具有尺度、旋转和光照不变性 。SIFT 关键点检测通过高斯金字塔与 DOG(Difference of Gaussian)尺度空间实现。在高斯金字塔构建中,对原始图像进行不同尺度的高斯模糊,并下采样得到不同分辨率的图像组 。DOG 尺度空间则通过相邻尺度的高斯模糊图像相减得到,在 DOG 尺度空间中检测极值点,这些极值点即为潜在的关键点。​

    在关键点方向赋值阶段,利用关键点邻域像素的梯度方向分布特性,为每个关键点指定方向参数,使关键点具有旋转不变性。通过统计关键点邻域的梯度方向直方图,将直方图峰值对应的方向作为关键点的主方向,若存在其他峰值能量达到主峰值 80% 的方向,则将其作为辅方向 。​

    SIFT 描述子生成时,以关键点为中心,将其邻域划分为多个子区域,计算每个子区域的梯度方向直方图,最终将这些直方图串联成一个 128 维的向量,作为关键点的描述符。这个描述符对光照变化、视角变化等具有一定的鲁棒性 。在 Python 中,使用 OpenCV 库进行 SIFT 特征检测与匹配,代码如下:​

import cv2​
import numpy as np​
​
# 读取图像​
img1 = cv2.imread('image1.jpg', cv2.IMREAD_GRAYSCALE)​
img2 = cv2.imread('image2.jpg', cv2.IMREAD_GRAYSCALE)​
​
# 创建SIFT对象​
sift = cv2.SIFT_create()​
​
# 检测关键点和计算描述符​
kp1, des1 = sift.detectAndCompute(img1, None)​
kp2, des2 = sift.detectAndCompute(img2, None)​
​
# 创建BFMatcher对象​
bf = cv2.BFMatcher()​
​
# 进行特征匹配​
matches = bf.knnMatch(des1, des2, k = 2)​
​
# 筛选好的匹配​
good_matches = []for m, n in matches:if m.distance < 0.75 * n.distance:​
        good_matches.append(m)​
​
# 绘制匹配结果​
img_matches = cv2.drawMatches(img1, kp1, img2, kp2, good_matches, None, flags = cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)​
​
# 显示结果​
cv2.imshow('SIFT Matches', img_matches)​
cv2.waitKey(0)​
cv2.destroyAllWindows()


    这段代码展示了如何使用 SIFT 算法进行图像特征提取与匹配,通过cv2.SIFT_create创建 SIFT 对象,detectAndCompute方法检测关键点并计算描述符,BFMatcher进行特征匹配,最后筛选并绘制匹配结果 。在实际应用中,SIFT 算法常用于图像拼接、目标识别等领域。在图像拼接中,通过 SIFT 特征匹配找到不同图像间的对应关系,从而实现图像的无缝拼接;在目标识别中,利用 SIFT 描述符的独特性,在复杂背景下准确识别目标物体 。​

3.2 HOG 特征计算​

    梯度方向直方图(HOG)是一种用于物体检测的特征描述子,它通过计算和统计图像局部区域的梯度方向直方图来构成特征 。HOG 特征计算首先对图像进行灰度化和 Gamma 校正,以减少光照因素的影响,增强图像的对比度 。然后计算图像每个像素的梯度,包括梯度大小和方向,常用的方法是使用 [-1, 0, 1] 和 [1, 0, -1] T 梯度算子分别对图像进行卷积,得到 x 和 y 方向的梯度分量 。​

    将图像划分成小的细胞单元(cell),统计每个 cell 的梯度直方图,即可形成每个 cell 的描述符。例如,将 cell 的梯度方向 180 度分成 9 个方向块,对 cell 内每个像素的梯度方向在直方图中进行加权投影,得到该 cell 的梯度方向直方图 。将每几个 cell 组成一个块(block),一个 block 内所有 cell 的特征描述符串联起来便得到该 block 的 HOG 特征描述符 。​

    在 Python 中,使用 OpenCV 库进行 HOG 特征计算与行人检测,代码如下:​

import cv2​
​
# 读取图像​
image = cv2.imread('pedestrian.jpg')​
​
# 创建HOG描述符对象​
hog = cv2.HOGDescriptor()​
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())​
​
# 进行行人检测​
rects, weights = hog.detectMultiScale(image, winStride=(8, 8), padding=(16, 16), scale=1.05)​
​
# 绘制检测结果​
for (x, y, w, h) in rects:​
    cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)​
​
# 显示结果​
cv2.imshow('HOG Pedestrian Detection', image)​
cv2.waitKey(0)​
cv2.destroyAllWindows()



    这段代码通过cv2.HOGDescriptor创建 HOG 描述符对象,setSVMDetector设置默认的行人检测模型,detectMultiScale进行行人检测,最后绘制检测到的行人矩形框 。HOG 特征在行人检测中表现出色,因为它对图像几何和光学形变具有较好的不变性,能够有效处理行人姿势的细微变化 。在智能安防监控系统中,HOG 特征被广泛应用于实时行人检测,通过分析监控视频中的图像,快速准确地识别出行人,为安全管理提供有力支持 。​

四、 机器学习分类实战​

4.1 数据集预处理​

    以 CIFAR-10 数据集为例,它包含 10 个不同类别的 60000 张彩色图像,常用于图像分类任务的基准测试。在使用该数据集进行机器学习分类实战时,首先要进行数据加载与划分。使用torchvision库可以方便地加载 CIFAR-10 数据集,并将其划分为训练集和测试集 。​

import torch​
import torchvision​
import torchvision.transforms as transforms​
​
# 数据预处理​
transform = transforms.Compose([​
    transforms.Resize((32, 32)),  # 调整图像大小​
    transforms.ToTensor(),  # 转换为张量​
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))  # 归一化​
])​
​
# 加载训练集​
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,​
                                        download=True, transform=transform)​
trainloader = torch.utils.data.DataLoader(trainset, batch_size=32,​
                                          shuffle=True, num_workers=2)​
​
# 加载测试集​
testset = torchvision.datasets.CIFAR10(root='./data', train=False,​
                                       download=True, transform=transform)​
testloader = torch.utils.data.DataLoader(testset, batch_size=32,​
                                         shuffle=False, num_workers=2)​
​


    在这段代码中,transforms.Compose将多个预处理操作组合在一起,Resize调整图像大小为 32x32 像素,ToTensor将图像转换为 PyTorch 张量,Normalize对图像进行归一化处理 。通过torchvision.datasets.CIFAR10加载数据集,并使用DataLoader创建数据加载器,方便在训练和测试过程中按批次读取数据 。​

4.2 SVM 分类器实现​

    支持向量机(SVM)是一种常用的分类算法,在图像分类中也有广泛应用 。在 Python 中,可以使用sklearn库来实现 SVM 分类器 。首先,需要将图像数据转换为特征向量,这里可以使用之前介绍的 HOG 特征 。​

from sklearn import svm​
from sklearn.metrics import accuracy_score, confusion_matrix​
import numpy as np​
from skimage.feature import hog​
​
​
# 提取HOG特征​
def extract_hog_features(images):​
    hog_features = []for image in images:​
        fd = hog(image, orientations = 9, pixels_per_cell=(8, 8), cells_per_block=(2, 2), visualize = False)​
        hog_features.append(fd)return np.array(hog_features)​
​
​
# 提取训练集和测试集的HOG特征​
train_images = []​
train_labels = []for images, labels in trainloader:​
    train_images.extend(images.numpy())​
    train_labels.extend(labels.numpy())​
train_images = np.array(train_images)​
train_labels = np.array(train_labels)​
train_hog_features = extract_hog_features(train_images)​
​
test_images = []​
test_labels = []for images, labels in testloader:​
    test_images.extend(images.numpy())​
    test_labels.extend(labels.numpy())​
test_images = np.array(test_images)​
test_labels = np.array(test_labels)​
test_hog_features = extract_hog_features(test_images)​
​
​
# 训练SVM分类器​
clf = svm.SVC(kernel='linear')​
clf.fit(train_hog_features, train_labels)​
​
# 预测​
predictions = clf.predict(test_hog_features)​
​
# 评估模型​
accuracy = accuracy_score(test_labels, predictions)​
conf_matrix = confusion_matrix(test_labels, predictions)​
​
print(f'Accuracy: {accuracy}')print(f'Confusion Matrix:\n{conf_matrix}')



    在这段代码中,extract_hog_features函数用于提取图像的 HOG 特征 。通过遍历训练集和测试集的数据加载器,将图像数据转换为 NumPy 数组,并提取 HOG 特征 。然后,使用svm.SVC创建 SVM 分类器,设置核函数为线性核,调用fit方法进行训练 。最后,使用训练好的模型对测试集进行预测,并使用准确率、混淆矩阵等指标评估模型性能 。准确率反映了模型预测正确的样本比例,混淆矩阵则展示了模型在各个类别上的预测情况,包括真阳性、假阳性、真阴性和假阴性的数量,有助于更全面地了解模型的性能 。​

五、卷积神经网络详解​

5.1 LeNet-5 模型实现​

    LeNet-5 是卷积神经网络(CNN)的经典模型,由 Yann LeCun 等人于 1998 年提出,主要用于手写数字识别任务 。它的网络结构简洁高效,包含了卷积层、池化层和全连接层,为后续的 CNN 发展奠定了基础 。​

    LeNet-5 的输入层接收 32x32 的灰度图像 。第一层卷积层 C1 使用 6 个大小为 5x5 的卷积核,对输入图像进行卷积操作,得到 6 个大小为 28x28 的特征图 。卷积层通过局部连接和权重共享,大大减少了参数数量,提高了计算效率 。以其中一个卷积核为例,它在图像上滑动,对每个 5x5 的局部区域进行卷积运算,将其转化为一个特征值,这些特征值构成了特征图 。在 Python 中,使用 PyTorch 实现 C1 层的代码如下:​

import torch​
import torch.nn as nn​
​
​
class LeNet5(nn.Module):def __init__(self):super(LeNet5, self).__init__()​
        self.conv1 = nn.Conv2d(1, 6, kernel_size = 5)



    在这段代码中,nn.Conv2d表示二维卷积层,第一个参数1表示输入图像的通道数为 1(灰度图像),第二个参数6表示输出的特征图数量为 6,kernel_size = 5表示卷积核大小为 5x5 。​

    第一层池化层 S2 采用 2x2 的最大池化,步长为 2,对 C1 层的 6 个特征图进行下采样,得到 6 个大小为 14x14 的特征图 。池化层的作用是降低特征图的分辨率,减少计算量,同时保留主要特征 。最大池化是在每个 2x2 的区域中选择最大值作为输出,这样可以突出图像中的关键特征 。使用 PyTorch 实现 S2 层的代码如下:​

class LeNet5(nn.Module):def __init__(self):super(LeNet5, self).__init__()​
        self.conv1 = nn.Conv2d(1, 6, kernel_size = 5)​
        self.pool1 = nn.MaxPool2d(kernel_size = 2, stride = 2)​
​


    在这段代码中,nn.MaxPool2d表示最大池化层,kernel_size = 2表示池化核大小为 2x2,stride = 2表示步长为 2 。​

    第二层卷积层 C3 使用 16 个大小为 5x5 的卷积核,对 S2 层的特征图进行卷积操作,得到 16 个大小为 10x10 的特征图 。C3 层进一步提取图像的高级特征,每个特征图都是由 S2 层的部分或全部特征图组合而成 。在实际应用中,C3 层的卷积核会学习到不同的特征模式,如笔画的拐角、线条的方向等 。使用 PyTorch 实现 C3 层的代码如下:​

class LeNet5(nn.Module):def __init__(self):super(LeNet5, self).__init__()​
        self.conv1 = nn.Conv2d(1, 6, kernel_size = 5)​
        self.pool1 = nn.MaxPool2d(kernel_size = 2, stride = 2)​
        self.conv2 = nn.Conv2d(6, 16, kernel_size = 5)



    在这段代码中,nn.Conv2d的第一个参数6表示输入的特征图数量为 6(来自 S2 层),第二个参数16表示输出的特征图数量为 16 。

    第二层池化层 S4 同样采用 2x2 的最大池化,步长为 2,对 C3 层的 16 个特征图进行下采样,得到 16 个大小为 5x5 的特征图 。S4 层进一步降低特征图的维度,减少计算量 。使用 PyTorch 实现 S4 层的代码如下:​

class LeNet5(nn.Module):def __init__(self):super(LeNet5, self).__init__()​
        self.conv1 = nn.Conv2d(1, 6, kernel_size = 5)​
        self.pool1 = nn.MaxPool2d(kernel_size = 2, stride = 2)​
        self.conv2 = nn.Conv2d(6, 16, kernel_size = 5)​
        self.pool2 = nn.MaxPool2d(kernel_size = 2, stride = 2)



    在这段代码中,nn.MaxPool2d的参数设置与 S2 层类似 。​

    全连接层 C5 将 S4 层的 16 个 5x5 的特征图展平为一维向量,然后连接到 120 个神经元 。C5 层的作用是将卷积层提取的特征映射到分类空间,为后续的分类做准备 。使用 PyTorch 实现 C5 层的代码如下:​

class LeNet5(nn.Module):def __init__(self):super(LeNet5, self).__init__()​
        self.conv1 = nn.Conv2d(1, 6, kernel_size = 5)​
        self.pool1 = nn.MaxPool2d(kernel_size = 2, stride = 2)​
        self.conv2 = nn.Conv2d(6, 16, kernel_size = 5)​
        self.pool2 = nn.MaxPool2d(kernel_size = 2, stride = 2)​
        self.fc1 = nn.Linear(16 * 5 * 5, 120)



在这段代码中,nn.Linear表示全连接层,第一个参数16 * 5 * 5表示输入向量的长度(S4 层展平后的向量长度),第二个参数120表示输出的神经元数量 。​
全连接层 F6 连接到 84 个神经元,进一步对特征进行变换 。F6 层的神经元会综合考虑 C5 层的输出,提取更高级的特征表示 。使用 PyTorch 实现 F6 层的代码如下:​

class LeNet5(nn.Module):def __init__(self):super(LeNet5, self).__init__()​
        self.conv1 = nn.Conv2d(1, 6, kernel_size = 5)​
        self.pool1 = nn.MaxPool2d(kernel_size = 2, stride = 2)​
        self.conv2 = nn.Conv2d(6, 16, kernel_size = 5)​
        self.pool2 = nn.MaxPool2d(kernel_size = 2, stride = 2)​
        self.fc1 = nn.Linear(16 * 5 * 5, 120)​
        self.fc2 = nn.Linear(120, 84)​
​


    在这段代码中,nn.Linear的第一个参数120表示输入的神经元数量(来自 C5 层),第二个参数84表示输出的神经元数量 。​

    输出层连接到 10 个神经元,对应 10 个数字类别,使用 Softmax 函数进行分类 。Softmax 函数将输出的数值转化为概率分布,每个类别对应一个概率值,概率最大的类别即为预测结果 。使用 PyTorch 实现输出层的代码如下:​

class LeNet5(nn.Module):def __init__(self):super(LeNet5, self).__init__()​
        self.conv1 = nn.Conv2d(1, 6, kernel_size = 5)​
        self.pool1 = nn.MaxPool2d(kernel_size = 2, stride = 2)​
        self.conv2 = nn.Conv2d(6, 16, kernel_size = 5)​
        self.pool2 = nn.MaxPool2d(kernel_size = 2, stride = 2)​
        self.fc1 = nn.Linear(16 * 5 * 5, 120)​
        self.fc2 = nn.Linear(120, 84)​
        self.fc3 = nn.Linear(84, 10)​
​
​
    def forward(self, x):​
        x = self.pool1(torch.relu(self.conv1(x)))​
        x = self.pool2(torch.relu(self.conv2(x)))​
        x = x.view(-1, 16 * 5 * 5)​
        x = torch.relu(self.fc1(x))​
        x = torch.relu(self.fc2(x))​
        x = self.fc3(x)return x​



    在这段代码中,nn.Linear的第一个参数84表示输入的神经元数量(来自 F6 层),第二个参数10表示输出的类别数量 。forward方法定义了模型的前向传播过程,包括卷积、池化、激活函数和全连接层的计算 。​

    在训练 LeNet-5 模型时,通常使用交叉熵损失函数和随机梯度下降(SGD)等优化器 。以 MNIST 手写数字数据集为例,训练代码如下:​

import torch​
import torch.nn as nn​
import torch.optim as optim​
from torchvision import datasets, transforms​
​
​
# 数据预处理​
transform = transforms.Compose([​
    transforms.Resize((32, 32)),​
    transforms.ToTensor(),​
    transforms.Normalize((0.1307,), (0.3081,))])​
​
​
# 加载数据集​
train_dataset = datasets.MNIST(root='./data', train=True,​
                                 download=True, transform=transform)​
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size = 64,​
                                           shuffle = True)​
​
test_dataset = datasets.MNIST(root='./data', train=False,​
                                download=True, transform=transform)​
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size = 64,​
                                          shuffle = False)​
​
​
# 初始化模型、损失函数和优化器​
model = LeNet5()​
criterion = nn.CrossEntropyLoss()​
optimizer = optim.SGD(model.parameters(), lr = 0.01, momentum = 0.9)​
​
​
# 训练模型​
for epoch in range(10):​
    model.train()for images, labels in train_loader:​
        optimizer.zero_grad()​
        outputs = model(images)​
        loss = criterion(outputs, labels)​
        loss.backward()​
        optimizer.step()print(f'Epoch {epoch + 1}, Loss: {loss.item()}')​
​
​
# 测试模型​
model.eval()​
correct = 0​
total = 0with torch.no_grad():for images, labels in test_loader:​
        outputs = model(images)​
        _, predicted = torch.max(outputs.data, 1)​
        total += labels.size(0)​
        correct += (predicted == labels).sum().item()​
​
print(f'Accuracy: {correct / total}')

    在这段代码中,首先对 MNIST 数据集进行预处理,包括调整图像大小、转换为张量和归一化 。然后加载训练集和测试集,初始化 LeNet-5 模型、交叉熵损失函数和 SGD 优化器 。在训练过程中,通过反向传播更新模型参数,每个 epoch 打印损失值 。训练完成后,在测试集上评估模型的准确率 。​

六、高级视觉任务实现​

6.1 YOLOv5 目标检测​

    YOLOv5 是一种高效的单阶段目标检测算法,在实时检测图像中的目标方面表现出色 。它将目标检测任务视为回归问题,通过一个卷积神经网络(CNN)对整个图像进行处理,直接输出目标的类别和边界框信息 。​

    YOLOv5 的网络结构包括输入端、骨干网络(Backbone)、颈部结构(Neck)和头部结构(Head) 。在输入端,采用 Mosaic 数据增强技术,将四张图片进行随机缩放、裁剪和拼接,丰富了数据集,提升了小目标检测性能,同时节省了 GPU 资源 。自适应锚框计算功能,使模型能根据不同数据集自适应计算最佳锚框,提高检测精度 。自适应图片缩放方法,通过添加最少的黑边,减少了信息冗余,提升了推理速度 。​

    YOLOv5骨干网络使用 BottleNeckCSP 结构,从输入图像中提取丰富的信息特征 。其中,Focus 结构对图像进行切片后再 Concat,降低了参数量;CSP1_x 模块借鉴 CSPNet 网络结构,通过分割梯度流,减少计算量的同时保证了模型识别精度 。Neck 部分采用 FPN+PAN 结构,FPN 自顶向下传达强语义特征,PAN 自底向上传达强定位特征,两者结合实现了不同尺度特征的融合,提高了检测性能 。Head 输出层将分类和定位任务结合,实现对目标的准确检测 。​

    YOLOv5在 Python 中,使用 PyTorch 实现 YOLOv5 目标检测,首先需要安装相关依赖库,如torchtorchvisionultralytics 。以下是一个简单的示例代码:​

import torch​
from PIL import Image​
import matplotlib.pyplot as plt​
​
​
# 加载YOLOv5模型​
model = torch.hub.load('ultralytics/yolov5', 'yolov5s')​
​
# 读取图像​
img = Image.open('test.jpg')​
​
# 进行目标检测​
results = model(img)​
​
# 展示检测结果​
results.show()



    在这段代码中,torch.hub.load函数加载预训练的 YOLOv5s 模型,Image.open读取图像,model(img)进行目标检测,results.show展示检测结果,包括检测到的目标类别、边界框和置信度 。在实际应用中,可根据需求对模型进行微调,如更换数据集、调整超参数等,以提高检测性能 。在安防监控领域,YOLOv5 可实时检测视频中的人物、车辆等目标,为安全管理提供支持;在智能交通中,可用于车辆检测、行人检测等,助力自动驾驶技术的发展 。​

6.2 U-Net 图像分割​

    U-Net 是一种经典的图像分割网络,其结构独特,由编码器和解码器组成,呈 U 型结构 。编码器通过卷积和池化操作提取图像的高级特征,逐渐降低特征图的分辨率,实现信息抽象;解码器则通过反卷积和上采样操作,将高级特征恢复为高分辨率,同时利用跳跃连接,将编码器中不同层次的特征与解码器对应层次的特征进行融合,保留了图像的细节信息,实现了对图像中每个像素的分类 。​

    以医学影像分割为例,U-Net 在肿瘤检测、器官分割等任务中发挥着重要作用 。在 Python 中,使用 PyTorch 实现 U-Net 图像分割,代码示例如下:​

import torch​
import torch.nn as nn​
import torch.optim as optim​
from torchvision import transforms, datasets​
​
​
class UNet(nn.Module):def __init__(self, n_channels, n_classes):super(UNet, self).__init__()​
        self.encoder1 = nn.Sequential(​
            nn.Conv2d(n_channels, 64, kernel_size = 3, padding = 1),​
            nn.BatchNorm2d(64),​
            nn.ReLU(inplace = True),​
            nn.Conv2d(64, 64, kernel_size = 3, padding = 1),​
            nn.BatchNorm2d(64),​
            nn.ReLU(inplace = True))​
        self.pool1 = nn.MaxPool2d(kernel_size = 2, stride = 2)​
        self.encoder2 = nn.Sequential(​
            nn.Conv2d(64, 128, kernel_size = 3, padding = 1),​
            nn.BatchNorm2d(128),​
            nn.ReLU(inplace = True),​
            nn.Conv2d(128, 128, kernel_size = 3, padding = 1),​
            nn.BatchNorm2d(128),​
            nn.ReLU(inplace = True))​
        self.pool2 = nn.MaxPool2d(kernel_size = 2, stride = 2)​
        self.encoder3 = nn.Sequential(​
            nn.Conv2d(128, 256, kernel_size = 3, padding = 1),​
            nn.BatchNorm2d(256),​
            nn.ReLU(inplace = True),​
            nn.Conv2d(256, 256, kernel_size = 3, padding = 1),​
            nn.BatchNorm2d(256),​
            nn.ReLU(inplace = True))​
        self.pool3 = nn.MaxPool2d(kernel_size = 2, stride = 2)​
        self.encoder4 = nn.Sequential(​
            nn.Conv2d(256, 512, kernel_size = 3, padding = 1),​
            nn.BatchNorm2d(512),​
            nn.ReLU(inplace = True),​
            nn.Conv2d(512, 512, kernel_size = 3, padding = 1),​
            nn.BatchNorm2d(512),​
            nn.ReLU(inplace = True))​
        self.pool4 = nn.MaxPool2d(kernel_size = 2, stride = 2)​
        self.bottleneck = nn.Sequential(​
            nn.Conv2d(512, 1024, kernel_size = 3, padding = 1),​
            nn.BatchNorm2d(1024),​
            nn.ReLU(inplace = True),​
            nn.Conv2d(1024, 1024, kernel_size = 3, padding = 1),​
            nn.BatchNorm2d(1024),​
            nn.ReLU(inplace = True))​
        self.upconv4 = nn.ConvTranspose2d(1024, 512, kernel_size = 2, stride = 2)​
        self.decoder4 = nn.Sequential(​
            nn.Conv2d(1024, 512, kernel_size = 3, padding = 1),​
            nn.BatchNorm2d(512),​
            nn.ReLU(inplace = True),​
            nn.Conv2d(512, 512, kernel_size = 3, padding = 1),​
            nn.BatchNorm2d(512),​
            nn.ReLU(inplace = True))​
        self.upconv3 = nn.ConvTranspose2d(512, 256, kernel_size = 2, stride = 2)​
        self.decoder3 = nn.Sequential(​
            nn.Conv2d(512, 256, kernel_size = 3, padding = 1),​
            nn.BatchNorm2d(256),​
            nn.ReLU(inplace = True),​
            nn.Conv2d(256, 256, kernel_size = 3, padding = 1),​
            nn.BatchNorm2d(256),​
            nn.ReLU(inplace = True))​
        self.upconv2 = nn.ConvTranspose2d(256, 128, kernel_size = 2, stride = 2)​
        self.decoder2 = nn.Sequential(​
            nn.Conv2d(256, 128, kernel_size = 3, padding = 1),​
            nn.BatchNorm2d(128),​
            nn.ReLU(inplace = True),​
            nn.Conv2d(128, 128, kernel_size = 3, padding = 1),​
            nn.BatchNorm2d(128),​
            nn.ReLU(inplace = True))​
        self.upconv1 = nn.ConvTranspose2d(128, 64, kernel_size = 2, stride = 2)​
        self.decoder1 = nn.Sequential(​
            nn.Conv2d(128, 64, kernel_size = 3, padding = 1),​
            nn.BatchNorm2d(64),​
            nn.ReLU(inplace = True),​
            nn.Conv2d(64, 64, kernel_size = 3, padding = 1),​
            nn.BatchNorm2d(64),​
            nn.ReLU(inplace = True))​
        self.final_conv = nn.Conv2d(64, n_classes, kernel_size = 1)​
​
​
    def forward(self, x):​
        enc1 = self.encoder1(x)​
        enc2 = self.encoder2(self.pool1(enc1))​
        enc3 = self.encoder3(self.pool2(enc2))​
        enc4 = self.encoder4(self.pool3(enc3))​
        bottleneck = self.bottleneck(self.pool4(enc4))​
        dec4 = self.decoder4(torch.cat([self.upconv4(bottleneck), enc4], dim = 1))​
        dec3 = self.decoder3(torch.cat([self.upconv3(dec4), enc3], dim = 1))​
        dec2 = self.decoder2(torch.cat([self.upconv2(dec3), enc2], dim = 1))​
        dec1 = self.decoder1(torch.cat([self.upconv1(dec2), enc1], dim = 1))​
        out = self.final_conv(dec1)return out​
​
​
# 数据预处理​
transform = transforms.Compose([​
    transforms.Resize((256, 256)),​
    transforms.ToTensor()])​
​
# 加载数据集​
trainset = datasets.ImageFolder(root='train_data', transform = transform)​
trainloader = torch.utils.data.DataLoader(trainset, batch_size = 16, shuffle = True)​
​
testset = datasets.ImageFolder(root='test_data', transform = transform)​
testloader = torch.utils.data.DataLoader(testset, batch_size = 16, shuffle = False)​
​
​
# 初始化模型、损失函数和优化器​
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")​
model = UNet(n_channels = 3, n_classes = 2).to(device)​
criterion = nn.CrossEntropyLoss()​
optimizer = optim.Adam(model.parameters(), lr = 0.001)​
​
​
# 训练模型​
for epoch in range(10):​
    model.train()​
    running_loss = 0.0for i, data in enumerate(trainloader, 0):​
        inputs, labels = data[0].to(device), data[1].to(device)​
​
        optimizer.zero_grad()​
​
        outputs = model(inputs)​
        loss = criterion(outputs, labels)​
        loss.backward()​
        optimizer.step()​
​
        running_loss += loss.item()print(f'Epoch {epoch + 1}, Loss: {running_loss / len(trainloader)}')​
​
​
# 测试模型​
model.eval()​
correct = 0​
total = 0with torch.no_grad():for data in testloader:​
        images, labels = data[0].to(device), data[1].to(device)​
        outputs = model(images)​
        _, predicted = torch.max(outputs.data, 1)​
        total += labels.size(0)​
        correct += (predicted == labels).sum().item()​
​
print(f'Accuracy: {correct / total}')

    在上述代码中,首先定义了 U-Net 网络结构,包括编码器、解码器和跳跃连接 。然后对医学影像数据集进行预处理,包括调整图像大小和转换为张量 。接着初始化模型、损失函数和优化器,在训练过程中,通过反向传播更新模型参数,每个 epoch 打印损失值 。训练完成后,在测试集上评估模型的准确率 。在自动驾驶道路识别中,U-Net 可对道路、行人、车辆等不同对象进行分割,为自动驾驶系统提供准确的环境感知信息,保障行车安全 。​

七、总结与未来展望​

7.1 技术趋势​

    计算机视觉技术正朝着多模态融合、自监督学习和边缘计算方向快速发展,这些趋势将为该领域带来更多突破和应用场景。​

    多模态融合技术结合文本、语音等多维度信息,使计算机视觉系统能更全面地理解图像和视频内容。例如,在智能安防监控中,结合图像识别和语音识别技术,不仅能识别出可疑人员,还能通过语音分析其行为意图,提高监控的准确性和智能化程度 。在智能驾驶领域,多模态融合可将摄像头图像与雷达、激光雷达数据相结合,提升自动驾驶系统对复杂路况的感知能力,保障行车安全 。多模态融合还能应用于智能教育,通过分析学生的表情、动作和语音,实现个性化学习辅导,提高学习效果 。​

    自监督学习利用无标注数据提升模型泛化性,是解决标注数据成本高、数量有限问题的有效途径。通过设计各种自监督任务,如预测图像的旋转角度、遮挡区域等,模型能从大量无标注数据中学习到有用的特征表示,从而提升在不同任务上的性能 。在医学图像分析中,自监督学习可利用大量未标注的医学影像数据,学习到疾病的特征模式,辅助医生进行疾病诊断 。在遥感图像识别中,自监督学习能从海量的卫星图像中提取特征,实现对土地利用、植被覆盖等信息的准确分类 。​

    边缘计算推动轻量化模型在移动端的部署优化,使计算机视觉技术能在资源受限的设备上实时运行。通过模型压缩、量化等技术,降低模型的计算量和存储需求,使其能在手机、智能摄像头等边缘设备上高效运行 。在智能安防监控中,边缘计算可在摄像头端直接进行目标检测和识别,减少数据传输量,提高响应速度 。在智能家居领域,边缘计算可实现智能门锁的人脸识别、智能家电的手势控制等功能,提升用户体验 。​

7.2 学习建议​

    对于想要深入学习计算机视觉的初学者和爱好者,以下建议有助于构建扎实的知识体系和实践能力。​

    熟练掌握 OpenCV/PyTorch 核心操作是入门的关键。OpenCV 提供了丰富的图像处理和计算机视觉算法,如滤波、特征提取、目标检测等,通过学习 OpenCV 的函数和方法,能快速上手图像处理任务 。

    PyTorch 作为深度学习框架,具有灵活的动态图机制和丰富的神经网络模块,学习 PyTorch 可实现各种深度学习模型,如卷积神经网络、循环神经网络等 。通过实践项目,如使用 OpenCV 进行图像去噪、使用 PyTorch 实现图像分类模型,加深对这两个工具的理解和应用能力 。​

    动手实现经典算法,如 SIFT、CNN,能加深对计算机视觉原理的理解。SIFT 算法是传统特征提取的经典算法,通过实现 SIFT,可了解尺度不变特征的提取原理和应用场景 。CNN 是深度学习在计算机视觉领域的核心算法,实现 LeNet-5、AlexNet 等经典 CNN 模型,能掌握卷积层、池化层、全连接层的工作原理和模型训练过程 。在实现过程中,可尝试调整参数、改进模型结构,观察对性能的影响,提升对算法的掌握程度 。​

    积极参与 Kaggle 竞赛或开源项目,如 COCO 数据集挑战,能在实际项目中积累经验,提升解决问题的能力。Kaggle 竞赛提供了丰富的数据集和实际问题,与全球开发者竞争合作,可学习到不同的解题思路和技术方法 。COCO 数据集挑战是目标检测和图像分割领域的重要竞赛,参与其中可接触到前沿的算法和技术,提升在该领域的实践能力 。参与开源项目,如贡献代码、提出改进建议,能与社区开发者交流,了解行业最新动态,拓宽技术视野 。

7.3 学习资料视频文档下载

    关于 计算机视觉相关资料 放网盘了,需要的自取,建议先保存到自己的网盘,网盘数据如果找不见了,联系博主免费获取!

致读者一封信

        亲爱的朋友,无论前路如何漫长与崎岖,都请怀揣梦想的火种,因为在生活的广袤星空中,总有一颗属于你的璀璨星辰在熠熠生辉,静候你抵达。

         愿你在这纷繁世间,能时常收获微小而确定的幸福,如春日微风轻拂面庞,所有的疲惫与烦恼都能被温柔以待,内心永远充盈着安宁与慰藉。

        至此,文章已至尾声,而您的故事仍在续写,不知您对文中所叙有何独特见解?期待您在心中与我对话,开启思想的新交流。


----------- 业精于勤,荒于嬉 -----------
 

请添加图片描述

----------- 行成于思,毁于随 -----------

在这里插入图片描述


     💞 关注博主 带你实现畅游前后端

     🏰 大屏可视化 带你体验酷炫大屏

     💯 神秘个人简介 带你体验不一样得介绍

     🎀 酷炫邀请函 带你体验高大上得邀请


     ① 🉑提供云服务部署;
     ② 🉑提供前端、后端、应用程序、H5、小程序、公众号等相关业务;
     ③ 🉑提供产品测评,产品推广业务;
     如🈶合作请联系我,期待您的联系。
    :本文撰写于CSDN平台,作者:xcLeigh所有权归作者所有)https://xcleigh.blog.csdn.net/,如果相关下载没有跳转,请查看这个地址,相关链接没有跳转,皆是抄袭本文,转载请备注本文原地址。


     亲,码字不易,动动小手,欢迎 点赞 ➕ 收藏,如 🈶 问题请留言(评论),博主看见后一定及时给您答复,💌💌💌


原文地址:https://xcleigh.blog.csdn.net/article/details/146712441(防止抄袭,原文地址不可删除)


网站公告

今日签到

点亮在社区的每一天
去签到