사진이 수만 장 쌓이면 흔들린 사진, 아무것도 안 찍힌 사진, 비슷한 사진을 하나씩 넘겨 보며 지울 엄두가 나지 않습니다. PhotoSlimmer는 그 후보를 기기 안에서만 찾아 보여 주고, 지울지 말지는 사람이 정합니다.
제 아이폰에는 사진이 8만 장 있습니다. 정리하려고 앨범을 열면 10분 만에 포기하게 됩니다.
흔들린 사진, 주머니에서 찍힌 검은 사진, 같은 장면을 열 번 찍은 사진이 수천 장 섞여 있지만, 그걸 찾으려면 8만 장을 다 봐야 합니다.
사진 정리 앱 상당수가 분석·광고 SDK를 넣거나 구독을 요구합니다. 아이 사진이 든 라이브러리를 그런 앱에 맡기고 싶지 않았습니다.
삭제는 되돌릴 수 없습니다. 그래서 자동화는 "후보를 찾는 것"까지만 하고, 삭제는 반드시 사람이 고르고 확인하도록 했습니다.
App Store에 출시되어 실제로 동작하는 범위만 적었습니다. (2026-05-10 개발 시작 · 현재 v1.5.8 출시 중)
화면을 격자로 나눠 "가장 선명한 부분"의 선명도를 재서 전체가 흐린 사진을 추려 줍니다. 어두운 사진은 선명도가 낮게 나오는 착시가 있어 판정에서 따로 걸러냅니다. 미리 선택해 두지 않습니다 — 고르는 것은 사용자입니다.
촬영 시각으로 같은 순간을 찾고 이미지 임베딩으로 검증해 묶습니다. 묶음 안에서 얼굴 품질이 가장 좋은 사진에 별 배지를 답니다.
iOS의 백그라운드 처리 작업으로 화면을 잠가도 스캔이 계속됩니다. 기간을 골라 나눠서 스캔할 수 있습니다.
분석 경로에는 네트워크 접근이 없습니다. 분석·광고 SDK도, 자체 수집도 없어 App Store 프라이버시 라벨이 "데이터를 수집하지 않음"입니다.
AI는 두 곳에 있습니다. 제품 안에서 사진을 보는 AI와, 이 제품을 만드는 과정의 AI입니다.
서버 모델은 쓰지 않습니다. 직접 학습시킨 모델도 아직 제품에 넣지 않았습니다 — 검증이 끝나지 않았기 때문입니다.
AI는 그럴듯한 숫자를 쉽게 지어냅니다. 그래서 프로젝트 규칙으로 못 박았습니다: 모든 임계값은 제가 직접 라벨링한 사진으로 잰 근거가 있어야 한다. 앱 안에 라벨링 도구를 만들어 실제 라이브러리에서 사진을 뽑아 결함을 표시하고, 그 결과로 신호별 AUC를 냅니다. Claude가 세운 가설도 같은 방식으로 기각됩니다 — 실제로 "입력 해상도가 원인"이라는 가설과 "얼굴 선명도로 눈감음을 잡을 수 있다(소표본 AUC 0.795)"는 가설은 추가 측정에서 각각 기각(후자는 0.522)됐습니다.
앱을 쓰다 든 위화감이 출발점이었습니다. Claude는 코드에서 원인을 짚었습니다 — 선명도를 재는 연산(Laplacian)에는 방향·위치 정보가 없어 배경만 흐린 좋은 사진과 진짜 흐린 사진을 원리상 구분하지 못한다는 것. 그런데 검증하려고 보니 라벨 자체가 둘을 섞고 있었습니다. 그래서 라벨링 도구부터 고쳤습니다: 사람도 가르기 어려운 "흔들림이냐 초점이냐"는 버리고, 누구나 판단할 수 있는 "어디가 흐린가"(전체 / 피사체만 / 배경만)로 바꿨습니다. 그 기준으로 하루에 505장을 다시 라벨링해 쟀습니다.
새 신호를 만들 필요 없이, 이미 모든 사진에 계산해 두던 값으로 풀리는 문제였습니다. 판정 산식에 반영하는 작업은 다음 업데이트에 들어갑니다.
스캔은 몇 시간씩 백그라운드에서 돌기 때문에 디버거를 붙일 수 없습니다. 앱이 스스로 진단 로그(메모리, 구간별 처리량, 생명주기)를 남기게 하고, 그 로그와 크래시 리포트를 Claude가 읽어 원인을 좁힙니다. 나중에는 환경변수로 앱이 혼자 스캔을 시작하고 Mac이 로그를 회수하는 무인 실험 루프까지 만들어, 사람 손 없이 가설을 하나씩 꺼 보며 검증했습니다.
전부 제 실기기(iPhone 16 Pro, 사진 8만 장)에서 잰 값입니다. 아래 개선은 9월 18~20일 개발 빌드에서 이뤄졌고, 출시 버전(v1.5.8)에는 다음 업데이트로 들어갑니다.
| 무엇을 | 전 | 후 | 어떻게 찾았나 |
|---|---|---|---|
| 전체 라이브러리 스캔 | 도중에 반복 종료 | 80,167장 완주 | 시스템 메모리 리포트로 "가장 큰 프로세스라 먼저 종료됨"을 확인 → 8만 개 객체 물질화 제거, 5장마다 저장해 중단이 손실이 아니라 일시정지가 되게 함 |
| 분석에 들어가는 이미지 | 긴 변 120px | 480px | "왜 흐림 검출이 약한가"를 추적하다 실제 입력이 원본의 3.5%였음을 실측으로 발견 |
| 유사 사진 조회 | 8.2초 | 0.02초 | 임베딩(3KB)이 같은 테이블 페이지에 있어 전체를 읽던 것 → 커버링 인덱스 |
| 후보 분류 1회 | 4.68초 · 461MB | 1.6초 · 31MB | 사진 객체 8만 개를 한꺼번에 만들던 것 → ID만 다루고 통과한 것만 조회 |
| 앱 데이터베이스 크기 | 3.1GB | 377MB | 라벨 분석용으로 DB를 꺼내다 발견. 조회 문장이 읽기 잠금을 쥐고 있어 로그 파일이 한 번도 정리되지 않았음 |
| 좋은 아웃포커싱 사진과 진짜 흐린 사진 구분 | AUC 0.68 | AUC 0.90 | 직접 라벨링한 505장으로 측정. 쓰고 있던 선명도 신호는 둘을 거의 못 갈랐고, 이미 계산해 두던 Apple 미학 점수가 가른다는 것을 확인 |
검증되지 않은 것은 되는 것처럼 쓰지 않습니다.
라벨링한 결함의 22%가 눈 감은 사진인데, 어떤 신호로도 거의 잡히지 않습니다(미학 점수 AUC 0.54). 분석 입력 480px에서 눈은 폭 10~26픽셀에 불과하기 때문입니다. 얼굴 영역만 고해상도로 다시 보는 2단계 분석을 설계 중입니다.
현재 출시 버전의 판정은 직접 라벨링한 505장 기준 정밀도 50% · 재현율 44%입니다. 미학 점수만으로도 정밀도 76% · 재현율 52%가 나온다는 것을 쟀지만, 아직 제품에 넣지 않았습니다 — 컷을 정하고 회귀 테스트를 붙인 뒤에 나갑니다.
사진 1장당 약 10KB씩 메모리가 늘어납니다. 데이터베이스·이미지 캐시는 원인이 아님을 실험으로 확인했고, 원인은 아직 찾는 중입니다.
App Store에 출시된 버전의 화면입니다.


