П/ВИН

Поиск дубликатов фото: как ИИ разобрал 36 000 снимков

·6 мин чтения

💬 От автора: Поиск дубликатов фото я годами откладывал в ту самую папку «когда-нибудь разберём» - и давно жду, когда подобный сценарий перестанет быть гиковским экспериментом и станет нормой для обычного бизнеса. Тут ведь главное не "разобрать фотки", а схема: дорогая фронтир-модель оркеструет, дешёвые локальные модели перемалывают объём, человек только нажимает кнопки. Лично я вижу здесь готовый шаблон для любой компании, где годами копятся гигабайты документов, сканов и переписки, которые "когда-нибудь разберём". И мне важно, что вся тяжёлая работа шла на своём железе почти бесплатно - значит, порог входа для малого бизнеса в РФ уже сегодня близок к нулю.

Есть задачи, которые не делаются никогда. Не потому что сложные, а потому что объём убивает любое намерение на втором часу. У автора такой задачей оказался личный фотоархив: около 36 000 фото и видео, 222 ГБ, копившиеся 20 лет и раскиданные вообще везде.

Часть лежала в OneDrive по годам, часть там же в свалках - дампы с телефонов, выгрузки из WhatsApp, папка с названием "разобрать старые фото", которая ждала своего часа лет десять. Часть уже была в Apple Photos с iPhone, сама по себе. А часть застряла в почте: годами приходила тяжёлыми письмами и осела вложениями. Имена половины файлов человеческие, половина - IMG_4348.JPG. EXIF где-то корректный, где-то врёт, где-то его нет.

Разобрать это руками означало однажды сесть и просмотреть десятки тысяч файлов. То есть никогда.

Гора неразобранных фотографий и видеофайлов на экране — хаос личного архива за 20 лет


С чего всё началось

Повод был будничный: пришло уведомление, что в почте кончается место, и сервис предложил докупить квоту. Но за 20 лет ящик ни разу толком не чистили, и логичнее было разобрать один раз.

Решили делать не руками, а через агента. Ему выдали доступ к Gmail API и попросили проанализировать ящик. Агент вернулся с раскладкой по отправителям, размерам и годам, и дальше почту разрулили целиком его руками. По дороге выяснилось, что куча фотографий осела в тяжёлых письмах. Их захотели вытащить и закинуть в Apple Photos. Тут вспомнили про старый архив в OneDrive. И понеслось.

Оркестратором был Claude Code на модели Opus 4.8. Он сам писал одноразовые скрипты под каждый шаг и дёргал нужные инструменты.


Почему агент не бросился смотреть 36 тысяч фото

Когда агента попросили "разобрать 36 тысяч фотографий", он сказал прямо: гонять такой объём через фронтир-модель бессмысленно. В контекст не влезет, по токенам разорит.

Правильный путь, по его словам, - поднять локальные модели, которые сделают тяжёлую работу почти даром на своём железе. А фронтир-агент возьмёт на себя оркестрацию и контроль качества.

Это и задало всю архитектуру. Локальные модели перемалывают десятки тысяч файлов почти бесплатно. Фронтир-агент пишет под каждый шаг одноразовый скрипт, склеивает инструменты и сам проверяет результат. Человек принимает финальные решения и ловит то, что машина знать не может.

💡 Не гоняю весь объём через дорогую модель: локальные модели перемалывают файлы почти даром, а фронтир-агент только оркеструет и проверяет результат.

Первый урок прилетел сразу на почте. Около 9 500 явного мусора отправили в Корзину, но в эту пачку уехала рассылка живого интернет-магазина - формально спам, фактически рабочая история проекта. Спасло то, что удаляли только в Корзину: восстановили одной командой, отправителя занесли в исключения. Никаких "удалить насовсем", пока человек не подтвердил.


Дедуп, теги и лица как диаризация

