news 2026/10/9 6:32:29

30种球类运动图像识别数据集详解:从目录结构到分类训练实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
30种球类运动图像识别数据集详解:从目录结构到分类训练实战

简介:这是一个面向目标检测与图像分类学习者的30种球类运动图像识别数据集,覆盖篮球、足球、棒球、台球、高尔夫等常见球类,共30个类别。数据已按训练集、验证集、测试集划分并存放于独立文件夹中,其中训练集图片3595张,验证集和测试集各150张,可直接用于YOLOv5分类任务及各类CNN分类网络的训练和评估。资源包附带分类标签字典JSON文件,方便加载类别映射;同时提供show可视化脚本,便于快速浏览和检查数据质量。压缩包内共2000个文件,以1998个jpg图片为主,另含1个py脚本和1个json文件,整体大小约76.74MB,轻量易下载。目前已有190人学习使用,适合正在实践YOLOv5或图像分类项目、需要一份已划分好且可直接投入训练的标准数据集的学习者和开发者。

1. 30种球类运动图像识别数据集:分类训练的第一批数据怎么选

做图像识别分类项目,最难的不是搭网络,而是找一份能直接开训的数据集。这份30种球类运动图像识别数据集,把篮球、足球、棒球、台球、高尔夫等30个常见球类类别整理成了训练集、验证集、测试集三份,训练集3595张、验证集150张、测试集150张,额外附带一份类别字典json文件。它解决的问题非常具体:让「从零到能跑通一次球类分类训练」这段路尽量短。适合两类人——刚要把分类网络完整跑一遍的初学者,以及正在做球类识别预研、需要一份干净数据验证方案的从业者。

2. 目录结构与类别字典文件:train、valid、test和json如何对应

2.1 data目录内部结构:三套同构的类别文件夹

拿到资源别急着写训练代码,第一件事是看清目录结构。data目录下面按使用场景拆成训练集、验证集、测试集三套(个别打包版本会把测试集并入验证集,实际以你拿到的目录为准),每一套内部结构完全一致,都是「类别文件夹 → 图片文件」的两层组织。train/高尔夫下面存放该类别全部jpg,valid/高尔夫下面是验证用的jpg,test/高尔夫下面是测试用的jpg。图片命名没有固定规律,009.jpg、46.jpg、096.jpg这种混合命名在采集类数据集里很常见,代码里千万别依赖文件名排序。

我拿到手第一步是把目录树打出来核对:

# 只看两级目录:data/train/篮球、data/train/足球 这一层 find data -maxdepth 2 -type d | sort | head -50

输出的前几行应该是data、data/train、data/train/棒球……一路列到30个类别。核对重点有两个:一是train、valid、test三套目录都存在,二是每个类别文件夹在训练集里都有对应目录,不能出现某类别只在训练集出现、验证集里却找不到的情况。如果验证集少了几个类别,说明原始划分不均衡,后续要按分层策略重新拆。

为什么分类数据集普遍用文件夹组织而不是csv标注?核心原因是分类任务的标注本质是「图片-类别」映射,文件夹天然表达这种关系,不需要额外维护image_id到label的关联表,图片一改名就失配。torchvision的ImageFolder、Keras的flow_from_directory、yolov5分类模式全都默认这种结构,这是这份数据能跨框架复用的根因。

2.2 类别字典json:从分类名到整数标签的映射

资源里附带的json文件就是类别字典,解决文本类名和数字标签的对应问题。分类网络最后输出30个类别的概率向量,训练时每个类别必须有一个整数索引,这份json干的就是这件事。json的文件名在不同打包里可能叫category.json或labels.json,内容结构一致,都是这种映射:

{ "篮球": 0, "足球": 1, "棒球": 2, "台球": 3, "高尔夫": 4 }

后面继续列出剩下25个类别。key是类别文件夹名,value是从0开始的整数。这里有个容易踩的坑:yolov5分类模式是按子文件夹字典序自动生成标签,中文拼音排序顺序和你json里手动定义的顺序大概率不一致。所以json里如果key顺序和文件夹顺序对不上,后面画的混淆矩阵标签会整体错位。正确做法是写一个比对脚本,把json的key set和目录的文件夹名 set做差集,确保完全一致再开训。

2.3 样本规模与适用任务边界:3595张图能做什么

