Refactor HVideoTool to support project-based workflow: introduced project management features, updated UI for project handling, and enhanced documentation in README and CLAUDE.md. The tool now organizes images and settings into projects, improving usability and detection caching.
This commit is contained in:
@@ -2,10 +2,29 @@
|
||||
|
||||
Десктопная утилита с графическим интерфейсом для **обнаружения уже наложенной
|
||||
цензуры** (мозаика, пикселизация, размытие, чёрные плашки) на **картинках**.
|
||||
Открываете папку с изображениями (или раскадровываете ролик кнопкой «Создать из
|
||||
ролика…») — приложение прогоняет каждый кадр через детектор, **обводит найденные
|
||||
области** и показывает **подробный список** того, что нашлось на каждой картинке.
|
||||
Отобранные кадры можно перемещать в **коллекции** (для сбора датасета/примеров).
|
||||
Работа организована в **проекты**: создаёте проект (или раскадровываете ролик кнопкой
|
||||
«Создать из ролика…») — приложение прогоняет каждый кадр через детектор, **обводит
|
||||
найденные области** и показывает **подробный список** того, что нашлось на каждой
|
||||
картинке. Отобранные кадры можно перемещать в **избранное** (для сбора датасета/
|
||||
примеров).
|
||||
|
||||
### Проект
|
||||
|
||||
Проект — это папка со всем необходимым:
|
||||
|
||||
```
|
||||
МойПроект/
|
||||
├── project.json # настройки проекта (детектор, модель, порог, движок) + метаданные
|
||||
├── frames/ # картинки проекта
|
||||
├── detections.json # кэш детекций
|
||||
└── collections/ # коллекции; «Избранное» — папка для отобранных кадров
|
||||
```
|
||||
|
||||
Настройки (детектор / модель / порог / движок восстановления) хранятся **внутри
|
||||
проекта** — каждый проект помнит, как его настраивали. Глобальные настройки
|
||||
(`~/HVideoTool/settings.json`) задают лишь **значения по умолчанию для новых проектов**
|
||||
и список недавних. При запуске без аргументов автоматически открывается последний
|
||||
проект.
|
||||
|
||||
> Инструмент для просмотра, отладки детекции и отбора кадров. Видео раскадровывает
|
||||
> через ffmpeg (ставится автоматически с пакетом `imageio-ffmpeg`; системный ffmpeg
|
||||
@@ -15,62 +34,97 @@
|
||||
|
||||
## Возможности
|
||||
|
||||
- **Создать из ролика…** — раскадровка видео в папку-коллекцию. Два режима:
|
||||
**только ключевые кадры** (в разы быстрее — декодируются лишь I-кадры) и
|
||||
- **Проекты**: «Создать проект…», «Открыть проект…», «Импортировать папку как
|
||||
проект…» (копирует картинки из обычной папки в `frames/` нового проекта) и подменю
|
||||
**«Недавние проекты»**.
|
||||
- **Создать из ролика…** — раскадровка видео в новый проект (кадры в `frames/`). Два
|
||||
режима: **только ключевые кадры** (в разы быстрее — декодируются лишь I-кадры) и
|
||||
**каждый N-й кадр**; опциональный даунскейл (меньше файлов и нагрузки на диск/АВ).
|
||||
ffmpeg идёт в комплекте (`imageio-ffmpeg`); системный ffmpeg из PATH — в приоритете.
|
||||
- **Коллекции**: «Создать коллекцию…» + «В коллекцию» (Ctrl+M) перемещает выбранные
|
||||
кадры в активную папку-коллекцию (мультивыбор поддерживается).
|
||||
- **Открыть папку** с картинками (`.jpg/.png/.bmp/.webp/.tif`) — список слева.
|
||||
- **Избранное**: «★ В избранное» (Ctrl+M) перемещает выбранные кадры в папку
|
||||
`collections/Избранное` внутри проекта — для отбора кадров (мультивыбор
|
||||
поддерживается). Папка создаётся автоматически.
|
||||
- Картинки проекта (`.jpg/.png/.bmp/.webp/.tif`) — список слева.
|
||||
- Картинка с **обводкой контуром** найденных областей — по центру.
|
||||
- **Подробная таблица детекций** справа: тип, уверенность, bbox, число точек
|
||||
полигона. Выбор строки **подсвечивает** конкретную область на картинке.
|
||||
- **Ленивая детекция**: картинка прогоняется при первом открытии, результат
|
||||
кэшируется. Кнопка **«Детектировать все»** обходит всю папку.
|
||||
- **Ленивая детекция**: картинка прогоняется по двойному клику / кнопке «Рассчитать
|
||||
кадр», результат кэшируется.
|
||||
- **Кэш детекций сохраняется в проект** (см. [ниже](#кэш-детекций)) — при повторном
|
||||
открытии проекта результаты подхватываются, не нужно считать заново.
|
||||
- **Три режима пересчёта**:
|
||||
- **«Детектировать все»** — *дозапуск*: считает только ещё не посчитанные кадры
|
||||
(можно прерывать и продолжать);
|
||||
- **«Все заново»** — полная регенерация: очищает кэш и пересчитывает весь проект;
|
||||
- **«Рассчитать кадр»** (Space / двойной клик) — всегда пересчитывает текущий кадр.
|
||||
- **Кнопка «■ Стоп» (Esc)** отменяет любую текущую длинную операцию (детекция всего
|
||||
проекта, раскадровка ролика, импорт папки, восстановление DeepMosaics). Уже
|
||||
посчитанное при отмене сохраняется в кэш.
|
||||
- **Навигация под картинкой**: ◀ ▶ (`,`/`.`), ползунок-перемотка и переходы к
|
||||
кадрам с детекцией ◀/▶ (`[`/`]`). На ползунке **бирюзовыми метками** отмечены кадры
|
||||
с найденной цензурой; строки списка **подсвечиваются цветом** (🔴 цензура найдена,
|
||||
🟢 проверено и чисто).
|
||||
- Переключение **детектора** (`classic` / `yolo` / `combined`) и **порога**
|
||||
уверенности прямо в тулбаре — удобно сравнивать.
|
||||
- Выбор файла весов модели кнопкой **«Модель…»**.
|
||||
|
||||
## Кэш детекций
|
||||
|
||||
Результаты детекции сохраняются в корне проекта в файл `detections.json`. Это даёт:
|
||||
|
||||
- **возобновление между сессиями** — открыли проект повторно, готовые детекции сразу
|
||||
на месте (метки на ползунке и подсветка строк восстанавливаются);
|
||||
- **дозапуск** — «Детектировать все» пропускает уже посчитанные кадры;
|
||||
- **отказоустойчивость** — при отмене/закрытии посчитанное не теряется.
|
||||
|
||||
Кэш помечен «удостоверением» детектора (детектор + модель + порог `conf`/`imgsz`).
|
||||
Если открыть проект **другим** детектором, чужой кэш не загружается (чтобы не выдавать
|
||||
старые результаты за текущие). Полностью пересчитать — кнопка **«Все заново»**.
|
||||
|
||||
> Ключи внутри файла — **имена файлов**, поэтому кэш переживает перемещение/
|
||||
> переименование проекта. Хранится результат **одного** детектора за раз: посчитали
|
||||
> одним, переключились на другой и посчитали — кэш перезапишется.
|
||||
|
||||
## Восстановление (расцензуривание)
|
||||
|
||||
Кнопка **«Расцензурить кадр»** восстанавливает найденные области на текущем кадре,
|
||||
**«Показать оригинал/результат»** переключает вид, **«Сохранить результат»** пишет
|
||||
`<имя>_restored.jpg` (в активную коллекцию или рядом с кадром). Движок выбирается в
|
||||
`<имя>_restored.jpg` рядом с кадром. Движок выбирается в
|
||||
меню **Файл → Движок восстановления…**.
|
||||
|
||||
Два движка:
|
||||
|
||||
- **Инпейнт (cv2)** — по умолчанию, без модели и GPU. ⚠️ *Заполняет* область по
|
||||
окружению, но **не реконструирует** скрытые детали (замазывает, а не раскрывает).
|
||||
- **DeepMosaics** — реальное генеративное удаление мозаики. Требует **GPU NVIDIA/CUDA**
|
||||
(на CPU очень медленно) и отдельной установки. На аниме качество ограничено
|
||||
(модели обучены на реальном видео).
|
||||
- **DeepMosaics** — реальное генеративное удаление мозаики. Код **встроен** в
|
||||
приложение (vendored, GPL-3.0), ставить его отдельно не нужно — требуются только
|
||||
**веса** и (желательно) **GPU NVIDIA/CUDA**. На аниме качество ограничено (модели
|
||||
обучены на реальном видео).
|
||||
|
||||
### Настройка DeepMosaics
|
||||
|
||||
```powershell
|
||||
git clone https://github.com/HypoX64/DeepMosaics
|
||||
# установите зависимости DeepMosaics (см. его README; нужен torch с CUDA)
|
||||
# скачайте веса (clean_youknow_resnet_9blocks.pth + mosaic_position.pth) в pretrained_models/mosaic
|
||||
```
|
||||
Нужны только **веса** — положите их в **`models/deepmosaics/`** (папка в `.gitignore`,
|
||||
веса большие, ~92 МБ). Скачать: официальная папка
|
||||
([Google Drive](https://drive.google.com/drive/folders/1LTERcN33McoiztYEwBxMuRjjgxh4DEPs),
|
||||
Baidu код `1x0a`):
|
||||
|
||||
Затем в приложении: **Файл → Движок восстановления… → DeepMosaics**, укажите папку
|
||||
DeepMosaics (с `deepmosaic.py`), файл весов и GPU id (`-1` = CPU). Приложение вызывает
|
||||
DeepMosaics на текущем кадре и показывает результат.
|
||||
- **`clean_youknow_resnet_9blocks.pth`** — картиночная clean-модель;
|
||||
- **`mosaic_position.pth`** — локатор мозаики (должен лежать рядом).
|
||||
|
||||
> **Важно:** для покадрового режима берите **картиночную** модель
|
||||
> `clean_youknow_resnet_9blocks.pth`. Видеомодель `clean_youknow_video.pth` (BVDNet)
|
||||
> покадрово **не работает** — ей нужен соседний кадр. Если кадр без мозаики, движок
|
||||
> вернёт его без изменений.
|
||||
Затем в приложении: **Файл → Движок восстановления… → DeepMosaics**, выберите **модель
|
||||
из выпадающего списка** (наполняется из `models/deepmosaics`; есть «Обзор…» для файла в
|
||||
другом месте) и GPU id (`-1` = CPU). Если веса в `models/deepmosaics` — работает сразу;
|
||||
модель грузится один раз, дальше кадры считаются быстро.
|
||||
|
||||
> **Важно:** берите именно **картиночную** модель `clean_youknow_resnet_9blocks.pth`.
|
||||
> Видеомодель `clean_youknow_video.pth` (BVDNet) покадрово **не работает** — ей нужен
|
||||
> соседний кадр (приложение это распознаёт и подскажет). Если на кадре нет мозаики,
|
||||
> результат = исходный кадр.
|
||||
>
|
||||
> DeepMosaics 2021 года рассчитан на старые версии (`torch 1.7`, `numpy 1.19`).
|
||||
> Проверено: на современных `torch 2.x`/`numpy 2.x` картиночная модель запускается
|
||||
> (CPU ~7 с/кадр), но если столкнётесь с несовместимостью — заведите для DeepMosaics
|
||||
> отдельное окружение по его `requirements.txt` и укажите его `python.exe` в диалоге.
|
||||
|
||||
> Движок подключается через интерфейс `core/restore/base.Restorer` (`build_restorer`).
|
||||
> [LADA](https://github.com/ladaapp/lada) (BasicVSR++, лучшее качество на реальном
|
||||
> видео, но видеомодель) пока не подключён.
|
||||
> Код DeepMosaics (GPL-3.0) лежит в `core/restore/_deepmosaics/` и поэтому **весь
|
||||
> проект распространяется под GPL-3.0**. Запускается на современных `torch 2.x`/
|
||||
> `numpy 2.x` (проверено). [LADA](https://github.com/ladaapp/lada) (видеомодель,
|
||||
> лучшее качество на реальном видео) пока не подключён.
|
||||
|
||||
## Что НЕ делает (осознанно вне области задачи)
|
||||
|
||||
@@ -105,11 +159,11 @@ pip install -e .
|
||||
## Запуск
|
||||
|
||||
```powershell
|
||||
# Без аргументов — папку открываете в приложении (тулбар → «Открыть папку…»)
|
||||
# Без аргументов — открывается последний проект (или создайте/откройте новый в тулбаре)
|
||||
python -m hvideotool
|
||||
|
||||
# Необязательно: сразу открыть папку / переопределить детектор и модель
|
||||
python -m hvideotool "C:\path\to\images" --detector yolo --model models\lada_mosaic_detection_model_v4_accurate.pt
|
||||
# Необязательно: сразу открыть проект / переопределить детектор и модель (по умолчанию)
|
||||
python -m hvideotool "C:\path\to\МойПроект" --detector yolo --model models\lada_mosaic_detection_model_v4_accurate.pt
|
||||
```
|
||||
|
||||
Выбор детектора, путь к модели и порог сохраняются в `~/HVideoTool/settings.json`
|
||||
@@ -176,24 +230,28 @@ hvideotool/
|
||||
├── __main__.py # точка входа + CLI (всё опционально)
|
||||
├── app.py # инициализация QApplication
|
||||
├── config.py # настройки: пороги детекции, оверлей, детектор/модель
|
||||
├── settings_store.py # детектор/модель/порог/последняя папка → settings.json
|
||||
├── settings_store.py # дефолты новых проектов + последний/недавние → settings.json
|
||||
├── ui/
|
||||
│ ├── main_window.py # окно: список файлов | картинка | таблица детекций
|
||||
│ └── image_view.py # отрисовка картинки + оверлей-контуры (QPainter)
|
||||
│ ├── image_view.py # отрисовка картинки + оверлей-контуры (QPainter)
|
||||
│ └── marker_slider.py # ползунок-перемотка с метками кадров с детекцией
|
||||
└── core/
|
||||
├── imageio.py # unicode-safe чтение/запись картинок (Windows-пути)
|
||||
├── project.py # Project: раскладка (project.json/frames/detections.json/collections) + настройки
|
||||
├── video/frame.py # Frame (картинка BGR + индекс + pts) — вход детектора
|
||||
└── detection/
|
||||
├── base.py # Detector (ABC): detect(frame) -> list[Detection]
|
||||
├── factory.py # build_detector(config) -> classic/yolo/combined
|
||||
├── types.py # Detection (+ to_dict/from_dict), CensorType
|
||||
├── cache.py # сохранение/загрузка кэша детекций (detections.json в проекте)
|
||||
├── classic_cv.py # эвристический детектор (mosaic/blur/black_bar)
|
||||
├── yolo.py # YOLO-детектор (Ultralytics, маски→полигоны)
|
||||
└── composite.py # CompositeDetector: объединение детекторов
|
||||
```
|
||||
|
||||
Детекция синхронная (по клику/по кнопке «Детектировать все»); тяжёлый YOLO на CPU
|
||||
заметно медленнее, чем на CUDA.
|
||||
заметно медленнее, чем на CUDA. Длинные операции можно прервать кнопкой «■ Стоп»
|
||||
(Esc), а результаты кэшируются на диск — см. [Кэш детекций](#кэш-детекций).
|
||||
|
||||
## Технологический стек
|
||||
|
||||
|
||||
Reference in New Issue
Block a user