LuckyOda's picture
Add files using upload-large-folder tool
ba088fc verified
Raw
History Blame Contribute Delete
4.03 kB
# SPDX-License-Identifier: MIT
# Copyright (C) 2025 ComfyUI-Multiband Contributors
"""NumPy file I/O for MULTIBAND_IMAGE."""
import os
from typing import Dict, List, Any, Optional, Tuple
import numpy as np
def load_numpy(path: str, normalize: bool = True) -> Tuple[np.ndarray, Optional[List[str]], Dict[str, Any]]:
"""
Load a .npy file.
Args:
path: Path to .npy file
normalize: Whether to normalize to [0, 1] range
Returns:
Tuple of (array, channel_names, metadata)
channel_names and metadata are None for .npy files
"""
arr = np.load(path)
if normalize and arr.max() > 1.0:
arr = arr.astype(np.float32) / 255.0 if arr.max() <= 255 else arr.astype(np.float32) / arr.max()
return arr, None, {}
def save_numpy(path: str, arr: np.ndarray) -> str:
"""
Save array to .npy file.
Args:
path: Output path
arr: Array to save
Returns:
Saved file path
"""
# Ensure .npy extension
if not path.endswith('.npy'):
path = path + '.npy'
# Create directory if needed
os.makedirs(os.path.dirname(path) or '.', exist_ok=True)
np.save(path, arr)
return path
def load_npz(path: str, normalize: bool = True) -> Tuple[np.ndarray, Optional[List[str]], Dict[str, Any]]:
"""
Load a .npz file with optional channel_names and metadata.
Expected keys:
- 'samples': the main array (required)
- 'channel_names': string array of channel names (optional)
- Other keys become metadata
Args:
path: Path to .npz file
normalize: Whether to normalize to [0, 1] range
Returns:
Tuple of (array, channel_names, metadata)
"""
data = np.load(path, allow_pickle=True)
# Get samples array
if 'samples' in data:
arr = data['samples']
elif 'arr_0' in data:
# Fallback for simple npz files
arr = data['arr_0']
else:
# Try first key
keys = list(data.keys())
if not keys:
raise ValueError(f"Empty npz file: {path}")
arr = data[keys[0]]
if normalize and arr.max() > 1.0:
arr = arr.astype(np.float32) / 255.0 if arr.max() <= 255 else arr.astype(np.float32) / arr.max()
# Get channel names
channel_names = None
if 'channel_names' in data:
cn = data['channel_names']
if isinstance(cn, np.ndarray):
channel_names = cn.tolist()
else:
channel_names = list(cn)
# Get metadata (all other keys)
metadata = {}
exclude_keys = {'samples', 'arr_0', 'channel_names'}
for key in data.keys():
if key not in exclude_keys:
val = data[key]
# Handle numpy arrays that might contain pickled dicts
if isinstance(val, np.ndarray) and val.ndim == 0:
val = val.item()
metadata[key] = val
return arr, channel_names, metadata
def save_npz(
path: str,
arr: np.ndarray,
channel_names: Optional[List[str]] = None,
metadata: Optional[Dict[str, Any]] = None,
compressed: bool = True
) -> str:
"""
Save array to .npz file with optional channel_names and metadata.
Args:
path: Output path
arr: Array to save
channel_names: Optional list of channel names
metadata: Optional metadata dict
compressed: Whether to use compression
Returns:
Saved file path
"""
# Ensure .npz extension
if not path.endswith('.npz'):
path = path + '.npz'
# Create directory if needed
os.makedirs(os.path.dirname(path) or '.', exist_ok=True)
# Build save dict
save_dict = {'samples': arr}
if channel_names is not None:
save_dict['channel_names'] = np.array(channel_names, dtype=object)
if metadata:
for key, val in metadata.items():
save_dict[key] = val
# Save
if compressed:
np.savez_compressed(path, **save_dict)
else:
np.savez(path, **save_dict)
return path