训练集3595张、验证集150张、测试集150张,这个规模属于「小样本但能跑通」的档位。3595张摊到30个类别,平均每类约120张,热门类别多一些,冷门类别少一些。这份数据适合做三件事:验证分类网络整体流程,用ResNet18或MobileNetV3在几十个epoch内把验证精度抬到80%以上;做yolov5分类模式的可行性预研;用于课程设计、毕业设计的实验对比。

不适合做的一件事是期待它直接达到工业级精度。120张每类的数据量,碰到「斯诺克台球」和「美式台球」这种细粒度差异很容易混。验证集只有150张也有隐患,每类平均5张,算出的准确率置信区间很大,可能一次实验高5个点、下一次低5个点。我的习惯是把训练集拿一部分出来重新分层划分,让验证集每类至少10张,评估才稳定,具体做法在第6章展开。

3. 运行show脚本可视化:先看数据再谈训练

3.1 show脚本的核心逻辑:采样、拼图、叠加类别名

资源里附带的show脚本用来可视化数据集,这是训练前必须走的一步。可视化说白了就是把每个类别随机抽几张图拼成大图矩阵,人工确认图片和类别是否对应、画面是否清晰、有没有脏数据。算法训练时很难自动发现语义性错标,一张标错的图混进去,轻则拉低几个点精度,重则让模型学到错误纹理。

典型的show脚本实现长这样:

import os import json import matplotlib.pyplot as plt from PIL import Image root = "data/train" # 想验证集就改成 data/valid json_path = "category.json" # 实际文件名以包内为准 sample_per_class = 4 # 每个类别抽几张图 with open(json_path, "r", encoding="utf-8") as f: label_map = json.load(f) cols = len(label_map) fig, axes = plt.subplots(sample_per_class, cols, figsize=(2 * cols, 8)) for col, (cls_name, label) in enumerate(label_map.items()): cls_dir = os.path.join(root, cls_name) images = [x for x in os.listdir(cls_dir) if x.lower().endswith((".jpg", ".png", ".jpeg"))] picked = images[:sample_per_class] for row, img_name in enumerate(picked): img = Image.open(os.path.join(cls_dir, img_name)).convert("RGB") axes[row][col].imshow(img) axes[row][col].axis("off") if row == 0: axes[row][col].set_title(f"{cls_name}({len(images)})", fontsize=8) plt.tight_layout() plt.show()

三个参数值得说明。sample_per_class控制每类抽几张,取4够用,取多了图太长;figsize的宽度等于2*cols,30类就是60英寸宽,屏幕上会压缩到看不清,建议图出来后横向滑着看,或者把cols减半分两次画。root指向data/train,想看验证集改成data/valid即可。脚本第一行标题带上了该类别图片总数,这一个细节能帮你快速定位哪些类别样本特别少。

实际资源里的show脚本写法可能不完全一样,但核心检查点相同:采样别只取前几张,否则你永远看到同一批图。我一般把picked那行改成random.shuffle后再取,每跑一次看到的样本都不一样,更容易暴露问题:

import random random.shuffle(images) # 先打乱再取前N张,每次都能看到不同样本 picked = images[:sample_per_class]

3.2 可视化结果怎么读:错标、模糊、背景单一三类问题

可视化图出来之后,重点盯三类问题。第一类是错标,「棒球」目录下混进「网球」是最典型的,两者直径差异不大,只有缝线细节不同,肉眼都得盯几秒才能分辨,这种样本会让模型非常困惑。第二类是模糊图,手机随手拍的运动球类很容易糊,一张模糊图在训练集里影响有限,但出现在验证集里会把该类的precision拉下一个量级。第三类是背景单一问题,某类图片如果大量都是同一块绿色草地或白色台面,模型学的可能是背景纹理而不是球本身,这类问题靠后面的数据增广做缓解。

3.3 图像尺寸与重复样本检查:跑一次全集统计

可视化看完,再花两分钟做一次全集的尺寸和去重检查。球类照片来源杂,有的来自爬虫、有的来自手机拍摄,分辨率可能从几百像素到几千像素不等。分类网络输入固定到224,训练时都会缩放,但差异过大的尺寸分布说明数据来源复杂,需要留意。去重检查更重要:同一张图出现在不同类别里,训练会把模型往错误方向带。

import hashlib import os from collections import defaultdict def file_md5(path): h = hashlib.md5() with open(path, "rb") as f: h.update(f.read()) return h.hexdigest() root = "data/train" dup_map = defaultdict(list) for cls_name in sorted(os.listdir(root)): cls_dir = os.path.join(root, cls_name) if not os.path.isdir(cls_dir): continue for img_name in os.listdir(cls_dir): path = os.path.join(cls_dir, img_name) dup_map[file_md5(path)].append(path) for md5_val, paths in dup_map.items(): if len(paths) > 1: print("dup:", paths)

