You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将乐谱转换为MIDI编号或音高音符?代码实现问询

乐谱图片转音高音符/MIDI编号实现方案

要把乐谱图片转换成你需要的音高列表(如['0','C#5', 'G#5', ...])或MIDI编号列表(如[-1, 73, 80, ...]),核心分为乐谱图片光学识别和识别结果转目标格式两个步骤。你已经掌握了音高转MIDI的代码,下面重点解决从乐谱图片到音高的转换问题:

推荐实现路径:MuseScore + music21

这是最省心且准确率较高的方案,无需从零训练模型:

1. 工具准备

  • 安装MuseScore(免费开源的乐谱编辑软件),确保其命令行工具mscore能在终端直接调用
  • 安装Python依赖:pip install music21

2. 图片转MusicXML

用Python调用MuseScore将乐谱图片转为标准化的MusicXML格式:

import subprocess

def image_to_musicxml(image_path, output_xml_path):
    # 调用MuseScore转换图片到MusicXML
    subprocess.run(
        ['mscore', '-o', output_xml_path, image_path],
        check=True,
        capture_output=True
    )

3. 解析MusicXML提取音高与MIDI编号

用music21解析XML文件,直接提取音高和对应的MIDI编号,同时处理休止符(对应你示例中的0或-1):

from music21 import converter, note, rest

def parse_musicxml(xml_path):
    score = converter.parse(xml_path)
    pitch_list = []
    midi_list = []
    
    for elem in score.flat:
        if isinstance(elem, note.Note):
            # 获取带八度的音高字符串(如C#5)
            pitch_str = elem.pitch.nameWithOctave
            pitch_list.append(pitch_str)
            # 直接获取MIDI编号
            midi_list.append(elem.pitch.midi)
        elif isinstance(elem, rest.Rest):
            # 用0表示休止符(对应你的示例格式)
            pitch_list.append('0')
            midi_list.append(-1)
    
    return pitch_list, midi_list

4. 完整流程示例

# 示例调用
image_path = "your_sheet_music.png"
xml_path = "output.xml"

# 图片转XML
image_to_musicxml(image_path, xml_path)
# 解析得到目标列表
pitches, midi_nums = parse_musicxml(xml_path)

print("音高列表:", pitches)
print("MIDI编号列表:", midi_nums)

其他可选方案

  • OpenCV模板匹配:适合简单单旋律乐谱,需自制音符模板,手动匹配识别,准确率较低,仅适合小范围场景
  • 自定义AI模型:基于TensorFlow/PyTorch训练乐谱识别模型,需大量标注数据集,开发成本高,但可适配复杂乐谱

补充:你提供的音高转MIDI代码

如果不想用music21自带的MIDI转换,可继续使用你已有的代码:

NOTES_FLAT = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B']
NOTES_SHARP = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']

def NoteToMidi(KeyOctave):
    # KeyOctave is formatted like 'C#3'
    key = KeyOctave[:-1]  # eg C, Db
    octave = KeyOctave[-1]   # eg 3, 4
    answer = -1

    try:
        if 'b' in key:
            pos = NOTES_FLAT.index(key)
        else:
            pos = NOTES_SHARP.index(key)
    except:
        print('The key is not valid', key)
        return answer

    answer += pos + 12 * (int(octave) + 1) + 1
    return answer

内容的提问来源于stack exchange,提问作者Megan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 04:15:25