Update super resolution, add frame generation and true HDR (#42)
This commit is contained in:
@@ -1,5 +1,151 @@
|
||||
# Nvidia_RTX_Nodes_ComfyUI
|
||||
# NVIDIA RTX Nodes for ComfyUI
|
||||
|
||||
Contains the "RTX Video Super Resolution" upscaling node to upscale images and videos. Only works on Nvidia RTX GPUs.
|
||||
CUDA-accelerated ComfyUI nodes powered by the NVIDIA Video Effects (VFX) SDK and its `nvidia-vfx` Python bindings.
|
||||
|
||||
Search RTX in the ComfyUI manager to install it.
|
||||
This extension provides:
|
||||
|
||||
- **RTX Video Super Resolution** — upscale, denoise, deblur, or enhance images and video frames.
|
||||
- **RTX TrueHDR** — convert SDR images to normalized BT.2020/PQ or BT.2020/HLG HDR image data.
|
||||
- **RTX Video Frame Generation** — interpolate frames between adjacent images for frame-rate conversion or slow motion.
|
||||
|
||||
## Requirements
|
||||
|
||||
- An NVIDIA RTX GPU
|
||||
- A working ComfyUI installation with CUDA-enabled PyTorch
|
||||
- A Python environment supported by the [`nvidia-vfx`](https://pypi.org/project/nvidia-vfx/) package
|
||||
|
||||
The nodes use the CUDA device selected by ComfyUI. CPU-only execution and non-NVIDIA GPUs are not supported.
|
||||
|
||||
## Installation
|
||||
|
||||
### ComfyUI Manager
|
||||
|
||||
1. Open **ComfyUI Manager**.
|
||||
2. Search for **ComfyUI_NVIDIA_RTX_Nodes**.
|
||||
3. Install the extension and restart ComfyUI.
|
||||
|
||||
### Manual installation
|
||||
|
||||
Clone the repository into `ComfyUI/custom_nodes`, then install its dependency with the Python interpreter used by ComfyUI:
|
||||
|
||||
```bash
|
||||
cd ComfyUI/custom_nodes
|
||||
git clone https://github.com/Comfy-Org/Nvidia_RTX_Nodes_ComfyUI.git
|
||||
cd Nvidia_RTX_Nodes_ComfyUI
|
||||
python -m pip install -r requirements.txt
|
||||
```
|
||||
|
||||
Restart ComfyUI after installation.
|
||||
|
||||
## RTX Video Super Resolution
|
||||
|
||||
Find the node under **image/upscaling**. It accepts a ComfyUI `IMAGE` batch and returns `upscaled_images` as another `IMAGE` batch.
|
||||
|
||||
### Inputs
|
||||
|
||||
| Input | Values | Description |
|
||||
| --- | --- | --- |
|
||||
| `images` | `IMAGE` batch | Images or decoded video frames to process. |
|
||||
| `resize_type` | `scale by multiplier` / `target dimensions` | Selects how upscaled output dimensions are calculated. |
|
||||
| `scale` | `1.00`–`4.00`, default `2.00` | Width and height multiplier. Available when scaling by multiplier. |
|
||||
| `width` | `64`–`8192`, default `1920` | Requested output width. Available for target dimensions. |
|
||||
| `height` | `64`–`8192`, default `1080` | Requested output height. Available for target dimensions. |
|
||||
| `quality` | See below; default `ULTRA` | Selects the VFX processing model. |
|
||||
| `strength` | `0.00`–`1.00`, default `1.00` | Effect strength. |
|
||||
| `image_encoding` | `8-bit RGB` / `10-bit RGB (RGB10A2)` | Pixel encoding used internally by the SDK. |
|
||||
|
||||
The 10-bit option packs ComfyUI's normalized RGB values into RGB10A2 before inference and unpacks the result back to a normal ComfyUI `IMAGE`. It preserves more precision but does not convert SDR content to HDR.
|
||||
|
||||
### Quality modes
|
||||
|
||||
| Modes | Operation |
|
||||
| --- | --- |
|
||||
| `BICUBIC` | Non-AI bicubic interpolation. |
|
||||
| `LOW`, `MEDIUM`, `HIGH`, `ULTRA` | Standard AI upscaling for typical compressed sources, from fastest to maximum detail preservation. |
|
||||
| `DENOISE_LOW`, `DENOISE_MEDIUM`, `DENOISE_HIGH`, `DENOISE_ULTRA` | Same-resolution noise and compression-artifact removal. Higher levels remove more noise but may soften texture. |
|
||||
| `DEBLUR_LOW`, `DEBLUR_MEDIUM`, `DEBLUR_HIGH`, `DEBLUR_ULTRA` | Same-resolution sharpening for soft or blurry sources. |
|
||||
| `HIGHBITRATE_LOW`, `HIGHBITRATE_MEDIUM`, `HIGHBITRATE_HIGH`, `HIGHBITRATE_ULTRA` | AI upscaling for clean, high-bitrate, or lossless sources; avoids unnecessary artifact suppression. |
|
||||
| `STREAMING_MEDIUM`, `STREAMING_ULTRA` | Upscaling optimized for broadcast and webcam streams. |
|
||||
|
||||
`DENOISE_*` and `DEBLUR_*` always keep the input dimensions, regardless of the selected resize settings. All other modes use the requested output size, rounded to the nearest multiple of 8. To limit working memory, the node chooses a chunk size targeting no more than 16 megapixels of output at once, with a minimum of one frame per chunk.
|
||||
|
||||
### Image workflow
|
||||
|
||||
Connect an image batch to **RTX Video Super Resolution**, choose an operation and settings, then connect `upscaled_images` to **Save Image** or another image node.
|
||||
|
||||

|
||||
|
||||
### Video workflow
|
||||
|
||||
Decode a video to an `IMAGE` batch, process the frames, and pass the result to video creation/encoding nodes. Super Resolution changes frame dimensions but not frame count or frame rate.
|
||||
|
||||

|
||||
|
||||
Importable Super Resolution examples are available in [`example_workflows`](example_workflows):
|
||||
|
||||
- [`rtx_image_upscale.json`](example_workflows/rtx_image_upscale.json)
|
||||
- [`rtx_video_upscale.json`](example_workflows/rtx_video_upscale.json)
|
||||
|
||||
## RTX TrueHDR
|
||||
|
||||
Find the node under **image/enhancement**. It converts each SDR input image with NVIDIA RTX TrueHDR and returns `hdr_images` at the original dimensions.
|
||||
|
||||
### Inputs
|
||||
|
||||
| Input | Range/default | Description |
|
||||
| --- | --- | --- |
|
||||
| `images` | `IMAGE` batch | Normalized SDR RGB input images. |
|
||||
| `contrast` | `0`–`200`, default `100` | Output contrast. |
|
||||
| `saturation` | `0`–`200`, default `100` | Output saturation. |
|
||||
| `middle_gray` | `10`–`100`, default `50` | Middle-grey reference level. |
|
||||
| `luminance` | `400`–`2000`, default `650` | Target HDR display peak luminance in nits. |
|
||||
| `debanding` | default enabled | Applies the SDK's DL-Debander pass. |
|
||||
| `output_colorspace` | `HDR` / `HDR PQ` | Selects BT.2020/HLG or BT.2020/PQ output data. Default: `HDR` (HLG). |
|
||||
|
||||
`HDR PQ` returns the SDK's BT.2020/PQ signal as normalized RGB values. `HDR` converts that result to BT.2020/HLG using the selected peak luminance.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> A ComfyUI `IMAGE` does not carry HDR color-space metadata. The values this node outputs are meant for HDR workflows — downstream tools that save the video or image need to mark or encode them with the selected transfer function. If you display or save them as regular SDR data, they won't look the way HDR intends.
|
||||
|
||||
## RTX Video Frame Generation
|
||||
|
||||
Find the node under **video**. It processes every adjacent pair in an input `IMAGE` batch and returns `interpolated_images`, containing the original frames plus generated intermediate frames.
|
||||
|
||||
At least two input frames are required for interpolation. A one-frame batch is returned unchanged.
|
||||
|
||||
### Inputs
|
||||
|
||||
| Input | Values | Description |
|
||||
| --- | --- | --- |
|
||||
| `images` | `IMAGE` batch | Ordered source video frames. |
|
||||
| `generation_type` | `frame rate multiplier` / `specific timestep` | Selects uniform frame multiplication or one explicit interpolation position per pair. |
|
||||
| `multiplier` | `2`–`16`, default `2` | Output frame-rate multiplier. Available in multiplier mode. |
|
||||
| `timestep` | `0.01`–`0.99`, default `0.50` | Position between the previous frame (`0`) and current frame (`1`). Available in timestep mode. |
|
||||
| `mode` | `LOW`, `MEDIUM`, `HIGH`; default `MEDIUM` | Frame-generation quality mode. |
|
||||
| `automatic_shot_change_detection` | default enabled | Lets the SDK detect shot boundaries automatically. |
|
||||
| `shot_change` | default disabled | Advanced option that marks every submitted pair as a shot change; useful when processing one known cut. |
|
||||
| `image_encoding` | `8-bit RGB` / `10-bit RGB (RGB10A2)` | Pixel encoding used internally by the SDK. |
|
||||
|
||||
### Output timing
|
||||
|
||||
For \(N\) input frames and multiplier \(M\), multiplier mode returns \((N - 1)M + 1\) frames. To preserve the source video's duration, multiply its frame rate by \(M\) when encoding the output.
|
||||
|
||||
Specific-timestep mode inserts one generated frame between each pair and returns \(2N - 1\) frames. A timestep of `0.5` creates evenly spaced 2× interpolation. Other timestep values create nonuniform temporal spacing, so use them for selecting frames or with a downstream workflow that can represent custom timestamps.
|
||||
|
||||
## Implementation notes
|
||||
|
||||
ComfyUI images use channels-last `(B, H, W, C)` tensors. The nodes move each frame to ComfyUI's selected CUDA device, convert it to the SDK's channels-first RGB8 or packed RGB10A2 representation, and pass it through DLPack. Every SDK-owned DLPack result is cloned immediately before the next inference call or before the effect closes, then converted back to a standard channels-last ComfyUI `IMAGE`.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **`nvidia-vfx` cannot be imported:** install `requirements.txt` with the same Python interpreter that launches ComfyUI, then restart it.
|
||||
- **CUDA/device error:** confirm that ComfyUI is using CUDA-enabled PyTorch and has selected a supported NVIDIA RTX GPU.
|
||||
- **VFX load or inference error:** verify the dimensions, GPU support, driver/runtime installation, and available VRAM. The bindings report SDK failures as `nvvfx.NvVFXError`.
|
||||
- **Out of memory:** reduce the resolution, scale factor, quality level, or number of frames supplied in one batch.
|
||||
- **Super Resolution output size differs slightly from the requested multiplier:** upscaling dimensions are rounded to the nearest multiple of 8.
|
||||
- **HDR output looks incorrect:** ensure downstream tools interpret the data as BT.2020/HLG for `HDR` or BT.2020/PQ for `HDR PQ`; do not treat it as SDR/sRGB.
|
||||
- **Generated video duration is wrong:** adjust the encoded output frame rate as described under [Output timing](#output-timing).
|
||||
|
||||
## License
|
||||
|
||||
Licensed under Apache License 2.0. See [`LICENSE`](LICENSE).
|
||||
|
||||
+341
-35
@@ -1,17 +1,104 @@
|
||||
import torch
|
||||
import nvvfx
|
||||
from enum import Enum
|
||||
import math
|
||||
from typing import TypedDict
|
||||
|
||||
import nvvfx
|
||||
import torch
|
||||
import torch.nn.functional as F
|
||||
from typing_extensions import override
|
||||
|
||||
import comfy.model_management
|
||||
from comfy_api.latest import ComfyExtension, io
|
||||
|
||||
|
||||
MAX_BATCH_PIXELS = 1024 * 1024 * 16
|
||||
VSR_QUALITY_OPTIONS = list(nvvfx.QualityLevel.__members__)
|
||||
|
||||
PQ_M1 = 2610 / 16384
|
||||
PQ_M2 = 2523 / 4096 * 128
|
||||
PQ_C1 = 3424 / 4096
|
||||
PQ_C2 = 2413 / 4096 * 32
|
||||
PQ_C3 = 2392 / 4096 * 32
|
||||
|
||||
HLG_A = 0.17883277
|
||||
HLG_B = 1 - 4 * HLG_A
|
||||
HLG_C = 0.5 - HLG_A * math.log(4 * HLG_A)
|
||||
|
||||
|
||||
class UpscaleType(str, Enum):
|
||||
SCALE_BY = "scale by multiplier"
|
||||
TARGET_DIMENSIONS = "target dimensions"
|
||||
|
||||
|
||||
class FrameGenerationType(str, Enum):
|
||||
MULTIPLIER = "frame rate multiplier"
|
||||
TIMESTEP = "specific timestep"
|
||||
|
||||
|
||||
class ImageEncodingType(str, Enum):
|
||||
RGB8 = "8-bit RGB"
|
||||
RGB10A2 = "10-bit RGB (RGB10A2)"
|
||||
|
||||
|
||||
class HDRColorSpace(str, Enum):
|
||||
HLG = "HDR"
|
||||
PQ = "HDR PQ"
|
||||
|
||||
|
||||
def get_effect_device() -> tuple[torch.device, int]:
|
||||
device = comfy.model_management.get_torch_device()
|
||||
if device.type != "cuda":
|
||||
raise RuntimeError("NVIDIA RTX Video Effects require a CUDA device.")
|
||||
device_index = device.index if device.index is not None else torch.cuda.current_device()
|
||||
return device, device_index
|
||||
|
||||
|
||||
def pack_rgb10a2(image: torch.Tensor) -> torch.Tensor:
|
||||
rgb = image.clamp(0.0, 1.0).mul(1023.0).round().to(torch.int32)
|
||||
packed = rgb[..., 0] | (rgb[..., 1] << 10) | (rgb[..., 2] << 20) | -1073741824
|
||||
return packed.view(torch.uint32).contiguous()
|
||||
|
||||
|
||||
def unpack_rgb10a2(packed: torch.Tensor) -> torch.Tensor:
|
||||
packed = packed.view(torch.int32)
|
||||
red = packed.bitwise_and(0x3FF)
|
||||
green = packed.bitwise_right_shift(10).bitwise_and(0x3FF)
|
||||
blue = packed.bitwise_right_shift(20).bitwise_and(0x3FF)
|
||||
return torch.stack((red, green, blue), dim=-1).to(torch.float32).div_(1023.0)
|
||||
|
||||
|
||||
def pq_to_hlg(image: torch.Tensor, peak_luminance: float) -> torch.Tensor:
|
||||
pq = image.clamp(0.0, 1.0).pow(1.0 / PQ_M2)
|
||||
display_light = ((pq.sub(PQ_C1).clamp_min(0.0) / (PQ_C2 - PQ_C3 * pq)) ** (1.0 / PQ_M1)) * 10000.0
|
||||
display_light.clamp_(max=peak_luminance)
|
||||
|
||||
display_luminance = 0.2627 * display_light[..., 0] + 0.6780 * display_light[..., 1] + 0.0593 * display_light[..., 2]
|
||||
system_gamma = 1.2 + 0.42 * math.log10(peak_luminance / 1000.0)
|
||||
luminance_ratio = (display_luminance / peak_luminance).clamp_min(torch.finfo(display_light.dtype).eps)
|
||||
scene_light = (display_light / peak_luminance) * luminance_ratio.unsqueeze(-1).pow((1.0 - system_gamma) / system_gamma)
|
||||
scene_light.clamp_(0.0, 1.0)
|
||||
|
||||
low = torch.sqrt(3.0 * scene_light)
|
||||
high = HLG_A * torch.log((12.0 * scene_light - HLG_B).clamp_min(torch.finfo(scene_light.dtype).eps)) + HLG_C
|
||||
return torch.where(scene_light <= 1.0 / 12.0, low, high)
|
||||
|
||||
|
||||
def prepare_frame(image: torch.Tensor, device: torch.device, image_encoding: ImageEncodingType) -> torch.Tensor:
|
||||
image = image.to(device=device, dtype=torch.float32)
|
||||
if image_encoding == ImageEncodingType.RGB10A2:
|
||||
return pack_rgb10a2(image)
|
||||
return image.movedim(-1, 0).contiguous()
|
||||
|
||||
|
||||
def copy_effect_output(dlpack_output, destination: torch.Tensor, image_encoding: ImageEncodingType) -> None:
|
||||
output = torch.from_dlpack(dlpack_output).clone()
|
||||
if image_encoding == ImageEncodingType.RGB10A2:
|
||||
output = unpack_rgb10a2(output)
|
||||
else:
|
||||
output = output.movedim(0, -1)
|
||||
destination.copy_(output)
|
||||
|
||||
|
||||
class RTXVideoSuperResolution(io.ComfyNode):
|
||||
class UpscaleTypedDict(TypedDict):
|
||||
resize_type: UpscaleType
|
||||
@@ -25,23 +112,36 @@ class RTXVideoSuperResolution(io.ComfyNode):
|
||||
node_id="RTXVideoSuperResolution",
|
||||
display_name="RTX Video Super Resolution",
|
||||
category="image/upscaling",
|
||||
search_aliases=["rtx", "nvidia", "upscale", "super resolution", "vsr"],
|
||||
description="Upscale, denoise, or deblur images with NVIDIA Video Effects.",
|
||||
search_aliases=["rtx", "nvidia", "upscale", "super resolution", "vsr", "denoise", "deblur"],
|
||||
inputs=[
|
||||
io.Image.Input("images"),
|
||||
io.DynamicCombo.Input(
|
||||
"resize_type",
|
||||
tooltip="Choose to scale by a multiplier or to exact target dimensions.",
|
||||
tooltip="Choose to scale by a multiplier or to exact target dimensions. Denoise and deblur modes keep the input dimensions.",
|
||||
options=[
|
||||
io.DynamicCombo.Option(UpscaleType.SCALE_BY, [
|
||||
io.Float.Input("scale", default=2.0, min=1.0, max=4.0, step=0.01, tooltip="Scale factor (e.g., 2.0 doubles the size)."),
|
||||
]),
|
||||
io.DynamicCombo.Option(UpscaleType.TARGET_DIMENSIONS, [
|
||||
io.Int.Input("width", default=1920, min=64, max=8192, step=8, tooltip="Target width in pixels."),
|
||||
io.Int.Input("height", default=1080, min=64, max=8192, step=8, tooltip="Target height in pixels.")
|
||||
])
|
||||
io.Int.Input("height", default=1080, min=64, max=8192, step=8, tooltip="Target height in pixels."),
|
||||
]),
|
||||
],
|
||||
),
|
||||
io.Combo.Input("quality", options=["LOW", "MEDIUM", "HIGH", "ULTRA"], default="ULTRA"),
|
||||
io.Combo.Input(
|
||||
"quality",
|
||||
options=VSR_QUALITY_OPTIONS,
|
||||
default="ULTRA",
|
||||
tooltip="Select the SDK model. DENOISE and DEBLUR process at the original resolution; HIGHBITRATE modes preserve clean sources.",
|
||||
),
|
||||
io.Float.Input("strength", default=1.0, min=0.0, max=1.0, step=0.01, tooltip="Effect strength."),
|
||||
io.Combo.Input(
|
||||
"image_encoding",
|
||||
options=[encoding.value for encoding in ImageEncodingType],
|
||||
default=ImageEncodingType.RGB8,
|
||||
tooltip="SDK pixel encoding. 10-bit preserves more precision but does not by itself convert SDR content to HDR.",
|
||||
),
|
||||
],
|
||||
outputs=[
|
||||
io.Image.Output("upscaled_images"),
|
||||
@@ -49,7 +149,16 @@ class RTXVideoSuperResolution(io.ComfyNode):
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def execute(cls, images: torch.Tensor, resize_type: UpscaleTypedDict, quality: str) -> io.NodeOutput:
|
||||
def execute(
|
||||
cls,
|
||||
images: torch.Tensor,
|
||||
resize_type: UpscaleTypedDict,
|
||||
quality: str,
|
||||
strength: float = 1.0,
|
||||
image_encoding: str = ImageEncodingType.RGB8,
|
||||
) -> io.NodeOutput:
|
||||
alpha = images[..., 3:4] if images.shape[-1] > 3 else None
|
||||
images = images[..., :3]
|
||||
b, h, w, c = images.shape
|
||||
|
||||
selected_type = resize_type["resize_type"]
|
||||
@@ -63,39 +172,230 @@ class RTXVideoSuperResolution(io.ComfyNode):
|
||||
else:
|
||||
raise ValueError(f"Unsupported resize type: {selected_type}")
|
||||
|
||||
output_width = max(8, round(output_width / 8) * 8)
|
||||
output_height = max(8, round(output_height / 8) * 8)
|
||||
if quality.startswith(("DENOISE_", "DEBLUR_")):
|
||||
output_width = w
|
||||
output_height = h
|
||||
else:
|
||||
output_width = max(8, round(output_width / 8) * 8)
|
||||
output_height = max(8, round(output_height / 8) * 8)
|
||||
|
||||
MAX_PIXELS = 1024 * 1024 * 16
|
||||
output = torch.empty((b, output_height, output_width, c), device=images.device, dtype=images.dtype)
|
||||
device, device_index = get_effect_device()
|
||||
batch_size = max(1, MAX_BATCH_PIXELS // (output_width * output_height))
|
||||
selected_encoding = ImageEncodingType(image_encoding)
|
||||
|
||||
out_pixels = output_width * output_height
|
||||
batch_size = max(1, MAX_PIXELS // out_pixels)
|
||||
with torch.cuda.device(device), nvvfx.VideoSuperRes(
|
||||
quality=nvvfx.QualityLevel[quality],
|
||||
strength=strength,
|
||||
device=device_index,
|
||||
image_encoding=nvvfx.ImageEncoding.RGB10A2 if selected_encoding == ImageEncodingType.RGB10A2 else nvvfx.ImageEncoding.RGB8,
|
||||
) as effect:
|
||||
effect.output_width = output_width
|
||||
effect.output_height = output_height
|
||||
effect.load()
|
||||
|
||||
quality_mapping = {
|
||||
"LOW": nvvfx.effects.QualityLevel.LOW,
|
||||
"MEDIUM": nvvfx.effects.QualityLevel.MEDIUM,
|
||||
"HIGH": nvvfx.effects.QualityLevel.HIGH,
|
||||
"ULTRA": nvvfx.effects.QualityLevel.ULTRA,
|
||||
}
|
||||
selected_quality = quality_mapping.get(quality, nvvfx.effects.QualityLevel.HIGH)
|
||||
|
||||
with nvvfx.VideoSuperRes(selected_quality) as sr:
|
||||
sr.output_width = output_width
|
||||
sr.output_height = output_height
|
||||
sr.load()
|
||||
|
||||
out_tensor = torch.empty((images.shape[0], output_height, output_width, c), device=images.device, dtype=images.dtype)
|
||||
for i in range(0, images.shape[0], batch_size):
|
||||
batch = images[i:i + batch_size]
|
||||
batch_cuda = batch.to(device=device, dtype=torch.float32)
|
||||
if selected_encoding == ImageEncodingType.RGB10A2:
|
||||
batch_cuda = pack_rgb10a2(batch_cuda)
|
||||
else:
|
||||
batch_cuda = batch_cuda.movedim(-1, 1).contiguous()
|
||||
for j, frame in enumerate(batch_cuda):
|
||||
copy_effect_output(effect.run(frame).image, output[i + j], selected_encoding)
|
||||
|
||||
batch_cuda = batch.cuda().permute(0, 3, 1, 2).float().contiguous()
|
||||
if alpha is not None:
|
||||
upscaled_alpha = F.interpolate(
|
||||
alpha.movedim(-1, 1),
|
||||
size=(output_height, output_width),
|
||||
mode="bilinear",
|
||||
align_corners=False,
|
||||
).movedim(1, -1)
|
||||
output = torch.cat((output, upscaled_alpha), dim=-1)
|
||||
|
||||
for j in range(batch_cuda.shape[0]):
|
||||
input_frame = batch_cuda[j]
|
||||
dlpack_out = sr.run(input_frame).image
|
||||
out_tensor[i + j: i + j + 1] = torch.from_dlpack(dlpack_out).movedim(0, -1).unsqueeze(0)
|
||||
return io.NodeOutput(output)
|
||||
|
||||
return io.NodeOutput(out_tensor)
|
||||
|
||||
class RTXTrueHDR(io.ComfyNode):
|
||||
@classmethod
|
||||
def define_schema(cls):
|
||||
return io.Schema(
|
||||
node_id="RTXTrueHDR",
|
||||
display_name="RTX TrueHDR",
|
||||
category="image/enhancement",
|
||||
description="Convert SDR images to HLG or PQ HDR image data with NVIDIA RTX TrueHDR.",
|
||||
search_aliases=["rtx", "nvidia", "true hdr", "hdr10", "hlg", "pq", "sdr to hdr"],
|
||||
inputs=[
|
||||
io.Image.Input("images"),
|
||||
io.Int.Input("contrast", default=100, min=0, max=200),
|
||||
io.Int.Input("saturation", default=100, min=0, max=200),
|
||||
io.Int.Input("middle_gray", default=50, min=10, max=100, tooltip="Middle-grey reference level."),
|
||||
io.Int.Input("luminance", default=650, min=400, max=2000, tooltip="Target HDR display peak luminance in nits."),
|
||||
io.Boolean.Input("debanding", default=True, tooltip="Apply the SDK's DL-Debander pass."),
|
||||
io.Combo.Input(
|
||||
"output_colorspace",
|
||||
options=[colorspace.value for colorspace in HDRColorSpace],
|
||||
default=HDRColorSpace.HLG,
|
||||
tooltip="HDR outputs BT.2020/HLG using the selected peak luminance. HDR PQ returns the SDK's BT.2020/PQ signal unchanged.",
|
||||
),
|
||||
],
|
||||
outputs=[
|
||||
io.Image.Output("hdr_images", tooltip="Normalized RGB values using the selected HDR colorspace."),
|
||||
],
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def execute(
|
||||
cls,
|
||||
images: torch.Tensor,
|
||||
contrast: int,
|
||||
saturation: int,
|
||||
middle_gray: int,
|
||||
luminance: int,
|
||||
debanding: bool,
|
||||
output_colorspace: str = HDRColorSpace.HLG,
|
||||
) -> io.NodeOutput:
|
||||
alpha = images[..., 3:4] if images.shape[-1] > 3 else None
|
||||
images = images[..., :3]
|
||||
device, device_index = get_effect_device()
|
||||
output = torch.empty(images.shape, device=images.device, dtype=torch.float32)
|
||||
selected_colorspace = HDRColorSpace(output_colorspace)
|
||||
|
||||
with torch.cuda.device(device), nvvfx.TrueHDR(
|
||||
contrast=contrast,
|
||||
saturation=saturation,
|
||||
middle_gray=middle_gray,
|
||||
luminance=luminance,
|
||||
debanding_off=int(not debanding),
|
||||
device=device_index,
|
||||
) as effect:
|
||||
effect.load()
|
||||
for i, image in enumerate(images):
|
||||
result = effect.run(prepare_frame(image, device, ImageEncodingType.RGB8))
|
||||
hdr_image = unpack_rgb10a2(torch.from_dlpack(result.image).clone())
|
||||
if selected_colorspace == HDRColorSpace.HLG:
|
||||
hdr_image = pq_to_hlg(hdr_image, luminance)
|
||||
output[i].copy_(hdr_image)
|
||||
|
||||
if alpha is not None:
|
||||
output = torch.cat((output, alpha.to(dtype=output.dtype)), dim=-1)
|
||||
|
||||
return io.NodeOutput(output)
|
||||
|
||||
|
||||
class RTXVideoFrameGeneration(io.ComfyNode):
|
||||
class GenerationTypedDict(TypedDict):
|
||||
generation_type: FrameGenerationType
|
||||
multiplier: int
|
||||
timestep: float
|
||||
|
||||
@classmethod
|
||||
def define_schema(cls):
|
||||
return io.Schema(
|
||||
node_id="RTXVideoFrameGeneration",
|
||||
display_name="RTX Video Frame Generation",
|
||||
category="video",
|
||||
description="Generate intermediate video frames with NVIDIA Video Effects.",
|
||||
search_aliases=["rtx", "nvidia", "frame generation", "interpolation", "slow motion", "vfi"],
|
||||
inputs=[
|
||||
io.Image.Input("images"),
|
||||
io.DynamicCombo.Input(
|
||||
"generation_type",
|
||||
options=[
|
||||
io.DynamicCombo.Option(FrameGenerationType.MULTIPLIER, [
|
||||
io.Int.Input("multiplier", default=2, min=2, max=16, tooltip="Output frame-rate multiplier."),
|
||||
]),
|
||||
io.DynamicCombo.Option(FrameGenerationType.TIMESTEP, [
|
||||
io.Float.Input("timestep", default=0.5, min=0.01, max=0.99, step=0.01, tooltip="Position between each adjacent input pair."),
|
||||
]),
|
||||
],
|
||||
),
|
||||
io.Combo.Input("mode", options=["LOW", "MEDIUM", "HIGH"], default="MEDIUM", tooltip="Frame-generation quality mode."),
|
||||
io.Boolean.Input("automatic_shot_change_detection", default=True),
|
||||
io.Boolean.Input("shot_change", default=False, tooltip="Mark every submitted pair as a shot change. Useful when processing a single pair."),
|
||||
io.Combo.Input(
|
||||
"image_encoding",
|
||||
options=[encoding.value for encoding in ImageEncodingType],
|
||||
default=ImageEncodingType.RGB8,
|
||||
tooltip="SDK pixel encoding. 10-bit preserves more precision but does not by itself convert SDR content to HDR.",
|
||||
),
|
||||
],
|
||||
outputs=[
|
||||
io.Image.Output("interpolated_images"),
|
||||
],
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def execute(
|
||||
cls,
|
||||
images: torch.Tensor,
|
||||
generation_type: GenerationTypedDict,
|
||||
mode: str,
|
||||
automatic_shot_change_detection: bool,
|
||||
shot_change: bool,
|
||||
image_encoding: str = ImageEncodingType.RGB8,
|
||||
) -> io.NodeOutput:
|
||||
images = images[..., :3]
|
||||
if images.shape[0] < 2:
|
||||
return io.NodeOutput(images)
|
||||
|
||||
selected_type = generation_type["generation_type"]
|
||||
if selected_type == FrameGenerationType.MULTIPLIER:
|
||||
multiplier = generation_type["multiplier"]
|
||||
generated_per_pair = multiplier - 1
|
||||
elif selected_type == FrameGenerationType.TIMESTEP:
|
||||
multiplier = 2
|
||||
generated_per_pair = 1
|
||||
else:
|
||||
raise ValueError(f"Unsupported frame generation type: {selected_type}")
|
||||
|
||||
output_count = (images.shape[0] - 1) * (generated_per_pair + 1) + 1
|
||||
output = torch.empty((output_count, *images.shape[1:]), device=images.device, dtype=images.dtype)
|
||||
output[0].copy_(images[0])
|
||||
|
||||
_, height, width, _ = images.shape
|
||||
device, device_index = get_effect_device()
|
||||
selected_encoding = ImageEncodingType(image_encoding)
|
||||
with torch.cuda.device(device), nvvfx.VideoFrameGeneration(
|
||||
mode=nvvfx.VideoFrameGeneration.Mode[mode],
|
||||
automatic_shot_change_detection_enabled=automatic_shot_change_detection,
|
||||
device=device_index,
|
||||
image_encoding=nvvfx.ImageEncoding.RGB10A2 if selected_encoding == ImageEncodingType.RGB10A2 else nvvfx.ImageEncoding.RGB8,
|
||||
) as effect:
|
||||
effect.input_width = width
|
||||
effect.input_height = height
|
||||
effect.frame_multiplier = multiplier
|
||||
effect.load()
|
||||
|
||||
output_index = 1
|
||||
previous_frame = prepare_frame(images[0], device, selected_encoding)
|
||||
for current_image in images[1:]:
|
||||
current_frame = prepare_frame(current_image, device, selected_encoding)
|
||||
if selected_type == FrameGenerationType.MULTIPLIER:
|
||||
for frame_index in range(1, multiplier):
|
||||
result = effect.run(
|
||||
previous_frame,
|
||||
current_frame,
|
||||
frame_index=frame_index,
|
||||
shot_change=shot_change,
|
||||
)
|
||||
copy_effect_output(result.image, output[output_index], selected_encoding)
|
||||
output_index += 1
|
||||
else:
|
||||
result = effect.run_at_timestep(
|
||||
previous_frame,
|
||||
current_frame,
|
||||
generation_type["timestep"],
|
||||
shot_change=shot_change,
|
||||
)
|
||||
copy_effect_output(result.image, output[output_index], selected_encoding)
|
||||
output_index += 1
|
||||
|
||||
output[output_index].copy_(current_image)
|
||||
output_index += 1
|
||||
previous_frame = current_frame
|
||||
|
||||
return io.NodeOutput(output)
|
||||
|
||||
|
||||
class NVVFXVideoExtension(ComfyExtension):
|
||||
@@ -103,12 +403,18 @@ class NVVFXVideoExtension(ComfyExtension):
|
||||
async def get_node_list(self) -> list[type[io.ComfyNode]]:
|
||||
return [
|
||||
RTXVideoSuperResolution,
|
||||
RTXTrueHDR,
|
||||
RTXVideoFrameGeneration,
|
||||
]
|
||||
|
||||
|
||||
async def comfy_entrypoint() -> NVVFXVideoExtension:
|
||||
return NVVFXVideoExtension()
|
||||
|
||||
# hack so registry picks up the node name
|
||||
# Registry scanner compatibility.
|
||||
if False:
|
||||
NODE_CLASS_MAPPINGS = {"RTXVideoSuperResolution": RTXVideoSuperResolution}
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"RTXVideoSuperResolution": RTXVideoSuperResolution,
|
||||
"RTXTrueHDR": RTXTrueHDR,
|
||||
"RTXVideoFrameGeneration": RTXVideoFrameGeneration,
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 10 KiB |
@@ -1,57 +1,19 @@
|
||||
{
|
||||
"id": "e6b92a63-6d7e-4d2b-b9e3-2e054825db02",
|
||||
"revision": 0,
|
||||
"last_node_id": 5,
|
||||
"last_link_id": 4,
|
||||
"last_node_id": 6,
|
||||
"last_link_id": 7,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 3,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
-736.406353661491,
|
||||
-677.7778796179039
|
||||
],
|
||||
"size": [
|
||||
270,
|
||||
270
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 2
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.16.4",
|
||||
"enableTabs": false,
|
||||
"tabWidth": 65,
|
||||
"tabXOffset": 10,
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65,
|
||||
"Node name for S&R": "SaveImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
"ComfyUI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"type": "RTXVideoSuperResolution",
|
||||
"pos": [
|
||||
-1064.2136453281578,
|
||||
-677.7778796179039
|
||||
-1050,
|
||||
-560
|
||||
],
|
||||
"size": [
|
||||
285.8072916666667,
|
||||
124.44010416666667
|
||||
154
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
@@ -68,12 +30,12 @@
|
||||
"name": "upscaled_images",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
2,
|
||||
4
|
||||
6
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "RTXVideoSuperResolution",
|
||||
"cnr_id": "comfyui_nvidia_rtx_nodes",
|
||||
"ver": "0.1.0",
|
||||
"enableTabs": false,
|
||||
@@ -82,21 +44,29 @@
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65,
|
||||
"Node name for S&R": "RTXVideoSuperResolution"
|
||||
"secondTabWidth": 65
|
||||
},
|
||||
"widgets_values": [
|
||||
"scale by multiplier",
|
||||
2,
|
||||
"ULTRA"
|
||||
]
|
||||
"ULTRA",
|
||||
1,
|
||||
"8-bit RGB"
|
||||
],
|
||||
"widgets_values_named": {
|
||||
"resize_type": "scale by multiplier",
|
||||
"resize_type.scale": 2,
|
||||
"quality": "ULTRA",
|
||||
"strength": 1,
|
||||
"image_encoding": "8-bit RGB"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "ImageCompare",
|
||||
"pos": [
|
||||
-424.40635366149104,
|
||||
-677.7778796179039
|
||||
-417.90450850159755,
|
||||
-653.9377806982941
|
||||
],
|
||||
"size": [
|
||||
233.33333333333334,
|
||||
@@ -116,11 +86,12 @@
|
||||
"name": "image_b",
|
||||
"shape": 7,
|
||||
"type": "IMAGE",
|
||||
"link": 4
|
||||
"link": 7
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"properties": {
|
||||
"Node name for S&R": "ImageCompare",
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.16.4",
|
||||
"enableTabs": false,
|
||||
@@ -129,17 +100,17 @@
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65,
|
||||
"Node name for S&R": "ImageCompare"
|
||||
"secondTabWidth": 65
|
||||
},
|
||||
"widgets_values": []
|
||||
"widgets_values": [],
|
||||
"widgets_values_named": {}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "LoadImage",
|
||||
"pos": [
|
||||
-1389.000103661491,
|
||||
-677.7778796179039
|
||||
-1382.4982585015975,
|
||||
-653.9377806982941
|
||||
],
|
||||
"size": [
|
||||
282.78645833333337,
|
||||
@@ -165,6 +136,7 @@
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "LoadImage",
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.16.4",
|
||||
"enableTabs": false,
|
||||
@@ -173,32 +145,63 @@
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65,
|
||||
"Node name for S&R": "LoadImage"
|
||||
"secondTabWidth": 65
|
||||
},
|
||||
"widgets_values": [
|
||||
"example.png",
|
||||
"image"
|
||||
]
|
||||
],
|
||||
"widgets_values_named": {
|
||||
"image": "example.png",
|
||||
"upload": "image"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "SaveImageAdvanced",
|
||||
"pos": [
|
||||
-730,
|
||||
-560
|
||||
],
|
||||
"size": [
|
||||
270,
|
||||
130
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 6
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
7
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"ComfyUI",
|
||||
"png",
|
||||
"8-bit",
|
||||
"sRGB"
|
||||
],
|
||||
"widgets_values_named": {
|
||||
"filename_prefix": "ComfyUI",
|
||||
"format": "png",
|
||||
"format.bit_depth": "8-bit",
|
||||
"format.input_color_space": "sRGB"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
1,
|
||||
2,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
3,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
3,
|
||||
2,
|
||||
@@ -208,8 +211,24 @@
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
4,
|
||||
1,
|
||||
2,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
6,
|
||||
1,
|
||||
0,
|
||||
6,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
7,
|
||||
6,
|
||||
0,
|
||||
5,
|
||||
1,
|
||||
@@ -223,11 +242,11 @@
|
||||
"ds": {
|
||||
"scale": 0.922814962898653,
|
||||
"offset": [
|
||||
1714.9164154028422,
|
||||
1133.1650830129668
|
||||
2242.6495142142044,
|
||||
1203.059918481823
|
||||
]
|
||||
},
|
||||
"frontendVersion": "1.39.19",
|
||||
"frontendVersion": "1.53.6",
|
||||
"VHS_latentpreview": false,
|
||||
"VHS_latentpreviewrate": 0,
|
||||
"VHS_MetadataImage": true,
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
@@ -0,0 +1,360 @@
|
||||
{
|
||||
"id": "e6b92a63-6d7e-4d2b-b9e3-2e054825db02",
|
||||
"revision": 0,
|
||||
"last_node_id": 10,
|
||||
"last_link_id": 12,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 7,
|
||||
"type": "GetVideoComponents",
|
||||
"pos": [
|
||||
-1361.201171875,
|
||||
-680
|
||||
],
|
||||
"size": [
|
||||
193.530859375,
|
||||
106
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"link": 5
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
11
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "audio",
|
||||
"type": "AUDIO",
|
||||
"links": [
|
||||
8
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fps",
|
||||
"type": "FLOAT",
|
||||
"links": [
|
||||
9
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "bit_depth",
|
||||
"type": "COMBO",
|
||||
"links": null
|
||||
},
|
||||
{
|
||||
"name": "color_space",
|
||||
"type": "COMBO",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "GetVideoComponents",
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.16.4",
|
||||
"enableTabs": false,
|
||||
"tabWidth": 65,
|
||||
"tabXOffset": 10,
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "SaveVideo",
|
||||
"pos": [
|
||||
-370,
|
||||
-680
|
||||
],
|
||||
"size": [
|
||||
570,
|
||||
520
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"link": 10
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.16.4",
|
||||
"enableTabs": false,
|
||||
"tabWidth": 65,
|
||||
"tabXOffset": 10,
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65,
|
||||
"Node name for S&R": "SaveVideo"
|
||||
},
|
||||
"widgets_values": [
|
||||
"video/ComfyUI",
|
||||
"auto",
|
||||
"auto",
|
||||
"auto"
|
||||
],
|
||||
"widgets_values_named": {
|
||||
"filename_prefix": "video/ComfyUI",
|
||||
"format": "auto",
|
||||
"format.codec": "auto",
|
||||
"codec": "auto"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "CreateVideo",
|
||||
"pos": [
|
||||
-690,
|
||||
-680
|
||||
],
|
||||
"size": [
|
||||
270,
|
||||
150
|
||||
],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 12
|
||||
},
|
||||
{
|
||||
"name": "audio",
|
||||
"shape": 7,
|
||||
"type": "AUDIO",
|
||||
"link": 8
|
||||
},
|
||||
{
|
||||
"name": "fps",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "fps"
|
||||
},
|
||||
"link": 9
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "VIDEO",
|
||||
"type": "VIDEO",
|
||||
"links": [
|
||||
10
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CreateVideo",
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.16.4",
|
||||
"enableTabs": false,
|
||||
"tabWidth": 65,
|
||||
"tabXOffset": 10,
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65
|
||||
},
|
||||
"widgets_values": [
|
||||
30,
|
||||
"auto",
|
||||
"sRGB",
|
||||
"none"
|
||||
],
|
||||
"widgets_values_named": {
|
||||
"fps": 30,
|
||||
"bit_depth": "auto",
|
||||
"color_space": "sRGB",
|
||||
"codec": "none"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "LoadVideo",
|
||||
"pos": [
|
||||
-1790,
|
||||
-680
|
||||
],
|
||||
"size": [
|
||||
386.798828125,
|
||||
510
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "VIDEO",
|
||||
"type": "VIDEO",
|
||||
"links": [
|
||||
5
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "LoadVideo",
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.16.4",
|
||||
"enableTabs": false,
|
||||
"tabWidth": 65,
|
||||
"tabXOffset": 10,
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65
|
||||
},
|
||||
"widgets_values": [
|
||||
"input.mp4",
|
||||
"image"
|
||||
],
|
||||
"widgets_values_named": {
|
||||
"file": "input.mp4",
|
||||
"upload": "image"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"type": "RTXVideoFrameGeneration",
|
||||
"pos": [
|
||||
-1090,
|
||||
-680
|
||||
],
|
||||
"size": [
|
||||
356,
|
||||
178
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 11
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "interpolated_images",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
12
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "RTXVideoFrameGeneration"
|
||||
},
|
||||
"widgets_values": [
|
||||
"frame rate multiplier",
|
||||
2,
|
||||
"MEDIUM",
|
||||
true,
|
||||
false,
|
||||
"8-bit RGB"
|
||||
],
|
||||
"widgets_values_named": {
|
||||
"generation_type": "frame rate multiplier",
|
||||
"generation_type.multiplier": 2,
|
||||
"mode": "MEDIUM",
|
||||
"automatic_shot_change_detection": true,
|
||||
"shot_change": false,
|
||||
"image_encoding": "8-bit RGB"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
5,
|
||||
6,
|
||||
0,
|
||||
7,
|
||||
0,
|
||||
"VIDEO"
|
||||
],
|
||||
[
|
||||
8,
|
||||
7,
|
||||
1,
|
||||
8,
|
||||
1,
|
||||
"AUDIO"
|
||||
],
|
||||
[
|
||||
9,
|
||||
7,
|
||||
2,
|
||||
8,
|
||||
2,
|
||||
"FLOAT"
|
||||
],
|
||||
[
|
||||
10,
|
||||
8,
|
||||
0,
|
||||
9,
|
||||
0,
|
||||
"VIDEO"
|
||||
],
|
||||
[
|
||||
11,
|
||||
7,
|
||||
0,
|
||||
10,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
12,
|
||||
10,
|
||||
0,
|
||||
8,
|
||||
0,
|
||||
"IMAGE"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"workflowRendererVersion": "LG",
|
||||
"ds": {
|
||||
"scale": 0.8526983761385988,
|
||||
"offset": [
|
||||
2203.9999858436086,
|
||||
1155.2227371031956
|
||||
]
|
||||
},
|
||||
"frontendVersion": "1.53.6",
|
||||
"VHS_latentpreview": false,
|
||||
"VHS_latentpreviewrate": 0,
|
||||
"VHS_MetadataImage": true,
|
||||
"VHS_KeepIntermediate": true
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
@@ -0,0 +1,412 @@
|
||||
{
|
||||
"id": "e6b92a63-6d7e-4d2b-b9e3-2e054825db02",
|
||||
"revision": 0,
|
||||
"last_node_id": 12,
|
||||
"last_link_id": 15,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 7,
|
||||
"type": "GetVideoComponents",
|
||||
"pos": [
|
||||
-1361.201171875,
|
||||
-680
|
||||
],
|
||||
"size": [
|
||||
193.530859375,
|
||||
106
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"link": 5
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
13
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "audio",
|
||||
"type": "AUDIO",
|
||||
"links": [
|
||||
8
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fps",
|
||||
"type": "FLOAT",
|
||||
"links": [
|
||||
9
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "bit_depth",
|
||||
"type": "COMBO",
|
||||
"links": null
|
||||
},
|
||||
{
|
||||
"name": "color_space",
|
||||
"type": "COMBO",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "GetVideoComponents",
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.16.4",
|
||||
"enableTabs": false,
|
||||
"tabWidth": 65,
|
||||
"tabXOffset": 10,
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "SaveVideo",
|
||||
"pos": [
|
||||
-430,
|
||||
-680
|
||||
],
|
||||
"size": [
|
||||
570,
|
||||
520
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"link": 10
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.16.4",
|
||||
"enableTabs": false,
|
||||
"tabWidth": 65,
|
||||
"tabXOffset": 10,
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65,
|
||||
"Node name for S&R": "SaveVideo"
|
||||
},
|
||||
"widgets_values": [
|
||||
"video/ComfyUI",
|
||||
"auto",
|
||||
"auto",
|
||||
"auto"
|
||||
],
|
||||
"widgets_values_named": {
|
||||
"filename_prefix": "video/ComfyUI",
|
||||
"format": "auto",
|
||||
"format.codec": "auto",
|
||||
"codec": "auto"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "CreateVideo",
|
||||
"pos": [
|
||||
-750,
|
||||
-680
|
||||
],
|
||||
"size": [
|
||||
270,
|
||||
150
|
||||
],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 14
|
||||
},
|
||||
{
|
||||
"name": "audio",
|
||||
"shape": 7,
|
||||
"type": "AUDIO",
|
||||
"link": 8
|
||||
},
|
||||
{
|
||||
"name": "fps",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "fps"
|
||||
},
|
||||
"link": 9
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "VIDEO",
|
||||
"type": "VIDEO",
|
||||
"links": [
|
||||
10
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CreateVideo",
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.16.4",
|
||||
"enableTabs": false,
|
||||
"tabWidth": 65,
|
||||
"tabXOffset": 10,
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65
|
||||
},
|
||||
"widgets_values": [
|
||||
30,
|
||||
"auto",
|
||||
"sRGB",
|
||||
"none"
|
||||
],
|
||||
"widgets_values_named": {
|
||||
"fps": 30,
|
||||
"bit_depth": "auto",
|
||||
"color_space": "sRGB",
|
||||
"codec": "none"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "LoadVideo",
|
||||
"pos": [
|
||||
-1790,
|
||||
-680
|
||||
],
|
||||
"size": [
|
||||
386.798828125,
|
||||
510
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "VIDEO",
|
||||
"type": "VIDEO",
|
||||
"links": [
|
||||
5
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "LoadVideo",
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.16.4",
|
||||
"enableTabs": false,
|
||||
"tabWidth": 65,
|
||||
"tabXOffset": 10,
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65
|
||||
},
|
||||
"widgets_values": [
|
||||
"IkxCORHGJxLXORejeew86_minimax-h3.mp4",
|
||||
"image"
|
||||
],
|
||||
"widgets_values_named": {
|
||||
"file": "IkxCORHGJxLXORejeew86_minimax-h3.mp4",
|
||||
"upload": "image"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"type": "RTXTrueHDR",
|
||||
"pos": [
|
||||
-1070,
|
||||
-680
|
||||
],
|
||||
"size": [
|
||||
270,
|
||||
178
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 13
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "hdr_images",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
14,
|
||||
15
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "RTXTrueHDR"
|
||||
},
|
||||
"widgets_values": [
|
||||
100,
|
||||
100,
|
||||
50,
|
||||
650,
|
||||
true,
|
||||
"HDR"
|
||||
],
|
||||
"widgets_values_named": {
|
||||
"contrast": 100,
|
||||
"saturation": 100,
|
||||
"middle_gray": 50,
|
||||
"luminance": 650,
|
||||
"debanding": true,
|
||||
"output_colorspace": "HDR"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"type": "SaveImageAdvanced",
|
||||
"pos": [
|
||||
-430,
|
||||
-70
|
||||
],
|
||||
"size": [
|
||||
270,
|
||||
130
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"showAdvanced": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 15
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"ComfyUI",
|
||||
"exr",
|
||||
"16-bit float",
|
||||
"HDR"
|
||||
],
|
||||
"widgets_values_named": {
|
||||
"filename_prefix": "ComfyUI",
|
||||
"format": "exr",
|
||||
"format.bit_depth": "16-bit float",
|
||||
"format.input_color_space": "HDR"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
5,
|
||||
6,
|
||||
0,
|
||||
7,
|
||||
0,
|
||||
"VIDEO"
|
||||
],
|
||||
[
|
||||
8,
|
||||
7,
|
||||
1,
|
||||
8,
|
||||
1,
|
||||
"AUDIO"
|
||||
],
|
||||
[
|
||||
9,
|
||||
7,
|
||||
2,
|
||||
8,
|
||||
2,
|
||||
"FLOAT"
|
||||
],
|
||||
[
|
||||
13,
|
||||
7,
|
||||
0,
|
||||
11,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
14,
|
||||
11,
|
||||
0,
|
||||
8,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
10,
|
||||
8,
|
||||
0,
|
||||
9,
|
||||
0,
|
||||
"VIDEO"
|
||||
],
|
||||
[
|
||||
15,
|
||||
11,
|
||||
0,
|
||||
12,
|
||||
0,
|
||||
"IMAGE"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"workflowRendererVersion": "LG",
|
||||
"ds": {
|
||||
"scale": 0.9846153846153847,
|
||||
"offset": [
|
||||
2125,
|
||||
1013.0859375
|
||||
]
|
||||
},
|
||||
"frontendVersion": "1.53.10",
|
||||
"VHS_latentpreview": false,
|
||||
"VHS_latentpreviewrate": 0,
|
||||
"VHS_MetadataImage": true,
|
||||
"VHS_KeepIntermediate": true
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 12 KiB |
@@ -13,7 +13,7 @@
|
||||
],
|
||||
"size": [
|
||||
193.530859375,
|
||||
66
|
||||
106
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
@@ -46,9 +46,20 @@
|
||||
"links": [
|
||||
9
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "bit_depth",
|
||||
"type": "COMBO",
|
||||
"links": null
|
||||
},
|
||||
{
|
||||
"name": "color_space",
|
||||
"type": "COMBO",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "GetVideoComponents",
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.16.4",
|
||||
"enableTabs": false,
|
||||
@@ -57,21 +68,19 @@
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65,
|
||||
"Node name for S&R": "GetVideoComponents"
|
||||
},
|
||||
"widgets_values": []
|
||||
"secondTabWidth": 65
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"type": "RTXVideoSuperResolution",
|
||||
"pos": [
|
||||
-1125.6703125,
|
||||
-1100,
|
||||
-680
|
||||
],
|
||||
"size": [
|
||||
285.8072916666667,
|
||||
106
|
||||
154
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
@@ -93,6 +102,7 @@
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "RTXVideoSuperResolution",
|
||||
"cnr_id": "comfyui_nvidia_rtx_nodes",
|
||||
"ver": "0.1.0",
|
||||
"enableTabs": false,
|
||||
@@ -101,20 +111,28 @@
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65,
|
||||
"Node name for S&R": "RTXVideoSuperResolution"
|
||||
"secondTabWidth": 65
|
||||
},
|
||||
"widgets_values": [
|
||||
"scale by multiplier",
|
||||
2,
|
||||
"ULTRA"
|
||||
]
|
||||
"ULTRA",
|
||||
1,
|
||||
"8-bit RGB"
|
||||
],
|
||||
"widgets_values_named": {
|
||||
"resize_type": "scale by multiplier",
|
||||
"resize_type.scale": 2,
|
||||
"quality": "ULTRA",
|
||||
"strength": 1,
|
||||
"image_encoding": "8-bit RGB"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "SaveVideo",
|
||||
"pos": [
|
||||
-485.86302083333317,
|
||||
-460,
|
||||
-680
|
||||
],
|
||||
"size": [
|
||||
@@ -131,7 +149,13 @@
|
||||
"link": 10
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.16.4",
|
||||
@@ -147,19 +171,26 @@
|
||||
"widgets_values": [
|
||||
"video/ComfyUI",
|
||||
"auto",
|
||||
"auto",
|
||||
"auto"
|
||||
]
|
||||
],
|
||||
"widgets_values_named": {
|
||||
"filename_prefix": "video/ComfyUI",
|
||||
"format": "auto",
|
||||
"format.codec": "auto",
|
||||
"codec": "auto"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "CreateVideo",
|
||||
"pos": [
|
||||
-797.8630208333332,
|
||||
-770,
|
||||
-680
|
||||
],
|
||||
"size": [
|
||||
270,
|
||||
78
|
||||
150
|
||||
],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
@@ -195,6 +226,7 @@
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CreateVideo",
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.16.4",
|
||||
"enableTabs": false,
|
||||
@@ -203,12 +235,20 @@
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65,
|
||||
"Node name for S&R": "CreateVideo"
|
||||
"secondTabWidth": 65
|
||||
},
|
||||
"widgets_values": [
|
||||
30
|
||||
]
|
||||
30,
|
||||
"auto",
|
||||
"sRGB",
|
||||
"none"
|
||||
],
|
||||
"widgets_values_named": {
|
||||
"fps": 30,
|
||||
"bit_depth": "auto",
|
||||
"color_space": "sRGB",
|
||||
"codec": "none"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
@@ -235,6 +275,7 @@
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "LoadVideo",
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.16.4",
|
||||
"enableTabs": false,
|
||||
@@ -243,13 +284,16 @@
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65,
|
||||
"Node name for S&R": "LoadVideo"
|
||||
"secondTabWidth": 65
|
||||
},
|
||||
"widgets_values": [
|
||||
"input.mp4",
|
||||
"image"
|
||||
]
|
||||
],
|
||||
"widgets_values_named": {
|
||||
"file": "input.mp4",
|
||||
"upload": "image"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
@@ -261,14 +305,6 @@
|
||||
0,
|
||||
"VIDEO"
|
||||
],
|
||||
[
|
||||
6,
|
||||
7,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
7,
|
||||
1,
|
||||
@@ -293,6 +329,14 @@
|
||||
2,
|
||||
"FLOAT"
|
||||
],
|
||||
[
|
||||
6,
|
||||
7,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
10,
|
||||
8,
|
||||
@@ -307,13 +351,13 @@
|
||||
"extra": {
|
||||
"workflowRendererVersion": "LG",
|
||||
"ds": {
|
||||
"scale": 0.5824044642706089,
|
||||
"scale": 0.8526983761385988,
|
||||
"offset": [
|
||||
2224.646676974563,
|
||||
1182.1948771278435
|
||||
2198.136247691975,
|
||||
1166.950213406463
|
||||
]
|
||||
},
|
||||
"frontendVersion": "1.39.19",
|
||||
"frontendVersion": "1.53.6",
|
||||
"VHS_latentpreview": false,
|
||||
"VHS_latentpreviewrate": 0,
|
||||
"VHS_MetadataImage": true,
|
||||
|
||||
Reference in New Issue
Block a user