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:
@@ -1,7 +1,9 @@
|
||||
"""Configure the restoration ("расцензурить") engine.
|
||||
|
||||
inpaint — no setup. deepmosaics — point at a user-installed DeepMosaics folder and
|
||||
its clean weights; a CUDA GPU is strongly recommended (set GPU id, -1 = CPU/slow).
|
||||
inpaint — no setup. deepmosaics — the network code is vendored (built-in); the user
|
||||
picks a clean model from a dropdown of the bundled ``models/deepmosaics`` weights
|
||||
(or browses to another ``clean_*.pth``). ``mosaic_position.pth`` must sit beside the
|
||||
chosen model. A CUDA GPU is strongly recommended (GPU id, -1 = CPU/slow).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -22,6 +24,7 @@ from PySide6.QtWidgets import (
|
||||
)
|
||||
|
||||
from ..config import AppConfig
|
||||
from ..core.restore.deepmosaics import discover_models
|
||||
|
||||
|
||||
class RestoreDialog(QDialog):
|
||||
@@ -29,7 +32,7 @@ class RestoreDialog(QDialog):
|
||||
super().__init__(parent)
|
||||
self._cfg = config
|
||||
self.setWindowTitle("Движок восстановления")
|
||||
self.setMinimumWidth(520)
|
||||
self.setMinimumWidth(560)
|
||||
|
||||
self.engine = QComboBox()
|
||||
self.engine.addItem("Инпейнт (быстро, замазывает — без модели)", "inpaint")
|
||||
@@ -37,24 +40,21 @@ class RestoreDialog(QDialog):
|
||||
self.engine.setCurrentIndex(1 if config.restorer == "deepmosaics" else 0)
|
||||
self.engine.currentIndexChanged.connect(self._sync)
|
||||
|
||||
self.dm_dir = QLineEdit(config.dm_dir or "")
|
||||
self.dm_model = QLineEdit(config.dm_model or "")
|
||||
self.dm_python = QLineEdit(config.dm_python or "")
|
||||
self.dm_python.setPlaceholderText("по умолчанию — python текущего venv")
|
||||
# Model dropdown — bundled clean models, plus the configured one if external.
|
||||
self.model_combo = QComboBox()
|
||||
self._populate_models(config.dm_model)
|
||||
|
||||
self.dm_gpu = QLineEdit(config.dm_gpu or "0")
|
||||
self.dm_gpu.setPlaceholderText("0 = первая CUDA-карта, -1 = CPU (медленно)")
|
||||
|
||||
form = QFormLayout(self)
|
||||
form.addRow("Движок:", self.engine)
|
||||
form.addRow("Папка DeepMosaics:", self._with_browse(self.dm_dir, self._browse_dir))
|
||||
form.addRow("Веса (clean_*.pth):", self._with_browse(self.dm_model, self._browse_model))
|
||||
form.addRow("Python для DeepMosaics:", self._with_browse(self.dm_python, self._browse_python))
|
||||
form.addRow("Модель:", self._with_browse(self.model_combo, self._browse_model))
|
||||
form.addRow("GPU id:", self.dm_gpu)
|
||||
hint = QLabel(
|
||||
"DeepMosaics ставится отдельно (git clone + зависимости). Рядом с весами "
|
||||
"clean_*.pth должен лежать mosaic_position.pth.\n"
|
||||
"Для покадрового режима берите clean_youknow_resnet_9blocks.pth — "
|
||||
"видеомодель clean_youknow_video.pth покадрово не работает. См. README."
|
||||
"Модели берутся из models/deepmosaics. Нужны clean_youknow_resnet_9blocks.pth "
|
||||
"и mosaic_position.pth (рядом). Видеомодель clean_*_video.pth покадрово не "
|
||||
"работает и в списке не показывается. На CPU медленно — лучше GPU. См. README."
|
||||
)
|
||||
hint.setWordWrap(True)
|
||||
form.addRow(hint)
|
||||
@@ -65,41 +65,41 @@ class RestoreDialog(QDialog):
|
||||
form.addRow(buttons)
|
||||
self._sync()
|
||||
|
||||
def _with_browse(self, line: QLineEdit, slot) -> QWidget:
|
||||
def _populate_models(self, current: str | None) -> None:
|
||||
self.model_combo.clear()
|
||||
for name, path in discover_models():
|
||||
self.model_combo.addItem(name, path)
|
||||
# Keep an externally-configured model selectable even if it's outside the folder.
|
||||
if current and self.model_combo.findData(current) < 0:
|
||||
self.model_combo.addItem(Path(current).stem + " (внешняя)", current)
|
||||
if self.model_combo.count() == 0:
|
||||
self.model_combo.addItem("(модели не найдены — положите в models/deepmosaics)", None)
|
||||
idx = self.model_combo.findData(current) if current else 0
|
||||
self.model_combo.setCurrentIndex(max(0, idx))
|
||||
|
||||
def _with_browse(self, widget: QWidget, slot) -> QWidget:
|
||||
w = QWidget()
|
||||
h = QHBoxLayout(w)
|
||||
h.setContentsMargins(0, 0, 0, 0)
|
||||
h.addWidget(line, 1)
|
||||
btn = QPushButton("…")
|
||||
btn.setMaximumWidth(32)
|
||||
h.addWidget(widget, 1)
|
||||
btn = QPushButton("Обзор…")
|
||||
btn.clicked.connect(slot)
|
||||
h.addWidget(btn)
|
||||
return w
|
||||
|
||||
def _sync(self) -> None:
|
||||
is_dm = self.engine.currentData() == "deepmosaics"
|
||||
for w in (self.dm_dir, self.dm_model, self.dm_python, self.dm_gpu):
|
||||
w.setEnabled(is_dm)
|
||||
|
||||
def _browse_dir(self) -> None:
|
||||
d = QFileDialog.getExistingDirectory(self, "Папка DeepMosaics", self.dm_dir.text())
|
||||
if d:
|
||||
self.dm_dir.setText(d)
|
||||
self.model_combo.setEnabled(is_dm)
|
||||
self.dm_gpu.setEnabled(is_dm)
|
||||
|
||||
def _browse_model(self) -> None:
|
||||
start = self.dm_model.text() or self.dm_dir.text()
|
||||
p, _ = QFileDialog.getOpenFileName(self, "Веса DeepMosaics", start, "Веса (*.pth);;Все файлы (*.*)")
|
||||
p, _ = QFileDialog.getOpenFileName(self, "Веса DeepMosaics", "", "Веса (*.pth);;Все файлы (*.*)")
|
||||
if p:
|
||||
self.dm_model.setText(p)
|
||||
|
||||
def _browse_python(self) -> None:
|
||||
p, _ = QFileDialog.getOpenFileName(self, "Python для DeepMosaics", self.dm_python.text(), "python (*.exe);;Все файлы (*.*)")
|
||||
if p:
|
||||
self.dm_python.setText(p)
|
||||
if self.model_combo.findData(p) < 0:
|
||||
self.model_combo.addItem(Path(p).stem, p)
|
||||
self.model_combo.setCurrentIndex(self.model_combo.findData(p))
|
||||
|
||||
def apply_to_config(self) -> None:
|
||||
self._cfg.restorer = self.engine.currentData()
|
||||
self._cfg.dm_dir = self.dm_dir.text().strip() or None
|
||||
self._cfg.dm_model = self.dm_model.text().strip() or None
|
||||
self._cfg.dm_python = self.dm_python.text().strip() or None
|
||||
self._cfg.dm_model = self.model_combo.currentData()
|
||||
self._cfg.dm_gpu = self.dm_gpu.text().strip() or "0"
|
||||
|
||||
Reference in New Issue
Block a user