finalize stabstitch
@@ -28,7 +28,7 @@ Download the model [here](https://github.com/Yuehan717/RealViformer?tab=readme-o
|
||||
|
||||
[workflow_realviformer.json](workflow/workflow_realviformer.json)
|
||||
|
||||

|
||||

|
||||
|
||||
(Not a workflow-embedded image)
|
||||
|
||||
@@ -77,7 +77,7 @@ To install, `pip install [].whl`
|
||||
|
||||
[workflow_vfi_mamba.json](workflow/workflow_vfi_mamba.json)
|
||||
|
||||

|
||||

|
||||
|
||||
(Not a workflow-embedded image)
|
||||
|
||||
@@ -146,6 +146,13 @@ models/stabstitch/spatial_warp.pth
|
||||
models/stabstitch/smooth_warp.pth
|
||||
```
|
||||
|
||||
| StabStitch | StabStitch Stabilize |
|
||||
|-|-|
|
||||
| [stabstitch_stitch.json](workflow/stabstitch_stitch.json) (Example videos in `examples\stabstitch`) | [stabstich_stabilize.json](workflow/stabstitch_stabilize.json) |
|
||||
|  |  |
|
||||
|
||||
(Not workflow-embedded images)
|
||||
|
||||
## Credits
|
||||
|
||||
```
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
from .run import (
|
||||
WFEN,
|
||||
RealViFormerSR,
|
||||
ProPIH_Harmonizer,
|
||||
CoLIE_LowLight_Enhance,
|
||||
StabStitch,
|
||||
ProPIH_Harmonizer,
|
||||
RealViFormerSR,
|
||||
)
|
||||
|
||||
from .run_convir import (
|
||||
ConvIR_DefocusDeblur,
|
||||
ConvIR_DeHaze,
|
||||
ConvIR_DeRain,
|
||||
ConvIR_DeSnow,
|
||||
ConvIR_MotionDeBlur,
|
||||
ConvIR_DefocusDeblur,
|
||||
)
|
||||
from .run_stabstitch import (
|
||||
StabStitch_Crop_Resize,
|
||||
StabStitch_Stabilize,
|
||||
StabStitch_Stitch,
|
||||
)
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
@@ -24,7 +27,9 @@ NODE_CLASS_MAPPINGS = {
|
||||
"ConvIR_DeSnow": ConvIR_DeSnow,
|
||||
"ConvIR_MotionDeBlur": ConvIR_MotionDeBlur,
|
||||
"ConvIR_DefocusDeblur": ConvIR_DefocusDeblur,
|
||||
"StabStitch": StabStitch,
|
||||
"StabStitch": StabStitch_Stitch,
|
||||
"StabStitch_Stabilize": StabStitch_Stabilize,
|
||||
"StabStitch_Crop_Resize": StabStitch_Crop_Resize,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
@@ -38,6 +43,8 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"ConvIR_MotionDeBlur": "ConvIR Motion DeBlur",
|
||||
"ConvIR_DefocusDeblur": "ConvIR Defocus Deblur",
|
||||
"StabStitch": "StabStitch",
|
||||
"StabStitch_Stabilize": "StabStitch Stabilize",
|
||||
"StabStitch_Crop_Resize": "StabStitch Crop Resize",
|
||||
}
|
||||
|
||||
try:
|
||||
|
||||
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 28 KiB |
@@ -1,12 +1,12 @@
|
||||
import torch
|
||||
from torchvision.transforms import GaussianBlur
|
||||
import torch.nn.functional as F
|
||||
import tqdm
|
||||
from . import torch_tps_transform
|
||||
from torchvision.transforms import GaussianBlur
|
||||
|
||||
from . import torch_tps_transform, torch_tps_transform_point
|
||||
from .smooth_network import SmoothNet, build_SmoothNet
|
||||
from .spatial_network import SpatialNet, build_SpatialNet
|
||||
from .temporal_network import TemporalNet, build_TemporalNet
|
||||
from . import torch_tps_transform_point
|
||||
|
||||
grid_h = 6
|
||||
grid_w = 8
|
||||
@@ -15,6 +15,53 @@ img_h = 360
|
||||
img_w = 480
|
||||
|
||||
|
||||
def crop_or_resize(tensor, target_h, target_w, crop_side="left"):
|
||||
B, H, W, C = tensor.shape
|
||||
aspect_ratio = W / H
|
||||
target_aspect_ratio = target_w / target_h
|
||||
|
||||
if aspect_ratio == target_aspect_ratio:
|
||||
# Just resize
|
||||
resized = F.interpolate(
|
||||
tensor.permute(0, 3, 1, 2),
|
||||
size=(target_h, target_w),
|
||||
mode="bilinear",
|
||||
align_corners=False,
|
||||
)
|
||||
return resized.permute(0, 2, 3, 1)
|
||||
|
||||
elif aspect_ratio > target_aspect_ratio:
|
||||
# Crop width, then resize
|
||||
new_w = int(H * target_aspect_ratio)
|
||||
if crop_side == "left":
|
||||
cropped = tensor[:, :, :new_w, :]
|
||||
elif crop_side == "right":
|
||||
cropped = tensor[:, :, -new_w:, :]
|
||||
else:
|
||||
raise ValueError("crop_side must be 'left' or 'right'")
|
||||
|
||||
resized = F.interpolate(
|
||||
cropped.permute(0, 3, 1, 2),
|
||||
size=(target_h, target_w),
|
||||
mode="bilinear",
|
||||
align_corners=False,
|
||||
)
|
||||
return resized.permute(0, 2, 3, 1)
|
||||
|
||||
else:
|
||||
# Crop height, then resize
|
||||
new_h = int(W / target_aspect_ratio)
|
||||
cropped = tensor[:, :new_h, :, :]
|
||||
|
||||
resized = F.interpolate(
|
||||
cropped.permute(0, 3, 1, 2),
|
||||
size=(target_h, target_w),
|
||||
mode="bilinear",
|
||||
align_corners=False,
|
||||
)
|
||||
return resized.permute(0, 2, 3, 1)
|
||||
|
||||
|
||||
def video_preprocess(src_video: torch.Tensor, h: int, w: int):
|
||||
# [B, H, W, C] [0, 1]
|
||||
tensor = src_video.permute(0, 3, 1, 2) # [B, C, H, W]
|
||||
@@ -36,39 +83,44 @@ def stabstitch_inference(
|
||||
temporal_path: str,
|
||||
smooth_path: str,
|
||||
device,
|
||||
mode: str,
|
||||
do_linear_blend: bool,
|
||||
):
|
||||
spatial_net = SpatialNet().to(device)
|
||||
temporal_net = TemporalNet().to(device)
|
||||
smooth_net = SmoothNet().to(device)
|
||||
|
||||
spatial_net.load_state_dict(torch.load(spatial_path)["model"])
|
||||
temporal_net.load_state_dict(torch.load(temporal_path)["model"])
|
||||
smooth_net.load_state_dict(torch.load(smooth_path)["model"])
|
||||
|
||||
spatial_net.eval()
|
||||
temporal_net.eval()
|
||||
smooth_net.eval()
|
||||
spatial_net, temporal_net, smooth_net = load_models(
|
||||
spatial_path, temporal_path, smooth_path, device
|
||||
)
|
||||
|
||||
video_1 = video_preprocess(src_video_1, img_h, img_w).to(device)
|
||||
video_2 = video_preprocess(src_video_2, img_h, img_w).to(device)
|
||||
|
||||
video_list_1 = video_to_list_ts(video_1)
|
||||
video_list_2 = video_to_list_ts(video_2)
|
||||
|
||||
num_frames = len(video_list_1)
|
||||
smotion_tensor_list = []
|
||||
omask_tensor_list = []
|
||||
return inference(
|
||||
mode,
|
||||
do_linear_blend,
|
||||
spatial_net,
|
||||
temporal_net,
|
||||
smooth_net,
|
||||
video_list_1,
|
||||
video_list_2,
|
||||
)
|
||||
|
||||
|
||||
def inference(
|
||||
mode,
|
||||
do_linear_blend,
|
||||
spatial_net,
|
||||
temporal_net,
|
||||
smooth_net,
|
||||
video_list_1,
|
||||
video_list_2,
|
||||
):
|
||||
num_frames = len(video_list_2)
|
||||
# motion estimation
|
||||
for k in tqdm.tqdm(range(num_frames), desc="Motion estimating"):
|
||||
# step 1: spatial warp
|
||||
with torch.no_grad():
|
||||
spatial_batch_out = build_SpatialNet(
|
||||
spatial_net, video_list_1[k], video_list_2[k]
|
||||
)
|
||||
smotion = spatial_batch_out["motion"]
|
||||
omask = spatial_batch_out["overlap_mesh"]
|
||||
smotion_tensor_list.append(smotion)
|
||||
omask_tensor_list.append(omask)
|
||||
smotion_tensor_list, omask_tensor_list = spatial_warping(
|
||||
spatial_net, video_list_1, video_list_2, num_frames
|
||||
)
|
||||
|
||||
# step 2: temporal warp
|
||||
with torch.no_grad():
|
||||
@@ -78,37 +130,90 @@ def stabstitch_inference(
|
||||
##############################################
|
||||
############# data preparation ############
|
||||
# converting tmotion (t-th frame) into tsmotion ( (t-1)-th frame )
|
||||
rigid_mesh = get_rigid_mesh(1, img_h, img_w)
|
||||
norm_rigid_mesh = get_norm_mesh(rigid_mesh, img_h, img_w)
|
||||
|
||||
rigid_mesh = get_rigid_mesh(1, img_h, img_w)
|
||||
norm_rigid_mesh = get_norm_mesh(rigid_mesh, img_h, img_w)
|
||||
|
||||
smesh_list = []
|
||||
tsmotion_list = []
|
||||
|
||||
for k in tqdm.tqdm(range(len(tmotion_tensor_list)), desc="Temporal calculating"):
|
||||
smotion = smotion_tensor_list[k]
|
||||
smesh = rigid_mesh + smotion
|
||||
if k == 0:
|
||||
tsmotion = smotion.clone() * 0
|
||||
|
||||
else:
|
||||
smotion_1 = smotion_tensor_list[k - 1]
|
||||
smesh_1 = rigid_mesh + smotion_1
|
||||
tmotion = tmotion_tensor_list[k]
|
||||
tmesh = rigid_mesh + tmotion
|
||||
norm_smesh_1 = get_norm_mesh(smesh_1, img_h, img_w)
|
||||
norm_tmesh = get_norm_mesh(tmesh, img_h, img_w)
|
||||
tsmesh = torch_tps_transform_point.transformer(
|
||||
norm_tmesh, norm_rigid_mesh, norm_smesh_1
|
||||
)
|
||||
tsmotion = recover_mesh(tsmesh, img_h, img_w) - smesh
|
||||
# append
|
||||
smesh_list.append(smesh)
|
||||
tsmotion_list.append(tsmotion)
|
||||
smesh_list, tsmotion_list = temporaling(smotion_tensor_list, tmotion_tensor_list)
|
||||
|
||||
# step 3: smooth warp
|
||||
target_mesh = smooth_meshing(
|
||||
smooth_net,
|
||||
smotion_tensor_list,
|
||||
omask_tensor_list,
|
||||
tmotion_tensor_list,
|
||||
smesh_list,
|
||||
tsmotion_list,
|
||||
)
|
||||
|
||||
stable_list, mask_list_2, img_2_list, _, _ = get_stable_sqe(
|
||||
video_list_1, video_list_2, target_mesh, mode, do_linear_blend
|
||||
)
|
||||
|
||||
stable_list = [stable.unsqueeze(0)[:, [2, 1, 0], :, :] for stable in stable_list]
|
||||
|
||||
return stable_list, img_2_list, mask_list_2
|
||||
|
||||
|
||||
def stabstitch_single_inference(
|
||||
src_video_1: torch.Tensor,
|
||||
spatial_path: str,
|
||||
temporal_path: str,
|
||||
smooth_path: str,
|
||||
device,
|
||||
mode: str,
|
||||
do_linear_blend: bool,
|
||||
):
|
||||
spatial_net, temporal_net, smooth_net = load_models(
|
||||
spatial_path, temporal_path, smooth_path, device
|
||||
)
|
||||
|
||||
video_1 = video_preprocess(src_video_1[0].unsqueeze(0), img_h, img_w).to(device)
|
||||
video_2 = video_preprocess(src_video_1, img_h, img_w).to(device)
|
||||
|
||||
video_list_2 = video_to_list_ts(video_2)
|
||||
|
||||
num_frames = len(video_list_2)
|
||||
# motion estimation
|
||||
smotion_tensor_list, omask_tensor_list = spatial_warping_single(
|
||||
spatial_net, video_1, video_list_2, num_frames
|
||||
)
|
||||
|
||||
# step 2: temporal warp
|
||||
with torch.no_grad():
|
||||
temporal_batch_out = build_TemporalNet(temporal_net, video_list_2)
|
||||
tmotion_tensor_list = temporal_batch_out["motion_list"]
|
||||
|
||||
##############################################
|
||||
############# data preparation ############
|
||||
# converting tmotion (t-th frame) into tsmotion ( (t-1)-th frame )
|
||||
|
||||
smesh_list, tsmotion_list = temporaling(smotion_tensor_list, tmotion_tensor_list)
|
||||
|
||||
# step 3: smooth warp
|
||||
target_mesh = smooth_meshing(
|
||||
smooth_net,
|
||||
smotion_tensor_list,
|
||||
omask_tensor_list,
|
||||
tmotion_tensor_list,
|
||||
smesh_list,
|
||||
tsmotion_list,
|
||||
)
|
||||
|
||||
stable_list, mask_list_2, img_2_list, _, _ = get_stable_sqe(
|
||||
video_1, video_list_2, target_mesh, mode, do_linear_blend, is_single=True
|
||||
)
|
||||
|
||||
stable_list = [stable.unsqueeze(0)[:, [2, 1, 0], :, :] for stable in stable_list]
|
||||
|
||||
return stable_list, img_2_list, mask_list_2
|
||||
|
||||
|
||||
def smooth_meshing(
|
||||
smooth_net,
|
||||
smotion_tensor_list,
|
||||
omask_tensor_list,
|
||||
tmotion_tensor_list,
|
||||
smesh_list,
|
||||
tsmotion_list,
|
||||
):
|
||||
ori_mesh = 0
|
||||
target_mesh = 0
|
||||
|
||||
@@ -138,18 +243,69 @@ def stabstitch_inference(
|
||||
(target_mesh, _target_mesh[:, -1, ...].unsqueeze(1)), 1
|
||||
)
|
||||
|
||||
stable_list, mesh_list_2, img_2_list, out_width, out_height = get_stable_sqe(
|
||||
video_list_1, video_list_2, target_mesh
|
||||
)
|
||||
return target_mesh
|
||||
|
||||
stable_list = [stable.unsqueeze(0)[:, [2, 1, 0], :, :] for stable in stable_list]
|
||||
|
||||
print(f"{stable_list[0].shape=}") # ([3, 380, 757])
|
||||
print(f"{img_2_list[0].shape=}") # ([3, 380, 757])
|
||||
if mesh_list_2:
|
||||
print(f"{mesh_list_2[0].shape=}")
|
||||
def temporaling(smotion_tensor_list, tmotion_tensor_list):
|
||||
smesh_list = []
|
||||
tsmotion_list = []
|
||||
|
||||
return stable_list, img_2_list, mesh_list_2
|
||||
rigid_mesh = get_rigid_mesh(1, img_h, img_w)
|
||||
norm_rigid_mesh = get_norm_mesh(rigid_mesh, img_h, img_w)
|
||||
|
||||
for k in tqdm.tqdm(range(len(tmotion_tensor_list)), desc="Temporal calculating"):
|
||||
smotion = smotion_tensor_list[k]
|
||||
smesh = rigid_mesh + smotion
|
||||
if k == 0:
|
||||
tsmotion = smotion.clone() * 0
|
||||
|
||||
else:
|
||||
smotion_1 = smotion_tensor_list[k - 1]
|
||||
smesh_1 = rigid_mesh + smotion_1
|
||||
tmotion = tmotion_tensor_list[k]
|
||||
tmesh = rigid_mesh + tmotion
|
||||
norm_smesh_1 = get_norm_mesh(smesh_1, img_h, img_w)
|
||||
norm_tmesh = get_norm_mesh(tmesh, img_h, img_w)
|
||||
tsmesh = torch_tps_transform_point.transformer(
|
||||
norm_tmesh, norm_rigid_mesh, norm_smesh_1
|
||||
)
|
||||
tsmotion = recover_mesh(tsmesh, img_h, img_w) - smesh
|
||||
# append
|
||||
smesh_list.append(smesh)
|
||||
tsmotion_list.append(tsmotion)
|
||||
return smesh_list, tsmotion_list
|
||||
|
||||
|
||||
def spatial_warping(spatial_net, video_list_1, video_list_2, num_frames):
|
||||
smotion_tensor_list = []
|
||||
omask_tensor_list = []
|
||||
|
||||
for k in tqdm.tqdm(range(num_frames), desc="Motion estimating"):
|
||||
# step 1: spatial warp
|
||||
with torch.no_grad():
|
||||
spatial_batch_out = build_SpatialNet(
|
||||
spatial_net, video_list_1[k], video_list_2[k]
|
||||
)
|
||||
smotion = spatial_batch_out["motion"]
|
||||
omask = spatial_batch_out["overlap_mesh"]
|
||||
smotion_tensor_list.append(smotion)
|
||||
omask_tensor_list.append(omask)
|
||||
return smotion_tensor_list, omask_tensor_list
|
||||
|
||||
|
||||
def spatial_warping_single(spatial_net, video_1, video_list_2, num_frames):
|
||||
smotion_tensor_list = []
|
||||
omask_tensor_list = []
|
||||
|
||||
for k in tqdm.tqdm(range(num_frames), desc="Motion estimating"):
|
||||
# step 1: spatial warp
|
||||
with torch.no_grad():
|
||||
spatial_batch_out = build_SpatialNet(spatial_net, video_1, video_list_2[k])
|
||||
smotion = spatial_batch_out["motion"]
|
||||
omask = spatial_batch_out["overlap_mesh"]
|
||||
smotion_tensor_list.append(smotion)
|
||||
omask_tensor_list.append(omask)
|
||||
return smotion_tensor_list, omask_tensor_list
|
||||
|
||||
|
||||
def linear_blender(ref, tgt, ref_m, tgt_m, mask=False):
|
||||
@@ -224,30 +380,47 @@ def get_norm_mesh(mesh, height, width):
|
||||
|
||||
|
||||
# bs, T, h, w, 2 smooth_path
|
||||
# def get_stable_sqe(img2_list, ori_mesh):
|
||||
# batch_size, _, img_h, img_w = img2_list[0].shape
|
||||
def get_stable_sqe(
|
||||
img1_list, img2_list, ori_mesh, mode="FAST", do_linear_blend=False, is_single=False
|
||||
):
|
||||
norm_rigid_mesh, width_min, height_min, out_width, out_height = get_new_sizes(
|
||||
img2_list, ori_mesh
|
||||
)
|
||||
|
||||
# rigid_mesh = get_rigid_mesh(batch_size, img_h, img_w)
|
||||
# norm_rigid_mesh = get_norm_mesh(rigid_mesh, img_h, img_w)
|
||||
img1_warp = torch.zeros((1, 3, out_height, out_width)).cuda()
|
||||
|
||||
# stable_list = []
|
||||
# for i in range(len(img2_list)):
|
||||
# mesh = ori_mesh[:, i, :, :, :]
|
||||
# norm_mesh = get_norm_mesh(mesh, img_h, img_w)
|
||||
# img2 = (img2_list[i].cuda() + 1) / 2
|
||||
# print(img2)
|
||||
# mask = torch.ones_like(img2).cuda()
|
||||
# img2_warp = torch_tps_transform.transformer(
|
||||
# torch.cat([img2, mask], 1), norm_mesh, norm_rigid_mesh, (img_h, img_w)
|
||||
# )
|
||||
# stable_list.append(img2_warp)
|
||||
stable_list = []
|
||||
mask_list_2 = []
|
||||
img_2_list = []
|
||||
for i in range(len(img2_list)):
|
||||
if is_single:
|
||||
img1 = (img1_list.cuda() + 1) / 2
|
||||
else:
|
||||
img1 = (img1_list[i].cuda() + 1) / 2
|
||||
img2 = (img2_list[i].cuda() + 1) / 2
|
||||
mesh = ori_mesh[:, i, :, :, :]
|
||||
img2_warp, mask2, ave_fusion = get_fused(
|
||||
mode,
|
||||
do_linear_blend,
|
||||
norm_rigid_mesh,
|
||||
width_min,
|
||||
height_min,
|
||||
out_width,
|
||||
out_height,
|
||||
img1_warp,
|
||||
img1,
|
||||
img2,
|
||||
mesh,
|
||||
)
|
||||
|
||||
# return stable_list
|
||||
img_2_list.append(img2_warp)
|
||||
mask_list_2.append(mask2)
|
||||
stable_list.append(ave_fusion)
|
||||
|
||||
return stable_list, mask_list_2, img_2_list, out_width, out_height
|
||||
|
||||
|
||||
# FAST
|
||||
# NORMAL
|
||||
def get_stable_sqe(img1_list, img2_list, ori_mesh, mode="FAST", do_linear_blend=False):
|
||||
def get_new_sizes(img2_list, ori_mesh):
|
||||
batch_size, _, img_h, img_w = img2_list[0].shape
|
||||
|
||||
rigid_mesh = get_rigid_mesh(batch_size, img_h, img_w)
|
||||
@@ -268,70 +441,85 @@ def get_stable_sqe(img1_list, img2_list, ori_mesh, mode="FAST", do_linear_blend=
|
||||
height_max = height_max.int()
|
||||
out_width = width_max - width_min + 1
|
||||
out_height = height_max - height_min + 1
|
||||
return norm_rigid_mesh, width_min, height_min, out_width, out_height
|
||||
|
||||
print(out_width)
|
||||
print(out_height)
|
||||
|
||||
img1_warp = torch.zeros((1, 3, out_height, out_width)).cuda()
|
||||
def get_fused(
|
||||
mode,
|
||||
do_linear_blend,
|
||||
norm_rigid_mesh,
|
||||
width_min,
|
||||
height_min,
|
||||
out_width,
|
||||
out_height,
|
||||
img1_warp,
|
||||
img1,
|
||||
img2,
|
||||
mesh,
|
||||
):
|
||||
mesh_trans = torch.stack([mesh[..., 0] - width_min, mesh[..., 1] - height_min], 3)
|
||||
norm_mesh = get_norm_mesh(mesh_trans, out_height, out_width)
|
||||
|
||||
stable_list = []
|
||||
mask_list_2 = []
|
||||
img_2_list = []
|
||||
# mesh_tran_list = []
|
||||
for i in range(len(img2_list)):
|
||||
mesh = ori_mesh[:, i, :, :, :]
|
||||
mesh_trans = torch.stack(
|
||||
[mesh[..., 0] - width_min, mesh[..., 1] - height_min], 3
|
||||
)
|
||||
norm_mesh = get_norm_mesh(mesh_trans, out_height, out_width)
|
||||
img2 = (img2_list[i].cuda() + 1) / 2
|
||||
# mode = 'FAST': use F.grid_sample to interpolate. It's fast, but may produce thin black boundary.
|
||||
# mode = 'NORMAL': use our implemented interpolation function. It's a bit slower, but avoid the black boundary.
|
||||
img2_warp = torch_tps_transform.transformer(
|
||||
img2, norm_mesh, norm_rigid_mesh, (out_height, out_width), mode=mode
|
||||
)
|
||||
mask2 = torch_tps_transform.transformer(
|
||||
torch.ones_like(img2).cuda(),
|
||||
norm_mesh,
|
||||
norm_rigid_mesh,
|
||||
(out_height, out_width),
|
||||
)
|
||||
|
||||
# mode = 'FAST': use F.grid_sample to interpolate. It's fast, but may produce thin black boundary.
|
||||
# mode = 'NORMAL': use our implemented interpolation function. It's a bit slower, but avoid the black boundary.
|
||||
img2_warp = torch_tps_transform.transformer(
|
||||
img2, norm_mesh, norm_rigid_mesh, (out_height, out_width), mode=mode
|
||||
)
|
||||
img_2_list.append(img2_warp)
|
||||
if not do_linear_blend:
|
||||
# average blending
|
||||
img1_warp[
|
||||
:,
|
||||
:,
|
||||
int(0 - height_min) : int(0 - height_min) + 360,
|
||||
int(0 - width_min) : int(0 - width_min) + 480,
|
||||
] = img1
|
||||
|
||||
comp_1 = img1_warp[0] / (img1_warp[0] + img2_warp[0] + 1e-6)
|
||||
comp_2 = img2_warp[0] / (img1_warp[0] + img2_warp[0] + 1e-6)
|
||||
|
||||
ave_fusion = img1_warp[0] * comp_1 + img2_warp[0] * comp_2
|
||||
else:
|
||||
img1_warp[
|
||||
:,
|
||||
:,
|
||||
int(0 - height_min) : int(0 - height_min) + 360,
|
||||
int(0 - width_min) : int(0 - width_min) + 480,
|
||||
] = img1
|
||||
mask1 = img1_warp.clone()
|
||||
mask1[
|
||||
:,
|
||||
:,
|
||||
int(0 - height_min) : int(0 - height_min) + 360,
|
||||
int(0 - width_min) : int(0 - width_min) + 480,
|
||||
] = 1
|
||||
mask2 = torch_tps_transform.transformer(
|
||||
torch.ones_like(img2).cuda(),
|
||||
norm_mesh,
|
||||
norm_rigid_mesh,
|
||||
(out_height, out_width),
|
||||
)
|
||||
mask_list_2.append(mask2)
|
||||
ave_fusion = linear_blender(img1_warp, img2_warp, mask1, mask2)
|
||||
ave_fusion = ave_fusion[0]
|
||||
return img2_warp, mask2, ave_fusion
|
||||
|
||||
if not do_linear_blend:
|
||||
# average blending
|
||||
img1_warp[
|
||||
:,
|
||||
:,
|
||||
int(0 - height_min) : int(0 - height_min) + 360,
|
||||
int(0 - width_min) : int(0 - width_min) + 480,
|
||||
] = (img1_list[i].cuda() + 1) / 2
|
||||
|
||||
comp_1 = img1_warp[0] / (img1_warp[0] + img2_warp[0] + 1e-6)
|
||||
comp_2 = img2_warp[0] / (img1_warp[0] + img2_warp[0] + 1e-6)
|
||||
def load_models(spatial_path, temporal_path, smooth_path, device):
|
||||
spatial_net = SpatialNet().to(device)
|
||||
temporal_net = TemporalNet().to(device)
|
||||
smooth_net = SmoothNet().to(device)
|
||||
|
||||
ave_fusion = img1_warp[0] * comp_1 + img2_warp[0] * comp_2
|
||||
else:
|
||||
# linear blending
|
||||
img1_warp[
|
||||
:,
|
||||
int(0 - height_min) : int(0 - height_min) + 360,
|
||||
int(0 - width_min) : int(0 - width_min) + 480,
|
||||
] = (img1_list[i][0] + 1) / 2
|
||||
mask1 = img1_warp.clone()
|
||||
mask1[
|
||||
:,
|
||||
int(0 - height_min) : int(0 - height_min) + 360,
|
||||
int(0 - width_min) : int(0 - width_min) + 480,
|
||||
] = 1
|
||||
spatial_net.load_state_dict(torch.load(spatial_path)["model"])
|
||||
temporal_net.load_state_dict(torch.load(temporal_path)["model"])
|
||||
smooth_net.load_state_dict(torch.load(smooth_path)["model"])
|
||||
|
||||
ave_fusion = linear_blender(
|
||||
img1_warp.unsqueeze(0), img2_warp, mask1.unsqueeze(0), mask2
|
||||
)
|
||||
ave_fusion = ave_fusion[0]
|
||||
|
||||
stable_list.append(ave_fusion)
|
||||
|
||||
return stable_list, mask_list_2, img_2_list, out_width, out_height
|
||||
spatial_net.eval()
|
||||
temporal_net.eval()
|
||||
smooth_net.eval()
|
||||
return spatial_net, temporal_net, smooth_net
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "fm_nodes"
|
||||
description = "An expanding collection of ComfyUI nodes focused on new papers. Including: WFEN, RealViFormer, ProPIH, CoLIE, VFIMamba, ConvIR"
|
||||
version = "1.0.5"
|
||||
description = "An expanding collection of ComfyUI nodes focused on new papers. Including: WFEN, RealViFormer, ProPIH, CoLIE, VFIMamba, ConvIR, StabStitch"
|
||||
version = "1.0.6"
|
||||
license = {file = "LICENSE"}
|
||||
dependencies = ["torch", "einops"]
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@author: Fuou Marinas
|
||||
@title: FM Nodes
|
||||
@nickname: FM_nodes
|
||||
@description: A collection of nodes. WFEN Face Super Resolution.
|
||||
@description: A collection of nodes.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
@@ -12,22 +12,17 @@ import torch.nn.functional as F
|
||||
import tqdm
|
||||
from comfy.utils import ProgressBar
|
||||
|
||||
from .module_stabstitch.stabstitch_model import stabstitch_inference
|
||||
|
||||
from .module_colie.colie_model import CoLIE_Config, run_colie
|
||||
from .constants import (
|
||||
PROPIH_G_MODEL_PATH,
|
||||
PROPIH_VGG_MODEL_PATH,
|
||||
REALVIFORMER_MODEL_PATH,
|
||||
STAB_SPATIAL_PATH,
|
||||
STAB_TEMPORAL_PATH,
|
||||
STAB_SMOOTH_PATH,
|
||||
WFEN_MODEL_PATH,
|
||||
)
|
||||
from .module_colie.colie_model import CoLIE_Config, run_colie
|
||||
from .module_propih.propih_model import VGG19HRNetModel
|
||||
from .module_realviformer.realviformer_arch import RealViformer
|
||||
from .utils import ensure_size, img_to_mask
|
||||
from .module_wfen.wfen_model import WFENModel
|
||||
from .utils import ensure_size, img_to_mask
|
||||
|
||||
base_dir = Path(__file__).resolve().parent
|
||||
|
||||
@@ -288,54 +283,3 @@ class CoLIE_LowLight_Enhance:
|
||||
pbar.update_absolute(i, num_frames)
|
||||
|
||||
return (torch.cat(result, dim=0),)
|
||||
|
||||
|
||||
class StabStitch:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"video_1": ("IMAGE",),
|
||||
"video_2": ("IMAGE",),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = (
|
||||
"IMAGE",
|
||||
"IMAGE",
|
||||
"IMAGE",
|
||||
)
|
||||
RETURN_NAMES = (
|
||||
"combined",
|
||||
"stab",
|
||||
"mask",
|
||||
)
|
||||
FUNCTION = "todo"
|
||||
CATEGORY = "FM_nodes"
|
||||
|
||||
def todo(
|
||||
self,
|
||||
video_1: torch.Tensor,
|
||||
video_2: torch.Tensor,
|
||||
):
|
||||
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
||||
stable_list, video_frames_2, mask_frames_2 = stabstitch_inference(
|
||||
video_1,
|
||||
video_2,
|
||||
spatial_path=f"{base_dir}/{STAB_SPATIAL_PATH}",
|
||||
temporal_path=f"{base_dir}/{STAB_TEMPORAL_PATH}",
|
||||
smooth_path=f"{base_dir}/{STAB_SMOOTH_PATH}",
|
||||
device=device,
|
||||
)
|
||||
|
||||
out_video = torch.cat(stable_list, dim=0).permute(0, 2, 3, 1)
|
||||
out_mask = torch.cat(mask_frames_2, dim=0).permute(0, 2, 3, 1)
|
||||
out_img2 = torch.cat(video_frames_2, dim=0)[:, [2, 1, 0], :, :].permute(
|
||||
0, 2, 3, 1
|
||||
)
|
||||
|
||||
return (
|
||||
out_video,
|
||||
out_img2,
|
||||
out_mask,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
from pathlib import Path
|
||||
|
||||
import torch
|
||||
|
||||
from .constants import (
|
||||
STAB_CONSTRUCT_DEFAULT,
|
||||
STAB_CONSTRUCT_MODES,
|
||||
STAB_SMOOTH_PATH,
|
||||
STAB_SPATIAL_PATH,
|
||||
STAB_TEMPORAL_PATH,
|
||||
)
|
||||
from .module_stabstitch.stabstitch_model import (
|
||||
crop_or_resize,
|
||||
stabstitch_inference,
|
||||
stabstitch_single_inference,
|
||||
)
|
||||
|
||||
base_dir = Path(__file__).resolve().parent
|
||||
|
||||
|
||||
class StabStitch_Stitch:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"video_1": ("IMAGE",),
|
||||
"video_2": ("IMAGE",),
|
||||
# mode = 'FAST': use F.grid_sample to interpolate. It's fast, but may produce thin black boundary.
|
||||
# mode = 'NORMAL': use our implemented interpolation function. It's a bit slower, but avoid the black boundary.
|
||||
"interpolate_mode": (
|
||||
STAB_CONSTRUCT_MODES,
|
||||
{"default": STAB_CONSTRUCT_DEFAULT},
|
||||
),
|
||||
"do_linear_blend": (
|
||||
"BOOLEAN",
|
||||
{"default": False},
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = (
|
||||
"IMAGE",
|
||||
"IMAGE",
|
||||
"IMAGE",
|
||||
)
|
||||
RETURN_NAMES = (
|
||||
"combined",
|
||||
"stab",
|
||||
"mask",
|
||||
)
|
||||
FUNCTION = "todo"
|
||||
CATEGORY = "FM_nodes/StabStitch"
|
||||
|
||||
def todo(
|
||||
self,
|
||||
video_1: torch.Tensor,
|
||||
video_2: torch.Tensor,
|
||||
interpolate_mode: str,
|
||||
do_linear_blend: bool,
|
||||
):
|
||||
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
||||
stable_list, video_frames_2, mask_frames_2 = stabstitch_inference(
|
||||
video_1,
|
||||
video_2,
|
||||
spatial_path=f"{base_dir}/{STAB_SPATIAL_PATH}",
|
||||
temporal_path=f"{base_dir}/{STAB_TEMPORAL_PATH}",
|
||||
smooth_path=f"{base_dir}/{STAB_SMOOTH_PATH}",
|
||||
device=device,
|
||||
mode=interpolate_mode,
|
||||
do_linear_blend=do_linear_blend,
|
||||
)
|
||||
|
||||
out_video = torch.cat(stable_list, dim=0).permute(0, 2, 3, 1)
|
||||
out_mask = torch.cat(mask_frames_2, dim=0).permute(0, 2, 3, 1)
|
||||
out_img2 = torch.cat(video_frames_2, dim=0)[:, [2, 1, 0], :, :].permute(
|
||||
0, 2, 3, 1
|
||||
)
|
||||
|
||||
return (
|
||||
out_video,
|
||||
out_img2,
|
||||
out_mask,
|
||||
)
|
||||
|
||||
|
||||
class StabStitch_Stabilize:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"video_1": ("IMAGE",),
|
||||
# mode = 'FAST': use F.grid_sample to interpolate. It's fast, but may produce thin black boundary.
|
||||
# mode = 'NORMAL': use our implemented interpolation function. It's a bit slower, but avoid the black boundary.
|
||||
"interpolate_mode": (
|
||||
STAB_CONSTRUCT_MODES,
|
||||
{"default": STAB_CONSTRUCT_DEFAULT},
|
||||
),
|
||||
"do_linear_blend": (
|
||||
"BOOLEAN",
|
||||
{"default": False},
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = (
|
||||
"IMAGE",
|
||||
"IMAGE",
|
||||
"IMAGE",
|
||||
)
|
||||
RETURN_NAMES = (
|
||||
"combined",
|
||||
"stab",
|
||||
"mask",
|
||||
)
|
||||
FUNCTION = "todo"
|
||||
CATEGORY = "FM_nodes/StabStitch"
|
||||
|
||||
def todo(
|
||||
self,
|
||||
video_1: torch.Tensor,
|
||||
interpolate_mode: str,
|
||||
do_linear_blend: bool,
|
||||
):
|
||||
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
||||
stable_list, video_frames_2, mask_frames_2 = stabstitch_single_inference(
|
||||
video_1,
|
||||
spatial_path=f"{base_dir}/{STAB_SPATIAL_PATH}",
|
||||
temporal_path=f"{base_dir}/{STAB_TEMPORAL_PATH}",
|
||||
smooth_path=f"{base_dir}/{STAB_SMOOTH_PATH}",
|
||||
device=device,
|
||||
mode=interpolate_mode,
|
||||
do_linear_blend=do_linear_blend,
|
||||
)
|
||||
|
||||
out_video = torch.cat(stable_list, dim=0).permute(0, 2, 3, 1)
|
||||
out_mask = torch.cat(mask_frames_2, dim=0).permute(0, 2, 3, 1)
|
||||
out_img2 = torch.cat(video_frames_2, dim=0)[:, [2, 1, 0], :, :].permute(
|
||||
0, 2, 3, 1
|
||||
)
|
||||
|
||||
return (
|
||||
out_video,
|
||||
out_img2,
|
||||
out_mask,
|
||||
)
|
||||
|
||||
|
||||
class StabStitch_Crop_Resize:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"video_1": ("IMAGE",),
|
||||
"crop_side": (
|
||||
["left", "right"],
|
||||
{"default": "left"},
|
||||
),
|
||||
"target_h": (
|
||||
"INT",
|
||||
{"default": 360, "min": 1, "step": 1},
|
||||
),
|
||||
"target_w": (
|
||||
"INT",
|
||||
{"default": 480, "min": 1, "step": 1},
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
RETURN_NAMES = ("resized",)
|
||||
FUNCTION = "todo"
|
||||
CATEGORY = "FM_nodes/StabStitch"
|
||||
|
||||
def todo(
|
||||
self,
|
||||
video_1: torch.Tensor,
|
||||
crop_side: str,
|
||||
target_h: int,
|
||||
target_w: int,
|
||||
):
|
||||
resized_video = crop_or_resize(video_1, target_h, target_w, crop_side)
|
||||
|
||||
return (resized_video,)
|
||||
@@ -0,0 +1,458 @@
|
||||
{
|
||||
"last_node_id": 19,
|
||||
"last_link_id": 44,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 6,
|
||||
"type": "VHS_VideoCombine",
|
||||
"pos": [
|
||||
1348,
|
||||
27
|
||||
],
|
||||
"size": [
|
||||
315,
|
||||
536.03125
|
||||
],
|
||||
"flags": {
|
||||
"collapsed": false
|
||||
},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 44
|
||||
},
|
||||
{
|
||||
"name": "audio",
|
||||
"type": "AUDIO",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "meta_batch",
|
||||
"type": "VHS_BatchManager",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "Filenames",
|
||||
"type": "VHS_FILENAMES",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VHS_VideoCombine"
|
||||
},
|
||||
"widgets_values": {
|
||||
"frame_rate": 20,
|
||||
"loop_count": 0,
|
||||
"filename_prefix": "stabmask",
|
||||
"format": "video/h264-mp4",
|
||||
"pix_fmt": "yuv420p",
|
||||
"crf": 2,
|
||||
"save_metadata": true,
|
||||
"pingpong": false,
|
||||
"save_output": false,
|
||||
"videopreview": {
|
||||
"hidden": false,
|
||||
"paused": false,
|
||||
"params": {
|
||||
"filename": "stabmask_00001.mp4",
|
||||
"subfolder": "",
|
||||
"type": "temp",
|
||||
"format": "video/h264-mp4",
|
||||
"frame_rate": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 19,
|
||||
"type": "StabStitch_Stabilize",
|
||||
"pos": [
|
||||
296,
|
||||
55
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
122
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "video_1",
|
||||
"type": "IMAGE",
|
||||
"link": 41
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "combined",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
42
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "stab",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
43
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 1
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
44
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 2
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "StabStitch_Stabilize"
|
||||
},
|
||||
"widgets_values": [
|
||||
"FAST",
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 18,
|
||||
"type": "StabStitch_Crop_Resize",
|
||||
"pos": [
|
||||
406,
|
||||
229
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
106
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "video_1",
|
||||
"type": "IMAGE",
|
||||
"link": 40
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "resized",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
41
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "StabStitch_Crop_Resize"
|
||||
},
|
||||
"widgets_values": [
|
||||
"left",
|
||||
360,
|
||||
480
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 17,
|
||||
"type": "VHS_LoadVideo",
|
||||
"pos": [
|
||||
45,
|
||||
8
|
||||
],
|
||||
"size": [
|
||||
235.1999969482422,
|
||||
398.1134866403979
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "meta_batch",
|
||||
"type": "VHS_BatchManager",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
40
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "frame_count",
|
||||
"type": "INT",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "audio",
|
||||
"type": "AUDIO",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "video_info",
|
||||
"type": "VHS_VIDEOINFO",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VHS_LoadVideo"
|
||||
},
|
||||
"widgets_values": {
|
||||
"video": "cat.mp4",
|
||||
"force_rate": 0,
|
||||
"force_size": "Disabled",
|
||||
"custom_width": 512,
|
||||
"custom_height": 512,
|
||||
"frame_load_cap": 0,
|
||||
"skip_first_frames": 0,
|
||||
"select_every_nth": 1,
|
||||
"choose video to upload": "image",
|
||||
"videopreview": {
|
||||
"hidden": false,
|
||||
"paused": false,
|
||||
"params": {
|
||||
"frame_load_cap": 0,
|
||||
"skip_first_frames": 0,
|
||||
"force_rate": 0,
|
||||
"filename": "cat.mp4",
|
||||
"type": "input",
|
||||
"format": "video/mp4",
|
||||
"select_every_nth": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"type": "VHS_VideoCombine",
|
||||
"pos": [
|
||||
995,
|
||||
28
|
||||
],
|
||||
"size": [
|
||||
315,
|
||||
536.03125
|
||||
],
|
||||
"flags": {
|
||||
"collapsed": false
|
||||
},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 43
|
||||
},
|
||||
{
|
||||
"name": "audio",
|
||||
"type": "AUDIO",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "meta_batch",
|
||||
"type": "VHS_BatchManager",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "Filenames",
|
||||
"type": "VHS_FILENAMES",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VHS_VideoCombine"
|
||||
},
|
||||
"widgets_values": {
|
||||
"frame_rate": 20,
|
||||
"loop_count": 0,
|
||||
"filename_prefix": "stab",
|
||||
"format": "video/h264-mp4",
|
||||
"pix_fmt": "yuv420p",
|
||||
"crf": 2,
|
||||
"save_metadata": true,
|
||||
"pingpong": false,
|
||||
"save_output": true,
|
||||
"videopreview": {
|
||||
"hidden": false,
|
||||
"paused": false,
|
||||
"params": {
|
||||
"filename": "stab_00001.mp4",
|
||||
"subfolder": "",
|
||||
"type": "temp",
|
||||
"format": "video/h264-mp4",
|
||||
"frame_rate": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "VHS_VideoCombine",
|
||||
"pos": [
|
||||
644,
|
||||
27
|
||||
],
|
||||
"size": [
|
||||
315,
|
||||
536.03125
|
||||
],
|
||||
"flags": {
|
||||
"collapsed": false
|
||||
},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 42
|
||||
},
|
||||
{
|
||||
"name": "audio",
|
||||
"type": "AUDIO",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "meta_batch",
|
||||
"type": "VHS_BatchManager",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "Filenames",
|
||||
"type": "VHS_FILENAMES",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VHS_VideoCombine"
|
||||
},
|
||||
"widgets_values": {
|
||||
"frame_rate": 20,
|
||||
"loop_count": 0,
|
||||
"filename_prefix": "stabstitch",
|
||||
"format": "video/h264-mp4",
|
||||
"pix_fmt": "yuv420p",
|
||||
"crf": 2,
|
||||
"save_metadata": true,
|
||||
"pingpong": false,
|
||||
"save_output": true,
|
||||
"videopreview": {
|
||||
"hidden": false,
|
||||
"paused": false,
|
||||
"params": {
|
||||
"filename": "stabstitch_00007.mp4",
|
||||
"subfolder": "",
|
||||
"type": "output",
|
||||
"format": "video/h264-mp4",
|
||||
"frame_rate": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
40,
|
||||
17,
|
||||
0,
|
||||
18,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
41,
|
||||
18,
|
||||
0,
|
||||
19,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
42,
|
||||
19,
|
||||
0,
|
||||
3,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
43,
|
||||
19,
|
||||
1,
|
||||
15,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
44,
|
||||
19,
|
||||
2,
|
||||
6,
|
||||
0,
|
||||
"IMAGE"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 0.9090909090909091,
|
||||
"offset": [
|
||||
86.31161530434264,
|
||||
196.97150602340395
|
||||
]
|
||||
}
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
@@ -0,0 +1,474 @@
|
||||
{
|
||||
"last_node_id": 18,
|
||||
"last_link_id": 49,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 15,
|
||||
"type": "VHS_VideoCombine",
|
||||
"pos": [
|
||||
995,
|
||||
28
|
||||
],
|
||||
"size": [
|
||||
315,
|
||||
473
|
||||
],
|
||||
"flags": {
|
||||
"collapsed": false
|
||||
},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 48
|
||||
},
|
||||
{
|
||||
"name": "audio",
|
||||
"type": "AUDIO",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "meta_batch",
|
||||
"type": "VHS_BatchManager",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "Filenames",
|
||||
"type": "VHS_FILENAMES",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VHS_VideoCombine"
|
||||
},
|
||||
"widgets_values": {
|
||||
"frame_rate": 20,
|
||||
"loop_count": 0,
|
||||
"filename_prefix": "stab",
|
||||
"format": "video/h264-mp4",
|
||||
"pix_fmt": "yuv420p",
|
||||
"crf": 2,
|
||||
"save_metadata": true,
|
||||
"pingpong": false,
|
||||
"save_output": false,
|
||||
"videopreview": {
|
||||
"hidden": false,
|
||||
"paused": false,
|
||||
"params": {
|
||||
"filename": "stab_00002.mp4",
|
||||
"subfolder": "",
|
||||
"type": "temp",
|
||||
"format": "video/h264-mp4",
|
||||
"frame_rate": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "VHS_VideoCombine",
|
||||
"pos": [
|
||||
1348,
|
||||
27
|
||||
],
|
||||
"size": [
|
||||
315,
|
||||
473
|
||||
],
|
||||
"flags": {
|
||||
"collapsed": false
|
||||
},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 49
|
||||
},
|
||||
{
|
||||
"name": "audio",
|
||||
"type": "AUDIO",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "meta_batch",
|
||||
"type": "VHS_BatchManager",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "Filenames",
|
||||
"type": "VHS_FILENAMES",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VHS_VideoCombine"
|
||||
},
|
||||
"widgets_values": {
|
||||
"frame_rate": 20,
|
||||
"loop_count": 0,
|
||||
"filename_prefix": "stabmask",
|
||||
"format": "video/h264-mp4",
|
||||
"pix_fmt": "yuv420p",
|
||||
"crf": 2,
|
||||
"save_metadata": true,
|
||||
"pingpong": false,
|
||||
"save_output": false,
|
||||
"videopreview": {
|
||||
"hidden": false,
|
||||
"paused": false,
|
||||
"params": {
|
||||
"filename": "stabmask_00002.mp4",
|
||||
"subfolder": "",
|
||||
"type": "temp",
|
||||
"format": "video/h264-mp4",
|
||||
"frame_rate": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "VHS_VideoCombine",
|
||||
"pos": [
|
||||
649,
|
||||
27
|
||||
],
|
||||
"size": [
|
||||
315,
|
||||
473
|
||||
],
|
||||
"flags": {
|
||||
"collapsed": false
|
||||
},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 47
|
||||
},
|
||||
{
|
||||
"name": "audio",
|
||||
"type": "AUDIO",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "meta_batch",
|
||||
"type": "VHS_BatchManager",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "Filenames",
|
||||
"type": "VHS_FILENAMES",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VHS_VideoCombine"
|
||||
},
|
||||
"widgets_values": {
|
||||
"frame_rate": 20,
|
||||
"loop_count": 0,
|
||||
"filename_prefix": "stabstitch",
|
||||
"format": "video/h264-mp4",
|
||||
"pix_fmt": "yuv420p",
|
||||
"crf": 2,
|
||||
"save_metadata": true,
|
||||
"pingpong": false,
|
||||
"save_output": true,
|
||||
"videopreview": {
|
||||
"hidden": false,
|
||||
"paused": false,
|
||||
"params": {
|
||||
"filename": "stabstitch_00006.mp4",
|
||||
"subfolder": "",
|
||||
"type": "output",
|
||||
"format": "video/h264-mp4",
|
||||
"frame_rate": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "VHS_LoadImagesPath",
|
||||
"pos": [
|
||||
73,
|
||||
218
|
||||
],
|
||||
"size": [
|
||||
226.8000030517578,
|
||||
363.2251838887286
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "meta_batch",
|
||||
"type": "VHS_BatchManager",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
45
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "MASK",
|
||||
"type": "MASK",
|
||||
"links": null,
|
||||
"shape": 3,
|
||||
"slot_index": 1
|
||||
},
|
||||
{
|
||||
"name": "frame_count",
|
||||
"type": "INT",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VHS_LoadImagesPath"
|
||||
},
|
||||
"widgets_values": {
|
||||
"directory": "J:\\AI\\stabber\\video1",
|
||||
"image_load_cap": 0,
|
||||
"skip_first_images": 0,
|
||||
"select_every_nth": 1,
|
||||
"choose folder to upload": "image",
|
||||
"videopreview": {
|
||||
"hidden": false,
|
||||
"paused": false,
|
||||
"params": {
|
||||
"frame_load_cap": 0,
|
||||
"skip_first_images": 0,
|
||||
"filename": "J:\\AI\\stabber\\video1",
|
||||
"type": "path",
|
||||
"format": "folder",
|
||||
"select_every_nth": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"type": "VHS_LoadImagesPath",
|
||||
"pos": [
|
||||
323,
|
||||
213
|
||||
],
|
||||
"size": [
|
||||
226.8000030517578,
|
||||
363.2251838887286
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "meta_batch",
|
||||
"type": "VHS_BatchManager",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
46
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "MASK",
|
||||
"type": "MASK",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "frame_count",
|
||||
"type": "INT",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VHS_LoadImagesPath"
|
||||
},
|
||||
"widgets_values": {
|
||||
"directory": "J:\\AI\\stabber\\video2",
|
||||
"image_load_cap": 0,
|
||||
"skip_first_images": 0,
|
||||
"select_every_nth": 1,
|
||||
"choose folder to upload": "image",
|
||||
"videopreview": {
|
||||
"hidden": false,
|
||||
"paused": false,
|
||||
"params": {
|
||||
"frame_load_cap": 0,
|
||||
"skip_first_images": 0,
|
||||
"filename": "J:\\AI\\stabber\\video2",
|
||||
"type": "path",
|
||||
"format": "folder",
|
||||
"select_every_nth": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 18,
|
||||
"type": "StabStitch",
|
||||
"pos": [
|
||||
330,
|
||||
37
|
||||
],
|
||||
"size": [
|
||||
215.16154450854913,
|
||||
122
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "video_1",
|
||||
"type": "IMAGE",
|
||||
"link": 45
|
||||
},
|
||||
{
|
||||
"name": "video_2",
|
||||
"type": "IMAGE",
|
||||
"link": 46
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "combined",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
47
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "stab",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
48
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 1
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
49
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 2
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "StabStitch"
|
||||
},
|
||||
"widgets_values": [
|
||||
"FAST",
|
||||
true
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
45,
|
||||
9,
|
||||
0,
|
||||
18,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
46,
|
||||
10,
|
||||
0,
|
||||
18,
|
||||
1,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
47,
|
||||
18,
|
||||
0,
|
||||
3,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
48,
|
||||
18,
|
||||
1,
|
||||
15,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
49,
|
||||
18,
|
||||
2,
|
||||
6,
|
||||
0,
|
||||
"IMAGE"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 1,
|
||||
"offset": [
|
||||
29.8384554914509,
|
||||
163.0904108785293
|
||||
]
|
||||
}
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
|
Before Width: | Height: | Size: 336 KiB After Width: | Height: | Size: 336 KiB |
|
After Width: | Height: | Size: 448 KiB |
|
After Width: | Height: | Size: 237 KiB |
|
Before Width: | Height: | Size: 641 KiB After Width: | Height: | Size: 641 KiB |