WingLens:让索尼相机拍下的鸟,自动变成一条观鸟记录
从 A7C2 获取最新照片,用 YOLO 找鸟、BioCLIP 识别鸟种,再由 iPhone 自动记录时间与地点。
拍鸟的时候,我经常遇到一个问题。
相机里积累了很多照片,但真正回到家整理时,需要先筛选,再判断鸟种,然后补拍摄时间、地点和备注。一天拍得多了,整理就变成负担。
于是我开始做一个轻量级观鸟识别工具:WingLens。
它的目标不是替代相机,也不是做一个普通的「上传图片识物」应用,而更像相机和观鸟记录之间的一座桥:
为什么从索尼 A7C2 开始
项目主要围绕我已有的 Sony A7C II 展开。
专业相机在画质、对焦和长焦上远强于手机,但相机本身不适合承担复杂的识别和记录管理。iPhone 则很适合做中间层:
- 连接相机、获取最新照片
- 获取当前位置
- 运行轻量检测模型
- 调用识别服务
- 保存观鸟记录
- 展示和修改识别结果
因此第一版的核心不是实时取景,而是「拿到刚刚拍下的照片」。实时画面可以关闭,也不是 MVP 的必要能力。
两条相机连接路径
iPhone 可以通过 USB 或 Wi-Fi 连接相机。但索尼开放能力、系统权限和传输方式存在限制,因此还设计了一条更工程化的路径:
Sony A7C2
│ USB-C / Wi-Fi
▼
Mac / Linux / 树莓派 / 小主机
│ Camera Remote Command
▼
本地相机控制服务
│ HTTP / WebSocket
▼
iPhone App
本地服务负责:监听拍摄事件、获取最新图片、暴露统一 API、封装不同相机协议、向 iPhone 推送新照片状态。
这条路径更适合后续自己开发 App,也方便扩展到其他品牌。它并不限于观鸟,还可用于照相亭、医疗影像、智能交通等相机集成场景。
一张照片可能有不止一只鸟
鸟类识别不能直接把整张照片丢给分类模型。照片里可能有大片天空或水面、复杂树枝背景、多只不同位置的鸟、主体只占很小一块,以及主体和陪体并存。
因此识别拆成两个阶段。
第一步:YOLO 检测鸟的位置
YOLO 返回所有鸟框:
{
"boxes": [
{
"x": 812,
"y": 436,
"width": 620,
"height": 498,
"confidence": 0.91
}
]
}
多只鸟时要保留多个框,而不是只识别最大的一只。iPhone 可跑 YOLOv8n 或 Core ML 模型,服务端也可以跑 YOLO,形成两种模式:
模式 A:客户端已完成 YOLO — iPhone 上传原图、鸟框坐标或已裁剪鸟图,服务端直接分类。
模式 B:客户端未完成 YOLO — iPhone 上传原图,服务端执行 YOLO → crop → BioCLIP → Top5。
两种模式可共存:性能较好的手机优先本地检测,旧设备把完整流程交给服务端。
为什么使用 BioCLIP
最初我收集了北京常见鸟类图片,大约前 50 个目录,多数类别约 20 张,部分更少。这个规模不适合从头训练大型分类网络。
因此采用:
YOLO 检测鸟位置
↓
裁剪鸟图
↓
BioCLIP 提取视觉特征
↓
轻量分类或相似度匹配
↓
Top-5 鸟种候选
BioCLIP 已学习大量生物图像和文本知识。第一阶段不必重训整个模型,只需固定 BioCLIP、提取向量,再训练轻量分类头,或与类别文本、样本向量算相似度。这比用几十张图从零训练更现实。
第一版不追求完美 Top-1
近似鸟种很难区分,雌鸟、幼鸟、冬羽和夏羽外观也可能不同。因此第一版成功标准不是每次给出唯一正确答案,而是:
正确鸟种是否出现在 Top-3 或 Top-5 中。
例如:
{
"predictions": [
{ "bird_id": "4230", "name": "白骨顶", "confidence": 0.62 },
{ "bird_id": "4218", "name": "黑水鸡", "confidence": 0.21 }
]
}
用户可以快速确认,而不是从几百种鸟里手动查找。目录名中的编号也会保留:训练目录 白骨顶_4230 对应 API 的 bird_id: 4230,便于与图鉴和观鸟记录系统稳定关联。
地区和季节也是识别信息
单独靠照片,有时难以区分相似鸟种;位置和拍摄时间可以显著缩小候选范围:
- 当前地区是否有该鸟种分布
- 当前月份是否处于迁徙期
- 该鸟种在北京是否常见
- 拍摄环境是湿地、山林还是城市
- 用户最近是否连续观察到同一群鸟
最终排序可综合:视觉置信度 + 地理分布 + 季节 + 常见程度 + 用户历史。eBird 一类数据更适合做地区和季节过滤,而不是直接承担图像识别。
iPhone 端的产品流程
WingLens 的 iPhone 端使用 SwiftUI。第一版围绕三个动作:
1. 获取照片
从相机获取最新照片,或从系统相册选择;以后再加自动监听相机新照片。图片可能是 JPG 或 HEIF/HIF,需要先稳定解码。
2. 识别与确认
展示原图、检测到的鸟框、每只鸟的 Top-5、鸟名编号与置信度、手动修改入口。多鸟照片里,每个框都应可单独确认。
3. 保存观鸟记录
确认后自动保存:鸟种与 ID、原图或裁剪图、拍摄时间、GPS、相机与镜头信息、识别置信度、用户备注。后续可在 Mac 端整理、复核、导出和同步。
OrniVision:识别服务端
鸟类识别后端命名为 OrniVision,是独立的 FastAPI 应用,核心接口类似 POST /api/predict。
当前设计支持:上传原图;YOLO 检测合格鸟框(置信度阈值约 0.60);每框进入 BioCLIP 分类并返回 Top-5;保存原图与裁剪图;对错误结果人工标注;按鸟种目录积累新训练数据。
服务端既是识别 API,也是数据闭环工具:用户纠正后,原图和裁剪图可进入对应鸟种目录,成为未来训练数据。
本地混合推理
随着识别量增加,还规划了本地混合推理:
CPU 服务器
├─ Nginx / Web / API
├─ 认证 / 队列 / 图片存储
└─ 可选 YOLO
Jetson Orin Nano Super 8GB
└─ BioCLIP 分类 Worker
CPU 负责常规服务和调度,Jetson 专注模型推理。更轻量的开发环境是在 Mac mini M4 上用 OrbStack 和 uv 管理 Python 项目。
价值在于:图片不必全部交给第三方;可控长期成本;模型和鸟种库可持续更新;可针对本地常见鸟类优化;相机、iPhone 和 Mac 可共享同一识别服务。
数据采集是最费时间的部分
模型方案确定后,真正耗时的是数据。我曾设计半自动 ADB 流程:脚本读鸟名列表、复制到 Android 剪贴板,用户手动搜索选图,按回车触发截图,脚本经 ADB 拉回并按目录保存。
脚本不自动抓图,也不改原始目录,只减少重复的命名、截图和整理。这让我更清楚:
鸟类识别项目的壁垒,最终不只是模型,而是高质量、可追溯、符合真实拍摄场景的数据。
为什么叫 WingLens
项目最终定名为 羽感 WingLens。「Wing」代表鸟与羽翼,「Lens」代表相机和观察。「羽感」更接近我想要的体验:不是给出冷冰冰的分类结果,而是让相机拍下的一瞬间,自动连接到鸟种、地点、时间和观察记录。
它应该是对自然观察的增强,而不是替代。
写在最后
WingLens 第一版不必实现所有能力。最重要的是先跑通:
选择或获取照片
→ 找到所有鸟
→ 返回 Top-5
→ 用户确认
→ 保存观鸟记录
之后再逐步增加:索尼相机自动取图、本地 Core ML 检测、地区与季节过滤、Mac 端复核、离线模型、鸟声识别、相机端自动跟踪拍摄。
拍照识别鸟,看起来只是图像分类。但完整产品需要连接相机、手机、模型、地理信息、数据管理和用户确认。当这些环节串起来之后,一张照片才会真正变成一次可保存、可回忆的观鸟记录。