TuringsSolutions/Fibonacci-Compressor-Gradio
1
1import gradio as gr2import os, math, tempfile3import numpy as np4from PIL import Image, UnidentifiedImageError5 6# ==========================================7# FLC v1.3 Logic Engine (The "Secret Sauce")8# ==========================================9PHI = (1.0 + 5.0**0.5) / 2.010 11def fibonacci_sequence(n):12 fibs = [1, 2]13 while len(fibs) < n: fibs.append(fibs[-1] + fibs[-2])14 return np.array(fibs[:n], dtype=np.int64)15 16def fibonacci_frequency_boundaries(n_coeffs, n_bands):17 if n_bands < 2: return [0, n_coeffs]18 fibs = fibonacci_sequence(n_bands).astype(np.float64)19 w = fibs / (fibs.sum() + 1e-12)20 cum = np.cumsum(w)21 b = [0]22 for i in range(n_bands - 1): b.append(int(round(n_coeffs * cum[i])))23 b.append(n_coeffs)24 for i in range(1, len(b)):25 if b[i] <= b[i-1]: b[i] = b[i-1] + 126 return b27 28def dct_ortho_1d(x):29 N = x.shape[0]30 v = np.concatenate([x, x[::-1]])31 V = np.fft.fft(v)32 k = np.arange(N)33 X = np.real(V[:N] * np.exp(-1j * np.pi * k / (2 * N)))34 X *= 2.035 X[0] *= (1.0 / math.sqrt(4 * N))36 X[1:] *= (1.0 / math.sqrt(2 * N))37 return X38 39def idct_ortho_1d(X):40 N = X.shape[0]41 x0, xr = X[0] * math.sqrt(4 * N), X[1:] * math.sqrt(2 * N)42 c = np.empty(N, dtype=np.complex128)43 c[0], c[1:] = x0 / 2.0, xr / 2.044 k = np.arange(N)45 c = c * np.exp(1j * np.pi * k / (2 * N))46 V = np.zeros(2 * N, dtype=np.complex128)47 V[:N] = c48 V[N+1:] = np.conj(c[1:][::-1])49 return np.fft.ifft(V).real[:N]50 51# --- Visualization Helpers ---52def hologram_spectrum_image(zints):53 # Visualizes the frequency domain data as a 2D spectrum54 z = zints[:262144]; v = np.tanh(z / 32.0)55 theta = (2 * math.pi / (PHI**2)) * np.arange(v.size) + 2.0 * math.pi * (v * 0.25)56 r = 1.0 + 0.35 * np.abs(v)57 syms = r * np.cos(theta) + 1j * r * np.sin(theta)58 N = int(2**math.ceil(math.log2(math.sqrt(syms.size or 1))))59 U = np.pad(syms, (0, N*N - syms.size)).reshape(N, N)60 mag = np.log1p(np.abs(np.fft.fftshift(np.fft.fft2(U))))61 mag = (mag - mag.min()) / (mag.max() - mag.min() + 1e-12)62 return (mag * 255).astype(np.uint8)63 64def bytes_to_fib_spiral_image(data):65 # Visualizes linear data arranged on a Fibonacci spiral tiling66 arr = np.frombuffer(data, dtype=np.uint8)[:262144]67 fibs = [1, 1]68 while sum(s*s for s in fibs) < arr.size: fibs.append(fibs[-1] + fibs[-2])69 tiles, minx, miny, maxx, maxy, curr_x, curr_y = [], 0, 0, 0, 0, 0, 070 for i, s in enumerate(fibs):71 d = (i-1)%472 if i>0:73 if d == 0: curr_x = maxx; curr_y = miny74 elif d == 1: curr_x = maxx-s; curr_y = maxy75 elif d == 2: curr_x = minx-s; curr_y = maxy-s76 else: curr_x = minx; curr_y = miny-s77 tiles.append((curr_x, curr_y, s))78 minx, miny, maxx, maxy = min(minx, curr_x), min(miny, curr_y), max(maxx, curr_x+s), max(maxy, curr_y+s)79 img, idx = np.zeros((maxy-miny, maxx-minx), dtype=np.uint8), 080 for x, y, s in tiles:81 take = min(s*s, arr.size - idx)82 if take <= 0: break83 block = np.pad(arr[idx:idx+take], (0, s*s-take)).reshape(s, s)84 img[img.shape[0]-(y-miny+s):img.shape[0]-(y-miny), x-minx:x-minx+s] = block85 idx += take86 return img87 88# ==========================================89# Main Processing Logic90# ==========================================91def run_demo(input_file_wrapper, fidelity):92 # Determine input type and prepare data93 is_image = False94 orig_pil = None95 img_dims = None96 97 try:98 # Try opening as an image99 orig_pil = Image.open(input_file_wrapper.name).convert('L') # Convert to grayscale for core engine100 # Resize large images for demo performance constraint101 orig_pil.thumbnail((512, 512)) 102 img_dims = orig_pil.size # (width, height)103 raw_data = np.array(orig_pil).tobytes()104 is_image = True105 except (UnidentifiedImageError, OSError):106 # Fallback for non-image binary data107 with open(input_file_wrapper.name, "rb") as f:108 raw_data = f.read()109 110 orig_size = len(raw_data)111 112 # FLC Parameters based on user selection113 q_settings = {"High Compression (Lossy)": 6, "Balanced": 12, "Near-Lossless": 24}114 n_bands = q_settings[fidelity]115 # Aggressive steps for lower tiers to show visual difference116 step = 0.15 if fidelity == "High Compression (Lossy)" else (0.01 if fidelity == "Balanced" else 0.0001)117 118 # --- Step 1: Transform & Quantize (Compression Simulation) ---119 # Normalize data to range [-1, 1]120 x = (np.frombuffer(raw_data, dtype=np.uint8).astype(float) - 127.5) / 127.5121 block_len = 1024122 pad_len = (-x.size) % block_len123 X = np.pad(x, (0, pad_len)).reshape(-1, block_len)124 125 # Forward DCT126 C = np.array([dct_ortho_1d(b) for b in X])127 # Determine Fibonacci bands128 bnds = fibonacci_frequency_boundaries(block_len, n_bands)129 # Quantize using Phi-scaling130 Q = np.zeros_like(C, dtype=np.int32)131 for bi in range(len(bnds)-1):132 Q[:, bnds[bi]:bnds[bi+1]] = np.round(C[:, bnds[bi]:bnds[bi+1]] / (step * (PHI**bi)))133 134 # Simulated compressed size estimate (entropy estimate)135 compressed_size_est = int(np.count_nonzero(Q) * 1.5) + 512 # base overhead136 ratio = compressed_size_est / orig_size137 138 # --- Step 2: Progressive Reconstruction (Animation) ---139 frames = []140 final_recon_data = None141 142 # Iterate through bands to create progressive frames143 for t in range(1, n_bands + 1):144 # Partial quantization buffer145 Q_p = np.zeros_like(Q)146 for bi in range(t): Q_p[:, bnds[bi]:bnds[bi+1]] = Q[:, bnds[bi]:bnds[bi+1]]147 148 # Dequantize back to coefficients149 C_p = np.zeros_like(Q_p, dtype=float)150 for bi in range(len(bnds)-1):151 C_p[:, bnds[bi]:bnds[bi+1]] = Q_p[:, bnds[bi]:bnds[bi+1]] * (step * (PHI**bi))152 153 # Inverse DCT and denormalize154 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)155 156 if t == n_bands:157 final_recon_data = recon_1d158 159 # Create visualization frames160 h_img = Image.fromarray(hologram_spectrum_image(Q_p.flatten())).resize((256, 256)).convert("RGB")161 s_img = Image.fromarray(bytes_to_fib_spiral_image(recon_1d.tobytes())).resize((256, 256)).convert("RGB")162 163 # Combine into one frame164 frame = Image.new("RGB", (512, 280), (15, 15, 25))165 frame.paste(h_img, (0, 12)); frame.paste(s_img, (256, 12))166 frames.append(frame)167 168 # Save animation169 gif_path = tempfile.mktemp(suffix=".gif")170 frames[0].save(gif_path, save_all=True, append_images=frames[1:], duration=120, loop=0)171 172 stats = f"Original Size: {orig_size:,} bytes\nSimulated Compressed Size: ~{compressed_size_est:,} bytes\ncompression Ratio: {ratio:.2%}"173 174 # --- Step 3: Prepare Final Comparison Images ---175 recon_pil = None176 if is_image and final_recon_data is not None:177 # Reshape 1D reconstructed data back to 2D image dimensions178 recon_pil = Image.fromarray(final_recon_data.reshape((img_dims[1], img_dims[0])))179 180 # Return results based on input type181 if is_image:182 return gif_path, stats, orig_pil, recon_pil183 else:184 # If not an image, return None for image image components so they don't display weirdly185 return gif_path, stats, None, None186 187 188# ==========================================189# Gradio UI Layout190# ==========================================191with gr.Blocks(title="FLC v1.3 | Unified Fibonacci Demo", theme=gr.themes.Soft(primary_hue="amber", neutral_hue="slate")) as demo:192 gr.Markdown("# ๐ Fibonacci Lattice Compression (FLC)")193 gr.Markdown("Upload an image to see the **Golden Ratio** compress data and reconstruct it progressively.")194 195 with gr.Row():196 with gr.Column(scale=1):197 with gr.Group():198 file_input = gr.File(label="1. Upload Input (Image recommended)", file_count="single")199 radio_input = gr.Radio(["High Compression (Lossy)", "Balanced", "Near-Lossless"], value="Balanced", label="2. Select Fidelity Tier")200 run_btn = gr.Button("๐ Run Holographic Compression", variant="primary")201 202 stats_output = gr.Textbox(label="Compression Metrics", interactive=False, lines=4)203 204 with gr.Column(scale=2):205 gr.Markdown("### ๐๏ธ Progressive Reconstruction Animation")206 gr.Markdown("_Left: Frequency Hologram filling up. Right: Data organizing into Fibonacci Spiral._")207 gif_output = gr.Image(label="Animation Sequence", show_label=False)208 209 gr.Markdown("---")210 gr.Markdown("### ๐ Visual Verification: Original vs. Reconstructed")211 gr.Markdown("_Determine if the 'Secret Sauce' maintained enough quality at the chosen compression tier._")212 213 with gr.Row():214 orig_image_output = gr.Image(label="Original Input (Grayscale)", type="pil", interactive=False)215 recon_image_output = gr.Image(label="Final Decompressed Result", type="pil", interactive=False)216 217 # Define the action218 run_btn.click(219 fn=run_demo,220 inputs=[file_input, radio_input],221 outputs=[gif_output, stats_output, orig_image_output, recon_image_output]222 )223 224if __name__ == "__main__":225 demo.launch()