File size: 9,374 Bytes
a9aa180 4e9e766 a9aa180 83b86f7 a9aa180 83b86f7 a9aa180 83b86f7 a9aa180 83b86f7 a9aa180 83b86f7 a9aa180 4e9e766 a9aa180 83b86f7 a9aa180 83b86f7 4e9e766 83b86f7 4e9e766 83b86f7 a9aa180 83b86f7 a9aa180 83b86f7 a9aa180 83b86f7 a9aa180 83b86f7 a9aa180 83b86f7 a9aa180 83b86f7 4e9e766 83b86f7 a9aa180 83b86f7 a9aa180 83b86f7 a9aa180 83b86f7 a9aa180 4e9e766 a9aa180 83b86f7 a9aa180 83b86f7 4e9e766 83b86f7 a9aa180 83b86f7 a9aa180 83b86f7 4e9e766 83b86f7 4e9e766 83b86f7 4e9e766 83b86f7 4e9e766 83b86f7 a9aa180 83b86f7 a9aa180 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
import gradio as gr
import os, math, tempfile
import numpy as np
from PIL import Image, UnidentifiedImageError
# ==========================================
# FLC v1.3 Logic Engine (The "Secret Sauce")
# ==========================================
PHI = (1.0 + 5.0**0.5) / 2.0
def fibonacci_sequence(n):
fibs = [1, 2]
while len(fibs) < n: fibs.append(fibs[-1] + fibs[-2])
return np.array(fibs[:n], dtype=np.int64)
def fibonacci_frequency_boundaries(n_coeffs, n_bands):
if n_bands < 2: return [0, n_coeffs]
fibs = fibonacci_sequence(n_bands).astype(np.float64)
w = fibs / (fibs.sum() + 1e-12)
cum = np.cumsum(w)
b = [0]
for i in range(n_bands - 1): b.append(int(round(n_coeffs * cum[i])))
b.append(n_coeffs)
for i in range(1, len(b)):
if b[i] <= b[i-1]: b[i] = b[i-1] + 1
return b
def dct_ortho_1d(x):
N = x.shape[0]
v = np.concatenate([x, x[::-1]])
V = np.fft.fft(v)
k = np.arange(N)
X = np.real(V[:N] * np.exp(-1j * np.pi * k / (2 * N)))
X *= 2.0
X[0] *= (1.0 / math.sqrt(4 * N))
X[1:] *= (1.0 / math.sqrt(2 * N))
return X
def idct_ortho_1d(X):
N = X.shape[0]
x0, xr = X[0] * math.sqrt(4 * N), X[1:] * math.sqrt(2 * N)
c = np.empty(N, dtype=np.complex128)
c[0], c[1:] = x0 / 2.0, xr / 2.0
k = np.arange(N)
c = c * np.exp(1j * np.pi * k / (2 * N))
V = np.zeros(2 * N, dtype=np.complex128)
V[:N] = c
V[N+1:] = np.conj(c[1:][::-1])
return np.fft.ifft(V).real[:N]
# --- Visualization Helpers ---
def hologram_spectrum_image(zints):
# Visualizes the frequency domain data as a 2D spectrum
z = zints[:262144]; v = np.tanh(z / 32.0)
theta = (2 * math.pi / (PHI**2)) * np.arange(v.size) + 2.0 * math.pi * (v * 0.25)
r = 1.0 + 0.35 * np.abs(v)
syms = r * np.cos(theta) + 1j * r * np.sin(theta)
N = int(2**math.ceil(math.log2(math.sqrt(syms.size or 1))))
U = np.pad(syms, (0, N*N - syms.size)).reshape(N, N)
mag = np.log1p(np.abs(np.fft.fftshift(np.fft.fft2(U))))
mag = (mag - mag.min()) / (mag.max() - mag.min() + 1e-12)
return (mag * 255).astype(np.uint8)
def bytes_to_fib_spiral_image(data):
# Visualizes linear data arranged on a Fibonacci spiral tiling
arr = np.frombuffer(data, dtype=np.uint8)[:262144]
fibs = [1, 1]
while sum(s*s for s in fibs) < arr.size: fibs.append(fibs[-1] + fibs[-2])
tiles, minx, miny, maxx, maxy, curr_x, curr_y = [], 0, 0, 0, 0, 0, 0
for i, s in enumerate(fibs):
d = (i-1)%4
if i>0:
if d == 0: curr_x = maxx; curr_y = miny
elif d == 1: curr_x = maxx-s; curr_y = maxy
elif d == 2: curr_x = minx-s; curr_y = maxy-s
else: curr_x = minx; curr_y = miny-s
tiles.append((curr_x, curr_y, s))
minx, miny, maxx, maxy = min(minx, curr_x), min(miny, curr_y), max(maxx, curr_x+s), max(maxy, curr_y+s)
img, idx = np.zeros((maxy-miny, maxx-minx), dtype=np.uint8), 0
for x, y, s in tiles:
take = min(s*s, arr.size - idx)
if take <= 0: break
block = np.pad(arr[idx:idx+take], (0, s*s-take)).reshape(s, s)
img[img.shape[0]-(y-miny+s):img.shape[0]-(y-miny), x-minx:x-minx+s] = block
idx += take
return img
# ==========================================
# Main Processing Logic
# ==========================================
def run_demo(input_file_wrapper, fidelity):
# Determine input type and prepare data
is_image = False
orig_pil = None
img_dims = None
try:
# Try opening as an image
orig_pil = Image.open(input_file_wrapper.name).convert('L') # Convert to grayscale for core engine
# Resize large images for demo performance constraint
orig_pil.thumbnail((512, 512))
img_dims = orig_pil.size # (width, height)
raw_data = np.array(orig_pil).tobytes()
is_image = True
except (UnidentifiedImageError, OSError):
# Fallback for non-image binary data
with open(input_file_wrapper.name, "rb") as f:
raw_data = f.read()
orig_size = len(raw_data)
# FLC Parameters based on user selection
q_settings = {"High Compression (Lossy)": 6, "Balanced": 12, "Near-Lossless": 24}
n_bands = q_settings[fidelity]
# Aggressive steps for lower tiers to show visual difference
step = 0.15 if fidelity == "High Compression (Lossy)" else (0.01 if fidelity == "Balanced" else 0.0001)
# --- Step 1: Transform & Quantize (Compression Simulation) ---
# Normalize data to range [-1, 1]
x = (np.frombuffer(raw_data, dtype=np.uint8).astype(float) - 127.5) / 127.5
block_len = 1024
pad_len = (-x.size) % block_len
X = np.pad(x, (0, pad_len)).reshape(-1, block_len)
# Forward DCT
C = np.array([dct_ortho_1d(b) for b in X])
# Determine Fibonacci bands
bnds = fibonacci_frequency_boundaries(block_len, n_bands)
# Quantize using Phi-scaling
Q = np.zeros_like(C, dtype=np.int32)
for bi in range(len(bnds)-1):
Q[:, bnds[bi]:bnds[bi+1]] = np.round(C[:, bnds[bi]:bnds[bi+1]] / (step * (PHI**bi)))
# Simulated compressed size estimate (entropy estimate)
compressed_size_est = int(np.count_nonzero(Q) * 1.5) + 512 # base overhead
ratio = compressed_size_est / orig_size
# --- Step 2: Progressive Reconstruction (Animation) ---
frames = []
final_recon_data = None
# Iterate through bands to create progressive frames
for t in range(1, n_bands + 1):
# Partial quantization buffer
Q_p = np.zeros_like(Q)
for bi in range(t): Q_p[:, bnds[bi]:bnds[bi+1]] = Q[:, bnds[bi]:bnds[bi+1]]
# Dequantize back to coefficients
C_p = np.zeros_like(Q_p, dtype=float)
for bi in range(len(bnds)-1):
C_p[:, bnds[bi]:bnds[bi+1]] = Q_p[:, bnds[bi]:bnds[bi+1]] * (step * (PHI**bi))
# Inverse DCT and denormalize
recon_1d = np.clip((np.array([idct_ortho_1d(B) for B in C_p]).flatten()[:orig_size] * 127.5) + 127.5, 0, 255).astype(np.uint8)
if t == n_bands:
final_recon_data = recon_1d
# Create visualization frames
h_img = Image.fromarray(hologram_spectrum_image(Q_p.flatten())).resize((256, 256)).convert("RGB")
s_img = Image.fromarray(bytes_to_fib_spiral_image(recon_1d.tobytes())).resize((256, 256)).convert("RGB")
# Combine into one frame
frame = Image.new("RGB", (512, 280), (15, 15, 25))
frame.paste(h_img, (0, 12)); frame.paste(s_img, (256, 12))
frames.append(frame)
# Save animation
gif_path = tempfile.mktemp(suffix=".gif")
frames[0].save(gif_path, save_all=True, append_images=frames[1:], duration=120, loop=0)
stats = f"Original Size: {orig_size:,} bytes\nSimulated Compressed Size: ~{compressed_size_est:,} bytes\ncompression Ratio: {ratio:.2%}"
# --- Step 3: Prepare Final Comparison Images ---
recon_pil = None
if is_image and final_recon_data is not None:
# Reshape 1D reconstructed data back to 2D image dimensions
recon_pil = Image.fromarray(final_recon_data.reshape((img_dims[1], img_dims[0])))
# Return results based on input type
if is_image:
return gif_path, stats, orig_pil, recon_pil
else:
# If not an image, return None for image image components so they don't display weirdly
return gif_path, stats, None, None
# ==========================================
# Gradio UI Layout
# ==========================================
with gr.Blocks(title="FLC v1.3 | Unified Fibonacci Demo", theme=gr.themes.Soft(primary_hue="amber", neutral_hue="slate")) as demo:
gr.Markdown("# π Fibonacci Lattice Compression (FLC)")
gr.Markdown("Upload an image to see the **Golden Ratio** compress data and reconstruct it progressively.")
with gr.Row():
with gr.Column(scale=1):
with gr.Group():
file_input = gr.File(label="1. Upload Input (Image recommended)", file_count="single")
radio_input = gr.Radio(["High Compression (Lossy)", "Balanced", "Near-Lossless"], value="Balanced", label="2. Select Fidelity Tier")
run_btn = gr.Button("π Run Holographic Compression", variant="primary")
stats_output = gr.Textbox(label="Compression Metrics", interactive=False, lines=4)
with gr.Column(scale=2):
gr.Markdown("### ποΈ Progressive Reconstruction Animation")
gr.Markdown("_Left: Frequency Hologram filling up. Right: Data organizing into Fibonacci Spiral._")
gif_output = gr.Image(label="Animation Sequence", show_label=False)
gr.Markdown("---")
gr.Markdown("### π Visual Verification: Original vs. Reconstructed")
gr.Markdown("_Determine if the 'Secret Sauce' maintained enough quality at the chosen compression tier._")
with gr.Row():
orig_image_output = gr.Image(label="Original Input (Grayscale)", type="pil", interactive=False)
recon_image_output = gr.Image(label="Final Decompressed Result", type="pil", interactive=False)
# Define the action
run_btn.click(
fn=run_demo,
inputs=[file_input, radio_input],
outputs=[gif_output, stats_output, orig_image_output, recon_image_output]
)
if __name__ == "__main__":
demo.launch() |