Первое правило большого архива - сначала убрать дубли. Точные дубли по хэшу не ловят пересохранения и ресайзы, поэтому сравнивали не байты, а изображения: перцептивный хэш через инструмент czkawka. Из пяти почти одинаковых кадров оставляли лучший по разрешению, остальное в карантин, обратимо. Поверх czkawka агент за 15 минут собрал браузерную страничку для ревью с миниатюрами и предвыбранным лучшим кадром.

Дальше нужно было понять, что вообще на снимках. Для грубых тегов взяли CLIP (open_clip, ViT-B-32): пляж, дети, еда, документ. Заодно отделили сканы и скриншоты от настоящих снимков. Имена событий собирала зрительная модель Qwen2.5-VL-7B через mlx-vlm нативно на Apple Silicon - она описывала кадры вроде "Дети на катке с маскотом в виде зайца", и из этого складывалось человеческое название альбома. Фронтир-модель на ту же работу потратила бы около 17 секунд на кадр и кучу токенов.

Кластеризация лиц: эмбеддинги группируются в персоны, человек называет каждого по разу

Самая красивая часть - лица. Задача "кто на фото" оказалась той же, что диаризация спикеров в аудио: разбить на персон, а человек назовёт каждого по разу. Лица детектировали, считали эмбеддинги через InsightFace (ArcFace), кластеризовали kNN и union-find - получилось 2 153 персоны. При мягком пороге кластеризация схлопнула пол-архива в один мегакластер на 30 000 лиц, где люди вперемешку. Подняли порог строже - получили чистые кластеры.

Качество проверял сам агент: вырезал по несколько лиц из крупнейших кластеров и смотрел своим зрением, один это человек или каша. Назвали только верхние несколько десятков частых персон - это покрыло больше 15 тысяч фото, а имена вписались тегами прямо в файлы через XMP/IPTC и теперь ищутся в любом просмотрщике.


Видео, сортировка и почему EXIF врёт

Роликов в архиве было 1 754, и отдельный стек для них не понадобился. ffmpeg достаёт из видео несколько кадров, дальше работают те же модели. Людей в видео искали в два прохода: сначала все ролики по 5 кадров, потом те, где никого не нашли, прогнали плотнее по 12 кадров. Итого людей распознали в 608 роликах: 470 в первом проходе плюс 138 во втором. Логика та же - сначала дёшево закрыть основной объём, потом точечно дожать остаток.

Целевая структура была хронологической: год, внутри ГГГГ-ММ-ДД, событие. Делали через манифест с предпросмотром и полным undo-логом, сначала пилот на одном годе. Пилот сразу себя оправдал: пачка фото с корпоратива 2008 года уехала в 2005. Причина в том, что у старых камер со сбитыми часами EXIF по умолчанию ставит 2005-01-01, а у сканов хранит дату оцифровки, а не съёмки. Решение - при расхождении доверять имени папки, а не EXIF: человек, который называл папку "2008-09 корпоратив", знал год точно.

💡 При расхождении дат доверяю имени папки, а не EXIF: человек, который назвал папку "2008-09 корпоратив", знал год точно, а часы камеры врут.

Первый автоматический результат дробил одно событие на несколько папок по дням. Поправили в два прохода: день свернули в месяц, а "папки-людей" и длящиеся истории вроде ремонта - в год, потому что это субъекты, а не разовые события. Для одного 2013 года это сократило около 200 папок-по-дням до 49.

Хронологическая структура папок: год, дата, событие — итог автоматической сортировки

Дальше осталась только полировка: где-то слить два похожих события, где-то подправить имя. По всему OneDrive нашлось около 37 000 изображений и видео, разбросанных не только по фотоархиву, но и по самым разным папкам, из них около 4 400 - в свалках "разобрать" и старых бэкапах. Главное, что основной объём оказался сделан, а человеку остались только финальные решения.


Источники

Паша Вин
Паша Вин

AI-инженер, предприниматель, маркетолог. Основатель feberra.com и x10seo.ru. 13 лет в перфоманс-маркетинге, 3 года в системной интеграции AI в бизнес.