CUHK02数据集全链路解析:解压、标注读取与检测基线实战
简介CUHK02_release(dataset).7z 是香港中文大学发布的人脸识别研究数据集面向计算机视觉研究者与算法工程师可用于跨视角人脸识别、光照变化及低分辨率场景下的模型训练与评测。压缩包共含 7270 个文件以 7264 张 PNG 图像为主体配合 Python 脚本与标注说明文档图像涵盖实验室高分辨率与街拍低分辨率两种质量且每位个体均有双摄像头不同角度的采集便于开展跨视角识别研究。包体约 122.61MB目录按个体划分结构清晰已提供精确人脸边界框标注可直接用于特征提取与深度学习模型训练。目前已有 1034 人学习使用适合需要真实场景数据支撑人脸检测、识别与验证算法迭代的研究者。无论是复现经典方法还是验证新模型这份数据集都能提供贴近实际监控环境的评测基准。 上个月有个朋友从某个学术镜像站拉下来一个文件文件名是cuhk02_release(dataset).7z解压之后对着满屏的.mat标注文件和一堆编号文件夹发了一天呆。他跑来问我这个数据集到底还能不能用里面这些文件怎么组织起来的训练代码该怎么写这问题我太熟了——两年前我第一次碰 CUHK02 时光是搞清楚目录结构和标注格式就花了一个周末。这篇文章就把整条链路完整拆一遍CUHK02 数据集的定位和结构、7z 压缩包的正确解压与校验方式、读取标注并跑通第一个 baseline 实验的全过程最后把我在这个数据集上踩过的坑一起列出来。不管你是刚入门的检测方向研究生还是想找个干净的小数据集做快速验证的老手这篇文章应该都能帮你省下不少时间。1. CUHK02数据集的前世今生一个老数据集为什么还值得研究1.1 它解决什么问题多视角行人检测与部分遮挡CUHK02 是香港中文大学多媒体实验室发布的多视角行人检测数据集跟我后面要提到的 CUHK01、CUHK03 是同门师兄弟。它最早作为 CVPR 2009 那篇经典的An HOG-LBP Human Detector with Partial Occlusion Handling的评测基准出现核心任务是行人检测pedestrian detection而且特别强调**部分遮挡partial occlusion**场景下的鲁棒性。数据集包含大约 5 个不同场景下的双目图像对总计约 2000 对每张图像中都有用边界框标注好的行人。场景覆盖了校园、街道、商场、公交站这类常见监控视角每个场景下面又细分为不同的拍摄位点。这里有个很容易被忽略的点因为拍摄设备是双目相机每对图像都包含左右两个视角在视觉上能提供一定的视差信息。早期研究者用这对立体信息做遮挡推理后来很多人干脆只用单目图把双目当成两份独立数据来用——这个做法对不对我后面在“踩坑”部分会专门讲。为什么一个 2009 年的数据集到今天还有人引用我的理解是它的“小而干净”。它不像 CityPersons、Caltech 那样动辄上万张图但行人框的遮挡比例真实、标注质量高而且数据规模适中非常适合做快速迭代和消融实验。你今天拿一个 SOTA 检测器往上一跑几分钟就能出一轮结果用来 debug 网络结构、观察过拟合行为比在大数据集上盲调高效得多。1.2 和 CUHK01/CUHK03 的定位差异从检测到重识别很多人分不清 CUHK01、CUHK02、CUHK03 这三个数据集我干脆用一张表把它们拆开。数据集发布年份主要任务规模标注形式CUHK012012行人重识别re-ID971 个行人手工边界框CUHK022009行人检测含双目、遮挡5 场景约 2000 对立体图像行人级边界框CUHK032014行人重识别re-ID1467 个行人手工框 检测框关键联系在这里CUHK03 的“检测框”detected boxes设置就是用检测器在 CUHK02 这类检测数据集上自动检测得到的。所以如果你做重识别想模拟“检测 识别”的真实全流程CUHK02 经常被拿来当检测前端的数据源。换句话说CUHK02 不只是个单纯的历史数据集它是整个 CUHK 重识别系列里检测能力的底层支撑。在动手之前你还需要搞清楚一个现实问题这个数据集的权威版本通常以.7z压缩包形式分发包内文件名还带括号这给不少人的解压过程制造了障碍。接下来我重点处理这部分。2. 7z数据包的处理链路解压、校验、跨平台一条龙2.1 为什么学术数据集偏爱7z而不是zip先聊个很容易被忽略的问题为什么很多学术数据集的下载链接都是.7z而不是更通用的.zip核心原因就两个压缩率和分卷支持。7z 格式使用 LZMA/LZMA2 压缩算法对图像序列、标注文件这类有大量重复冗余的数据压缩率通常比 zip 高 10% 到 20%。CUHK02 这类数据集动辄几个 GB压缩率差一点服务器带宽和用户下载压力就差不少。另一个是分卷能力。学术镜像站往往有单文件大小限制7z 可以拆成.7z.001、.7z.002这样的分卷包发布下载完只要对第一个分卷执行解压命令就能自动合并。zip 的分卷在实现完整性和跨平台一致性上要差不少。还有一个很实际的问题解压工具。Windows 上很多人会遇到一个两难局面——系统自带解压不支持 7z去网上搜“7z 解压工具”又容易被各种带广告、带捆绑的国产压缩软件截胡。我的建议非常直接用 7-Zip 官方原版或者直接用命令行版。命令行版只有不到 2MB没有广告弹窗没有文件关联劫持也不会有“试用会员试用期已到”这种破事。2.2 Windows、Linux、macOS三平台的解压方案在 Windows 上装了 7-Zip 之后右键那个cuhk02_release(dataset).7z文件会有两个选项值得注意“解压到当前文件夹”和“解压到cuhk02_release(dataset)\”。前者会把压缩包内部的所有内容直接铺在当前目录如果压缩包顶层文件夹和你预期的不一致文件会散落一地后者会新建一个同名文件夹再解压。我建议一律用后者宁可多一层目录也好过后面写代码时路径混乱。在 Linux 服务器上先装 p7zip然后这样解压# Debian/Ubuntu sudo apt update sudo apt install -y p7zip-full # CentOS/RHEL sudo yum install -y p7zip # 进入下载目录后执行 7z x cuhk02_release(dataset).7z -o./cuhk02_data注意这里两个细节。第一命令里的文件名我用了双引号包住因为文件名里的圆括号是 shell 的保留字符不处理会直接报bash: syntax error near unexpected token (。第二-o参数后面不能有空格-o./cuhk02_data是一个整体。另外建议加个7z l cuhk02_release(dataset).7z先查看压缩包内顶层目录结构确认里面到底是一层CUHK02_release还是直接散着一堆文件夹避免解压后出现“套娃目录”。macOS 用户直接用 Homebrew 装 p7zip命令行参数和 Linux 完全一致不想用命令行的可以用 Keka 或 The Unarchiver都能干净解压 7z。强调一下这里说的“干净”是指没有广告、没有捆绑、不会偷偷改你的默认打开方式。2.3 哈希校验这一步不是可选项在解压之前强烈建议先校验文件完整性。学术数据集不像商业软件有安装引导下载过程断点续传不完整、镜像站同步出问题都是常有的事。如果压缩包在传输中损坏但没被完全发现解压出来的图片可能缺帧标注文件可能悄悄丢字段而你当时的反应往往只是“哦数据有点小”不会立刻意识到数据本身已经坏了。校验方法很简单。如果数据集发布页提供了 SHA256 值就在对应平台执行# Linux sha256sum cuhk02_release(dataset).7z # Windows PowerShell Get-FileHash cuhk02_release(dataset).7z -Algorithm SHA256 | Format-List # macOS shasum -a 256 cuhk02_release(dataset).7z然后把输出值和发布页给出的哈希做对比。我自己的习惯是把两个哈希值全选复制到一个文本文件里用任何对比工具或在线 diff 服务比对前 8 位和后 8 位就够了全串肉眼核对不现实。你可能会说7z 格式自带 CRC 校验解压时不是会自动报错吗确实会但要明白7z 的 CRC 错误是在解压阶段才暴露的如果损坏只发生在极少数字节工具可能会尝试跳过错误块最后给你一套不完整的、看似正常的文件。真正等你训练到一半发现数据对不上再回头排查下载包浪费的时间就不是几分钟了。哈希校验通过之后解压工作才算真正结束。接下来回到数据集本身解压出来的这些文件到底该怎么组织、怎么读、怎么用。3. 解压之后怎么用目录结构、标注解析与第一个baseline实验3.1 解压后的目录结构场景、拍摄位点与双目图像对解压完成后用tree或find命令粗略看一下整体结构tree -L 3 CUHK02_release/ | head -50典型结构大致是这样的逻辑顶层是CUHK02_release下面按场景分目录校园、街道、商场等每个场景里再按拍摄位点编号分子目录比如 0、1、2每个位点目录下存放双目图像对和对应的.mat标注文件。图像对命名一般能看出左右视角比如L_0001.jpg和R_0001.jpg这样成对出现。这里要提醒一句拿到任何数据集的第一件事不是直接写训练代码而是把目录结构打出来对照发布页的 README 理解一遍。很多人的数据读取 bug 根本不在代码逻辑而在路径假设错误——你以为每个场景下有 5 个位点实际有的位点编号跳号你以为所有场景位点结构一致结果某个场景偏偏多了子目录。先find CUHK02_release -maxdepth 2 -type d把所有目录列出来心里有个完整地图后面代码写起来才不会莫名其妙报FileNotFoundError。3.2 读取annotation标注MAT文件解析CUHK02 的标注文件是 MATLAB 的.mat格式里面保存的是每张图像的行人边界框坐标。在 Python 里读取最直接的方案是scipy.io.loadmatimport scipy.io as sio mat sio.loadmat(annotation.mat) print(mat.keys()) # 输出里通常有 ground truth、bbox 或 anno 之类的字段 import numpy as np bbox mat[bbox] # 具体键名以实际文件为准 print(bbox.shape)如果你打印mat.keys()之后发现这里面只有__header__、__version__、__globals__这些元信息没有标注字段别急着怀疑文件坏了——大概率是 MATLAB 把文件保存成了 v7.3 格式这个我在第四章会专门讲。读取之后建议立刻做一次可视化验证。把边界框画到对应的原图上人眼扫一遍确认坐标尺度是否正确。这一步能帮你提前发现三类问题坐标是否归一化过了、是(x, y, w, h)还是(x1, y1, x2, y2)格式、图像和标注文件名是否一一对应。别小看这几分钟我见过不少人在一个坐标系假设错误上耗掉好几天。3.3 数据划分为什么按场景切而不是随机切接下来是训练数据划分。CUHK02 最常见的错误做法是把所有图像路径读进来用sklearn.model_selection.train_test_split按 8:2 随机划分。这在大规模自然图像数据集上也许问题不大但在视频序列类数据集上是致命的。原因在于视频帧之间的强相关性。同一个行人在相邻几帧、左右视图中反复出现姿态、衣着、背景几乎没变化。如果随机划分同一行人的不同帧极可能同时落在训练集和验证集里——你的模型实际上是在记忆这个人长得什么样而不是学习“行人”这一类目标的通用特征。最后测出来的准确率虚高换到真实场景立刻打回原形。正确的做法是按场景或按拍摄位点划分。常见协议有两种5 个场景里取 4 个做训练、1 个做测试轮转 5 次取平均类似交叉验证每个场景内部取前几个拍摄位点做训练、后几个做测试模拟跨视角评估。我个人更推荐第一种因为第二种在某些场景下容易引入视角偏差——同一个场景里不同位点的相机角度、光照条件差异可能不大模型学到的是场景特有属性而不是行人通用特征。3.4 从零跑一个HOG-LBP基线数据准备好了先用一个传统方法跑通基线。HOG-LBP 正好是 CUHK02 的原生方法效果够用且逻辑透明非常适合理解数据分布。简单说下原理。HOG方向梯度直方图把图像划分成小格子统计每个格子内像素梯度的方向分布再在块级别做归一化本质上是在描述行人的边缘轮廓——头肩、四肢的轮廓信息会被捕捉到。LBP局部二值模式对每个像素和它周围邻域做比较生成二进制编码并统计直方图对纹理更敏感、对光照变化更鲁棒。两者拼接成联合特征后HOG 负责“形”LBP 负责“纹”在部分遮挡场景下LBP 的局部统计特性使得即使某个区域被遮挡其他区域的纹理信息依然可用。代码框架可以参考下面的思路import cv2 import numpy as np from skimage.feature import hog, local_binary_pattern def extract_hog_lbp(img): img cv2.resize(img, (64, 128)) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # HOG特征 h hog(gray, orientations9, pixels_per_cell(8, 8), cells_per_block(2, 2), block_normL2-Hys) # LBP直方图 lbp local_binary_pattern(gray, P8, R1, methoduniform) hist, _ np.histogram(lbp.ravel(), bins10, range(0, 10)) hist hist / (np.sum(hist) 1e-6) return np.concatenate([h, hist])然后配合滑窗 线性 SVM 训练一个分类器。负样本怎么来在图像上不含行人的背景区域随机裁剪固定尺寸窗口。这里有一个重要技巧第一轮训练完之后用分类器在训练集的背景区域扫一遍把那些被误检成行人的窗口作为“困难负样本”加入训练集再训第二轮。这个 hard negative mining 过程在 CUHK02 这种小数据集上效果立竿见影往往能把误检率压下去一大截。关于预期指标我建议不要迷信论文里报的单个数字。CUHK02 的检测率对不同场景方差很大街场景明显比校园场景难而且你的具体划分协议不同结果差异也很大。更合理的做法是固定协议后自己跑出一组 baseline后续所有改进都跟这组数字比。4. 实操中的坑从解压到训练全流程避坑清单4.1 .mat文件版本问题v7.3与HDF5读取.mat文件最容易踩的坑就是 MATLAB 的 v7.3 格式。新版 MATLAB 在保存大文件时默认可能使用 v7.3这种文件内部实际上是 HDF5 格式scipy.io.loadmat读不了会报NotImplementedError或者读出来一堆乱码结构。判断方法很简单file annotation.mat输出里如果出现Hierarchical Data Format (version 5) data基本就是 v7.3 了。这时用h5py来读import h5py import numpy as np with h5py.File(annotation.mat, r) as f: # 先遍历结构 def print_structure(name, obj): print(name, type(obj)) f.visititems(print_structure) # 假设标注字段叫 bbox bbox np.array(f[bbox]) # 具体路径以实际结构为准需要注意HDF5 读出来的数组维度顺序和 MATLAB 内存布局是反的可能需要np.transpose一下才能得到(N, 4)的框坐标。这个细节很容易让人对坐标结果产生怀疑建议读出来后立刻可视化确认。4.2 文件名里的括号路径解析与脚本转义cuhk02_release(dataset).7z这个文件名本身就是个坑源。在 Linux/Mac 的 bash 脚本里文件名带括号会引发语法解析问题比如# 下面的写法会报错 7z x cuhk02_release(dataset).7z解决方案其实很简单所有涉及这个文件的命令都给路径加双引号。Python 代码里用pathlib.Path没有这类问题但如果你在 Python 里调用 subprocess 执行外部命令注意不要用shellTrue把命令和参数写成列表形式比如import subprocess filepath cuhk02_release(dataset).7z subprocess.run([7z, x, filepath, -o./cuhk02_data])还有个容易被忽视的点如果你的数据预处理脚本里用了os.system拼接 shell 命令遇到这种带特殊字符的文件名会非常痛苦。趁早统一改用subprocess.run加参数列表一次性根治。4.3 双目图像相关性不能简单把左右图当独立样本我在前面提到过双目信息这里展开讲。CUHK02 的每对图像包含左右两个视角同一时刻左右图里的行人是同一个人。如果你把左图和右图当作两条独立样本扔进训练集然后随机切验证集几乎必然出现“同一个行人的左视图在训练、右视图在验证”的情况。模型在验证集上的表现很可能是因为它已经在训练集里见过这个人的大致外观——它的“泛化”是假象。更合理的做法有三种第一做单目实验时明确用左图或右图其中一路全流程只用这一路第二必须用双目时把同一对左右图放到同一边要么都在训练集、要么都在验证集按图像对为单位做划分第三干脆把双目对拼成一个样本用双通道输入让模型自己去学视差关系。这三种我实测下来第二种最稳定也最容易写。4.4 遮挡样本和小数据集的特殊处理很多人在 CUHK02 上做实验时会下意识做一个操作把被遮挡严重的行人样本过滤掉理由是“我的模型学不会遮挡”。我的看法是如果你把遮挡样本都删了CUHK02 的核心价值就废了——这个数据集最大的卖点就是自然的遮挡分布。正确做法是统计每张图的行人遮挡比例可以粗略用标注框周围的环境颜色判断更精细的可以结合深度或视差单独分组评估而不是一刀切过滤。另外CUHK02 的规模决定了你不太可能直接端到端训一个深度模型。我的建议是先跑一个 HOG-LBP 或简单的 CNN 检测器做 baseline然后在这个基础上做两件事一是 hard negative mining把模型在背景区域上的误检挑出来循环训练二是数据增强裁剪、水平翻转、颜色抖动这些在小数据集上收益很大但注意水平翻转后要把边界框坐标同步镜像别让框和内容对不上。4.5 把CUHK02放进更大的项目检测到重识别的扩展最后说一点进阶思路。CUHK02 很少被单独当做最终产品它更常见的角色是检测前端。我的一个常用组合是用 CUHK02 训练检测器把检测出来的行人框交给 CUHK03 或其他重识别模型模拟真实监控场景下“先检测后识别”的完整链路。这个组合对检测器的要求不只是框得准还要求框具备结构完整性——头部和四肢不能丢。因为重识别模型对行人图像的裁剪质量很敏感你把一个人从脖子以下裁出来再强的 re-ID 网络也认不出来。所以如果做这个方向评估检测器时除了看 mAP还要在意“完整行人框比例”这个指标。5. 我的一些个人习惯补两个自己的实操习惯。第一拿到任何旧数据集先写一个 dump 脚本把每张图的标注可视化导出成一张大图或视频人眼整体过一遍再动工训练。这一步花的时间通常在半小时以内但能避免你在一个坐标格式错误或目录错配上浪费好几天。第二所有下载的压缩包我都在解压前做哈希校验并把校验结果存在项目根目录的checksum.txt里。这个习惯在团队协作时特别有用——队友问你“这个数据集怎么解压不了”的时候你至少能确认不是文件传输环节出了问题。CUHK02 虽然是个 2009 年的老数据集但它胜在规模小、标注干净、遮挡分布真实非常适合做快速迭代和消融实验。只要把解压校验、目录理解、标注可视化、合理划分这几步走扎实后面换更大的数据集也只是套路相同、数据量不同而已。如果按这套流程走下来实验还是异常那问题大概率出在模型设计上而不是数据准备上。本文还有配套的精品资源点击获取