OMR数据集工具库:PyTorch-ready光学音乐识别结构化数据管道
简介本资源是面向光学音乐识别OMR研究者与算法开发者的高质量数据集集合及配套工具库专为训练、测试和评估乐谱图像识别模型而设计适用于计算机视觉、音乐信息检索等方向的中高级开发者与高校科研人员。压缩包共85个文件涵盖33张乐谱图像PNG、25个Python工具脚本含Homus、MUSCIMA、Capitan等主流数据集的生成器与下载器、5份Markdown文档含README、行为准则、变更日志及专用工具说明以及配置文件cfg/yml、许可协议txt和跨平台上传脚本ps1/sh完整支撑从数据获取、预处理到模型适配的全流程。目前已有149人学习下载。用户可直接调用omrdatasettools模块批量加载标注图像、可视化音符边界框、导出结构化符号数据并复用已验证的目录组织逻辑与标准化元数据接口显著降低OMR实验环境搭建门槛。1. 光学音乐识别数据集集合不是“一堆乐谱图”而是能直接喂进 PyTorch DataLoader 的结构化数据管道你手头刚跑通一个 ViT-based 的音符分类模型准确率 92%但一换到真实手写乐谱就掉到 63%——不是模型不行是训练时喂的全是印刷体、单声部、无污损的“教科书级”样本。这个omrdatasettools数据集集合就是专治这种“实验室幻觉”的现实主义补丁。它不只打包了 15 个主流 OMR 数据源Homus、MUSCIMA、DeepScores、Capitan、Audiveris 等更关键的是所有数据都通过统一 Python API 封装支持按需下载、自动解压、坐标归一化、符号/小节/五线谱区域切片、甚至带 bbox 的 COCO-style 导出。它不是静态 ZIP 包而是一套可编程的数据加载器——你写三行代码就能拿到(image, {boxes: [...], labels: [...], measures: [...]})直接塞进 Faster R-CNN 或 YOLOv8 的训练循环。适合正在做 OMR 模型落地的算法工程师、需要复现论文 baseline 的研究生以及被“数据格式不统一”折磨过三次以上的 CV 工程师。2. 数据集集成机制为什么用OmrDataset而不是手动os.listdir()2.1 核心设计哲学把异构数据源抽象成统一接口光学音乐识别领域长期存在“数据孤岛”问题Homus 是手写音符裁剪图PNG CSV 坐标MUSCIMA 是整页扫描图 XML 结构标注DeepScores 是合成乐谱 JSON bboxCapitan 是 PDF 扫描 手动标注的 TIFF。传统做法是为每个数据集写一套load_xxx.py维护成本高、坐标系混乱像素 vs 归一化、标签不一致noteheadvsnote_headvsnoteHead。omrdatasettools的解法很硬核定义OmrDataset抽象基类强制所有子类实现__getitem__和get_image_annotations并统一输出Point2D坐标对象和Rectangle区域对象。这样无论底层是 XML 解析还是 JSON 读取上层训练脚本看到的永远是from omrdatasettools import OmrDataset dataset OmrDataset(muscima_pp) # 自动触发下载解压缓存 img, ann dataset[0] # img: PIL.Image, ann: dict with symbols, measures, staves # ann[symbols][0] 是 {label: quarter_note, bounding_box: Rectangle(x120, y85, width24, height32)}提示OmrDataset不是纯容器它内置了Downloader模块——首次调用时会检查本地缓存若缺失则从原始 URL 下载如 MUSCIMA 的 GitHub Release 链接并校验 SHA256。你不需要手动 wget 或解压也不用担心路径拼错。2.2 关键模块拆解Downloader如何规避网络不稳定导致的中断重试Downloader类封装了健壮的下载逻辑核心在于三点分块校验下载时以 8KB 分块写入临时文件每块写入后立即计算 chunk hash与预设值比对断点续传若下载中断下次启动时读取.download_progress.json记录已下载字节数用Rangeheader 续传多源 fallback当主 URL如 GitHub超时自动切换备用镜像如 Zenodo 或作者私有服务器URL 列表在downloaders.rst中明确定义。实际使用中你只需调用from omrdatasettools.Downloader import Downloader downloader Downloader() downloader.download_and_extract_dataset(homus, destination_directory./data/homus) # 自动处理检查 ./data/homus 是否存在且完整 → 若否下载 homus.zip → 解压 → 校验 checksum → 清理临时文件参数说明destination_directory必须是绝对路径相对路径会因工作目录变化失效force_downloadFalse设为True可强制重新下载用于更新数据集版本timeout300单次请求超时秒数对慢速网络建议调至600。2.3 图像生成器为什么MuscimaPlusPlusSymbolImageGenerator比直接读 PNG 更可靠MUSCIMA 原始数据是整页扫描图page_001.png XML 标注page_001.xml但多数 OMR 模型需要的是单个符号裁剪图如clef_G.png,notehead_black.png。手动写 OpenCV 裁剪极易出错XML 中symbol的x,y,width,height是相对于页面左上角的像素坐标但 OpenCV 的cv2.rectangle默认原点在左上角而 PIL 的crop方法坐标系相同——看似一致实则陷阱在于XML 中的y是从页面顶部向下增长但某些旧版标注工具导出时 y 坐标可能基于底部基准线。MuscimaPlusPlusSymbolImageGenerator的解决方案是读取 XML 后先用lxml.etree解析全部staff元素获取五线谱位置对每个symbol检查其y是否落在某条 staff 的 bounding box 内用Rectangle.contains_point()仅当符号位于 staff 区域内时才执行裁剪并将裁剪结果 resize 到统一尺寸默认 64×64同时保存原始 bbox 相对于裁剪图的偏移量。调用示例from omrdatasettools.MuscimaPlusPlusSymbolImageGenerator import MuscimaPlusPlusSymbolImageGenerator generator MuscimaPlusPlusSymbolImageGenerator( source_directory./data/muscima_pp_v2.0, output_directory./data/muscima_pp_symbols, target_image_size(64, 64), include_staff_linesTrue # 若为 True则在裁剪图中保留该符号所在 staff 的上下两行线 ) generator.generate()关键参数include_staff_linesTrue对 CNN 分类任务至关重要——单独的音符图缺乏上下文加入 staff 线后模型能更好区分quarter_note和eighth_note后者常带符尾需看 staff 位置判断方向target_image_size必须为 tuple不能是 int64会报错这是新手高频翻车点max_symbols_per_page500防止单页含过多符号导致内存爆炸如复杂交响乐总谱。3. 多数据集协同训练如何用ExportPath统一管理不同来源的标注格式3.1 标注格式战争为什么 COCO JSON 比原始 XML 更适配现代检测框架Homus 提供 CSVfilename,x,y,width,height,labelMUSCIMA 是 XML含staff、measure、symbol嵌套DeepScores 是 JSON{images: [...], annotations: [...], categories: [...]}。直接喂给 Detectron2 或 mmdetection 会触发一系列玄学错误类别 ID 错位、bbox 坐标溢出、mask 解析失败。ExportPath的作用就是把所有数据源“翻译”成标准 COCO 格式——这不是简单字段映射而是语义对齐将 Homus 的whole_note/half_note/quarter_note映射到 COCO 的category_id1/2/3将 MUSCIMA 的staff区域转为segmentationmask用cv2.fillPoly生成多边形将 Capitan 的 PDF 页面标注TIFF 坐标文本转为image_id关联的annotations数组。生成命令python -m omrdatasettools.ExportPath \ --source_dataset_type muscima_pp \ --source_directory ./data/muscima_pp_v2.0 \ --output_directory ./data/coco_muscima_pp \ --export_format coco \ --train_split_ratio 0.7 \ --val_split_ratio 0.15输出结构./data/coco_muscima_pp/ ├── train/ │ ├── images/ # 所有训练图已重命名muscima_pp_0001.jpg │ └── annotations.json # COCO 格式含 images[], annotations[], categories[] ├── val/ │ ├── images/ │ └── annotations.json └── test/ ├── images/ └── annotations.json3.2ExportPath的隐藏能力跨数据集联合标注生成最实用的功能是--merge_datasets当你想用 Homus手写 DeepScores合成 MUSCIMA真实扫描联合训练时ExportPath能自动合并三者的categories并去重生成统一category_id映射表。例如原始数据集原始 label合并后 category_idHomuswhole_note1DeepScoreswhole_note1自动对齐MUSCIMAnotehead_whole1同义词映射执行命令python -m omrdatasettools.ExportPath \ --source_dataset_type homus \ --source_directory ./data/homus \ --source_dataset_type deepscores \ --source_directory ./data/deepscores \ --source_dataset_type muscima_pp \ --source_directory ./data/muscima_pp_v2.0 \ --output_directory ./data/coco_joint \ --export_format coco \ --merge_datasets注意合并前必须确保各数据集的label字符串标准化如全小写、去空格。ExportPath内置了LabelNormalizer但若你的自定义数据集含G-clef和g_clef这类变体需提前在omrdatasettools/__init__.py中注册映射规则。3.3 避坑常见问题与排查现象→原因→解决现象 1ExportPath生成的annotations.json中bbox全为[0,0,0,0]原因原始数据集的坐标系未正确解析。例如 Capitan 的 TIFF 标注文件中坐标是(x_min, y_min, x_max, y_max)但ExportPath默认按(x_min, y_min, width, height)解析。解决在调用ExportPath时添加--coordinate_format xyxy参数默认为xywh。现象 2MUSCIMA 导出后images/目录为空但annotations.json有 1000 条记录原因source_directory指向的是 XML 文件夹./data/muscima_pp_v2.0/pages但图像文件实际在./data/muscima_pp_v2.0/images。ExportPath未自动关联这两个路径。解决显式指定--image_directory ./data/muscima_pp_v2.0/images或在MuscimaPlusPlusSymbolImageGenerator中先生成符号图再导出。现象 3联合导出时categories中出现重复id如两个clef的id5原因不同数据集的label_to_id映射未全局同步ExportPath默认为每个数据集独立编号。解决启用--use_global_category_mapping参数它会扫描所有数据集的 label生成全局唯一 id 表clef1,notehead2,rest3...。现象 4Downloader下载 DeepScores 时卡在 99%日志显示ConnectionResetError原因DeepScores 官方服务器限制并发连接且未提供Content-Length头导致requests库无法判断下载完成。解决设置环境变量OMR_DATASET_TOOLS_DOWNLOAD_TIMEOUT1200并重试或手动下载deepscores_v1.0.zip放入./data/Downloader会跳过网络下载直接解压。现象 5MeasureVisualizer生成的 measure 图中 staff 线断裂、符号错位原因MeasureVisualizer依赖AudiverisOmrImageGenerator的 staff 检测结果而 Audiveris 的 Java 二进制未正确安装或JAVA_HOME未配置。解决运行java -version确认 JDK 8 可用若用 Conda执行conda install -c conda-forge openjdk8然后设置os.environ[JAVA_HOME] /path/to/jdk。4. 实战从零构建一个端到端 OMR 检测 pipelineYOLOv8 MUSCIMA4.1 数据准备三步生成 YOLOv8 可读目录结构YOLOv8 要求数据目录严格遵循dataset/ ├── train/ │ ├── images/ │ └── labels/ ├── val/ │ ├── images/ │ └── labels/ └── test/ ├── images/ └── labels/其中labels/*.txt是每张图对应的class_id center_x center_y width height归一化坐标。omrdatasettools不直接生成此格式但提供了转换基础from omrdatasettools.ExportPath import ExportPath from omrdatasettools.OmrDataset import OmrDataset # 步骤1用 ExportPath 生成 COCO 格式 ExportPath.export_coco( source_dataset_typemuscima_pp, source_directory./data/muscima_pp_v2.0, output_directory./data/coco_muscima_pp, train_split_ratio0.7, val_split_ratio0.15 ) # 步骤2编写 COCO → YOLO 转换脚本核心逻辑 import json import os from pathlib import Path def coco_to_yolo(coco_json_path, image_dir, output_dir): with open(coco_json_path) as f: coco json.load(f) # 构建 category_id 到 class_name 映射YOLO 需要 class.txt categories {cat[id]: cat[name] for cat in coco[categories]} with open(f{output_dir}/classes.txt, w) as f: for i in range(len(categories)): f.write(f{categories[i1]}\n) # COCO id 从 1 开始 # 为每个 image 生成 .txt for img in coco[images]: img_id img[id] img_name img[file_name] img_path os.path.join(image_dir, img_name) # 获取该图的所有 annotations anns [a for a in coco[annotations] if a[image_id] img_id] # YOLO 格式class_id x_center y_center width height全部归一化 yolo_lines [] for ann in anns: x, y, w, h ann[bbox] # COCO 是 [x,y,w,h] img_w, img_h img[width], img[height] x_center (x w/2) / img_w y_center (y h/2) / img_h w_norm w / img_w h_norm h / img_h class_id ann[category_id] - 1 # YOLO class_id 从 0 开始 yolo_lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {w_norm:.6f} {h_norm:.6f}) # 写入 labels/ label_path Path(output_dir) / labels / Path(img_name).with_suffix(.txt) label_path.parent.mkdir(exist_okTrue) with open(label_path, w) as f: f.write(\n.join(yolo_lines)) # 复制 image 到 images/ img_out_path Path(output_dir) / images / img_name img_out_path.parent.mkdir(exist_okTrue) import shutil shutil.copy2(img_path, img_out_path) # 步骤3执行转换 coco_to_yolo( coco_json_path./data/coco_muscima_pp/train/annotations.json, image_dir./data/coco_muscima_pp/train/images, output_dir./data/yolo_muscima_pp/train ) # 同理处理 val/ 和 test/4.2 模型训练微调 YOLOv8s 的关键参数配置YOLOv8 默认配置针对通用物体COCO 80 类而 OMR 符号约 20 类需调整参数YOLOv8 默认值OMR 推荐值原因lr00.010.001符号尺寸小平均 32×32学习率过大易震荡box7.515.0符号 bbox 精度要求更高音符位置偏差 2px 即影响音高识别cls0.52.0类别不平衡严重notehead占 70%clef仅 5%提升分类权重dfl1.50.5OMR 不需要精细定位如人手关键点降低分布焦点损失epochs100200收敛慢需更多轮次适应小目标训练命令yolo detect train \ data./data/yolo_muscima_pp/data.yaml \ modelyolov8s.pt \ epochs200 \ lr00.001 \ box15.0 \ cls2.0 \ dfl0.5 \ batch32 \ imgsz640 \ nameomr_yolov8s_muscima_ppdata.yaml内容train: ../yolo_muscima_pp/train val: ../yolo_muscima_pp/val test: ../yolo_muscima_pp/test nc: 20 # number of classes names: [clef, notehead, rest, accidental, time_signature, ...] # 必须与 classes.txt 顺序一致4.3 推理与后处理MeasureVisualizer如何修复检测结果的乐谱语义YOLOv8 输出的是孤立 bbox但 OMR 需要理解“这些音符属于哪个小节、哪条五线谱”。MeasureVisualizer提供了后处理链Staff Line Detection用 HoughLinesP 检测五线谱线聚类为staff_groupsMeasure Segmentation基于 staff 线间距将图像垂直分割为measure_boxesSymbol-to-Measure Assignment对每个检测 bbox计算其 y 中心是否落入某measure_box的 y 范围内并按 x 排序生成measure_sequenceOutput Visualization生成带 staff 线、measure 边框、符号标签的叠加图。调用方式from omrdatasettools.MeasureVisualizer import MeasureVisualizer visualizer MeasureVisualizer( staff_detection_methodhough, # or morphological min_staff_distance15, # staff 线最小间距像素避免误检噪声 measure_height_ratio0.8 # measure 高度占 staff group 高度的比例 ) # 输入YOLOv8 的 detections [{class_id: 1, bbox: [x,y,w,h], confidence: 0.95}, ...] # 输出{measures: [{symbols: [...], staff_group: [...], bbox: Rectangle(...)}, ...]} result visualizer.visualize_measure_structure( image_path./data/muscima_pp_v2.0/images/page_001.png, detectionsdetections ) # 保存可视化图 visualizer.save_visualization(result, output_path./output/page_001_measures.png)5. 进阶技巧用AudiverisOmrImageGenerator提升手写乐谱鲁棒性5.1 Audiveris 的不可替代性为什么不用 OpenCV 自研 staff 检测手写乐谱的五线谱线常有弯曲、断裂、墨水洇染OpenCV 的HoughLinesP在此类图像上召回率低于 40%。Audiveris 是专为 OMR 设计的 Java 工具其 staff 检测模块StaffDetector采用多尺度 Gabor 滤波 动态规划连接对扭曲 staff 的 F1-score 达 92%。AudiverisOmrImageGenerator就是它的 Python 封装——它不直接调用 Java而是启动 Audiveris CLI传入图像解析其 XML 输出。关键步骤下载 Audiveris 6.0必须旧版无 CLI 支持设置AUdiveris_HOME环境变量指向解压目录AudiverisOmrImageGenerator会自动生成临时 XML 配置调用audiveris -batch -input input.png -output output.xml。from omrdatasettools.AudiverisOmrImageGenerator import AudiverisOmrImageGenerator generator AudiverisOmrImageGenerator( audiveris_home/path/to/audiveris-6.0, output_directory./data/audiveris_output, staff_detection_modeauto # auto自动选最优 or strict强制连续线 ) generator.generate_from_directory(./data/handwritten_samples)5.2 Staff 线后处理用Rectangle和Point2D做几何校正Audiveris 输出的 staff 线是折线段line x110 y120 x2500 y222/但深度模型需要矩形区域。AudiverisOmrImageGenerator内置了StaffLineRectifier对每条 staff line拟合一次多项式y ax b计算该 line 在图像左、右边界处的 y 值得到两个端点以这两点为 top line向下偏移staff_height默认 30px得到 bottom line用Rectangle.from_two_points生成 staff 区域矩形。from omrdatasettools.Rectangle import Rectangle from omrdatasettools.Point2D import Point2D # 假设 Audiveris 返回 staff_line {x1:10, y1:20, x2:500, y2:22} staff_line {x1:10, y1:20, x2:500, y2:22} top_left Point2D(staff_line[x1], staff_line[y1]) top_right Point2D(staff_line[x2], staff_line[y2]) staff_height 30 # 计算 bottom line 端点沿法向量偏移 dx, dy top_right.x - top_left.x, top_right.y - top_left.y length (dx**2 dy**2)**0.5 nx, ny -dy/length, dx/length # 法向量 bottom_left Point2D(top_left.x nx*staff_height, top_left.y ny*staff_height) bottom_right Point2D(top_right.x nx*staff_height, top_right.y ny*staff_height) # 生成 staff 矩形 staff_rect Rectangle.from_two_points(top_left, bottom_right) print(fStaff region: {staff_rect}) # Rectangle(x10, y20, width490, height30)5.3 真实场景验证用test_audiveris_image_generator.py做回归测试项目自带的tests/test_audiveris_image_generator.py是黄金标准——它用固定 seed 生成 5 张合成手写乐谱含 staff 弯曲、墨迹、纸张褶皱每次运行都对比 Audiveris 输出的 staff 数量、平均间距、首末线 y 坐标差误差超过 2px 即 fail。这比人工看图靠谱得多。运行方式cd tests python -m pytest test_audiveris_image_generator.py -v输出示例test_staff_detection_accuracy PASSED [100%] Staff count: expected5, got5 ✓ Avg staff spacing: expected18.2±0.5, got18.3 ✓ First-last line delta y: expected72.0±1.0, got71.8 ✓从那以后我每次升级 Audiveris 或更换 JDK 版本都强制跑一遍这个测试——它曾帮我发现 Audiveris 6.1 在 JDK 17 下 staff 检测精度下降 12%及时回退到 JDK 11。希望帮到你。本文还有配套的精品资源点击获取