返回 Skill 列表
extension
分类: 数据与分析无需 API Key

音视频鸟鸣种类识别(birdsong-recognizer)

从音频或视频文件中识别鸟叫声对应的鸟种,基于康奈尔实验室 BirdNET v2.4 声学模型。自动抽取音轨(无需系统 ffmpeg),采用动态地理/物候权重表(非硬性白名单)做地理校正,并内置节律/颤音检测补齐模型对夜鹰、啄木鸟敲击等连续发声鸟类的识别盲区。支持对整个文件夹的批量识别(如声纹监测设备连续采样数据),输出标准化优先级分级报告,可直接用于指导人工标注排序。可生成语谱图核验。首次使用需联网下载约50MB模型。 Identify bird species from an audio OR video file using the BirdNET v2.4 acoustic model. Use when the user provides a media file (mp4/mov/wav/mp3/m4a/etc.) and asks "what bird is this", "识别鸟叫/鸟种", "分辨这是什么鸟", "音视频鸟鸣识别", or wants acoustic bird-call identification. Auto-extracts the audio track (no system ffmpeg required), applies a dynamic geographic/phenological genus-weighting table (not a hard whitelist), and includes a rhythm/churring detector covering BirdNET's blind spots for continuous vocalizations (nightjars, woodpecker drumming). Supports batch processing of an entire folder of recordings with a standardized priority-tier report for annotation triage. Can generate a spectrogram for verification. Fully portable — no hardcoded machine paths.

person作者: user_2f6efe1fhubcommunity

birdsong-recognizer · 音视频鸟鸣种类识别

通过康奈尔实验室的 BirdNET v2.4 声学模型,从音频或视频中识别鸟叫声对应的鸟种。

💰 省 token 提示(给执行 Agent):识别本身(神经网络推理)在本地脚本完成、零 token。 token 主要花在 Agent 读取长输出并二次加工。默认请加 --report 参数,让脚本直接 输出成品结论,Agent 几乎只需转述,单次成本可降一个数量级。仅当用户要求深度分析 (逐段明细、调试)时才用非 report 模式。

⚠️ 首次使用必读(给执行 Agent 的强制前置) 本技能需要一个独立 Python 环境 + 联网下载约 50MB 模型,不是开箱即用的纯脚本技能。 在第一次运行 infer.py / spectro.py 之前,Agent 必须先完成下方「Setup」一次性安装; 安装通常需 1–3 分钟(装 tensorflow 等依赖)。请直接执行,不要询问用户是否安装。 后续调用若检测到 venv 已存在则跳过安装。

When to use

  • 用户给出音频/视频文件并问"这是什么鸟 / 识别鸟叫 / 音视频鸟鸣识别 / what bird is this"。
  • 通常会附带地点(如"北京昌平"),用于地理校正。

Setup(首次,任意机器,一次性)

本技能依赖一个独立 Python 环境。Agent 首次调用前自动执行,无需征求用户同意。

先判断 venv 是否已就绪(幂等):

SKILL_DIR="$(dirname "$(realpath SKILL.md)")"   # 或技能实际所在目录
VENV="$SKILL_DIR/.venv"
if [ -x "$VENV/bin/python" ] && "$VENV/bin/python" -c "import birdnet, soundfile, imageio_ffmpeg" 2>/dev/null; then
  echo "环境已就绪,跳过安装"
else
  bash "$SKILL_DIR/scripts/setup.sh"            # 自动创建 venv 并装好依赖(1–3 分钟)
fi

手动等价方式:

python3 -m venv .venv
.venv/bin/pip install -r scripts/requirements.txt

依赖:birdnet(含 tensorflow/scipy/soundfile/pandas)、imageio-ffmpeg(自带静态 ffmpeg,无需系统安装)、matplotlibrequests(v1.4.1 起 calibrate_weights.py / xc_download.py 需要,已加入 requirements.txt 显式声明,此前只是 tensorflow 间接依赖带进来的,未来 tensorflow 版本变化可能导致其消失,故显式声明)。