这段脚本的原理是对每个文件算md5,md5相同说明图片内容完全一致。把所有重复项打印出来,重点看两类情况:同一类别里的重复,删掉多余副本即可,这是采集时的正常现象;跨类别的重复,比如同一张图既出现在篮球又出现在足球,说明标注过程有疏漏。把root改成data/valid再跑一遍,还能发现验证集与训练集的重叠——验证集里混入训练图,会让验证精度虚高,这是评估里最隐蔽的坑。

4. 接入训练链路:yolov5分类模式与CNN分类网络的两种落地

4.1 yolov5分类模式:目录即标签,注意data目录指向

yolov5从v5.0开始内置图像分类训练脚本classify/train.py,不需要额外生成txt标注文件,训练集和验证集目录本身就定义了标签。这份数据的目录组织正好满足yolov5分类的默认要求,命令直接开跑:

python classify/train.py \ --model yolov5s-cls.pt \ --data data \ --epochs 50 \ --img 224 \ --batch 32 \ --workers 4 \ --project runs/train-cls \ --name ball30

| 参数 | 作用 | 建议值 | | --model | 预训练分类权重 | yolov5s-cls.pt,首次运行自动下载 | | --data | 数据集根目录 | data,内部需有train和val两个子目录 | | --img | 输入分辨率 | 224,球类细节多可提到288 | | --batch | 单卡批大小 | 8G显存32,显存小降到16 | | --epochs | 训练轮数 | 50,样本少再多轮数也意义不大 |

最需要注意的参数是--data,它要指向包含train和val子目录的根目录,不是指向data/train。yolov5源码会自己找data/train和data/val。这里有个常见问题:

提示:yolov5分类模式固定查找train和val两个目录名。如果你拿到的资源里验证集目录叫valid而不是val,启动前先执行 mv data/valid data/val,否则源码会提示找不到验证集路径。

训练出结果后,验证用classify/val.py,推理用classify/predict.py:

python classify/val.py --weights runs/train-cls/ball30/weights/best.pt --data data --img 224 python classify/predict.py --weights runs/train-cls/ball30/weights/best.pt --source data/test/篮球 --img 224

val.py运行后会在runs/val-cls/ball30下生成混淆矩阵图,我建议先看顶1准确率,再看混淆矩阵里哪两类互相错得最多。球类数据集上棒球和高尔夫球容易互认、足球和排球容易互认,重叠块的颜色深浅直接说明问题在哪。

4.2 自定义CNN分类网络:用Dataset类逐行读图和json

如果不想用yolov5自带分类器,而是参照摘要里提到的CNN分类网络项目自己搭,数据加载部分可以这样写。核心是继承torch的Dataset类,在__init__里读json拿映射、遍历图片路径,在__getitem__里完成读图和transform:

import json import os from PIL import Image from torch.utils.data import Dataset from torchvision import transforms class Ball30Dataset(Dataset): def __init__(self, root, json_path, split="train", img_size=224, train_mode=True): with open(json_path, "r", encoding="utf-8") as f: self.label_map = json.load(f) # 注意必须指定utf-8,Windows默认gbk会报错 self.samples = [] split_dir = os.path.join(root, split) # 遍历split下的每个类别子文件夹 for cls_name in os.listdir(split_dir): cls_path = os.path.join(split_dir, cls_name) if not os.path.isdir(cls_path): continue label = self.label_map[cls_name] for img_name in os.listdir(cls_path): if img_name.lower().endswith((".jpg", ".jpeg", ".png")): self.samples.append((os.path.join(cls_path, img_name), label)) if train_mode: # 训练:先放大再随机裁剪,留出crop空间 self.transform = transforms.Compose([ transforms.Resize((img_size + 32, img_size + 32)), transforms.RandomResizedCrop(img_size), transforms.RandomHorizontalFlip(), transforms.ColorJitter(0.2, 0.2, 0.2), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]) else: # 验证/测试:只做Resize和归一化,禁止任何随机增强 self.transform = transforms.Compose([ transforms.Resize((img_size, img_size)), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]) def __len__(self): return len(self.samples) def __getitem__(self, idx): img_path, label = self.samples[idx] img = Image.open(img_path).convert("RGB") img = self.transform(img) return img, label

