鸟类访客

Hacker News Top 工具

摘要

一个在阳台上安装USB麦克风捕捉鸟鸣的项目,使用BirdNET-Pi进行物种识别,并在网站上叠加花鸟画拼贴展示。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/05/31 07:32

# 鸟类访客 来源: https://theodore.net/projects/AvianVisitors/ - 01首页 (https://teddywarner.com/) - 02项目 (https://theodore.net/projects) - 03文章 (https://theodore.net/writings) --- 一开始我并没打算把这个当成一个“真正的”个人项目。我当然喜欢一份好的项目总结 (https://theodore.net/projects/),但坦白说,我觉得这不过是一个下午就能搞定的快速项目,撑死发条推文就够了,不值得写更多文档。但推特上的反应却出乎意料…… > 我在公寓阳台上装了一个小麦克风,用来听路过的鸟鸣,然后建了一个网站,每当听到鸟叫就把它们的图像拼贴出来 > pic.twitter.com/85KrLRL5tu (https://t.co/85KrLRL5tu) > — Teddy (@WarnerTeddy) 2026年5月28日 (https://x.com/WarnerTeddy/status/2060018688645115964?ref_src=twsrc%5Etfw) ……所以我就匆匆写了这篇短文,分享给那些也想在自己住处监测鸟类访客的人。现在内容简洁明了,为的是尽快发布,不过这项工作是我一系列与鸟类相关的项目中的一环,后续我会写更详细的总结! --- ### 公寓里的鸟儿 (https://theodore.net/projects/AvianVisitors/#apartment-birds) Avian Visitors 是 BirdNET-Pi (https://github.com/Nachtzuster/BirdNET-Pi) 的一个分支,在上面叠加了一层花鸟拼贴画(kachō-e collage)界面。BirdNET-Pi 负责音频采集和物种识别,它利用康奈尔大学的 BirdNET (https://birdnet.cornell.edu/) 声学分类器分析 Pi 上 USB 麦克风捕捉到的声音。你可以访问 bird.onethreenine.net (https://bird.onethreenine.net/) 查看运行效果: #### 物料清单 (https://theodore.net/projects/AvianVisitors/#bom) 自己搭建一个鸟类追踪站其实很简单。完整的项目仓库在 github.com/Twarner491/AvianVisitors (https://github.com/Twarner491/AvianVisitors)。你需要准备以下物品: | 数量 | 描述 | 价格 | 购买链接 | |------|------|------|----------| | 1 | 树莓派 (4B / 5 / Zero 2W) | ~$35-80 | Raspberry Pi (https://www.raspberrypi.com/products/) | | 1 | Micro SD 卡 (≥32 GB) | ~$10 | Amazon (https://www.amazon.com/s?k=32gb+micro+sd+card&i=electronics&crid=1RCJAD1J0EPDX&sprefix=32gb+micro+sd+card%2Celectronics%2C226&ref=nb_sb_noss_1) | | 1 | USB 领夹麦克风 | $16.95 | Amazon (https://www.amazon.com/dp/B0176NRE1G) | | 1 | 树莓派电源 | ~$10 | - | | **总计** | | **~$80** | | 显示全部 5 项 收起 顺便提一下,你还需要获取一个 Gemini API 密钥 (https://aistudio.google.com/apikey) 来重绘插画(免费版即可),以及一个 eBird API 密钥 (https://ebird.org/api/keygen) 来按地区筛选物种。 ### Birdnet.local (https://theodore.net/projects/AvianVisitors/#birdnet-dot-local) 使用 Raspberry Pi Imager (https://www.raspberrypi.com/software/) 烧录 SD 卡。选择 Raspberry Pi OS Lite(64 位)。在自定义设置中配置: - 用户名 - WiFi SSID 和密码 - 主机名:`birdnet` - 启用 SSH 并允许密码认证 将 USB 麦克风插入 Pi,放在窗户旁或固定在室外。我把它贴在朝向阳台的小窗户纱网上,Pi 则留在室内,免受风雨影响。然后开机! Pi 连上网络后,通过 SSH 登录并运行安装脚本: ``` ssh <用户名>@birdnet.local curl -s https://raw.githubusercontent.com/Twarner491/AvianVisitors/avian-visitors/newinstaller.sh | bash ``` 安装脚本假定已启用免密码 sudo(Raspberry Pi OS Lite 默认如此——如果你强化过安全设置,请先运行 `sudo raspi-config` -> *系统选项* -> 恢复默认设置)。脚本会克隆分支,运行 BirdNET-Pi 的安装程序(音频采集、模型、Web UI 等),将 AvianVisitors 的叠加层软链接到 Caddy Web 根目录,然后重启系统。整个过程根据 Pi 型号和 Wi-Fi 速度需要 20-40 分钟。Pi 重启后,拼贴页面位于 `http://birdnet.local/`,而原版 BirdNET-Pi 界面仍可通过 `http://birdnet.local/index.php` 访问。右上角的菜单抽屉提供了一个管理面板,包含原生设置、系统监控、日志和工具面板,它们通过 Pi 上的轻量 JSON 接口工作,因此无需离开拼贴页面即可调整分析器、查看服务状态和跟踪日志。 #### 从局域网向外转发(可选) 默认安装将一切保留在局域网内,但 `avian/forwarding/` (https://github.com/Twarner491/AvianVisitors/tree/avian-visitors/avian/forwarding) 目录提供了三种可选方案: *Cloudflare Tunnel* 这能提供一个公网 HTTPS 地址,无需端口转发,也不暴露家庭 IP,我正是用它来访问 bird.onethreenine.net (https://bird.onethreenine.net/) 的。需要一个免费 Cloudflare 账户,设置大约需要 5 分钟。首先在 Pi 上安装 `cloudflared`: ``` sudo apt install -y lsb-release curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg \ | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared $(lsb_release -cs) main" \ | sudo tee /etc/apt/sources.list.d/cloudflared.list sudo apt update && sudo apt install -y cloudflared ``` 然后进行认证并创建隧道,将其指向你拥有的域名下的一个主机名: ``` cloudflared tunnel login cloudflared tunnel create birds cloudflared tunnel route dns birds birds.your-domain.com ``` 将附带的配置文件放置到位,将 `tunnel:` 字段指向 `cloudflared tunnel create` 输出的 UUID,然后安装并启动服务: ``` sudo cp ~/BirdNET-Pi/avian/forwarding/cloudflared.yml /etc/cloudflared/config.yml sudo nano /etc/cloudflared/config.yml sudo cloudflared service install sudo systemctl restart cloudflared ``` 若想为公网地址添加密码保护,可设置 Cloudflare Access(免费版最多支持 50 个用户),并在主机名上添加策略。如果你更倾向于通过 Caddy 自身实现 HTTP Basic 认证,`caddy-auth.caddy` (https://github.com/Twarner491/AvianVisitors/blob/avian-visitors/avian/forwarding/caddy-auth.caddy) 片段中提供了可运行的示例。 *Home Assistant REST 传感器* 这将最新的检测结果以 `sensor.latest_bird` 形式暴露给 Home Assistant,你可以用它创建自动化(比如听到稀有物种时闪烁灯光、推送通知等)。在 `configuration.yaml` 中添加: ``` rest: - resource: http://birdnet.local/avian/api/birdnet-api.php?action=recent&hours=1 scan_interval: 60 sensor: - name: "Latest Bird" value_template: "{{ value_json.species[0].com if value_json.species else 'none' }}" json_attributes_path: "$.species[0]" json_attributes: - sci - n - last_seen - best_conf ``` `recent` 端点返回的物种已按数量降序排列,因此 `species[0]` 就是过去一小时内出现次数最多的鸟。如果你希望按 `last_seen` 排序,请相应调整 `value_template`。 *MQTT 桥接* MQTT 桥接每分钟轮询一次最近检测端点,并将新物种以 JSON 格式发布到 `birdnet/` 主题下,这对于希望将检测数据通过现有 MQTT 代理流入其他服务的情况非常有用。安装 paho-mqtt,复制桥接脚本和服务文件,然后启用: ``` sudo pip3 install paho-mqtt --break-system-packages cp ~/BirdNET-Pi/avian/forwarding/mqtt-bridge.py ~/avian-mqtt.py nano ~/avian-mqtt.py # 设置代理主机、主题前缀、凭据 sudo cp ~/BirdNET-Pi/avian/forwarding/avian-mqtt.service /etc/systemd/system/ sudo nano /etc/systemd/system/avian-mqtt.service # 如果不是 'birdnet' 用户,请设置 User= sudo systemctl daemon-reload sudo systemctl enable --now avian-mqtt ``` 去重仅存储在内存中,因此每次服务重启时,桥接会重新发布过去一小时的检测数据。下游消费者应具备幂等性。 #### 插画与拼贴 (https://theodore.net/projects/AvianVisitors/#illustrations-collage) 拼贴页面内置了 450 张北美常见物种的插画,这些插画通过 Gemini 的 `gemini-2.5-flash-image` (https://ai.google.dev/gemini-api/docs/image-generation) 模型生成。每个物种有两种姿态:栖息的 (perched) 和飞行的 (in-flight)。提示词模板位于 `avian/scripts/prompt.template.md` (https://github.com/Twarner491/AvianVisitors/blob/avian-visitors/avian/scripts/prompt.template.md): ``` 以江户时代日本花鸟木版画风格生成一张 {pose} 的 {com_name} ({sci_name}) 图像。 自信的墨绘线条搭配柔和的水彩晕染。 朴素克制的调色板:焦赭色、赭石色、靛蓝、朱红、柔和的绿色。 羽毛细节用短促的方向性笔触表现;眼睛、喙和脚用清晰墨线勾勒。 只有鸟这一主体。无背景,除非姿态需要(栖息时可带一根稀疏的细枝),无边框或画框,无文字或签名。 解剖结构必须符合所指定物种的生物特性: - 确切的两只翅膀。两条腿。一个头。一个喙。一条尾巴。 - 姿态、颜色、斑纹和身体比例需与野外观鸟指南中 {com_name} 的描述一致。 - 栖息姿态:一只翅膀收于体侧,另一只藏在身后。飞行姿态:双翅以自然的拍打姿势展开。 以高分辨率渲染在完全透明的背景上。干净地裁切出鸟的轮廓。无阴影,无纸纹,无标题。 ``` 每个请求会替换三个模板变量:学名、通用名、姿态。若要重绘整组图像,只需编辑此文件并重新运行预生成脚本(加上 `--force` 参数): ``` export GEMINI_API_KEY='your-key' # 重新渲染 BirdNET-Pi 模型中的所有物种: python3 ~/BirdNET-Pi/avian/scripts/pregen.py \ --labels ~/BirdNET-Pi/model/labels.txt --force # 或仅限定到 eBird 地区中观察到的物种: export EBIRD_API_KEY='your-key' python3 ~/BirdNET-Pi/avian/scripts/pregen.py \ --labels ~/BirdNET-Pi/model/labels.txt \ --ebird-region US-CA ``` 当传递 `--ebird-region` 时,预生成脚本会将 BirdNET 的全部物种列表与 eBird 报告在该地区观察到的物种进行交集运算。eBird 地区代码使用 `-` 分隔(例如 `US-CA` 表示州级筛选,或 `US-CA-085` 表示圣克拉拉县,进行更精确的筛选)。这会将渲染数量从全球约 3000 种减少到实际在你周围飞过的物种。 需要指出的是,Gemini 会相当频繁地出现解剖结构幻觉,因此仓库附带了经过后审核的图像集,其中已移除多余的翅膀、脱离身体的脚以及训练图像水印。生成当前捆绑集时的审核过程发现,栖息姿态的解剖缺陷约为 3%,飞行姿态约为 5%。飞行姿态更难处理,因为 Gemini 对“翅膀展开”有很强的先验,会将身体附近的任何羽毛团块都解读为可能的翅膀,因此同一只山雀可能需要尝试五六次才能生成干净的输出。 每个物种都附带一个二进制 alpha 蒙版(离线生成):将插画下采样到约 93 像素宽,对 alpha 通道进行阈值处理,并将结果打包成 base64 编码的位数组。完整的蒙版注册表位于 `avian/frontend/masks.json` (https://github.com/Twarner491/AvianVisitors/blob/avian-visitors/avian/frontend/masks.json),249 个物种约 280KB。该蒙版编码了鸟的轮廓。前端利用这些蒙版实现两件事:瓦片打包(只要轮廓不重叠,边界框可以重叠)和悬停命中测试(当鼠标悬停在两个瓦片边界框重叠的区域时,高亮显示正确的鸟)。 打包算法本身是一个中心向外螺旋:瓦片按面积降序排序,最大的放在中心位置,后续每个瓦片从中心向外螺旋,直到找到一个其蒙版不与任何已放置蒙版相交的位置。成本函数偏向水平方向,以产生更宽、更适合横屏显示的簇: \[ \text{cost}(x, y) = \sqrt{\left(\frac{\Delta x}{b}\right)^2 + \Delta y^2} \] 其中 \(b = 2.1\) 是椭圆纵横比偏差。 瓦片尺寸的计算是另一个需要仔细处理的问题。简单的方法是设置每个瓦片的面积为检测次数的幂,并限制每个瓦片的最大值: \[ A_i = \min(A_{\text{max}}, \, A_{\text{base}} \cdot n_i^{1.2}) \] 但一旦某个物种超过限制阈值,这种方法就会失效,因为所有高于阈值的物种都会以相同的最大尺寸渲染,而不管实际计数如何,这破坏了通过频率调整瓦片尺寸所带来的视觉层次感。解决办法是改用视口面积预算进行归一化:每个瓦片获得一个计数加权分数,所有分数按比例缩放,使它们的总和等于视口的一部分,然后根据缩放后的面积推导瓦片尺寸: \[ s_i = n_i^{0.65} \quad,\quad A_i = \max\left(A_{\text{min}}, \, \frac{B}{\sum_j s_j} \cdot s_i\right) \quad,\quad w_i = \sqrt{A_i \cdot \text{ar}_i} \] 其中 \(B\) 是视口面积预算(根据物种数量为视口的 28% 到 46%),\(\text{ar}_i\) 是物种的纵横比。0.65 指数提供了一个可见的层次结构(检测 400 次的物种渲染面积大约是检测 30 次的 5 倍),而不会出现上限导致的扁平化;而且由于所有值都是根据视口面积归一化的,相同的逻辑在任何屏幕尺寸下都能产生合理的布局。 初始打包后,如果有任何瓦片超出屏幕,所有瓦片会缩小 7%,然后重新打包整个布局,循环最多 10 次(此时线性缩放约为原始尺寸的 50%)。这保证了每个物种都能适应从 390px 移动设备宽度到 2560px 工作室显示器的任何视口,对于一个拼贴画本身就是页面的网站来说,这一点比你想象的要重要得多。 #### ~ 实时更新 (https://theodore.net/projects/AvianVisitors/#real-time) 前端每 30 秒轮询一次最近检测端点,当有新物种进入当前时间窗口时,它会在下次刷新时加入布局,簇会稍稍移动以腾出空间。前端会进行完全重新打包,而不是增量插入。在 Pi 4 客户端上,V8 引擎中重新打包约 10 个物种(当前网格步长为 4px)所需时间不到 20ms。 时间窗口选择器(`1H / 12H / 24H / 7D / ALL`)会以对应的 `?hours=N` 参数重新获取数据并就地重新渲染,整个过程非常安静,我曾连续几个小时开着页面都没有注意到这些变化。 点击拼贴中的任何瓦片(或图集视图中的任何卡片)会打开一个详情弹窗,该弹窗会调用 Wikipedia 摘要端点获取物种描述,并提供一个切换按钮显示栖息和飞行两种姿态。录音列表会获取该物种最近的 BirdNET-Pi 存档 MP3(按通用名匹配),来源为 `$HOME/BirdSongs/Extracted/By_Date/...`,每个音频文件与其频谱图一同渲染,底部还有维基百科和 eBird 的外部参考标签。 --- 好了,以上就是关于如何追踪路过的各位小鸟的一个相当简单的搭建方法 ;) 输入您的邮箱,偶尔接收更新。

相似文章

看见鸟鸣

Hacker News Top

Seeing Birdsong 是一个将鸟类鸣叫声转化为几何形态和 3D 可视化的框架,架起了艺术与声学科学之间的桥梁。它利用频谱描述符来构建数据丰富的结构,以用于研究、教育和艺术表演。

Kiwibit的AI喂鸟器成为我的新后院伙伴

TechCrunch AI

这是一篇关于Kiwibit AI喂鸟器的评测,它内置摄像头和鸟类识别算法,可追踪识别超过10,000种鸟类,提供有趣且连接自然的后院体验。

搜索鸟类

Hacker News Top

一个交互式数据故事,探索北美鸟类的Google搜索趋势,揭示哪些物种吸引人类注意,并以中央公园的一只Snowy Owl为例进行案例研究。