Skip to content

Commit 240d081

Browse files
authored
New mask nodes & reordering of all nodes
1 parent 2fb5b78 commit 240d081

File tree

3 files changed

+205
-12
lines changed

3 files changed

+205
-12
lines changed

__init__.py

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
E2ENode,
1212
E2Face,
1313
E2PNode,
14+
EMask2Face,
1415
Face2E,
16+
FaceMask2E,
17+
MaskE2ENode,
1518
MonoScopicToStereoNode,
1619
Pad180To360Node,
1720
PasteImageWithCoordsNode,
@@ -23,49 +26,69 @@
2326
)
2427

2528
NODE_CLASS_MAPPINGS = {
29+
# Equirectangular Single Face
30+
"Equirectangular to Face": E2Face,
31+
"Equirectangular Mask to Face": EMask2Face,
32+
"Face to Equirectangular": Face2E,
33+
"Face Mask to Equirectangular": FaceMask2E,
34+
# Equirectangular Full
2635
"Cubemap to Equirectangular": C2ENode,
2736
"Equirectangular to Cubemap": E2CNode,
2837
"Equirectangular to Perspective": E2PNode,
2938
"Equirectangular Rotation": E2ENode,
39+
"Mask Equirectangular Rotation": MaskE2ENode,
40+
"Pad 180 to 360 Equirectangular": Pad180To360Node,
41+
"Crop 360 to 180 Equirectangular": Crop360To180Node,
42+
# Cubemap
3043
"Split Cubemap Faces": SplitFacesNode,
3144
"Stack Cubemap Faces": StackFacesNode,
45+
# Miscellaneous
3246
"Roll Image Axes": RollImageNode,
47+
"Roll Mask Axes": RollMaskNode,
3348
"Masked Diff C2E": C2EMaskedDiffNode,
3449
"Crop Image with Coords": CropImageWithCoordsNode,
3550
"Paste Image with Coords": PasteImageWithCoordsNode,
36-
"Pad 180 to 360 Equirectangular": Pad180To360Node,
37-
"Crop 360 to 180 Equirectangular": Crop360To180Node,
51+
# Stereo
3852
"Crop Stereo to Monoscopic": StereoToMonoScopicNode,
3953
"Merge Monoscopic into Stereo": StereoToMonoScopicNode,
54+
# Models
4055
"Apply Circular Padding VAE": ApplyCircularConvPaddingVAE,
4156
"Apply Circular Padding Model": ApplyCircularConvPaddingModel,
57+
# Masks
4258
"Create Seam Mask": CreateSeamMask,
4359
"Create Pole Mask": CreatePoleMask,
44-
"Equirectangular to Face": E2Face,
45-
"Face to Equirectangular": Face2E,
46-
"Roll Mask Axes": RollMaskNode,
4760
}
4861

4962
NODE_DISPLAY_NAME_MAPPINGS = {
63+
# Equirectangular Single Face
64+
"Equirectangular to Face": "Equirectangular to Face",
65+
"Equirectangular Mask to Face": "Equirectangular Mask to Face",
66+
"Face to Equirectangular": "Face to Equirectangular",
67+
"Face Mask to Equirectangular": "Face Mask to Equirectangular",
68+
# Equirectangular Full
5069
"Cubemap to Equirectangular": "Cubemap to Equirectangular",
5170
"Equirectangular to Cubemap": "Equirectangular to Cubemap",
5271
"Equirectangular to Perspective": "Equirectangular to Perspective",
5372
"Equirectangular Rotation": "Equirectangular Rotation",
73+
"Mask Equirectangular Rotation": "Mask Equirectangular Rotation",
74+
"Pad 180 to 360 Equirectangular": "Pad 180 to 360 Equirectangular",
75+
"Crop 360 to 180 Equirectangular": "Crop 360 to 180 Equirectangular",
76+
# Cubemap
5477
"Split Cubemap Faces": "Split Cubemap Faces",
5578
"Stack Cubemap Faces": "Stack Cubemap Faces",
79+
# Miscellaneous
5680
"Roll Image Axes": "Roll Image Axes",
81+
"Roll Mask Axes": "Roll Mask Axes",
5782
"Masked Diff C2E": "Masked Diff C2E",
5883
"Crop Image with Coords": "Crop Image with Coords",
5984
"Paste Image with Coords": "Paste Image with Coords",
60-
"Pad 180 to 360 Equirectangular": "Pad 180 to 360 Equirectangular",
61-
"Crop 360 to 180 Equirectangular": "Crop 360 to 180 Equirectangular",
85+
# Stereo
6286
"Crop Stereo to Monoscopic": "Crop Stereo to Monoscopic",
6387
"Merge Monoscopic into Stereo": "Merge Monoscopic into Stereo",
88+
# Models
6489
"Apply Circular Padding VAE": "Apply Circular Padding VAE",
6590
"Apply Circular Padding Model": "Apply Circular Padding Model",
91+
# Masks
6692
"Create Seam Mask": "Create Seam Mask",
6793
"Create Pole Mask": "Create Pole Mask",
68-
"Equirectangular to Face": "Equirectangular to Face",
69-
"Face to Equirectangular": "Face to Equirectangular",
70-
"Roll Mask Axes": "Roll Mask Axes",
7194
}

