计算机视觉入门实战:图像识别、目标检测与图像分割核心任务解析

📅 2026/7/5 12:47:14
计算机视觉入门实战:图像识别、目标检测与图像分割核心任务解析
1. 从“能跑起来”开始理解计算机视觉的三大核心任务如果你刚开始接触计算机视觉面对“目标检测”、“图像分割”、“图像识别”这些术语感到一头雾水或者看了一堆理论却不知道如何动手那这篇文章就是为你准备的。我不打算从复杂的数学公式或网络结构讲起而是直接告诉你计算机视觉的入门核心就是搞清楚这三件事分别解决什么问题以及如何用最少的代码让它们在你的电脑上跑起来。很多人学了很久还是分不清“识别”和“检测”的区别更不明白“分割”到底在干什么。这会导致你拿到一个项目时根本不知道该用哪个模型。所以我们先抛开所有复杂的定义用最直白的话说清楚图像识别Image Classification回答“这是什么”的问题。给一张图模型告诉你它属于哪个类别比如这是一只猫这是一辆车。它只关心整张图的“身份”。目标检测Object Detection回答“有什么在哪里”的问题。不仅要找出图中的物体是什么类别还要用一个方框Bounding Box标出它的具体位置。比如一张街景图里能同时找出行人、汽车、交通灯并给每个都画上框。图像分割Image Segmentation回答“每个像素属于什么”的问题。它比检测更精细要把图像中每个像素都归类到某个物体或背景上。最终输出是一张“像素级”的标签图同一个物体的所有像素被标记为同一类。它又常分为语义分割Semantic Segmentation只区分类别不区分个体。比如把所有“人”的像素都标为红色但不区分这是张三还是李四。实例分割Instance Segmentation在语义分割基础上还要区分不同的个体。比如把张三的像素标为红色李四的标为蓝色。为什么这三个方向是核心因为绝大多数视觉应用无论是安防监控、自动驾驶、医疗影像分析还是工业质检最终都落在这三个任务的组合或变体上。理解了它们你就拿到了打开计算机视觉大门的钥匙。接下来我不会空谈理论。我会带你从环境搭建开始到用最流行的框架和模型比如PyTorch和YOLO、U-Net等分别跑通这三个任务的Demo最后告诉你如何判断一个模型跑得好不好以及遇到问题该先查哪里。我们的目标是看完就能动手跑通就有感觉。2. 环境准备别在第一步卡住CPU也能学很多教程一上来就要求你有高性能GPU这劝退了大部分人。实际上对于学习和验证核心概念CPU环境完全足够。我们的首要任务是“跑通”和“理解”而不是追求极致的训练速度。这里给出一个最小化、避坑的Python环境配置方案。2.1 基础环境搭建Anaconda PyTorch CPU版我强烈建议使用Anaconda或Miniconda来管理环境它能完美解决不同项目间包版本冲突的问题。安装Anaconda去官网下载对应你操作系统Windows/macOS/Linux的安装包一路默认安装即可。安装完成后打开“Anaconda Prompt”Windows或终端macOS/Linux。创建独立的虚拟环境这是好习惯避免把系统Python环境搞乱。# 创建一个名为cv_demo的Python 3.9环境 conda create -n cv_demo python3.9 # 激活这个环境 conda activate cv_demo安装PyTorch CPU版本这是目前最主流的深度学习框架之一生态丰富。去PyTorch官网https://pytorch.org/get-started/locally/选择你的操作系统包管理器选择Conda计算平台选择CPU。官网会生成一条命令类似下面这样直接复制到你的终端里运行。# 示例命令具体以官网生成为准 conda install pytorch torchvision torchaudio cpuonly -c pytorch这条命令会安装PyTorch及其常用的视觉工具库torchvision。安装其他必备工具包pip install opencv-python matplotlib numpy pillow jupyter notebookopencv-python图像处理的核心库用于读图、显示、画框等。matplotlib画图库用于可视化结果。numpy数值计算基础。pillow另一个常用的图像处理库。jupyter notebook交互式编程环境非常适合一步步调试和展示。注意如果安装过程因为网络问题失败可以尝试使用国内镜像源例如在pip命令后加上-i https://pypi.tuna.tsinghua.edu.cn/simple。2.2 验证环境与准备测试数据环境装好后别急着跑模型先验证基础功能是否正常。验证PyTorch在激活的cv_demo环境中打开Python解释器或创建一个新的Jupyter Notebook单元格输入import torch import torchvision print(torch.__version__) print(torchvision.__version__) # 检查CUDAGPU是否可用在CPU环境下会返回False这是正常的 print(torch.cuda.is_available())能正常输出版本号且不报错说明PyTorch安装成功。准备测试图片找几张清晰的图片放在项目目录里最好包含多种物体比如一张有猫有狗的图一张街景图。这是你后续测试的“燃料”。环境准备好后我们就可以进入正题从最简单的任务开始。3. 图像识别实战用预训练模型快速“认图”图像识别是基础。我们利用PyTorch官方提供的预训练模型无需自己训练直接体验“识别”的能力。这能让你在几分钟内获得正反馈。3.1 加载模型与预测单张图片PyTorch的torchvision.models里包含了许多经典模型如ResNet, VGG并且都提供了在ImageNet数据集上预训练好的权重。ImageNet有1000个类别基本覆盖常见物体。import torch from torchvision import models, transforms from PIL import Image import matplotlib.pyplot as plt # 1. 加载预训练的ResNet-18模型并设置为评估模式 model models.resnet18(weightsmodels.ResNet18_Weights.IMAGENET1K_V1) model.eval() # 评估模式关闭Dropout等训练特有的层 # 2. 定义图像预处理流程 # 必须与模型训练时使用的预处理保持一致 preprocess transforms.Compose([ transforms.Resize(256), # 缩放到256像素 transforms.CenterCrop(224), # 中心裁剪到224x224 transforms.ToTensor(), # 转为Tensor并归一化到[0,1] transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]), # 标准化 ]) # 3. 加载并预处理图片 img_path “你的测试图片路径例如cat_dog.jpg” image Image.open(img_path).convert(RGB) # 确保是RGB三通道 input_tensor preprocess(image) # 增加一个批次维度因为模型输入是 [batch_size, channels, height, width] input_batch input_tensor.unsqueeze(0) # 4. 进行预测禁用梯度计算以节省内存 with torch.no_grad(): output model(input_batch) # 5. 解析结果 # output是一个包含1000个类别分数的Tensor probabilities torch.nn.functional.softmax(output[0], dim0) # 6. 读取ImageNet的类别标签文件需要下载 # 这里我们用一个简单字典示例实际中你需要下载imagenet_classes.txt # 假设我们有一个从索引到类别名的映射字典 imagenet_classes # 你可以从网上下载这个文件内容格式是每行一个类别名 # with open(imagenet_classes.txt) as f: # categories [line.strip() for line in f.readlines()] # 为了演示我们直接取概率最高的前5个结果 top5_prob, top5_catid torch.topk(probabilities, 5) # 打印结果 for i in range(top5_prob.size(0)): # 这里 categories[top5_catid[i]] 需要替换成实际的类别名 print(f“Top-{i1}: 类别ID {top5_catid[i].item()} 概率 {top5_prob[i].item():.3f}”) # 如果你有categories列表可以打印名称 # print(f“Top-{i1}: {categories[top5_catid[i]]}, 概率 {top5_prob[i].item():.3f}”) # 7. 显示原图 plt.imshow(image) plt.axis(off) plt.show()关键点解释model.eval()至关重要。预训练模型有两种模式训练train()和评估eval()。评估模式会固定住Batch Normalization层和Dropout层的状态保证推理结果的一致性。预处理模型对输入图像的尺寸、颜色通道、数值范围有严格要求。transforms.Normalize使用的均值和标准差是ImageNet数据集统计得到的必须保持一致否则识别准确率会大幅下降。unsqueeze(0)深度学习模型通常处理一个批次的图片。即使我们只预测一张也要增加一个“批次”维度。with torch.no_grad()在这个上下文管理器内PyTorch不会计算梯度能显著减少内存消耗并加速推理这对验证阶段是必须的。3.2 如何判断识别结果的好坏跑通代码后你可能会发现模型把一只猫识别成了“虎猫”或“埃及猫”这其实是正确的因为ImageNet的类别非常细。判断好坏有几个层面Top-1准确率概率最高的类别是否正确。对于泛化类别如“猫”可能不准因为ImageNet分类太细。Top-5准确率概率前五的类别中是否包含正确类别。如果一张猫的图模型给出的Top-5结果里有“虎猫”、“暹罗猫”等说明模型“知道”这是猫只是细分错了这通常是可以接受的。置信度模型给出的概率值。通常高于0.550%我们认为模型比较确信。但要注意对于它没见过的奇异图像它也可能给出高置信度的错误答案。常见问题排查报错KeyError或找不到模型检查PyTorch版本新版torchvision加载权重的API有变化确保你用的是类似weightsmodels.ResNet18_Weights.IMAGENET1K_V1的写法。旧版的pretrainedTrue已逐渐废弃。识别结果完全不对首先检查图片预处理流程是否与训练时一致尤其是Normalize的参数。其次确认图片内容清晰、主体明确。最后ImageNet模型不认识文字、抽象画或特别罕见的物体是正常的。运行速度慢在CPU上ResNet-18推理一张图可能需要几百毫秒到一秒。这是正常的。如果想提速可以考虑更轻量的模型如MobileNet或者后续在有GPU的环境下运行。4. 目标检测实战用YOLO快速“找东西”目标检测比识别更进一步。这里我们选用**YOLOYou Only Look Once**系列因为它速度快、精度高、生态好是工业界和学术界的宠儿。我们将使用Ultralytics公司维护的ultralytics库它让YOLOv8的使用变得极其简单。4.1 安装YOLOv8并检测图片首先在之前创建的cv_demo环境中安装ultralytics库。pip install ultralytics然后用不到10行代码完成检测from ultralytics import YOLO import cv2 import matplotlib.pyplot as plt # 1. 加载官方的预训练YOLOv8模型这里是中等尺寸的版本 # 首次运行会自动从网上下载模型文件约50MB model YOLO(yolov8n.pt) # ‘n’代表nano最小。还有‘s’, ‘m’, ‘l’, ‘x’等更大更准的版本 # 2. 进行预测 img_path “你的测试图片路径例如street.jpg” results model(img_path) # 返回一个列表每个元素对应一张图的检测结果 # 3. 可视化结果 # results[0].plot() 会生成带框和标签的图片 res_plotted results[0].plot() # 返回一个BGR格式的numpy数组 # 4. 显示OpenCV是BGRmatplotlib是RGB需要转换 res_plotted_rgb cv2.cvtColor(res_plotted, cv2.COLOR_BGR2RGB) plt.figure(figsize(10, 8)) plt.imshow(res_plotted_rgb) plt.axis(off) plt.show() # 5. 打印检测到的物体信息 for box in results[0].boxes: # 获取类别ID、置信度、边界框坐标 cls_id int(box.cls[0]) conf float(box.conf[0]) xyxy box.xyxy[0].tolist() # 左上角和右下角坐标 [x1, y1, x2, y2] # 通过results[0].names可以获取类别名映射 class_name results[0].names[cls_id] print(f“检测到: {class_name}, 置信度: {conf:.2f}, 位置: {xyxy}”)关键点解释模型选择yolov8n.pt是最轻量级的速度最快精度稍低。yolov8s.pt,yolov8m.pt等更大更准但更慢。根据你的需求选择。CPU上跑yolov8n检测一张图大概需要0.5-2秒。结果解析results对象包含了丰富的信息。boxes属性存储了所有检测框。每个框有类别cls、置信度conf和坐标xyxy或xywh等格式。可视化plot()方法非常方便它自动把框、标签、置信度画在了图上。4.2 目标检测的评估与调参模型跑起来后你可能会关心它检测得准不准漏检了吗框的位置对吗置信度阈值conf这是最重要的参数之一。模型会输出很多框每个框有一个置信度。通过设置阈值可以过滤掉不可信的检测。results model(img_path, conf0.25) # 默认是0.25提高它如0.5可以减少误检但可能增加漏检。交并比阈值iou用于非极大值抑制NMS解决同一个物体被多个框检测到的问题。默认值0.7通常不错在物体重叠严重时可以调低。results model(img_path, iou0.45)如何判断检测质量查全率Recall该找出来的物体找出来了多少。如果图中明明有10辆车只检测出5辆查全率低。查准率Precision检测出来的框里有多少是正确的。如果检测出10个“车”框其中3个其实是路牌查准率低。mAP平均精度均值综合衡量检测器在不同置信度阈值下的性能是学术论文和比赛中最常用的指标。但对于我们快速验证直观地看可视化结果是否合理就够了。常见问题排查检测不到小物体YOLO对小物体检测能力相对较弱。可以尝试使用更大的模型如yolov8m或者将输入图片分辨率调大imgsz640默认是640可以尝试1280但会更慢。results model(img_path, imgsz1280)同一个物体被重复检测调整iou参数或者检查置信度阈值是否过低。类别识别错误YOLOv8预训练模型是在COCO数据集上训练的包含80个常见类别。如果物体不在这个列表里比如“热水壶”它可能会识别成相近的类别如“瓶子”。这是预训练模型的局限性需要通过自定义训练来解决。5. 图像分割实战用U-Net体验“像素级”分析图像分割尤其是语义分割在医疗影像、自动驾驶场景理解中至关重要。这里我们以经典的U-Net模型为例并使用一个简单的医学影像数据集进行演示。因为分割模型通常需要针对特定任务训练我们这里演示如何加载一个预训练模型并进行推理。为了简化我们使用segmentation-models-pytorch这个优秀的库它封装了许多分割模型。5.1 安装库与加载预训练模型pip install segmentation-models-pytorch pip install -q albumentations # 一个强大的数据增强库我们将使用在CamVid数据集上预训练的U-Net模型。注意这个模型是用于街景分割的有11个类别天空、建筑、道路等。import torch import segmentation_models_pytorch as smp import cv2 import numpy as np import matplotlib.pyplot as plt from torchvision import transforms # 1. 定义模型结构和预训练编码器 model smp.Unet( encoder_name“resnet34”, # 使用ResNet34作为编码器特征提取器 encoder_weights“imagenet”, # 编码器使用在ImageNet上预训练的权重 in_channels3, # 输入RGB三通道图片 classes11, # CamVid数据集的11个类别 ) # 2. 加载预训练的分割解码器权重这里需要手动下载 # 由于版权和存储我们这里模拟一个已加载权重的模型。 # 实际中你需要从segmentation-models-pytorch的仓库或相关项目找到.pth权重文件加载。 # model.load_state_dict(torch.load(‘unet_camvid.pth’)) model.eval() # 3. 定义预处理和后处理函数 def preprocess_image(image_path): image cv2.imread(image_path) image cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # OpenCV读入是BGR # 调整到模型期望的尺寸CamVid预训练模型通常是480x360或类似 image cv2.resize(image, (480, 360)) # 归一化到[0,1]并转为Tensor transform transforms.Compose([ transforms.ToTensor(), ]) image_tensor transform(image).unsqueeze(0) # 增加批次维度 return image_tensor, image def postprocess_output(output_tensor): # output_tensor形状: [1, 11, H, W] # 取每个像素点上概率最大的类别 prediction output_tensor.argmax(dim1).squeeze().cpu().numpy() # 得到[H, W]的预测图 return prediction # 4. 模拟推理因为缺少权重我们生成一个随机输出用于演示流程 img_path “你的测试图片路径” input_tensor, original_image preprocess_image(img_path) with torch.no_grad(): # 实际有权重时output model(input_tensor) # 模拟输出一个随机张量形状为[1, 11, 360, 480] output torch.randn(1, 11, 360, 480) pred_mask postprocess_output(output) # 预测的掩码图每个像素值是0-10的整数 # 5. 可视化 # 定义CamVid的11个类别颜色示例实际需对应 colors np.array([ [128, 128, 128], # 天空 [128, 0, 0], # 建筑 [192, 192, 128], # 柱子 # ... 其他类别颜色 ]) # 将预测的类别ID映射到颜色 colored_mask colors[pred_mask] fig, axes plt.subplots(1, 2, figsize(12, 5)) axes[0].imshow(original_image) axes[0].set_title(‘Original Image’) axes[0].axis(‘off’) axes[1].imshow(colored_mask) axes[1].set_title(‘Predicted Segmentation’) axes[1].axis(‘off’) plt.show()关键点解释编码器-解码器结构U-Net是典型的编码器-解码器结构。编码器如ResNet负责下采样提取高级语义特征解码器负责上采样将特征图恢复到原图尺寸并进行像素分类。预训练编码器使用在ImageNet上预训练的编码器encoder_weights“imagenet”可以大幅提升模型性能并加速收敛这是一种非常有效的迁移学习。输出解析分割模型的输出是一个[Batch, Classes, Height, Width]的张量。在Height x Width的每个位置上都有Classes个数值代表属于每个类别的概率或logits。我们通过argmax取概率最大的那个类别ID得到最终的预测掩码图。5.2 分割任务的特殊考量数据标注昂贵分割需要像素级的标注制作成本远高于检测框和分类标签。因此数据增强如旋转、翻转、色彩抖动对于防止过拟合、提升模型泛化能力至关重要。albumentations库是这方面的利器。评价指标最常用的是平均交并比Mean Intersection over Union, mIoU。计算每个类别的预测区域和真实区域的重叠面积与并集面积的比值再对所有类别求平均。mIoU越高分割越准。类别不平衡在医学图像中病灶区域可能只占图像的很小部分。直接训练会导致模型偏向背景。需要使用加权损失函数如Dice Loss, Focal Loss或在线难例挖掘等策略。实例分割如果需要区分同一类别的不同个体如分割出图像中的多个人则需要使用Mask R-CNN、YOLACT或SOLO等实例分割模型。这些模型通常在目标检测的基础上增加一个分割头来预测每个实例的掩码。常见问题排查输出全是一个类别通常是严重的类别不平衡或学习率设置不当导致。检查数据集中各类别的像素比例尝试使用带权重的损失函数。边界分割模糊分割任务在物体边界处容易出错。可以尝试使用条件随机场CRF作为后处理来细化边界或者使用关注边界的损失函数。显存不足分割模型由于要处理高分辨率特征图显存消耗大。如果遇到OOM内存溢出可以尝试减小输入图像尺寸imgsz。减小批次大小batch_size。使用更轻量的编码器如MobileNet代替ResNet。使用混合精度训练torch.cuda.amp。6. 从Demo到项目下一步该做什么跑通三个Demo只是第一步。要想真正掌握并应用到自己的项目中你需要系统地走完以下流程。这比单纯调参更重要。6.1 准备你自己的数据这是所有项目的基础也是最耗时的一步。数据收集根据你的任务收集图片或视频。确保数据覆盖了实际场景中可能出现的各种情况光照、角度、遮挡、背景等。数据标注分类只需给每张图打上类别标签。可以用文件夹分类也可以用CSV文件记录。检测需要用标注工具如LabelImg,CVAT,Roboflow画出物体边界框并指定类别。标注文件通常是YOLO格式.txt每行class_id x_center y_center width height坐标归一化或COCO格式.json。分割需要用像素级标注工具如Labelme,EISeg,CVAT勾勒出物体的精确轮廓。输出通常是PNG格式的掩码图或用多边形坐标表示的JSON文件。数据划分将数据分为训练集Training Set、验证集Validation Set和测试集Test Set。常用比例是7:2:1或8:1:1。验证集用于训练时监控模型表现、调整超参数测试集用于最终评估在训练过程中绝对不能使用。6.2 模型训练与调优有了数据就可以开始训练你自己的模型了。选择模型架构分类ResNet, EfficientNet, Vision Transformer (ViT)。检测YOLO系列v5, v8, v9 Faster R-CNN, DETR。分割U-Net, DeepLabV3, Mask R-CNN实例分割。迁移学习强烈推荐。不要从头开始训练。使用在大型数据集如ImageNet, COCO上预训练好的模型只替换最后的输出层然后在你的小数据集上进行微调Fine-tuning。这能极大加快收敛速度提升性能。训练流程定义数据加载器使用PyTorch的Dataset和DataLoader来高效读取和预处理数据包括数据增强。选择损失函数分类用交叉熵损失CrossEntropyLoss检测用YOLO自带的损失或SmoothL1Loss Focal Loss分割用交叉熵损失或Dice Loss。选择优化器Adam或SGD with Momentum是常用选择。设置学习率调度使用学习率预热Warmup和余弦退火Cosine Annealing等策略有助于模型收敛到更好的位置。开始训练循环遍历数据加载器前向传播计算损失反向传播更新权重。监控与调试使用TensorBoard或Weights Biases等工具可视化训练过程中的损失曲线、准确率/mAP/mIoU曲线。如果验证集指标不升反降可能是过拟合需要增加数据增强、使用Dropout或提前停止Early Stopping。6.3 模型部署与优化模型训练好后需要部署到实际应用中。模型导出将PyTorch模型.pt或.pth导出为更通用的格式以便在不同平台上运行。TorchScriptPyTorch自带的序列化格式可以在C中调用。ONNX开放的神经网络交换格式可以被TensorRT, OpenVINO, ONNX Runtime等多种推理引擎支持。# 以YOLOv8导出ONNX为例 from ultralytics import YOLO model YOLO(‘yolov8n.pt’) model.export(format‘onnx’) # 会生成一个 .onnx 文件推理优化量化将模型权重从浮点数FP32转换为整数INT8可以大幅减少模型体积和提升推理速度精度损失很小。PyTorch提供了torch.quantization模块。剪枝移除网络中不重要的连接或通道得到一个更小、更快的模型。使用专用推理引擎TensorRT(NVIDIA GPU)对N卡优化极致性能提升显著。OpenVINO(Intel CPU/GPU)对Intel硬件优化。ONNX Runtime跨平台支持CPU、GPU等多种硬件。集成到应用将优化后的模型集成到你的Web服务Flask, FastAPI、移动端PyTorch Mobile, TFLite或嵌入式设备NVIDIA Jetson, Raspberry Pi中。6.4 持续学习与资源推荐计算机视觉领域发展迅速保持学习至关重要。跟进前沿关注顶级会议CVPR, ICCV, ECCV, NeurIPS的最新论文。可以在Papers with Code网站上按任务和榜单查找SOTA模型。动手项目最好的学习方式是做项目。可以从Kaggle、天池等平台的竞赛开始或者自己设定一个小目标如“用手机摄像头识别垃圾分类”、“监控仓库货架空缺”。深入原理当你熟悉流程后回头去理解模型背后的原理卷积操作、反向传播、注意力机制等这能帮助你在遇到新问题时进行有效的调试和创新。关键资源课程吴恩达《深度学习专项课程》、李飞飞《CS231n》。书籍《深度学习》花书、《Python深度学习》。代码库PyTorch官方教程、MMDetection检测、MMSegmentation分割、Hugging Face TransformersViT等。社区GitHub, Stack Overflow, PyTorch论坛以及相关的技术博客。记住从“跑通Demo”到“解决实际问题”中间隔着大量的工程实践和问题排查。遇到报错时优先检查数据路径、数据格式、张量形状和库版本这些解决了90%的初级问题。然后耐心地调整数据、模型和训练参数每一次迭代都是向目标迈进的一步。