본문으로 건너뛰기
피드

라즈베리 파이로 새소리 감지하고 실시간 콜라주까지 만드는 Avian Visitors

open-source 약 12분
vote
0
댓글
북마크

Avian Visitors는 BirdNET-Pi를 포크해 라즈베리 파이와 USB 마이크로 주변 새소리를 감지하고, 감지된 종을 실시간 콜라주 UI로 보여주는 개인 프로젝트다. Gemini로 만든 새 일러스트, eBird 지역 필터, Cloudflare Tunnel, Home Assistant, MQTT 연동까지 들어가 있어 취미 프로젝트 치고 꽤 알차다.

  • 1

    BirdNET-Pi 기반으로 오디오 캡처와 조류 종 식별을 처리하고, 별도 콜라주 프론트엔드를 얹음

  • 2

    설치는 Raspberry Pi OS Lite 64비트, USB 마이크, SSH 설정 후 스크립트 실행으로 20-40분 정도 걸림

  • 3

    Gemini 2.5 Flash Image로 북미 흔한 새 450개 일러스트를 만들고, 해부학 오류를 수작업 감사해 제거함

  • 4

    실루엣 마스크와 center-out spiral packing으로 겹치지 않는 실시간 조류 콜라주 레이아웃을 구현함

  • 5

    Cloudflare Tunnel, Home Assistant REST sensor, MQTT bridge로 집 밖 공개와 자동화 연동까지 지원함

새소리 감지기를 예쁘게 만든 홈랩 프로젝트

  • Avian Visitors는 BirdNET-Pi를 포크해서 만든 “새 방문자 시각화” 프로젝트임

    • BirdNET-Pi가 라즈베리 파이의 USB 마이크로 소리를 잡고, Cornell의 BirdNET 음향 분류기로 어떤 새인지 식별함
    • Avian Visitors는 그 위에 일본 화조화(kachō-e) 느낌의 콜라주 오버레이를 얹음
    • 결과물은 단순한 로그 페이지가 아니라, 최근 감지된 새들이 화면 위에 그림처럼 배치되는 사이트임
  • 작성자는 처음엔 트윗 하나로 끝낼 생각이었는데, 반응이 커서 설치 글까지 썼다고 함

    • 프로젝트 저장소는 github.com/Twarner491/AvianVisitors
    • 실행 예시는 bird.onethreenine.net에서 볼 수 있다고 소개함

설치는 라즈베리 파이 + USB 마이크 조합

  • 기본 구성은 꽤 현실적인 홈랩 수준임

    • Raspberry Pi OS Lite 64비트를 SD 카드에 굽고, 사용자명·와이파이·호스트명 birdnet·SSH 비밀번호 인증을 설정함
    • USB 마이크를 Pi에 꽂고 창가나 외부에 설치함
    • 작성자는 Pi는 실내에 두고, 작은 창문 방충망 쪽에 마이크를 붙였다고 함
  • 설치 스크립트는 BirdNET-Pi와 AvianVisitors 오버레이를 한 번에 세팅함

    • BirdNET-Pi 설치, 오디오 캡처, 모델, 웹 UI, Caddy 웹 루트 심볼릭 링크까지 처리함
    • 설치 시간은 Pi 모델과 와이파이 속도에 따라 20-40분 정도
    • 재부팅 후 콜라주는 http://birdnet.local/, 기존 BirdNET-Pi UI는 http://birdnet.local/index.php에서 접근 가능함
  • 관리 UI도 그냥 덤 수준이 아님

    • 오른쪽 위 메뉴에서 설정, 시스템 상태, 로그, 도구 패널을 열 수 있음
    • Pi 안의 작은 JSON facade를 호출해서 analyzer 튜닝, 서비스 확인, 로그 tail을 콜라주 화면에서 바로 처리함