这段代码有两个关键设计。第一,__init__里直接遍历split_dir下的所有类别文件夹,用json映射到整数label,train、valid、test三套数据共用同一个类,改split参数即可,不用写三份加载逻辑。第二,train_mode区分训练和验证的增强策略:训练时用RandomResizedCrop加翻转和颜色抖动,验证测试时只做Resize和Normalize,绝不能加随机增强,否则验证集每次跑出来的结果都不一样,实验无法复现。

img_size传224时,我习惯先Resize到256再做RandomResizedCrop到224,给模型留出裁剪空间,这是分类任务的标准操作。显存紧张时直接Resize到224也行,训练快一些,精度略降。

自定义CNN网络建议用ImageNet预训练权重做初始化,而不是随机初始化。3595张的量级从头训练ResNet18在30类任务上很难收敛。用torchvision自带预训练权重微调,把最后全连接层换成30类输出头,backbone学习率设0.0001、分类头设0.001,几十个epoch就能看到80%左右的验证精度。

5. 避坑与排查:球类识别数据集训练中的五个典型问题

下面五条来自我跑这份数据的实际踩坑记录,每一条都按现象、原因、解决的顺序写,前三条在yolov5分类和CNN两条链路上都遇到过。

5.1 现象:分类准确率正常,换成目标检测框架训练直接报错

原因:这份数据是分类数据集,只有类别标签,没有边界框标注。目标检测数据集要求images和labels成对存在,labels里每行是class cx cy w h格式的坐标,这份数据根本满足不了。

解决:确认自己的任务边界。要转目标检测,方案是先把这份数据当分类预训练数据用,检测模型里加载它的分类权重当backbone;再拿lableImg等标注工具给球类图片补边界框,重新做成检测集。从零硬套detect管线只会浪费半天时间还收不到效果。

5.2 现象:训练时loss前几十个epoch正常,突然变成NaN

原因:多数是数据里混入了损坏图片,某张jpg只有几十字节或色彩通道异常。前几个epoch采样没碰到,跑到后面采到坏图,backbone输出的梯度直接异常。

解决:训练前先用PIL的verify()做一轮完整性扫描,不加载完整像素,几千张图几秒扫完:

from PIL import Image import os root = "data" for split in ["train", "valid", "test"]: split_dir = os.path.join(root, split) for cls_name in os.listdir(split_dir): cls_dir = os.path.join(split_dir, cls_name) for img_name in os.listdir(cls_dir): img_path = os.path.join(cls_dir, img_name) try: img = Image.open(img_path) img.verify() # verify后该对象不能再用,检查完就关 except Exception as e: print(f"bad image: {img_path}, {e}")

扫出来的问题图片直接删除或替换。注意verify()执行后图片对象内部状态会被清空,只能用于检查,不能用于之后的训练加载,训练DataLoader里还是要正常open。

5.3 现象:训练集准确率很高,验证集准确率明显偏低

原因:类别不平衡。30个类别里篮球、足球、棒球这类热门球样本多,冷门球样本可能只有三四十张,模型对大类别过拟合,少样本类别几乎学不到特征。总体准确率被大类别抬高,给人模型还不错的错觉。

解决:先按类别统计样本量,把排名靠后的五六个类别单独做增广,比如旋转、翻转、随机擦除。规范做法是训练时用WeightedRandomSampler按类别权重采样,让每个类别在每个batch里出现的概率接近一致。这个做法的代价是收敛变慢,epoch数要适当增加,50轮可能不够,我一般加到80轮。

5.4 现象:自己写数据加载脚本时,标签和实际图片类别对不上

原因:json是别人整理的,key顺序未必和文件夹字典序一致。如果直接用os.listdir的返回顺序去对应json的value,就整体错位。这是分类数据集最常见的翻车点。

解决:写一个10行的校验脚本,把json的key和目录下的文件夹名做成两个set比差集:

import json, os with open("category.json", "r", encoding="utf-8") as f: label_map = json.load(f) for split in ["train", "valid", "test"]: dirs = set(os.listdir(os.path.join("data", split))) keys = set(label_map.keys()) print(split, "missing:", keys - dirs, "extra:", dirs - keys)

missing和extra都是空集,说明json和文件夹准确对齐。出现差异时以文件夹实际内容为准重建json,不要反过来改文件夹名,因为yolov5分类模式的标签直接来自文件夹名,文件夹名是最终真相。

5.5 现象:同一份数据两次训练,验证精度差了五六个点

原因:验证集只有150张,每类平均5张,随机采样波动大。两次训练的shuffle顺序不同、数据增强的随机种子不同、甚至GPU的cudnn算法选择不同,都会让验证集上踩到的正负样本组合不一样。这属于训练里比较玄学的部分。