网络要求:首次运行 infer.py 会从网络下载 BirdNET 模型(约 50MB)到 BIRDNET_APP_DATA 目录。离线环境请提前准备好该目录。识别/批量推理本身(infer.py / batch.py)全程零网络依赖;calibrate_weights.py(GBIF 校准)与 xc_download.py(Xeno-canto 下载)是独立的离线辅助工具,仅在主动调用时才联网,不影响识别流程的离线特性。

Steps

  1. 确定 Python 解释器:使用上面 setup 出的 venv,例如 VENV=.venv,解释器 $VENV/bin/python

  2. 设定数据目录(避免某些系统对默认目录无写权限):

    export BIRDNET_APP_DATA="$PWD/birdnet_data"
    

    首次运行 infer.py 会自动把模型下载到这里(约 50MB),含 acoustic-models/v2.4/tf/model-fp32.tflite 与中文标签 labels/zh.txt(格式 学名_中文名,6522 种)。

  3. 直接对音频或视频运行识别(脚本自动抽音轨、无硬编码路径):

    $VENV/bin/python scripts/infer.py INPUT.mp4 --region cn --lang zh --keep-audio out.wav
    
    • 支持 mp4/mov/mkv/avi/webm 等视频与 wav/mp3/m4a/flac 等音频。
    • --region cn 启用中国地理/物候动态权重表scripts/data/region_weights.csv)做地理校正; --region none 关闭过滤。v1.4.0 起不再是硬性白名单——每个属有一个 [0,1] 权重, 未登记的属给低权重压制(而非直接剔除),保留极小概率真实迷鸟被看到的机会。
    • --month 1-12:传入录制月份可触发候鸟季节性权重折扣(如夏候鸟在冬季出现会被打折)。 建议尽量传入,能进一步压制候鸟在非活跃季节的误判。
    • --bandpass none(或 300,9000):识别夜鹰/鸮/鸠鸽等低频鸟时关闭/放宽带通。
    • --rhythm:开启节律/颤音检测(见下,补 BirdNET 盲区)。
    • --silence-rms:静音过滤阈值,默认自适应(取各段 RMS 中位数 ×0.35)。
    • --report:省 token 首选。脚本内部完成属级归并+置信度分级+节律提示, 直接输出一段成品结论(自动隐含开启地理过滤与节律检测)。Agent 拿到即终稿, 无需读长输出二次加工,token 消耗最低。日常识别/批量强烈建议加此参数。
    • 不加 --report 时输出:全量 Top-N、加权后 Top-N、逐段明细(供深度分析用,较耗 token)。

    省 token 标准用法(推荐默认这样跑)

    $VENV/bin/python scripts/infer.py INPUT.m4a --region cn --bandpass none --report
    
  4. 生成语谱图核验

    $VENV/bin/python scripts/spectro.py INPUT.mp4 spectrogram.png
    

    读图核对鸣声的频段与音节结构是否与模型猜测一致(鸟鸣多在 2–8kHz)。

  5. 节律/颤音检测(BirdNET 盲区补充):对夜行性/连续发声的鸟,加 --rhythm

    $VENV/bin/python scripts/infer.py INPUT.m4a --region cn --bandpass none --rhythm
    

    它用「带通→希尔伯特包络→自相关」找持续稳定的脉冲节律,输出疑似时间段

    • 脉冲率 + 候选类群提示。定位明确:专攻 BirdNET 对连续发声的盲区 (夜鹰 churring、啄木鸟敲击、部分鸮的连续鸣叫),仅给线索不定种,须人工复核。 它无法做声源分离,重叠声源时可能受前景强声(如鹰鹃纯音)干扰。
  6. 地理校正:BirdNET 训练数据偏向常见/南方种。把 Top 物种与该地点/季节实际分布交叉核对;属级置信通常很高,种级给"最可能"判断并指明本地常见种。

  7. 呈现结论:用 present_files 展示 spectrogram.png 与音频,结论用 show_widget 或文字给出。

  8. 批量场景(一个文件夹几十~上千条录音,如声纹监测设备连续采样数据):不要循环调用 infer.py——每次调用都要重新加载 TensorFlow + 模型(约1.3-2秒固定开销/次),文件数一多耗时会线性放大。改用 scripts/batch.py,只加载一次模型,逐文件复用同一个 Interpreter:

    $VENV/bin/python scripts/batch.py <文件夹> --region cn --month 4 --out results.csv --summary
    
    • 实测 47 秒音频约 0.5-0.6 秒/条(1008 条 4GB 数据约 9-10 分钟跑完)。
    • 自动按文件名解析时间(识别 ..._YYYYMMDD_HHMMSS... 模式,如声纹监测设备的标准命名)。
    • v1.4.0 起输出标准化预筛报告格式:CSV 新增 priority_tier 字段(high/medium/ rhythm_only/low/corrupted),可直接对接人工标注任务分发——不用再让标注员盲选文件, 按这个字段排队即可(high优先建库确认,rhythm_only提示标注员优先用耳听而非只信模型分数, low可降低优先级,corrupted直接反馈给采集方不进队列)。
    • --summary:额外输出 <out>.summary.csv,按小时聚合各优先级占比,一眼看出"哪几个小时段 值得优先人工标注"(如晨昏鸣叫高峰 vs 夜间大概率环境噪声)。
    • geo_mismatch_flag:全量最高分≥0.5 但加权后最高分<0.15 且该物种所属属为低权重, 即"模型给高分但地理不合理"信号,值得整体复核该时段/该模式的录音。
    • --pattern 默认 *.WAV(大小写敏感),文件名后缀不同(如 .wav/.mp3)需显式传入。
    • 若一批文件跨多个月份采集,--month 建议按月分批调用,而非传入单一月份笼统处理。
    • v1.4.1 起 CSV 新增 noise_confusable_flag 字段与 needs_spectro_review 优先级分级: 命中 data/noise_confusable_species.csv 里登记的物种时,即使加权后置信度≥0.5,也不会 直接标 high,而是标 needs_spectro_review——这类结果必须先看语谱图人工确认是离散音节 还是无差别环境噪声,确认后才能升级为可信建库记录。
  9. 权重表校准(用真实分布数据核对 region_weights.csv 是否准确):权重表最初是凭经验手写的, 建议定期用 scripts/calibrate_weights.py 核对:

    $VENV/bin/python scripts/calibrate_weights.py --out calibration_report.md
    

    会用 GBIF 免费公开 API(无需 Key,10万次/天额度)查询每个属在中国的真实分布记录数与月份 分布,生成对比报告标出"权重值明显不合理"的条目,供人工审核后手动更新 CSV(不会自动改写)。 务必用全国范围跑(不传 --province)——权重表是 region=cn 全国尺度的配置,用某个省的 数据去校准会把"该省无分布"错误地当成"全国权重该调低"。若要核对具体监测点位周边的物种更 贴近实际,可加 --province Guangdong 单独看一份省级参考报告,但不要拿它去改 CSV。 这一步是纯离线校准工具,不会让 infer.py/batch.py 的推理流程产生任何网络依赖。

