Aluode's picture
Upload folder using huggingface_hub
3bb804c verified
import numpy as np
import cv2
from scipy.fft import ifft2, ifftshift
import __main__
try:
BaseNode = __main__.BaseNode
QtGui = __main__.QtGui
except AttributeError:
class BaseNode:
def get_blended_input(self, name, mode): return None
import PyQt6.QtGui as QtGui
class HolographicIFFTNodeX(BaseNode):
"""
Holographic IFFT - The Inverse Reality
======================================
Treats the input image not as "Space", but as "Frequency" (k-space).
It effectively asks: "If this image were a diffraction pattern,
what hidden object created it?"
MECHANISM:
1. Input (Gradient/Field) -> Treated as MAGNITUDE spectrum.
2. Phase Synthesis -> We generate the missing phase (The "Light").
- 'Void': Phase = 0 (Autocorrelation)
- 'Chaos': Random Phase
- 'Structure': Phase derived from image structure
3. Inverse FFT -> Collapses the spectrum into a spatial image.
This reveals the "Reciprocal Ghost" - the hidden symmetries that
exist in the frequency domain of your field.
"""
NODE_CATEGORY = "Analysis"
NODE_TITLE = "Holographic IFFT 2"
NODE_COLOR = QtGui.QColor(100, 255, 200) # Spectral Cyan
def __init__(self):
super().__init__()
self.inputs = {
'diffraction_pattern': 'image', # The Gradient Field (treated as FFT Mag)
'phase_mod': 'signal', # Rotate the phase (The "Laser" angle)
'frequency_scale': 'signal', # Zoom in k-space
'reset': 'signal'
}
self.outputs = {
'hologram': 'image', # The reconstructed "Ghost"
'phase_mask': 'image' # The phase we used
}
self.size = 128
self.phase_mode = 'structure' # 'void', 'chaos', 'structure'
# Internal state
self.phase_map = None
self.t = 0.0
def step(self):
# 1. Get Inputs
pattern = self.get_blended_input('diffraction_pattern', 'first')
p_mod = self.get_blended_input('phase_mod', 'sum')
f_scale = self.get_blended_input('frequency_scale', 'sum')
if pattern is None: return
# Defaults
if p_mod is None: p_mod = 0.0
if f_scale is None: f_scale = 1.0
# Resize/Format
if pattern.shape[:2] != (self.size, self.size):
pattern = cv2.resize(pattern, (self.size, self.size))
if pattern.ndim == 3:
pattern = np.mean(pattern, axis=2)
# 2. Treat Input as MAGNITUDE (The Diffraction Pattern)
# We shift it so the center of the image is DC (0 frequency)
magnitude = np.abs(pattern)
# Apply Frequency Scaling (Zooming in Reciprocal Space)
if f_scale != 1.0 and f_scale > 0.1:
# Zooming the spectrum changes the size of the object
center = self.size // 2
M = cv2.getRotationMatrix2D((center, center), 0, f_scale)
magnitude = cv2.warpAffine(magnitude, M, (self.size, self.size))
# 3. Synthesize the Missing Phase
# This is where we "change the values" to catch the ghost
if self.phase_map is None:
self.phase_map = np.zeros_like(magnitude)
# Create a phase ramp (spatial offset) + modulation
y, x = np.ogrid[:self.size, :self.size]
# 'Structure' Mode: Phase is related to position (creates coherence)
# We animate the phase over time to "scan" the hologram
self.t += 0.05
phase_structure = (x * np.cos(self.t) + y * np.sin(self.t)) * (0.1 + p_mod * 0.1)
# Combine Magnitude and Phase into Complex Spectrum
# Z = Mag * e^(i * theta)
complex_spectrum = magnitude * np.exp(1j * phase_structure)
# 4. The Inverse FFT (The Reconstruction)
# We assume the input image had (0,0) in top-left, so we don't shift first.
# But usually spectral view has DC in center. Let's try shifting.
complex_spectrum = ifftshift(complex_spectrum)
reconstructed = ifft2(complex_spectrum)
# 5. Extract Real Component (The Hologram)
self.hologram = np.abs(reconstructed)
self.current_phase = np.angle(complex_spectrum)
def get_output(self, port_name):
if port_name == 'hologram':
if hasattr(self, 'hologram'):
return self._normalize(self.hologram)
elif port_name == 'phase_mask':
if hasattr(self, 'current_phase'):
return self._normalize(self.current_phase)
return None
def _normalize(self, img):
img = np.nan_to_num(img)
norm = (img - np.min(img)) / (np.max(img) - np.min(img) + 1e-10)
return (norm * 255).astype(np.uint8)
def get_display_image(self):
if not hasattr(self, 'hologram'): return None
# Display: The Hologram (Reconstructed Reality)
img = self._normalize(self.hologram)
display = cv2.applyColorMap(img, cv2.COLORMAP_OCEAN)
cv2.putText(display, "Holographic IFFT", (5, 15),
cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255,255,255), 1)
return QtGui.QImage(display.data, self.size, self.size,
self.size*3, QtGui.QImage.Format.Format_RGB888)
def get_config_options(self):
return [
("Resolution", "size", 128, None),
("Scale", "scale", 1.0, None)
]