ACMX 2.136.0
Dual-Backend Real-Time GPU Video Synthesis
Loading...
Searching...
No Matches
deep-dream-settings.cpp
Go to the documentation of this file.
2
3#include "custom_style.hpp"
4
5#include <QCheckBox>
6#include <QComboBox>
7#include <QDialogButtonBox>
8#include <QDoubleSpinBox>
9#include <QFile>
10#include <QFileDialog>
11#include <QFileInfo>
12#include <QFormLayout>
13#include <QGroupBox>
14#include <QHBoxLayout>
15#include <QJsonArray>
16#include <QJsonDocument>
17#include <QJsonObject>
18#include <QJsonParseError>
19#include <QLabel>
20#include <QLineEdit>
21#include <QMessageBox>
22#include <QPushButton>
23#include <QRandomGenerator>
24#include <QRegularExpression>
25#include <QScrollArea>
26#include <QSettings>
27#include <QSpinBox>
28#include <QStringList>
29#include <QVBoxLayout>
30
31#include <array>
32
34 QWidget *parent)
35 : QDialog(parent), gpu_filter_available(gpu_filter_enabled) {
36 setWindowTitle("Deep Dream Settings");
37 setMinimumSize(560, 620);
38
39 enable_check_box = new QCheckBox("Enable Deep Dream", this);
40 model_file_edit = new QLineEdit(this);
41 model_file_edit->setReadOnly(true);
42 model_file_edit->setPlaceholderText("Select a TorchScript .pt model...");
43 browse_model_button = new QPushButton("Browse...", this);
44 model_metadata_label = new QLabel(this);
45 model_metadata_label->setTextFormat(Qt::PlainText);
46 model_metadata_label->setWordWrap(true);
47
48 layer_combo_box = new QComboBox(this);
49 layer_combo_box->setEditable(true);
50 layer_combo_box->addItems(
51 {"relu1_1", "relu1_2", "relu2_1", "relu2_2", "relu3_1",
52 "relu3_2", "relu3_3", "relu4_1", "relu4_2", "relu4_3",
53 "relu5_1", "relu5_2", "relu5_3"});
54
55 iterations_spin_box = new QSpinBox(this);
56 iterations_spin_box->setRange(1, 100);
57 strength_spin_box = new QDoubleSpinBox(this);
58 strength_spin_box->setRange(0.0001, 10.0);
59 strength_spin_box->setDecimals(4);
60 strength_spin_box->setSingleStep(0.01);
61 feedback_spin_box = new QDoubleSpinBox(this);
62 feedback_spin_box->setRange(0.0, 0.99);
63 feedback_spin_box->setDecimals(3);
64 feedback_spin_box->setSingleStep(0.05);
65 zoom_spin_box = new QDoubleSpinBox(this);
66 zoom_spin_box->setRange(0.9, 1.1);
67 zoom_spin_box->setDecimals(4);
68 zoom_spin_box->setSingleStep(0.005);
69 rotation_spin_box = new QDoubleSpinBox(this);
70 rotation_spin_box->setRange(-5.0, 5.0);
71 rotation_spin_box->setDecimals(3);
72 rotation_spin_box->setSingleStep(0.1);
73
74 native_size_check_box = new QCheckBox("Use native input size", this);
75 maximum_dimension_spin_box = new QSpinBox(this);
76 maximum_dimension_spin_box->setRange(64, 4096);
77 maximum_dimension_spin_box->setSingleStep(64);
78 maximum_dimension_spin_box->setSuffix(" px");
79 fp16_check_box = new QCheckBox("Use FP16", this);
80 fp16_check_box->setToolTip(
81 "Use half-precision model and working tensors to reduce CUDA memory "
82 "and improve performance.");
83 channel_spin_box = new QSpinBox(this);
84 channel_spin_box->setRange(-1, 65535);
85 channel_spin_box->setSpecialValueText("All channels");
86 octaves_spin_box = new QSpinBox(this);
87 octaves_spin_box->setRange(1, 8);
88 octave_scale_spin_box = new QDoubleSpinBox(this);
89 octave_scale_spin_box->setRange(1.1, 3.0);
90 octave_scale_spin_box->setDecimals(2);
91 octave_scale_spin_box->setSingleStep(0.1);
92 jitter_spin_box = new QSpinBox(this);
93 jitter_spin_box->setRange(0, 64);
94 jitter_spin_box->setSuffix(" px");
95 smoothing_spin_box = new QSpinBox(this);
96 smoothing_spin_box->setRange(0, 16);
97 smoothing_spin_box->setSuffix(" px");
99 new QCheckBox("Run acidcam-gpu filters before Deep Dream", this);
100 gpu_filter_first_check_box->setToolTip(
102 ? "Transform the CUDA source with acidcam-gpu before LibTorch."
103 : "Enable an acidcam-gpu filter chain first.");
105 new QCheckBox("Independent-frame preview (--deep-orig)", this);
106 deep_original_check_box->setToolTip(
107 "Process each video frame independently without temporal feedback, "
108 "zoom, or rotation. Fully applies on the next launch.");
109
110 auto *model_group = new QGroupBox("Model", this);
111 auto *model_layout = new QFormLayout(model_group);
112 auto *model_row = new QHBoxLayout;
113 model_row->addWidget(model_file_edit, 1);
114 model_row->addWidget(browse_model_button);
115 model_layout->addRow("TorchScript model:", model_row);
116 model_layout->addRow("Model information:", model_metadata_label);
117 model_layout->addRow("Feature layer:", layer_combo_box);
118
119 auto *dream_group = new QGroupBox("Gradient Ascent", this);
120 auto *dream_layout = new QFormLayout(dream_group);
121 dream_layout->addRow("Iterations:", iterations_spin_box);
122 dream_layout->addRow("Strength:", strength_spin_box);
123 dream_layout->addRow("Target channel:", channel_spin_box);
124 dream_layout->addRow("Octaves:", octaves_spin_box);
125 dream_layout->addRow("Octave scale:", octave_scale_spin_box);
126 dream_layout->addRow("Spatial jitter:", jitter_spin_box);
127 dream_layout->addRow("Gradient smoothing:", smoothing_spin_box);
128
129 auto *feedback_group = new QGroupBox("Temporal Feedback", this);
130 auto *feedback_layout = new QFormLayout(feedback_group);
131 feedback_layout->addRow("Previous-frame blend:", feedback_spin_box);
132 feedback_layout->addRow("Feedback zoom:", zoom_spin_box);
133 feedback_layout->addRow("Feedback rotation:", rotation_spin_box);
134
135 auto *performance_group = new QGroupBox("Performance and Pipeline", this);
136 auto *performance_layout = new QFormLayout(performance_group);
137 performance_layout->addRow(native_size_check_box);
138 performance_layout->addRow("Maximum dimension:",
140 performance_layout->addRow(fp16_check_box);
141 performance_layout->addRow(deep_original_check_box);
142
143 auto *contents = new QWidget(this);
144 auto *contents_layout = new QVBoxLayout(contents);
145 contents_layout->addWidget(enable_check_box);
146 contents_layout->addWidget(gpu_filter_first_check_box);
147 contents_layout->addWidget(model_group);
148 contents_layout->addWidget(dream_group);
149 contents_layout->addWidget(feedback_group);
150 contents_layout->addWidget(performance_group);
151 contents_layout->addStretch();
152
153 auto *scroll_area = new QScrollArea(this);
154 scroll_area->setWidgetResizable(true);
155 scroll_area->setWidget(contents);
156
157 auto *buttons = new QDialogButtonBox(
158 QDialogButtonBox::Ok | QDialogButtonBox::Apply |
159 QDialogButtonBox::Cancel,
160 this);
161 QPushButton *randomize_button =
162 buttons->addButton("Randomize", QDialogButtonBox::ActionRole);
163 randomize_button->setToolTip(
164 "Generate and immediately apply a random Deep Dream preset.");
165 auto *layout = new QVBoxLayout(this);
166 layout->addWidget(scroll_area, 1);
167 layout->addWidget(buttons);
168
169 connect(enable_check_box, &QCheckBox::toggled, this,
170 [this](bool) { update_enabled_state(); });
171 connect(native_size_check_box, &QCheckBox::toggled, this,
172 [this](bool) { update_enabled_state(); });
173 connect(deep_original_check_box, &QCheckBox::toggled, this,
174 [this](bool) { update_enabled_state(); });
175 connect(browse_model_button, &QPushButton::clicked, this,
177 connect(buttons, &QDialogButtonBox::accepted, this,
179 connect(buttons->button(QDialogButtonBox::Apply), &QPushButton::clicked,
181 connect(randomize_button, &QPushButton::clicked, this,
183 connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
184
189}
190
193 result.enabled = enable_check_box->isChecked();
194 result.model_file = model_file_edit->text().trimmed();
195 result.layer = layer_combo_box->currentText().trimmed();
196 result.iterations = iterations_spin_box->value();
197 result.strength = strength_spin_box->value();
198 result.deep_original = deep_original_check_box->isChecked();
199 result.feedback = result.deep_original ? 0.0 : feedback_spin_box->value();
200 result.zoom = result.deep_original ? 1.0 : zoom_spin_box->value();
201 result.rotation = result.deep_original ? 0.0 : rotation_spin_box->value();
202 result.maximum_dimension =
203 native_size_check_box->isChecked()
204 ? 0
206 result.fp16 = fp16_check_box->isChecked();
207 result.channel = channel_spin_box->value();
208 result.octaves = octaves_spin_box->value();
209 result.octave_scale = octave_scale_spin_box->value();
210 result.jitter = jitter_spin_box->value();
211 result.smoothing = smoothing_spin_box->value();
212 result.gpu_filter_first = gpu_filter_first_check_box->isChecked();
213 return result;
214}
215
217 QSettings settings("LostSideDead", "acmx2");
218 QString directory = settings.value("deep_dream/last_model_directory")
219 .toString();
220 if (directory.isEmpty()) {
221 directory = QFileInfo(model_file_edit->text()).absolutePath();
222 }
223 const QString filename = QFileDialog::getOpenFileName(
224 this, "Select Deep Dream TorchScript Model", directory,
225 "TorchScript Models (*.pt *.pth);;All Files (*)");
226 if (filename.isEmpty()) {
227 return;
228 }
229 model_file_edit->setText(filename);
231 settings.setValue("deep_dream/last_model_directory",
232 QFileInfo(filename).absolutePath());
233}
234
236 const QString model_filename = model_file_edit->text().trimmed();
237 if (model_filename.isEmpty()) {
238 model_metadata_label->setText("Select a model to inspect its layers.");
239 return;
240 }
241
242 const QString metadata_filename = model_filename + ".json";
243 QFile metadata_file(metadata_filename);
244 const QFileInfo metadata_info(metadata_file);
245 QString error;
246 if (!metadata_info.isFile()) {
247 model_metadata_label->setText(
248 "No .pt.json sidecar found; enter a feature layer manually.");
249 return;
250 }
251 constexpr qint64 MAXIMUM_METADATA_BYTES = 1024 * 1024;
252 if (metadata_info.size() <= 0 ||
253 metadata_info.size() > MAXIMUM_METADATA_BYTES) {
254 error = "The model metadata sidecar has an invalid size.";
255 } else if (!metadata_file.open(QIODevice::ReadOnly)) {
256 error = "The model metadata sidecar could not be opened.";
257 }
258
259 QJsonDocument document;
260 if (error.isEmpty()) {
261 QJsonParseError parse_error;
262 document = QJsonDocument::fromJson(metadata_file.readAll(),
263 &parse_error);
264 if (parse_error.error != QJsonParseError::NoError ||
265 !document.isObject()) {
266 error = "The model metadata sidecar is not valid JSON.";
267 }
268 }
269
270 QString architecture;
271 QString default_layer;
272 QStringList layers;
273 int minimum_size = 0;
274 if (error.isEmpty()) {
275 const QJsonObject root = document.object();
276 if (root.value("format").toString() != "acmxvk-deep-dream" ||
277 root.value("version").toInt(-1) != 1) {
278 error = "The sidecar is not supported ACMXVK Deep Dream metadata.";
279 } else {
280 architecture = root.value("architecture").toString().trimmed();
281 default_layer = root.value("default_layer").toString().trimmed();
282 const QJsonArray layer_array = root.value("layers").toArray();
283 static const QRegularExpression name_pattern(
284 QStringLiteral("^[A-Za-z0-9_.-]{1,64}$"));
285 if (!name_pattern.match(architecture).hasMatch() ||
286 layer_array.isEmpty() || layer_array.size() > 256) {
287 error = "The model metadata fields are invalid.";
288 } else {
289 for (const QJsonValue value : layer_array) {
290 const QString name =
291 value.toObject().value("name").toString().trimmed();
292 if (!name_pattern.match(name).hasMatch() ||
293 layers.contains(name)) {
294 error = "The model metadata contains an invalid or duplicate layer.";
295 break;
296 }
297 layers.append(name);
298 }
299 }
300 const QJsonObject input = root.value("input").toObject();
301 minimum_size = input.value("minimum_size").toInt(0);
302 if (error.isEmpty() &&
303 (!layers.contains(default_layer) || minimum_size < 1 ||
304 minimum_size > 4096)) {
305 error = "The model default layer or input size is invalid.";
306 }
307 }
308 }
309
310 if (!error.isEmpty()) {
311 model_metadata_label->setText(error + " Enter a feature layer manually.");
312 model_metadata_label->setToolTip(metadata_filename);
313 if (report_error) {
314 QMessageBox::warning(this, "Invalid Deep Dream Metadata",
315 error + "\n\n" + metadata_filename);
316 }
317 return;
318 }
319
320 const QString selected_layer = layer_combo_box->currentText().trimmed();
321 layer_combo_box->clear();
322 layer_combo_box->addItems(layers);
323 layer_combo_box->setCurrentText(layers.contains(selected_layer)
324 ? selected_layer
325 : default_layer);
326 model_metadata_label->setText(
327 QString("%1, %2 feature layers, minimum input %3 px")
328 .arg(architecture)
329 .arg(layers.size())
330 .arg(minimum_size));
331 model_metadata_label->setToolTip(metadata_filename);
332}
333
335 if (enable_check_box->isChecked()) {
336 const QFileInfo model(model_file_edit->text().trimmed());
337 if (!model.isFile()) {
338 QMessageBox::warning(this, "Deep Dream Model Required",
339 "Select an existing TorchScript model file.");
340 model_file_edit->setFocus();
341 return false;
342 }
343 static const QRegularExpression layer_pattern(
344 QStringLiteral("^[A-Za-z0-9_.-]+$"));
345 if (!layer_pattern.match(layer_combo_box->currentText().trimmed())
346 .hasMatch()) {
347 QMessageBox::warning(
348 this, "Invalid Deep Dream Layer",
349 "Enter a named layer such as relu4_2 or a numeric layer index.");
350 layer_combo_box->setFocus();
351 return false;
352 }
353 if (gpu_filter_first_check_box->isChecked() &&
355 QMessageBox::warning(
356 this, "GPU Filter Required",
357 "Configure and enable an acidcam-gpu filter chain before "
358 "selecting GPU filters before Deep Dream.");
359 return false;
360 }
361 }
362 return true;
363}
364
366 iterations_spin_box->interpretText();
367 strength_spin_box->interpretText();
368 feedback_spin_box->interpretText();
369 zoom_spin_box->interpretText();
370 rotation_spin_box->interpretText();
371 maximum_dimension_spin_box->interpretText();
372 channel_spin_box->interpretText();
373 octaves_spin_box->interpretText();
374 octave_scale_spin_box->interpretText();
375 jitter_spin_box->interpretText();
376 smoothing_spin_box->interpretText();
377}
378
380 if (!QFileInfo(model_file_edit->text().trimmed()).isFile()) {
381 QMessageBox::warning(this, "Deep Dream Model Required",
382 "Select a TorchScript model before randomizing.");
383 model_file_edit->setFocus();
384 return;
385 }
386
387 QRandomGenerator *random = QRandomGenerator::global();
388 enable_check_box->setChecked(true);
389 if (layer_combo_box->count() > 0) {
390 layer_combo_box->setCurrentIndex(
391 random->bounded(layer_combo_box->count()));
392 }
393 iterations_spin_box->setValue(1);
394 strength_spin_box->setValue(0.01 + random->generateDouble() * 0.04);
395 channel_spin_box->setValue(-1);
396 octaves_spin_box->setValue(random->bounded(1, 3));
397 octave_scale_spin_box->setValue(1.2 + random->generateDouble() * 0.4);
398 jitter_spin_box->setValue(random->bounded(0, 5));
399 smoothing_spin_box->setValue(random->bounded(1, 4));
400 feedback_spin_box->setValue(0.55 + random->generateDouble() * 0.35);
401 zoom_spin_box->setValue(0.985 + random->generateDouble() * 0.03);
402 const double rotation_magnitude =
403 0.5 + random->generateDouble() * 2.5;
404 rotation_spin_box->setValue(random->bounded(2) == 0
405 ? -rotation_magnitude
406 : rotation_magnitude);
407 static constexpr std::array<int, 4> RANDOM_DIMENSIONS = {256, 384, 512,
408 640};
409 native_size_check_box->setChecked(false);
411 RANDOM_DIMENSIONS[static_cast<std::size_t>(
412 random->bounded(static_cast<int>(RANDOM_DIMENSIONS.size())))]);
414}
415
418 if (!validate_settings()) {
419 return;
420 }
422 emit settingsApplied();
423}
424
427 if (!validate_settings()) {
428 return;
429 }
431 emit settingsApplied();
432 accept();
433}
434
436 QSettings settings("LostSideDead", "acmx2");
437 enable_check_box->setChecked(
438 settings.value("deep_dream/enabled", false).toBool());
439 model_file_edit->setText(
440 settings.value("deep_dream/model_file", QString()).toString());
441 layer_combo_box->setCurrentText(
442 settings.value("deep_dream/layer", "relu4_2").toString());
443 iterations_spin_box->setValue(
444 settings.value("deep_dream/iterations", 1).toInt());
445 strength_spin_box->setValue(
446 settings.value("deep_dream/strength", 0.05).toDouble());
447 feedback_spin_box->setValue(
448 settings.value("deep_dream/feedback", 0.9).toDouble());
449 zoom_spin_box->setValue(
450 settings.value("deep_dream/zoom", 1.01).toDouble());
451 rotation_spin_box->setValue(
452 settings.value("deep_dream/rotation", 0.1).toDouble());
453 const int maximum_dimension =
454 settings.value("deep_dream/maximum_dimension", 512).toInt();
455 native_size_check_box->setChecked(maximum_dimension == 0);
457 maximum_dimension == 0 ? 512 : maximum_dimension);
458 fp16_check_box->setChecked(
459 settings.value("deep_dream/fp16", false).toBool());
460 channel_spin_box->setValue(
461 settings.value("deep_dream/channel", -1).toInt());
462 octaves_spin_box->setValue(
463 settings.value("deep_dream/octaves", 1).toInt());
464 octave_scale_spin_box->setValue(
465 settings.value("deep_dream/octave_scale", 1.4).toDouble());
466 jitter_spin_box->setValue(
467 settings.value("deep_dream/jitter", 0).toInt());
468 smoothing_spin_box->setValue(
469 settings.value("deep_dream/smoothing", 0).toInt());
470 gpu_filter_first_check_box->setChecked(
472 settings.value("deep_dream/gpu_filter_first", false).toBool());
473 deep_original_check_box->setChecked(
474 settings.value("deep_dream/deep_original", false).toBool());
475}
476
478 const DeepDreamConfiguration current = configuration();
479 QSettings settings("LostSideDead", "acmx2");
480 settings.setValue("deep_dream/enabled", current.enabled);
481 settings.setValue("deep_dream/model_file", current.model_file);
482 settings.setValue("deep_dream/layer", current.layer);
483 settings.setValue("deep_dream/iterations", current.iterations);
484 settings.setValue("deep_dream/strength", current.strength);
485 settings.setValue("deep_dream/feedback", feedback_spin_box->value());
486 settings.setValue("deep_dream/zoom", zoom_spin_box->value());
487 settings.setValue("deep_dream/rotation", rotation_spin_box->value());
488 settings.setValue("deep_dream/maximum_dimension",
489 current.maximum_dimension);
490 settings.setValue("deep_dream/fp16", current.fp16);
491 settings.setValue("deep_dream/channel", current.channel);
492 settings.setValue("deep_dream/octaves", current.octaves);
493 settings.setValue("deep_dream/octave_scale", current.octave_scale);
494 settings.setValue("deep_dream/jitter", current.jitter);
495 settings.setValue("deep_dream/smoothing", current.smoothing);
496 settings.setValue("deep_dream/gpu_filter_first",
497 current.gpu_filter_first);
498 settings.setValue("deep_dream/deep_original", current.deep_original);
499}
500
502 const bool enabled = enable_check_box->isChecked();
503 const std::array<QWidget *, 16> controls = {
510 for (QWidget *widget : controls) {
511 widget->setEnabled(enabled);
512 }
513 maximum_dimension_spin_box->setEnabled(
514 enabled && !native_size_check_box->isChecked());
515 const bool temporal_feedback_enabled =
516 enabled && !deep_original_check_box->isChecked();
517 feedback_spin_box->setEnabled(temporal_feedback_enabled);
518 zoom_spin_box->setEnabled(temporal_feedback_enabled);
519 rotation_spin_box->setEnabled(temporal_feedback_enabled);
520 deep_original_check_box->setEnabled(enabled);
521 gpu_filter_first_check_box->setEnabled(enabled && gpu_filter_available);
523 gpu_filter_first_check_box->setChecked(false);
524 }
525}
QDoubleSpinBox * octave_scale_spin_box
DeepDreamConfiguration configuration() const
void refresh_model_metadata(bool report_error)
DeepDreamSettingsDialog(bool gpu_filter_enabled, QWidget *parent=nullptr)
void applyCustomStyleIfEnabled(QWidget *widget)