Add -Upscale parameter to Clone-Image.ps1 for AI upscaling with upscayl-bin before ffmpeg processing, add -Model and -Keep parameters for model selection and output preservation, and update Stich-InBetween.ps1 to use RIFE_HOME and NCNN_GPU_ID environment variables for TNTwise fork compatibility
This commit is contained in:
+169
-1
@@ -27,6 +27,23 @@
|
||||
(0-6, higher means smaller files but slower encoding). Ignored for jpeg, avif, bmp and tiff.
|
||||
.PARAMETER Metadata
|
||||
When present, copies available metadata from the source image file to the target image file.
|
||||
.PARAMETER Upscale
|
||||
Optional upscaling factor (2, 3 or 4) applied to the source image with upscayl-bin.exe
|
||||
before ffmpeg runs. The upscaled image is written to a Windows temp PNG and used as the
|
||||
ffmpeg input, so any -Size / -LTX cover-scale-then-crop is applied to the upscaled image.
|
||||
Requires upscayl-bin.exe in PATH, the UPSCAYL_HOME environment variable pointing to the
|
||||
upscayl-bin install directory, and the NCNN_GPU_ID environment variable set to the desired
|
||||
GPU device ID (-1 for CPU, 0/1/2/... for GPU).
|
||||
.PARAMETER Model
|
||||
Upscayl model name (without extension) to use when -Upscale is specified. Defaults to
|
||||
'4xNomos8kSC'. The model files (<Model>.bin and <Model>.param) must exist under
|
||||
%UPSCAYL_HOME%\models. Ignored when -Upscale is not specified.
|
||||
.PARAMETER Keep
|
||||
Optional path to save a copy of the upscayl-bin output (i.e. the upscaled image, before
|
||||
ffmpeg's cover-scale-then-crop). The file extension determines the format; if it differs
|
||||
from .png (the upscayl output format) the temp PNG is converted with ffmpeg using the
|
||||
appropriate per-format encoder. If the extension is missing or unrecognised, .png is
|
||||
appended. Only valid when -Upscale is specified.
|
||||
.PARAMETER LTX
|
||||
When present, overrides the dimensions selected by -Size with the closest LTX-2 (Wan2GP by DeepBeepMeep)
|
||||
canonical resolution for the source's aspect ratio. Only valid when -Size is one of HD, 1080p, 720p or 480p.
|
||||
@@ -61,7 +78,17 @@ param(
|
||||
[switch]$Metadata,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[switch]$LTX
|
||||
[switch]$LTX,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[ValidateSet(0, 2, 3, 4)]
|
||||
[int]$Upscale = 0,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$Model = '4xNomos8kSC',
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$Keep = $null
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
@@ -259,6 +286,142 @@ switch ($targetFormat) {
|
||||
}
|
||||
}
|
||||
|
||||
# --- Optional upscayl-bin upscaling step (runs before ffmpeg). ---
|
||||
# When -Upscale is given (2/3/4) the source image is upscaled with upscayl-bin
|
||||
# into a temp PNG; that temp PNG then becomes the ffmpeg input so any -Size /
|
||||
# -LTX cover-scale-then-crop is applied to the already-upscaled image.
|
||||
$upscaledTempPath = $null
|
||||
if ($Upscale -gt 0) {
|
||||
$upscaylExe = Get-Command -Name 'upscayl-bin.exe' -ErrorAction SilentlyContinue
|
||||
if (-not $upscaylExe) {
|
||||
Write-Error 'upscayl-bin.exe not found in PATH. Install upscayl-bin and add it to the system PATH (see mkdocs/Upscalers.md).'
|
||||
exit 1
|
||||
}
|
||||
$upscaylExePath = $upscaylExe.Source
|
||||
|
||||
$upscaylHome = $env:UPSCAYL_HOME
|
||||
if (-not $upscaylHome) {
|
||||
Write-Error 'UPSCAYL_HOME environment variable is not set. Set it to the upscayl-bin install directory.'
|
||||
exit 1
|
||||
}
|
||||
$upscaylHome = $upscaylHome.TrimEnd('\', '/')
|
||||
if (-not (Test-Path -LiteralPath $upscaylHome -PathType Container)) {
|
||||
Write-Error ('UPSCAYL_HOME directory does not exist: {0}' -f $upscaylHome)
|
||||
exit 1
|
||||
}
|
||||
|
||||
$modelsDir = Join-Path $upscaylHome 'models'
|
||||
if (-not (Test-Path -LiteralPath $modelsDir -PathType Container)) {
|
||||
Write-Error ('Upscayl models directory not found: {0}' -f $modelsDir)
|
||||
exit 1
|
||||
}
|
||||
$modelBin = Join-Path $modelsDir ('{0}.bin' -f $Model)
|
||||
$modelParam = Join-Path $modelsDir ('{0}.param' -f $Model)
|
||||
if (-not (Test-Path -LiteralPath $modelBin -PathType Leaf) -or -not (Test-Path -LiteralPath $modelParam -PathType Leaf)) {
|
||||
Write-Error ('Upscayl model files not found for model ''{0}'' under {1} (expected {0}.bin and {0}.param).' -f $Model, $modelsDir)
|
||||
exit 1
|
||||
}
|
||||
|
||||
$gpuId = $env:NCNN_GPU_ID
|
||||
if (-not $gpuId) {
|
||||
Write-Error 'NCNN_GPU_ID environment variable is not set. Set it to -1 (CPU) or 0/1/2/... (GPU device index).'
|
||||
exit 1
|
||||
}
|
||||
if ($gpuId -notmatch '^-?\d+$') {
|
||||
Write-Error ('NCNN_GPU_ID must be an integer (-1 for CPU, 0+ for GPU). Current value: {0}' -f $gpuId)
|
||||
exit 1
|
||||
}
|
||||
|
||||
$upscaledTempPath = Join-Path ([System.IO.Path]::GetTempPath()) (('upscayl-{0}.png') -f ([System.Guid]::NewGuid().ToString()))
|
||||
|
||||
Write-Host ('Upscaling source with upscayl-bin (x{0}, model={1}, gpu={2})...' -f $Upscale, $Model, $gpuId)
|
||||
Write-Host (' Upscayl temp file: {0}' -f $upscaledTempPath)
|
||||
|
||||
if ($PSCmdlet.ShouldProcess($SourcePath, ('Upscale x{0} with upscayl-bin into temp file' -f $Upscale))) {
|
||||
$upscaylOutput = & $upscaylExePath -i $SourcePath -o $upscaledTempPath -s $Upscale.ToString() -n $Model -m $modelsDir -g $gpuId 2>&1
|
||||
$upscaylExit = $LASTEXITCODE
|
||||
if ($upscaylExit -ne 0) {
|
||||
Write-Host 'upscayl-bin error output:' -ForegroundColor Red
|
||||
$upscaylOutput | ForEach-Object { Write-Host $_ }
|
||||
Write-Error ('upscayl-bin failed with exit code: {0}' -f $upscaylExit)
|
||||
if (Test-Path -LiteralPath $upscaledTempPath) { Remove-Item -LiteralPath $upscaledTempPath -Force -ErrorAction SilentlyContinue }
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Switch ffmpeg's input to the upscaled image.
|
||||
$SourcePath = $upscaledTempPath
|
||||
|
||||
# Refresh informational source dimensions from the upscaled file.
|
||||
$ffprobeDimOutput2 = & ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=p=0:s=x -- $SourcePath 2>&1
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
$dimLine2 = $ffprobeDimOutput2 | Select-Object -First 1
|
||||
if ($dimLine2) {
|
||||
$sourceDimensions = ([string]$dimLine2).Trim() + (' (upscaled x{0})' -f $Upscale)
|
||||
}
|
||||
}
|
||||
|
||||
# --- Optional -Keep: save a copy of the upscaled image. ---
|
||||
if (-not [string]::IsNullOrWhiteSpace($Keep)) {
|
||||
$KeepPath = $Keep
|
||||
$keepExt = [System.IO.Path]::GetExtension($KeepPath).ToLowerInvariant()
|
||||
if ($supportedTargetExts -notcontains $keepExt) {
|
||||
$KeepPath += '.png'
|
||||
$keepExt = '.png'
|
||||
}
|
||||
$KeepDir = Split-Path -Parent $KeepPath
|
||||
if ($KeepDir -and -not (Test-Path -LiteralPath $KeepDir)) {
|
||||
Write-Error ('Keep target directory does not exist: {0}' -f $KeepDir)
|
||||
if (Test-Path -LiteralPath $upscaledTempPath) { Remove-Item -LiteralPath $upscaledTempPath -Force -ErrorAction SilentlyContinue }
|
||||
exit 1
|
||||
}
|
||||
|
||||
if ($keepExt -eq '.png') {
|
||||
# Upscayl already wrote a PNG; just copy.
|
||||
if ($PSCmdlet.ShouldProcess($KeepPath, 'Copy upscaled image (PNG)')) {
|
||||
Copy-Item -LiteralPath $upscaledTempPath -Destination $KeepPath -Force
|
||||
Write-Host ('Upscaled image saved to: {0}' -f $KeepPath)
|
||||
}
|
||||
} else {
|
||||
# Convert PNG -> requested format with ffmpeg, using sane defaults.
|
||||
switch ($keepExt) {
|
||||
'.jpg' { $keepFormat = 'jpeg' }
|
||||
'.jpeg' { $keepFormat = 'jpeg' }
|
||||
'.tif' { $keepFormat = 'tiff' }
|
||||
'.tiff' { $keepFormat = 'tiff' }
|
||||
default { $keepFormat = $keepExt.TrimStart('.') }
|
||||
}
|
||||
$keepEncoderArgs = @()
|
||||
switch ($keepFormat) {
|
||||
'jpeg' { $keepEncoderArgs += @('-c:v', 'mjpeg', '-pix_fmt', 'yuvj420p', '-q:v', '2') }
|
||||
'webp' { $keepEncoderArgs += @('-c:v', 'libwebp', '-quality', '90') }
|
||||
'avif' { $keepEncoderArgs += @('-c:v', 'libaom-av1', '-still-picture', '1', '-cpu-used', '4', '-crf', '25') }
|
||||
'bmp' { $keepEncoderArgs += @('-c:v', 'bmp') }
|
||||
'tiff' { $keepEncoderArgs += @('-c:v', 'tiff') }
|
||||
'png' { $keepEncoderArgs += @('-c:v', 'png') }
|
||||
}
|
||||
Write-Host ('Converting upscaled image to {0}: {1}' -f $keepFormat, $KeepPath)
|
||||
if ($PSCmdlet.ShouldProcess($KeepPath, ('Save upscaled image as {0}' -f $keepFormat))) {
|
||||
$keepFfmpegArgs = @('-y', '-i', $upscaledTempPath) + $keepEncoderArgs + @('-frames:v', '1', '-map_metadata', '-1', '--', $KeepPath)
|
||||
$keepFfmpegOutput = & ffmpeg @keepFfmpegArgs 2>&1
|
||||
$keepFfmpegExit = $LASTEXITCODE
|
||||
if ($keepFfmpegExit -ne 0) {
|
||||
Write-Host 'ffmpeg error output (Keep step):' -ForegroundColor Red
|
||||
$keepFfmpegOutput | ForEach-Object { Write-Host $_ }
|
||||
Write-Error ('ffmpeg failed to save upscaled image (-Keep) with exit code: {0}' -f $keepFfmpegExit)
|
||||
if (Test-Path -LiteralPath $upscaledTempPath) { Remove-Item -LiteralPath $upscaledTempPath -Force -ErrorAction SilentlyContinue }
|
||||
exit 1
|
||||
}
|
||||
Write-Host ('Upscaled image saved to: {0}' -f $KeepPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-not [string]::IsNullOrWhiteSpace($Keep) -and $Upscale -le 0) {
|
||||
Write-Warning '-Keep was specified without -Upscale; ignoring (nothing to save).'
|
||||
}
|
||||
|
||||
Write-Host ('Cloning image: {0}' -f $SourcePath)
|
||||
Write-Host (' Target format: {0}' -f $targetFormat)
|
||||
if ($sourceDimensions) {
|
||||
@@ -316,3 +479,8 @@ if ($PSCmdlet.ShouldProcess($TargetPath, 'Clone image file')) {
|
||||
|
||||
Write-Host ('Image cloned successfully to: {0}' -f $TargetPath)
|
||||
}
|
||||
|
||||
# --- Clean up the upscayl temp file (if any). ---
|
||||
if ($upscaledTempPath -and (Test-Path -LiteralPath $upscaledTempPath)) {
|
||||
Remove-Item -LiteralPath $upscaledTempPath -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
+36
-7
@@ -41,12 +41,17 @@
|
||||
|
||||
.NOTES
|
||||
Requires:
|
||||
- rife-ncnn-vulkan.exe in the system PATH
|
||||
- rife-ncnn-vulkan.exe (TNTwise fork, RIFE 4.26) in the system PATH
|
||||
- The RIFE_HOME environment variable set to the rife-ncnn-vulkan install directory
|
||||
(the same directory that is on PATH; it must contain the rife-v4.26 model folder)
|
||||
- The NCNN_GPU_ID environment variable set to the desired GPU device ID
|
||||
(-1 for CPU, 0/1/2/etc. for GPU) passed to rife-ncnn-vulkan via the -g flag
|
||||
- ffmpeg in the system PATH
|
||||
- PowerShell 7 or later
|
||||
|
||||
The script automatically locates rife-ncnn-vulkan.exe from PATH and expects
|
||||
the rife-v4 model directory to be in the same directory as the executable.
|
||||
The script locates rife-ncnn-vulkan.exe from PATH and resolves the rife-v4.26
|
||||
model directory from %RIFE_HOME%\rife-v4.26. The GPU device is selected from
|
||||
%NCNN_GPU_ID%.
|
||||
|
||||
Supports -WhatIf and -Confirm for safe execution.
|
||||
#>
|
||||
@@ -161,15 +166,39 @@ if (-not $rifeExe) {
|
||||
}
|
||||
|
||||
$rifeExePath = $rifeExe.Source
|
||||
$rifeDir = Split-Path -Parent $rifeExePath
|
||||
$rifeModelPath = Join-Path $rifeDir "rife-v4"
|
||||
|
||||
# Resolve the model directory via RIFE_HOME (required by the TNTwise fork's
|
||||
# install layout, see mkdocs/RIFE.md). RIFE_HOME must point to the install
|
||||
# folder containing the rife-v4.26 model directory.
|
||||
$rifeHome = $env:RIFE_HOME
|
||||
if (-not $rifeHome) {
|
||||
throw "RIFE_HOME environment variable is not set. Set it to the rife-ncnn-vulkan install directory (the same folder that is on PATH)."
|
||||
}
|
||||
$rifeHome = $rifeHome.TrimEnd('\', '/')
|
||||
|
||||
if (-not (Test-Path -LiteralPath $rifeHome -PathType Container)) {
|
||||
throw "RIFE_HOME directory does not exist: $rifeHome"
|
||||
}
|
||||
|
||||
$rifeModelPath = Join-Path $rifeHome "rife-v4.26"
|
||||
|
||||
if (-not (Test-Path -LiteralPath $rifeModelPath -PathType Container)) {
|
||||
throw "RIFE model directory not found at: $rifeModelPath"
|
||||
throw "RIFE model directory not found at: $rifeModelPath. Ensure the rife-v4.26 model folder ships under %RIFE_HOME%."
|
||||
}
|
||||
|
||||
# Resolve the GPU device ID for the -g flag from NCNN_GPU_ID.
|
||||
$gpuId = $env:NCNN_GPU_ID
|
||||
if (-not $gpuId) {
|
||||
throw "NCNN_GPU_ID environment variable is not set. Set it to -1 (CPU) or 0/1/2/etc. (GPU device index)."
|
||||
}
|
||||
if ($gpuId -notmatch '^-?\d+$') {
|
||||
throw "NCNN_GPU_ID must be an integer (-1 for CPU, 0+ for GPU). Current value: $gpuId"
|
||||
}
|
||||
|
||||
Write-Host "Found rife-ncnn-vulkan.exe at: $rifeExePath"
|
||||
Write-Host "Using RIFE_HOME: $rifeHome"
|
||||
Write-Host "Using model path: $rifeModelPath"
|
||||
Write-Host "Using GPU device (-g): $gpuId"
|
||||
|
||||
# --- Prepare TempDir ---
|
||||
|
||||
@@ -190,7 +219,7 @@ if (Test-Path -LiteralPath $tempDirPath) {
|
||||
|
||||
if ($PSCmdlet.ShouldProcess($TempDir, "Generate interpolated frames with rife-ncnn-vulkan (Count=$Count)")) {
|
||||
Write-Host "Executing rife-ncnn-vulkan.exe (Count=$Count, EndsAt=$EndsAt)..."
|
||||
& $rifeExePath -0 $FirstFilename -1 $LastFilename -i $InputTempDir -o $TempDir -n $Count -m $rifeModelPath
|
||||
& $rifeExePath -0 $FirstFilename -1 $LastFilename -i $InputTempDir -o $TempDir -n $Count -m $rifeModelPath -g $gpuId
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "rife-ncnn-vulkan.exe failed with exit code $LASTEXITCODE"
|
||||
|
||||
Reference in New Issue
Block a user