집 밖 공개와 자동화 연동도 준비됨

  • 기본 설치는 LAN 내부 전용이지만, 외부 공개 옵션도 3가지가 있음

    • Cloudflare Tunnel은 포트포워딩 없이 공개 HTTPS URL을 만들 수 있음
    • 작성자가 실제로 쓰는 방식이고, 무료 Cloudflare 계정으로 약 5분 세팅이라고 설명함
    • 공개 URL에 비밀번호를 걸고 싶으면 Cloudflare Access를 쓰거나 Caddy의 HTTP Basic auth 스니펫을 쓸 수 있음
  • Home Assistant 연동은 최근 감지된 새를 센서로 노출함

    • REST sensor로 sensor.latest_bird를 만들고, 최근 1시간 감지 결과를 60초마다 읽음
    • 희귀종이 들리면 조명을 깜빡이거나 알림을 보내는 자동화를 붙일 수 있음
  • MQTT bridge도 있음

    • 1분마다 최근 감지 endpoint를 polling하고, 새 종별로 birdnet/<slug> 아래 JSON을 publish함
    • dedup은 메모리 기반이라 서비스가 재시작되면 최근 1시간 감지를 다시 발행함
    • 그래서 downstream consumer는 idempotent하게 처리하는 게 좋다고 명시함

💡

> 홈 자동화에 붙일 거면 MQTT 재시작 재발행을 전제로 설계하는 게 좋다. “새 이벤트 1번 = 알림 1번”으로 단순 가정하면 재시작 때 알림이 중복으로 날아갈 수 있음.

Gemini로 만든 새 그림 450개

  • 콜라주에 쓰는 그림은 Gemini의 gemini-2.5-flash-image 모델로 생성함

    • 북미에서 흔한 새 종 450개 일러스트가 번들로 들어 있음
    • 각 종마다 앉은 자세(perched)와 나는 자세(in-flight) 2개 포즈를 제공함
    • 프롬프트 템플릿에는 학명, common name, pose가 변수로 들어감
  • eBird API로 지역 필터링도 가능함

    • --ebird-region을 넘기면 BirdNET 전체 종 목록과 해당 지역에서 관찰된 종 목록을 교차시킴
    • eBird 지역 코드는 US-CA 같은 주 단위나 US-CA-085 같은 카운티 단위까지 지원함
    • 전 세계 약 3000종을 다 렌더링하지 않고, 실제 자기 동네에서 날아다닐 가능성이 있는 종만 줄일 수 있음
  • 생성형 이미지답게 오류도 꽤 있었음

    • 작성자는 Gemini가 해부학을 적지 않게 환각한다고 솔직히 적음
    • 감사 과정에서 앉은 자세는 약 3%, 나는 자세는 약 5%의 해부학적 결함을 잡았다고 함
    • 특히 나는 자세는 “날개 펼침”에 대한 모델의 강한 prior 때문에, 깃털 덩어리를 추가 날개처럼 그리는 일이 많았고 같은 박새(chickadee)를 5-6번 재생성해야 깨끗한 결과가 나오기도 했다고 함

