Highlights
- Sortable & filterable target media list (new): the target videos/images panel can now be sorted by name, file date, file size, dimensions, total pixels or frame length in either direction, with file-type filters (images / videos / webcams) moved out of the popup menu into a togglable filter row, minimum width/height filters (synchronised slider + spin box), a search reset button, a loading progress bar, and rich tooltips showing name, type, date, size, path, dimensions and video length/frame rate/bitrate. Metadata is probed off the GUI thread (header-only for images, OpenCV properties for videos — no frame decoding), so sorting never blocks the UI.
- VR180 face detectors (new): two dedicated detection models trained on VR180 content — Yolov11 VR180 (960×960) and Yolov12 VR180 (640×640) — selectable from Face Detect Model. These models output boxes only, so 5-point landmarks are synthesised from each bounding box via the canonical ArcFace template offsets and then run through the shared filtering/refinement pipeline.
- Full K/V maps (new): a new Average K/V toggle lets you choose between averaging and full concatenation of the reference K/V maps used by the ReF-LDM denoiser. Embeddings now keep their raw, unbaked K/V tensor lists and merging is deferred to execution time, so switching the toggle takes effect immediately without re-extracting.
- Border Seam Blend (new): a localized blur applied strictly to the outer mask border (morphological gradient based) to hide seams and hard cutoffs, independent of the existing whole-face Final Blend. The old "Final Blend" control is now labelled Final Blend (Whole Face) to make the distinction clear.
- Worker architecture split (new): the monolithic
frame_worker.py(~6,200 lines) was decomposed into a slimFrameWorkerorchestrator plusPipelineProcessor(tensor math / inference / VRAM),StandardProcessor(flat video & images) andVRProcessor(VR180/360), and all model-function calls now route through a newFunctionWorkerfacade that owns the sub-processors centrally — worker threads no longer duplicate sub-processor caches. - Color correction fixes: the CDF-histogram and Reinhard transfer paths now exclude pure-black padding independently for source and target, which removes temporal flickering and the grey halos that could appear at warp edges.
- First-launch execution-provider prompt: on a fresh install (no
last_workspace.json), VisoMaster now asks which execution provider to use before anything loads, so you no longer trigger an unwanted TensorRT engine build on first start. - Legacy TensorRT engine support: engine caches are now written with an explicit per-model prefix, and existing legacy caches (generic
TensorrtExecutionProvider_*naming) are detected and reused instead of being rebuilt. - Schema-aware save/load sanitization: workspaces, jobs, markers and per-face parameters are now validated against the live control/parameter schema on both save and load, instead of against a hardcoded list of removed keys. Obsolete keys are dropped and missing keys fall back to defaults.
- Denoiser color controls simplified: the Denoiser Color Transfer Type selector and Color Strength slider were replaced by a single Color Correction toggle backed by masked Reinhard transfer at full strength.
- Performance: broad micro-optimization pass across the denoiser, restorers, Recast and frame edits — direct tensor indexing instead of
torch.gather, in-placetanh_/add_/mul_/clamp_chains, CPU scalar math instead oftorch.fullallocations,non_blockinghost↔device transfers, directmatmulinstead ofeinsum, cachedarangein head-pose decoding, and Kornia inverse affine warps. - Workspace conveniences: new Save Last Workspace / Reset Last Workspace and Quit / Quit without Saving menu entries, plus an Auto Save Last Workspace setting. Quit routes through
close()socloseEventstill shuts the processing threads down.
Changelog by version
3.9.3
Target media sorting & filtering (app/ui/widgets/sortable_widgets.py, target_videos_list_actions.py) — PR #267:
SortableListWidget/SortableListWidgetItemhold sort keys as item data;targetVideosListis promoted toTargetVideosListWidgetinMainWindow.ui.- Sort by name, file date, file size, dimensions, total pixels or frame length, ascending or descending.
- File type filters (images / videos / webcams) moved from the popup menu into a togglable filter row; new minimum width/height filters with synchronised slider and spin box.
- Search reset button, media-list loading progress bar and rich per-item tooltips.
- Metadata probed via
misc_helpers.probe_media_metadata()in the loader thread and delivered to the GUI thread on thethumbnail_readysignal — images read header-only via PIL, videos via OpenCV properties without decoding a frame. - The filter worker operates purely on a plain-value snapshot captured in the GUI thread; no
QListWidgetItemor card widget crosses a thread boundary. - Sorting tie-breaks on file name so equal keys stay in a predictable order; items with no sort data (webcams) sink to the bottom instead of scrambling the order.
- New icon glyph set for the filter/sort row.
Blend Adjustments:
- Border Seam Blend (
FinalBorderBlendEnableToggle) with Border Seam Blend Amount (1–50, default 5) — localized blur on the outer mask border only, implemented via a morphological gradient in the pipeline processor. - Final Blend renamed to Final Blend (Whole Face) with clarified help text; guarded against a zero sigma.
Denoiser:
- Removed
DenoiserColorTransferTypeSelectionandDenoiserColorSlider; added a single Color Correction toggle (DenoiserColorCorrectionToggle, default ON) that applies masked Reinhard transfer in LAB space at locked 100% strength.
Execution providers & TensorRT:
- First-launch Execution Provider prompt (CUDA / TensorRT / TensorRT-Engine / CPU) when no
last_workspace.jsonexists, applied system-wide before models load — prevents accidental engine generation on a fresh install. _check_tensorrt_cachereplaced by_check_tensorrt_cache_state, which reportsLEGACY(genericTensorrtExecutionProvider_*engine naming),EXPLICIT(custom per-model prefix) orNone. Legacy caches bypass the explicit prefix so existing engines are reused instead of rebuilt.- Engine caches now written with an explicit
trt_engine_cache_prefixper model to prevent collisions and make cleanup predictable. _clean_tensorrt_cachehandles both naming schemes, de-duplicates candidate prefixes, and sweeps auxiliary.profile/.cache/.timingfiles for every candidate prefix.
Save/load & job manager:
- New
sanitize_state_dictionary()validates a loaded control/parameter dict against the live reference dict (unknown keys dropped, missing keys defaulted) andsanitize_markers_dictionary()deep-sanitizes bothcontroland per-faceparametersinside markers. - Replaces
sanitize_removed_settings_controls(),purge_removed_settings_controls(),scrub_removed_settings_from_markers()and theREMOVED_SETTINGS_CONTROL_KEYSblacklist — old workspaces and jobs no longer carry obsolete UI schema keys forward. - Applied consistently on workspace save/load, job save/load and batch job loading.
- New Save Last Workspace / Reset Last Workspace and Quit / Quit without Saving menu entries; new Auto Save Last Workspace setting (writes
last_workspace.jsonto the project root at the end of a recording).
Other:
- Recast model components (
PerformRecastAppearanceFeatureExtractor,…MotionExtractor,…WarpingModule,…SpadeGenerator) are now registered inMODELS_TOGGLE_MAPagainstFaceExpressionEnableBothToggle, so their VRAM is managed with the per-face toggle. - Removed autosorting of the embeddings list (reverts the 3.9.0 alphabetical sort — manual order is preserved again).
3.9.2
VR180 face detection models (face_detectors.py, models_data.py):
- Yolov11 VR180 (
YoloFace11nVR180, trained at 960×960) and Yolov12 VR180 (YoloFace12nVR180, trained at 640×640) added to Face Detect Model. - Both models output boxes only (
output0: [1,5,N]= cx, cy, w, h, score) with no facial keypoints; a new_synthesize_kps_from_bboxes()helper derives 5-point landmarks from the box using canonical ArcFace 112×112 template offsets so the shared filtering/refinement path works unchanged. - Separate
detect_yoloface11_vr180()/detect_yoloface12_vr180()paths with lazy engine build handling, post-rotation normalization and correct score-shape handling. - The VR perspective-grid detection pass now defaults to OFF (it can be re-enabled per project; the dedicated VR180 detectors cover most of what it was compensating for).
3.9.1
Structural changes — worker decomposition:
app/processors/workers/frame_worker.pyreduced from ~6,300 lines to a focusedFrameWorkerorchestrator.- New
frame_worker_pipeline.py(PipelineProcessor): heavy tensor operations, model inference and VRAM management inside the worker's CUDA stream, with LRU-bounded Gabor/convolution kernel caches and EMA-smoothed AutoColor reference statistics. - New
frame_worker_standard.py(StandardProcessor): standard (flat) video and image processing. - New
frame_worker_vr.py(VRProcessor): VR180/360 specific operations. - New
function_worker.py(FunctionWorker): a thread-safe facade that centrally instantiates every sub-processor (detectors, landmarks, masks, restorers, swappers, enhancers, editors, re-aging, Recast, denoiser, frame edits), so worker threads no longer duplicate sub-processor caches andModelsProcessoris decoupled from inference routing. ModelsProcessorslimmed accordingly; every sub-processor now receives the models processor and the function worker, routing calls through the facade.- Follow-up commit completed the
FunctionWorkermigration across the pipeline, sequential detector, video processor and control actions. - Unit tests updated for the new module layout (
test_frame_worker_vr.py,test_face_reaging.py,test_perform_recast.py).
3.9.0
Full K/V maps:
- New Average K/V toggle (
AverageKVToggle, default ON): averages the reference K/V maps, or concatenates the full maps when disabled. - Embedding cards now store the raw, unbaked K/V tensor list (
kv_map_list) and merging is deferred to execution time, so the toggle takes effect without re-extraction; previously saved embeddings with a single bakedkv_mapstill load (backward compatible). handle_average_kv_toggle_change()synchronises the control dict before recalculating per-target-face K/V maps, fixing inverted merge behaviour, and clears the downstream combined VRAM maps.KVExtractor.extract_kv()/get_kv_map_for_face()now accept either a PIL image or a tensor.
Color correction fixes (faceutil.py):
histogram_matching()builds its CDF from non-padding pixels only and restores pure-black padding after LUT application, preventing grey halos at warp edges.histogram_matching_withmask()intersects the user mask with per-image validity masks so CDFs are computed strictly on real facial pixels (no zero-bin bias), with a safe early exit when nothing valid remains.apply_reinhard_color_transfer()computes source and target statistics on independently validated pixel sets, with failsafes for entirely black sources — removes temporal flickering.
Optimizations:
- Denoiser: direct tensor indexing instead of
torch.gather, fused in-place normalization withnon_blockingtransfers, CPU scalar math for the DDIM/single-step alpha terms instead oftorch.fullallocations, and in-placetanh_().add_().mul_().clamp_()chains on the pre-allocated decode buffer. - Recast / restorers / frame edits:
non_blockingmatrix uploads, in-place math on freshly allocated tensors, direct inverse GPU affine warps via Kornia,matmulinstead ofeinsum, a staticarangecache in head-pose decoding, and removal of redundantdel/try-except overhead. KVExtractorpadding path cleaned up.- Embeddings list gained alphabetical autosorting (removed again in 3.9.3).
- Robustness: control lookups in
calculate_assigned_input_embedding()use.get()with defaults, plus added type hints.
Contributors in this range
@Elricfae, @Glat0s, @mr-szgz — thanks to everyone who contributed code, fixes and reviews.
Upgrade notes
- Portable launcher users: download the latest
Start_Portable.batattached to this release (or via the "latest" link in the README). - No manual migration steps required; the launcher's dependency update handles environment changes on next start.
- The Yolov11 VR180 / Yolov12 VR180 detection models are downloaded on demand the first time you select them.
- Existing TensorRT engine caches are detected and reused — engines built by earlier versions do not need to be rebuilt.
- Workspaces and saved jobs from earlier versions load normally; the removed denoiser Color Transfer Type / Color Strength entries are sanitized out automatically and unknown keys now fall back to their defaults.
- On a fresh install (no
last_workspace.json), you will be asked to pick an execution provider on first launch. Choose CUDA or CPU if you want to avoid generating TensorRT engines during that first session.