解决:固定随机种子,保证实验可复现:

import random, numpy as np, torch def set_seed(seed=42): random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) torch.cuda.manual_seed_all(seed) torch.backends.cudnn.deterministic = True

固定完种子后如果验证精度还是波动大,那说明验证集规模不够,需要把训练集按类别分层匀一部分到验证集,让每类验证样本到10张以上。这一步做完,实验对比才有说服力。

6. 进阶:把这批数据扩成更可用训练资源的三步习惯

6.1 按类别统计样本数,补齐少样本类别

训练前先跑一个统计,把30个类别的样本数导出排序,锁定排名靠后的几个类别。对它们单独做颜色抖动和随机擦除,不做大的几何变形——球类照片拍摄角度本来就多样,过度几何增广会让模型学到畸变球体。增广只做在训练集,验证集和测试集永远保持原图。

6.2 固定seed重拆训练验证集

原始划分验证集每类只有5张,评估不稳定。我建议按8:1:1从全量数据重新分层采样,每类留10张验证、10张测试,其余全部进训练集,同时固定随机种子让拆分可复现。类别文件夹名和json都不用改,只是图片位置移动,脚本也就二三十行。

6.3 用混淆矩阵判断30类是否真的可分

训练结束后先看混淆矩阵,而不是只看整体准确率。两类球长得像,混淆矩阵会直接告诉你具体是哪两类在互认。这个信息决定后续动作:是补数据、抽出来单独清洗,还是换更强的backbone。经常是换模型不如把易混类别单独抽出来做一次数据清洗收益大。

从那以后,我每次拿到分类数据集都强制走一遍固定流程:先跑show脚本看错标和重复,再统计类别样本量,然后固定seed重拆数据,最后用混淆矩阵收尾。这套流程帮我挡掉了大量无效训练,也让我对所有基于这份数据的结论都有底气。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/9 6:32:22

多智能体协作触达编排:服务发现、路由与容错的Agent-Reach实践

去年下半年我在重构一个内部的多智能体协作平台时,被一个问题反复折磨:每个智能体单独拎出来都能干活,但一旦让它们互相调用、共享上下文、协同完成任务,整个系统就变成一团乱麻。有的 agent 不知道去找谁要数据,有的 …

作者头像 李华
网站建设 2026/10/9 6:30:40

Claude Code 三套配置体系:settings.json、CLAUDE.md 与 memory 分层详解

1. 三套配置体系到底在管什么很多人第一次接触 Claude Code,装完之后发现能跑起来就以为万事大吉了,结果用着用着就发现不对劲:每次对话都要重新交代项目背景,团队里每个人的行为风格不一样,换个项目又得从头调教。这些…

作者头像 李华
网站建设 2026/10/9 6:30:39

蝴蝶显微图像数据集:电子显微镜超分与去噪实战指南

简介:本资源是面向深度学习研究者与计算机视觉方向学生的显微图像专用数据集,聚焦电子显微镜图像质量提升任务,特别适用于超分辨率重建、图像去噪、细节增强等模型训练与验证。数据源自论文《Deep learning super-resolution electron micros…

作者头像 李华
网站建设 2026/10/9 6:29:54

分布式存储实战:优势、挑战与选型避坑指南

1. 单机存储撑不住的时候,分布式存储到底在解什么题1.1 先从一次“存储扩容事故”说起几年前我在团队里负责一个数据平台,业务跑着跑着,单机MySQL加上业务日志,容量已经到了十几TB。当时所有人的第一反应是“再加两块大盘子进去”…

作者头像 李华
网站建设 2026/10/9 6:28:23

Agent-Reach:解决智能体可达性缺失的轻量框架实践

如果你正在做 Agent 类应用,大概率遇过这样一种情况:模型本身能力不错,逻辑推理也到位,任务却还是莫名其妙地失败。不是它不会做,而是它“够不着”——上下文窗口被历史记录塞满,该找的资料找不到&#xff…

作者头像 李华
网站建设 2026/10/9 6:27:57

t3code:一句话生成可复用代码,打通团队代码资产沉淀闭环

如果你让我用一个词概括过去半年里对我日常编码习惯改变最大的东西,我会说 t3code。起因特别简单:我们团队每次接入新项目,都要在聊天记录里翻来翻去找“上次发过的那段鉴权代码”;每次写日期格式化,都要从旧工程里把那…

作者头像 李华