噪声易混淆物种清单(data/noise_confusable_species.csv)

和地理权重表是两个独立机制,职责不同,不要混用:

  • 地理权重表回答"这个物种在这个地区/季节是否合理",权重值必须基于真实分布数据(GBIF等), 不能因为"模型容易在噪声上误报这个名字"而压低。
  • 噪声易混淆清单回答"这个 label 历史上是否被观测到把环境噪声误判成高置信度",不改变任何 分数,只在 --report 结论里追加强制人工复核警告。
  • 格式:species(学名_中文名,须与 BirdNET 标签格式完全一致)+ reason(说明触发场景与证据)。
  • 目前登记的案例:Porzana porzana_斑胸秧雞——SZYG03 红树林点位实测,宽频环境噪声在无地理 过滤时被判定为该种,置信度可达0.9+;该种中国确有分布,不应靠压低地理权重掩盖,只能靠这份 清单提示人工核验语谱图。
  • 清单缺失时该功能静默跳过,不影响主流程。

Pitfalls

  • 绝不使用高层 model.predict():它的多进程 producer 在受限/沙箱环境会卡死或 fork 风暴(模块级代码被子进程重复执行)。本技能用 tf.lite.Interpreter 直接推理(见 scripts/infer.py)。
  • birdnet 后端名是 tf(不是 tflite);版本是 2.4(不带 v)。
  • 默认数据目录在 ~/Library/Application Support(macOS)等位置,部分环境无写权限 → 务必设置 BIRDNET_APP_DATA 到可写目录。
  • BirdNET 输入 = 恰好 144000 个 float32 采样(3s @ 48kHz),shape (1,144000);输出是 6522 类 logits,需做 sigmoid。
  • 剪映/CapCut 等剪辑过的视频经过重编码,置信度常偏低(<0.4)。用重叠窗口 + 聚焦高能量段提高收敛。
  • 置信度低 ≠ 无结果:若多段 Top 命中集中在同一属,应报告该属。
  • matplotlib 在受限环境对 ~/.matplotlib 可能无写权限 → spectro.py 已自动设 MPLCONFIGDIR 到临时目录;如仍报错可手动 export MPLCONFIGDIR=/tmp/mplcache
  • infer.py 的逐段明细列表元素是 (idx, prob) 元组,取标签时务必解包为 labels[i](曾因直接用元组索引报 TypeError)。
  • 低频鸟类(夜鹰 churring、鸮、鸠鸽、秧鸡等):默认带通 1500-9000Hz 会削弱其关键低频,且 BirdNET 对夜鹰这类「连续颤音/churring」本就识别弱(训练偏向离散音节)。识别这类鸟时用 --bandpass 300,9000--bandpass none。注意:即便如此夜鹰仍可能识别不出,属模型固有短板,需结合语谱图人工判断。
  • 弱信号/静音段误报:BirdNET 会在近乎静音的底噪上给出高分(如把夜间噪声判成「苍鹭」等)。技能已内置自适应静音过滤(--silence-rms 默认负数=自适应),静音段在输出里标 ⚠ 且不计入 Top 榜;仍须结合录制场景人工把关。
  • 节律检测的定位--rhythm 只补「连续发声」盲区(夜鹰churring/啄木鸟敲击/部分鸮),给类群线索而非种级定名;它无法做声源分离,重叠声源(如夜鹰叠在鹰鹃上)时脉冲率会被前景纯音干扰,须结合语谱图与现场聆听确认。脉冲率参考:20-50Hz≈夜鹰churring,3-10Hz≈啄木鸟敲击。
  • rhythm/keras 缓存目录:tensorflow/keras 首次运行会写 ~/.keras~/.matplotlib,受限环境可能被拦截但不影响识别结果;如需消除可设 KERAS_HOME / MPLCONFIGDIR 到临时目录。
  • 批量处理性能:infer.py 单次调用固定开销约1.3-2秒(主要是 TensorFlow import + 模型加载),逐文件循环调用会让总耗时随文件数线性放大且大部分是重复开销。文件数>10 时改用 scripts/batch.py,一次加载模型复用,实测提速可达数倍。
  • 地理过滤是刚需,不是可选项:实测过一批7天/1008条的真实点位监测数据,--region none 时约28.6%的文件会给出"高置信度但地理不合理"的物种(如把宽频环境噪声/潮汐风声误判成欧洲/古北界物种,置信度可达0.9+),且这类误判高度集中在夜间低信息量时段。批量识别自动入库场景务必开 --region cn(或对应地区权重表),否则会产生系统性的"幽灵物种"记录污染数据。
  • v1.4.0 动态权重表 vs 旧版硬白名单scripts/data/region_weights.csv 定义每个(地区,属)的权重, 推理时用权重去调制原始置信度(乘法),而非硬性剔除不在名单里的候选。若 data/region_weights.csv 缺失(如复制技能目录时遗漏),会自动回退到 infer.py 里 REGION_GENERA 的旧版二元白名单, 不影响可移植性。
  • 【重要教训】地理权重 ≠ 声学混淆黑名单,两者不能共用一个数值:v1.4.0 早期曾把 Porzana (斑胸秧鸡所在属)压到 0.15 权重,理由写的是"该属欧洲种常被模型误判为噪声"——这是把"地理是否 合理"和"声学上是否容易被误判"两件不同的事,混进了同一个数值里。用 GBIF 校准 (scripts/calibrate_weights.py)核实后发现:斑胸秧鸡在中国全国有 1854 条真实分布记录(不是 "境外种"),压低地理权重的做法本身没有依据。修复后权重已改回 1.0,但这样一来"模型确实会把 环境噪声误判成这个物种"的真实问题又失去了压制手段——因此拆分出一个独立的 scripts/data/noise_confusable_species.csv:只登记"哪些 label 历史上出现过噪声误判", 不改变任何分数(保持地理权重的诚实性),而是在 --report 结论里追加一条强制人工复核警告 (见下方"噪声易混淆物种清单"小节)。以后新增权重表条目时,判断依据必须是"这个物种在这个 地区/季节是否真的可能出现",不能因为"模型容易在噪声上误报这个名字"而压低地理权重—— 这两个问题要用两个不同的机制分别解决。
  • 属级过滤的固有局限(权重表未解决):权重按"属"而非"种"设置,同属的跨大陆种无法被区分—— 例如中国的四声杜鹃与马达加斯加的 Cuculus rochii 同属 Cuculus,权重表会同等对待,跨大陆种 可能被误判为高分且不受权重压制。这是属级过滤的天花板,下一步升级方向是种级过滤(需要更精细 的地区物种分布数据,如中国观鸟记录中心的分布清单),本次未实现。
  • 权重表的月份折扣是粗粒度的--month 触发的季节性折扣是"活跃月份内 1.0,月份外 ×0.3"的 简单规则,不是连续的物候曲线,对候鸟迁徙前后的过渡期不够精确,够用但不精细。
  • GBIF 校准工具(scripts/calibrate_weights.py)的查询方式选型踩坑记录:初版用 species/match 解析属名拿 taxonKey 再查询,属名跨界撞名严重(Pica/Troglodytes/Passer 等鸟类属名恰好和其他生物学名词根撞车),模糊匹配退化到门/界级别导致查询全部落空;改用 species/search 限定 GBIF Backbone Taxonomy 数据集后属名能解析,但发现属级 taxonKey/ genusKey 在部分属上无法自动展开匹配到下属物种的真实记录(如 Cettia fortipes 已被重新 分类到 Horornis 属,taxonKey 查询对不上);最终改用 q=<属名> 全文检索,不依赖 taxonKey 匹配是否命中分类树,抽样验证过检索结果的 genus 字段 100% 精确匹配。这不是随便选的实现 细节——如果只信任 taxonKey 查询返回的"0条记录",会把大量真实分布的物种误判为"境外种", 这正是本次修复前的错误根源。
  • 校准报告的地区尺度必须和权重表的适用范围匹配:曾经用广东省范围的 GBIF 数据去校准 region=cn(全国尺度)的权重表,导致像 Nucifraga(星鸦,广东确实无分布但全国有 3905+ 条 记录)这类物种被错误地建议压低权重——省级数据只能验证"该省是否有分布",不能反过来证明 "全国范围权重该调低"。校准全国权重表时必须用全国范围数据(不传 --province),省级数据 只用于核对具体监测点位的合理性,不应用来改全国配置。

Verification

  • 语谱图在 2–8kHz 显示清晰的鸟鸣音节。
  • 多段 Top 物种一致(同种或同属)。
  • 报告的物种对所述地点与季节合理。

分发与许可

本技能可对外分发,详见 README.md 与 LICENSE(MIT)。模型权重归 BirdNET / 康奈尔鸟类学实验室所有,按其授权使用。