콜라주 레이아웃이 생각보다 진심임

  • 각 새 그림에는 alpha mask가 같이 들어감

    • 그림을 약 93px 폭으로 다운샘플링하고, 알파 채널을 thresholding한 뒤 base64 bit-array로 패킹함
    • 전체 mask registry는 avian/frontend/masks.json에 있고, 249종 기준 약 280KB라고 함
    • 프론트엔드는 이 마스크를 타일 배치와 hover hit-test에 둘 다 씀
  • 박스가 아니라 실루엣 기준으로 겹침을 판단하는 게 포인트임

    • 이미지의 bounding box끼리는 겹쳐도, 실제 새 실루엣이 겹치지 않으면 배치 가능함
    • 여러 새 이미지 박스가 겹친 곳에서 마우스를 올려도, 실제 실루엣 기준으로 맞는 새가 highlight됨
  • packing 알고리즘은 center-out spiral 방식임

    • 타일을 면적 내림차순으로 정렬하고, 가장 큰 타일을 중심에 둠
    • 이후 타일은 중심에서 바깥으로 나선형 탐색을 하며 기존 마스크와 충돌하지 않는 위치를 찾음
    • 비용 함수는 가로로 더 넓은 클러스터를 만들도록 b = 2.1의 ellipse aspect bias를 둠
  • 타일 크기 계산도 단순 clamp에서 정규화 방식으로 바꿨음

    • 처음엔 감지 횟수 n_i에 대해 n_i^1.2로 면적을 키우고 최대값으로 clamp하려 했음
    • 하지만 일정 횟수 이상 감지된 종이 전부 같은 최대 크기로 눌리면서 시각적 계층이 망가짐
    • 최종 방식은 각 종 점수를 n_i^0.65로 계산하고, 전체 viewport 면적 예산 B 안에서 비례 배분함
    • 덕분에 400번 감지된 종은 30번 감지된 종보다 약 5배 면적으로 보이지만, 화면 크기에 따라 전체 레이아웃은 안정적으로 맞음

중요

> 이 프로젝트에서 제일 인상적인 숫자는 “400회 감지 종이 30회 감지 종보다 약 5배 면적”으로 보이게 만든 부분이다. 단순히 많이 나온 새를 크게 그리는 게 아니라, 화면 예산 안에서 시각적 위계를 유지한 설계임.

실시간 업데이트와 상세 모달

  • 프론트엔드는 최근 감지 endpoint를 30초마다 polling함

    • 새 종이 현재 시간 창에 새로 들어오면 다음 refresh에서 레이아웃에 합류함
    • incremental insertion이 아니라 전체 repack을 수행함
    • 현재 grid stride 4px 기준으로 약 10종 repack이 Pi 4 클라이언트의 V8에서 20ms 미만이라고 함
  • 시간 창은 1H / 12H / 24H / 7D / ALL로 바꿀 수 있음

    • 선택하면 ?hours=N으로 refetch하고 화면을 다시 그림
    • 작성자는 페이지를 몇 시간 켜둬도 전환이 거슬리지 않을 정도라고 설명함
  • 새 타일을 클릭하면 종 상세 모달이 열림

    • Wikipedia summary endpoint에서 설명을 가져옴
    • 앉은 자세와 나는 자세를 토글로 바꿔볼 수 있음
    • BirdNET-Pi가 아카이브한 mp3 녹음과 spectrogram도 같이 보여줌
    • 하단에는 Wikipedia와 eBird 외부 참조 chip이 붙음

기술 맥락

  • 이 프로젝트의 선택은 “분류 모델을 새로 만들지 않고 BirdNET-Pi 위에 UX를 얹는다”는 쪽이에요. 새소리 분류 자체는 이미 잘 돌아가는 오픈소스가 있으니, 작성자는 그 시간을 시각화와 운영 경험에 쓴 거죠. 그래서 오디오 캡처, 모델 실행, 웹 UI라는 기반은 재사용하고, 콜라주·관리 패널·외부 연동이 차별점이 됐어요.

  • 이미지 생성에도 현실적인 제약이 보여요. Gemini로 450개 종의 일러스트를 만들면 빠르게 에셋을 확보할 수 있지만, 새의 해부학 오류가 생기기 때문에 감사와 재생성이 필요했어요. 특히 나는 자세에서 오류율이 5%까지 나온 건, 생성형 이미지가 취미 프로젝트에서도 검수 비용을 만든다는 좋은 사례예요.

  • 레이아웃 알고리즘은 단순 CSS grid로 풀기 어려운 문제라 직접 계산한 이유가 있어요. 새 그림은 투명 배경이 있는 불규칙한 실루엣이라 bounding box 기준 배치는 빈 공간을 많이 낭비하거든요. 그래서 alpha mask로 실제 형태를 계산하고, 충돌하지 않는 위치를 spiral search로 찾는 방식이 잘 맞아요.

  • 크기 정규화도 중요한 결정이에요. 감지 횟수에 따라 면적을 키우되 최대값으로 자르면 인기 종들이 다 같은 크기가 돼서 데이터의 차이가 사라져요. viewport 면적 예산을 먼저 정하고 그 안에서 n_i^0.65 비율로 나누면, 작은 화면부터 2560px 디스플레이까지 같은 규칙으로 보기 좋은 결과를 만들 수 있어요.

  • 외부 연동은 홈랩 프로젝트답게 운영 레이어를 잘 나눴어요. 공개는 Cloudflare Tunnel로 처리하고, 자동화는 Home Assistant REST sensor와 MQTT bridge로 내보내요. 이렇게 하면 콜라주 UI는 사람에게 보여주는 화면이고, 감지 이벤트는 다른 시스템이 소비할 수 있는 데이터가 돼요.