nodes.py

Lines changed: 171 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1194,7 +1194,7 @@ def run(
11941194
# Stack all results into a single tensor [B,H,W,C]
11951195
output_mask = torch.cat(output_mask).permute(0, 3, 1, 2)
11961196

1197-
return (output_mask[:, 0:1, ...],)
1197+
return (output_mask[:, 0, ...],)
11981198

11991199

12001200
class Face2E:
@@ -1299,3 +1299,173 @@ def roll_mask(
12991299
roll_y = 0
13001300
roll_x = px_half
13011301
return (torch.roll(mask, shifts=(roll_y, roll_x), dims=(1, 2)),)
1302+
1303+
1304+
class FaceMask2E:
1305+
"""
1306+
Face Mask To Equirectangular
1307+
"""
1308+
1309+
@classmethod
1310+
def INPUT_TYPES(s) -> Dict:
1311+
return {
1312+
"required": {
1313+
"mask": ("MASK", {"default": None}),
1314+
"face": (
1315+
["Up", "Down", "Front", "Right", "Left", "Back"],
1316+
{"default": "Down"},
1317+
),
1318+
"base_equi_color": ("FLOAT", {"default": 0.0}),
1319+
"padding_mode": (
1320+
["bilinear", "bicubic", "nearest"],
1321+
{"default": "bilinear"},
1322+
),
1323+
},
1324+
}
1325+
1326+
RETURN_TYPES = ("MASK",)
1327+
RETURN_NAMES = ("Equirectangular Mask",)
1328+
1329+
FUNCTION = "run_facemask2e"
1330+
1331+
CATEGORY = "pytorch360convert"
1332+
1333+
def run_facemask2e(
1334+
self,
1335+
mask: torch.Tensor,
1336+
face: str = "Down",
1337+
base_equi_color: float = 0.0,
1338+
padding_mode: str = "bilinear",
1339+
) -> Tuple[torch.Tensor]:
1340+
assert mask.dim() == 3, f"Image should have 3 dimensions, got {mask.shape}"
1341+
1342+
output_mask = []
1343+
for f_mask in mask:
1344+
f_mask = f_mask = f_mask[None, ...]
1345+
cubemap_dict = {}
1346+
for face_name in ["Front", "Right", "Back", "Left", "Up", "Down"]:
1347+
if face_name != face:
1348+
cubemap_dict[face_name] = torch.ones_like(f_mask) * base_equi_color
1349+
else:
1350+
cubemap_dict[face_name] = mask.reshape(1, *mask.shape[1:])
1351+
output_mask += [
1352+
c2e(
1353+
cubemap=cubemap_dict,
1354+
cube_format="dict",
1355+
mode=padding_mode,
1356+
channels_first=True,
1357+
)
1358+
]
1359+
return (torch.cat(output_mask),)
1360+
1361+
1362+
class EMask2Face:
1363+
"""
1364+
Equirectangular Mask to Face
1365+
"""
1366+
1367+
@classmethod
1368+
def INPUT_TYPES(s) -> Dict:
1369+
return {
1370+
"required": {
1371+
"mask": ("MASK", {"default": None}),
1372+
"face_width": ("INT", {"default": -1}),
1373+
"padding_mode": (
1374+
["bilinear", "bicubic", "nearest"],
1375+
{"default": "bilinear"},
1376+
),
1377+
"cube_face": (
1378+
["Up", "Down", "Right", "Left", "Front", "Back"],
1379+
{"default": "Front"},
1380+
),
1381+
},
1382+
}
1383+
1384+
RETURN_TYPES = ("MASK",)
1385+
RETURN_NAMES = ("Face MASK",)
1386+
1387+
FUNCTION = "run_emask2face"
1388+
1389+
CATEGORY = "pytorch360convert"
1390+
1391+
def run_emask2face(
1392+
self,
1393+
mask: torch.Tensor,
1394+
face_width: int = -1,
1395+
padding_mode: str = "bilinear",
1396+
cube_face: str = "Front",
1397+
) -> Tuple[torch.Tensor]:
1398+
1399+
B, H, W = mask.shape
1400+
outputs = []
1401+
1402+
for i in range(B):
1403+
singlmask = mask[i : i + 1][..., None] # [H,W,C]
1404+
# Determine face width
1405+
face_w = H // 2 if face_width < 1 else face_width
1406+
1407+
# Convert single equirectangular mask to cubemap dict
1408+
cubemap = e2c(
1409+
singlmask,
1410+
face_w=face_w,
1411+
mode=padding_mode,
1412+
cube_format="dict",
1413+
channels_first=False,
1414+
)
1415+
1416+
# Pick requested face
1417+
face_tensor = cubemap[cube_face] # [face_w, face_w, C]
1418+
1419+
outputs.append(face_tensor) # [1,H,W,C]
1420+
1421+
# Concatenate into [B,H,W,C]
1422+
output_batch = torch.cat(outputs, dim=0)[..., 0]
1423+
return (output_batch,)
1424+
1425+
1426+
class MaskE2ENode:
1427+
"""
1428+
Mask Equirectangular Rotation
1429+
"""
1430+
1431+
@classmethod
1432+
def INPUT_TYPES(s) -> Dict:
1433+
return {
1434+
"required": {
1435+
"mask": ("MASK", {"default": None}),
1436+
"roll": ("FLOAT", {"default": 0.0}),
1437+
"h_deg": ("FLOAT", {"default": 0.0}),
1438+
"v_deg": ("FLOAT", {"default": 0.0}),
1439+
"padding_mode": (
1440+
["bilinear", "bicubic", "nearest"],
1441+
{"default": "bilinear"},
1442+
),
1443+
},
1444+
}
1445+
1446+
RETURN_TYPES = ("MASK",)
1447+
RETURN_NAMES = ("Rotated Mask",)
1448+
1449+
FUNCTION = "mask_e2e"
1450+
1451+
CATEGORY = "pytorch360convert"
1452+
1453+
def mask_e2e(
1454+
self,
1455+
mask: torch.Tensor,
1456+
roll: float = 0.0,
1457+
h_deg: float = 0.0,
1458+
v_deg: float = 0.0,
1459+
padding_mode: str = "bilinear",
1460+
) -> Tuple[torch.Tensor]:
1461+
assert mask.dim() == 3, f"mask should have 3 dimensions, got {mask.dim()}"
1462+
return (
1463+
e2e(
1464+
e_img=mask[..., None],
1465+
h_deg=h_deg,
1466+
v_deg=v_deg,
1467+
roll=roll,
1468+
mode=padding_mode,
1469+
channels_first=False,
1470+
)[..., 0],
1471+
)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[project]
22
name = "comfyui-pytorch360convert"
33
description = "A collection of custom nodes for working with and converting between and working with 360 degree equirectangular images, cubemap, and perspective images. Also includes Circular padding Conv2d options for models and VAEs, along with nodes to fix seams and polar artifacts. Panoramic 360 images are also sometimes known as VR photography (virtual reality), HDRI environments (ex: skyboxes), image spheres, spherical images, 360 pano."
4-
version = "1.0.9"
4+
version = "1.1.0"
55
license = {file = "LICENSE"}
66
dependencies = ["pytorch360convert"]
77

0 commit comments

Comments
 (0)