이 글의 재미는 ‘새 감지기 만들었어요’가 아니라, 작은 홈랩 프로젝트 안에 ML 추론, 이미지 생성, 레이아웃 알고리즘, 홈 자동화, 터널링까지 다 들어간다는 점이다. 개인 프로젝트라도 UX와 시스템 설계를 제대로 고민하면 읽는 맛이 확 살아남.

댓글

댓글

댓글을 불러오는 중...

open-source

Paint.NET, 22년 만에 드디어 paint.net 도메인을 손에 넣다

무료 이미지 편집 도구 Paint.NET이 2004년 출시 이후 22년 만에 paint.net 도메인을 확보했다. 기존 도메인 소유자가 Paint.NET 공식 사이트처럼 보이는 콘텐츠와 광고 링크를 올리면서 상표권 침해와 도메인 점유 문제가 명확해졌고, 제작자 릭 브루스터가 법적 대응 끝에 도메인을 가져왔다.

open-source

KORE, Parquet보다 더 작고 빠르다는 새 컬럼형 바이너리 포맷 공개

KORE는 분석 워크로드를 겨냥한 오픈소스 바이너리 파일 포맷으로, Parquet 대비 더 높은 압축률과 빠른 쿼리 성능을 주장한다. 다만 현재 공개된 내용에는 일부 구현이 스텁 처리됐다는 언급도 있어, 벤치마크 숫자는 흥미롭지만 실제 도입 전 검증이 필수다.

open-source

소설 쓰기에 맞춘 오프라인 텍스트 에디터, 치즈 페이퍼

치즈 페이퍼는 소설과 장문 글쓰기에 특화된 오픈소스 텍스트 에디터다. 장면별 본문은 마크다운으로, 노트와 요약은 TOML 헤더로 저장하고, 파일 동기화 도구와 함께 쓰는 오프라인 우선 구조를 택했다.

open-source

진짜 신용카드 두께에 컴퓨터를 넣어버린 DIY 하드웨어 프로젝트

Muxcard는 ESP32-C3, 전자종이 디스플레이, NFC를 실제 신용카드에 가까운 두께로 집어넣은 초박형 컴퓨터 프로토타입이다. 제작자는 약 1밀리미터 두께를 목표로 직접 플렉스 피시비를 만들고, 배터리·디스플레이 연결·기계적 피로 같은 현실적인 문제를 하나씩 검증했다.

open-source

브라 사이즈 계산기를 Emacs 안에 만든 사람의 진짜 Emacs식 생활 자동화

필자가 브라 사이즈를 다시 재야 하는 상황에서 Emacs Lisp로 EU, UK, US 브라 사이즈 계산기를 만든 이야기다. Emacs Calc의 단위 변환과 Org 테이블 수식을 엮어서, 측정값만 적으면 여러 지역 기준 사이즈가 자동으로 채워지는 작은 도구로 확장했다.