# -*- coding: utf-8 -*-
"""8---Perfoming encoding and decoding of image using deep autoencoder.

Automatically generated by Colab.

Original file is located at
    https://colab.research.google.com/drive/1Cef6TY4UreI4bjAEovxQ6zb6GHHvCzAr
"""

import tensorflow as tf
from tensorflow.keras import layers, models
import matplotlib.pyplot as plt
import numpy as np
import os
from tensorflow.keras.preprocessing.image import load_img, img_to_array
import kagglehub

# Download latest version of dataset
path = kagglehub.dataset_download("vishesh1412/celebrity-face-image-dataset")
print("Path to dataset files:", path)

# Load images from folder
def load_images_from_folder(folder_path, img_size=(64, 64)):
    images = []
    for filename in os.listdir(folder_path):
        img_path = os.path.join(folder_path, filename)
        img = load_img(img_path, target_size=img_size, color_mode="rgb")  # Ensure RGB
        img_array = img_to_array(img) / 255.0  # Normalize
        images.append(img_array)
    return np.array(images)

# Use downloaded dataset path
data_folder = os.path.join(path, "Celebrity Faces Dataset/Angelina Jolie")
x_train = load_images_from_folder(data_folder)
x_test = x_train[:10]

# Check channels
if x_train.shape[-1] != 3:
    raise ValueError("Input images must have 3 channels (RGB)")

# Build Autoencoder
def build_autoencoder(input_shape=(64, 64, 3)):
    # Encoder
    encoder_input = layers.Input(shape=input_shape)
    x = layers.Conv2D(32, (3,3), activation='relu', padding='same')(encoder_input)
    x = layers.MaxPooling2D((2,2), padding='same')(x)
    x = layers.Conv2D(64, (3,3), activation='relu', padding='same')(x)
    x = layers.MaxPooling2D((2,2), padding='same')(x)
    x = layers.Conv2D(128, (3,3), activation='relu', padding='same')(x)
    encoded = layers.MaxPooling2D((2,2), padding='same')(x)

    # Decoder
    decoder_input = layers.Input(shape=(8,8,128))
    x = layers.Conv2D(128,(3,3),activation='relu',padding='same')(decoder_input)
    x = layers.UpSampling2D((2,2))(x)
    x = layers.Conv2D(64,(3,3),activation='relu',padding='same')(x)
    x = layers.UpSampling2D((2,2))(x)
    x = layers.Conv2D(32,(3,3),activation='relu',padding='same')(x)
    x = layers.UpSampling2D((2,2))(x)
    decoded = layers.Conv2D(3,(3,3),activation='sigmoid',padding='same')(x)

    encoder = models.Model(encoder_input, encoded, name="encoder")
    decoder = models.Model(decoder_input, decoded, name="decoder")
    autoencoder = models.Model(encoder_input, decoder(encoder(encoder_input)), name="autoencoder")
    autoencoder.compile(optimizer='adam', loss='mse')
    return autoencoder, encoder, decoder

# Display images
def display_images(autoencoder, x_test, num_images=5):
    decoded_imgs = autoencoder.predict(x_test[:num_images])
    fig, axes = plt.subplots(2, num_images, figsize=(18,4))
    for i in range(num_images):
        axes[0,i].imshow(x_test[i])
        axes[0,i].axis('off')
        axes[1,i].imshow(decoded_imgs[i])
        axes[1,i].axis('off')
    plt.show()

# Train Autoencoder
autoencoder, encoder, decoder = build_autoencoder()
autoencoder.summary()

autoencoder.fit(
    x_train, x_train,
    epochs=10,
    batch_size=64,
    validation_data=(x_test, x_test)
)

# Display results
display_images(autoencoder, x_test)

# Save model
autoencoder.save("demo_autoencoder_for_celeb.h5")


























# autoencoder_celeb_faces.py
import tensorflow as tf
from tensorflow.keras import layers, models
import matplotlib.pyplot as plt
import numpy as np
import os
from tensorflow.keras.preprocessing.image import load_img, img_to_array
from PIL import UnidentifiedImageError

# -------------------------
# Configuration
# -------------------------
IMG_SIZE = (64, 64)
BATCH_SIZE = 32            # reduce if you hit OOM
AUTOTUNE = tf.data.AUTOTUNE
DATA_DIR = r"C:\Users\darsh\OneDrive\Desktop\Jupyter\Celebrity Faces Dataset\Brad Pitt"
VALIDATION_SPLIT = 0.1
SEED = 42

# -------------------------
# Helpers: file listing + loader
# -------------------------
def list_image_files(folder):
    exts = {'.jpg', '.jpeg', '.png', '.bmp'}
    files = []
    for fname in os.listdir(folder):
        _, ext = os.path.splitext(fname.lower())
        if ext in exts:
            files.append(os.path.join(folder, fname))
    return sorted(files)

def load_and_preprocess(path):
    try:
        img = load_img(path, target_size=IMG_SIZE, color_mode='rgb')
        arr = img_to_array(img).astype('float32') / 255.0
        return arr
    except (UnidentifiedImageError, OSError):
        return None

# -------------------------
# Build file lists and check
# -------------------------
file_list = list_image_files(DATA_DIR)
if len(file_list) == 0:
    raise ValueError(f"No image files found in folder: {DATA_DIR}. Check path and extensions.")

# Shuffle deterministically and split into train/val
rng = np.random.default_rng(SEED)
shuffled = np.array(file_list)[rng.permutation(len(file_list))]
split_idx = int(len(shuffled) * (1.0 - VALIDATION_SPLIT))
train_files = shuffled[:split_idx].tolist()
val_files = shuffled[split_idx:].tolist()

def gen_from_list(files):
    for p in files:
        img = load_and_preprocess(p)
        if img is not None:
            yield img

# -------------------------
# Create tf.data datasets
# -------------------------
train_ds = tf.data.Dataset.from_generator(
    lambda: gen_from_list(train_files),
    output_signature=tf.TensorSpec(shape=(*IMG_SIZE, 3), dtype=tf.float32)
)

val_ds = tf.data.Dataset.from_generator(
    lambda: gen_from_list(val_files),
    output_signature=tf.TensorSpec(shape=(*IMG_SIZE, 3), dtype=tf.float32)
)

# Shuffle, batch, map to (x, x) and prefetch
train_ds = train_ds.shuffle(buffer_size=1000, seed=SEED).batch(BATCH_SIZE).map(lambda x: (x, x)).prefetch(AUTOTUNE)
val_ds = val_ds.batch(BATCH_SIZE).map(lambda x: (x, x)).prefetch(AUTOTUNE)

# Sanity check: ensure dataset yields at least one batch
try:
    for images_batch, targets_batch in train_ds.take(1):
        print("Train batch shape:", images_batch.shape)
        break
except Exception as e:
    raise RuntimeError("No valid images in training dataset after filtering.") from e

# Create a small x_test for visualization (first few images from validation if available)
x_test = None
for images_batch, _ in val_ds.take(1):
    x_test = images_batch[:10].numpy()
    break
if x_test is None:
    # fallback: take from train_ds
    for images_batch, _ in train_ds.take(1):
        x_test = images_batch[:10].numpy()
        break

# -------------------------
# Autoencoder model builder
# -------------------------
def build_autoencoder(input_shape=(64,64,3)):
    # Encoder
    encoder_input = layers.Input(shape=input_shape)
    x = layers.Conv2D(32, 3, activation='relu', padding='same')(encoder_input)
    x = layers.MaxPooling2D(2, padding='same')(x)
    x = layers.Conv2D(64, 3, activation='relu', padding='same')(x)
    x = layers.MaxPooling2D(2, padding='same')(x)
    x = layers.Conv2D(128, 3, activation='relu', padding='same')(x)
    encoded = layers.MaxPooling2D(2, padding='same')(x)  # expected shape (8,8,128)

    # Decoder (Conv2DTranspose)
    x = layers.Conv2DTranspose(128, 3, strides=2, activation='relu', padding='same')(encoded)
    x = layers.Conv2DTranspose(64, 3, strides=2, activation='relu', padding='same')(x)
    x = layers.Conv2DTranspose(32, 3, strides=2, activation='relu', padding='same')(x)
    decoded = layers.Conv2D(3, 3, activation='sigmoid', padding='same')(x)

    autoencoder = models.Model(encoder_input, decoded, name="autoencoder")
    encoder = models.Model(encoder_input, encoded, name="encoder")

    # standalone decoder model (optional)
    encoded_input = layers.Input(shape=(8,8,128))
    d = layers.Conv2DTranspose(128, 3, strides=2, activation='relu', padding='same')(encoded_input)
    d = layers.Conv2DTranspose(64, 3, strides=2, activation='relu', padding='same')(d)
    d = layers.Conv2DTranspose(32, 3, strides=2, activation='relu', padding='same')(d)
    decoded_output = layers.Conv2D(3, 3, activation='sigmoid', padding='same')(d)
    decoder = models.Model(encoded_input, decoded_output, name="decoder")

    autoencoder.compile(optimizer='adam', loss='mse')
    return autoencoder, encoder, decoder

autoencoder, encoder, decoder = build_autoencoder(input_shape=(*IMG_SIZE, 3))
autoencoder.summary()

# -------------------------
# Training
# -------------------------
callbacks = [
    tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=5, restore_best_weights=True)
]

history = autoencoder.fit(
    train_ds,
    epochs=30,
    validation_data=val_ds,
    callbacks=callbacks,
    verbose=1
)

# -------------------------
# Visualization helper
# -------------------------
def display_images(model, x_samples, num_images=5):
    num_images = min(num_images, x_samples.shape[0])
    decoded = model.predict(x_samples[:num_images], verbose=0)
    fig, axes = plt.subplots(2, num_images, figsize=(num_images*3, 6))
    for i in range(num_images):
        axes[0,i].imshow(np.clip(x_samples[i], 0, 1))
        axes[0,i].axis('off')
        axes[1,i].imshow(np.clip(decoded[i], 0, 1))
        axes[1,i].axis('off')
    plt.tight_layout()
    plt.show()

display_images(autoencoder, x_test, num_images=min(5, x_test.shape[0]))

# -------------------------
# Save model
# -------------------------
autoencoder.save("demo_autoencoder_for_celeb.h5")
print("Saved autoencoder to demo_autoencoder_for_celeb.h5")
























# autoencoder_from_zip.py
import zipfile
import io
from PIL import Image, UnidentifiedImageError
import tensorflow as tf
from tensorflow.keras import layers, models
import matplotlib.pyplot as plt
import numpy as np
import os

# -------------------------
# Configuration
# -------------------------
IMG_SIZE = (64, 64)
BATCH_SIZE = 32            # reduce if you hit OOM
AUTOTUNE = tf.data.AUTOTUNE
DATA_ZIP = r"/content/Robert Downey Jr.zip"
VALIDATION_SPLIT = 0.1
SEED = 42
ALLOWED_EXTS = {'.jpg', '.jpeg', '.png', '.bmp'}

# -------------------------
# Helper: list image file names inside zip
# -------------------------
def list_image_files_in_zip(zip_path):
    with zipfile.ZipFile(zip_path, 'r') as z:
        names = [n for n in z.namelist()
                 if not n.endswith('/') and os.path.splitext(n)[1].lower() in ALLOWED_EXTS]
    return sorted(names)

# -------------------------
# Helper: load image bytes from zip and preprocess
# -------------------------
def load_image_from_zip(zip_path, member_name, img_size=IMG_SIZE):
    try:
        with zipfile.ZipFile(zip_path, 'r') as z:
            with z.open(member_name) as f:
                img_bytes = f.read()
        img = Image.open(io.BytesIO(img_bytes)).convert('RGB')
        img = img.resize(img_size, Image.BILINEAR)
        arr = np.asarray(img, dtype=np.float32) / 255.0
        return arr
    except (UnidentifiedImageError, OSError, zipfile.BadZipFile, KeyError):
        return None

# -------------------------
# Build file list and check
# -------------------------
file_list = list_image_files_in_zip(DATA_ZIP)
if len(file_list) == 0:
    raise ValueError(f"No image files found in zip: {DATA_ZIP}. Check path and extensions.")

# Shuffle deterministically and split into train/val
rng = np.random.default_rng(SEED)
shuffled = np.array(file_list)[rng.permutation(len(file_list))]
split_idx = int(len(shuffled) * (1.0 - VALIDATION_SPLIT))
train_files = shuffled[:split_idx].tolist()
val_files = shuffled[split_idx:].tolist()

# -------------------------
# Generator that yields images from a list of zip members
# -------------------------
def gen_from_zip(zip_path, members):
    for member in members:
        img = load_image_from_zip(zip_path, member)
        if img is not None:
            yield img

# -------------------------
# Create tf.data datasets
# -------------------------
train_ds = tf.data.Dataset.from_generator(
    lambda: gen_from_zip(DATA_ZIP, train_files),
    output_signature=tf.TensorSpec(shape=(*IMG_SIZE, 3), dtype=tf.float32)
)

val_ds = tf.data.Dataset.from_generator(
    lambda: gen_from_zip(DATA_ZIP, val_files),
    output_signature=tf.TensorSpec(shape=(*IMG_SIZE, 3), dtype=tf.float32)
)

# Shuffle, batch, map to (x, x) and prefetch
train_ds = train_ds.shuffle(buffer_size=1000, seed=SEED).batch(BATCH_SIZE).map(lambda x: (x, x)).prefetch(AUTOTUNE)
val_ds = val_ds.batch(BATCH_SIZE).map(lambda x: (x, x)).prefetch(AUTOTUNE)

# Sanity check: ensure dataset yields at least one batch
try:
    for images_batch, targets_batch in train_ds.take(1):
        print("Train batch shape:", images_batch.shape)
        break
except Exception as e:
    raise RuntimeError("No valid images in training dataset after filtering.") from e

# Create a small x_test for visualization (first few images from validation if available)
x_test = None
for images_batch, _ in val_ds.take(1):
    x_test = images_batch[:10].numpy()
    break
if x_test is None:
    for images_batch, _ in train_ds.take(1):
        x_test = images_batch[:10].numpy()
        break

# -------------------------
# Autoencoder model builder
# -------------------------
def build_autoencoder(input_shape=(64,64,3)):
    encoder_input = layers.Input(shape=input_shape)
    x = layers.Conv2D(32, 3, activation='relu', padding='same')(encoder_input)
    x = layers.MaxPooling2D(2, padding='same')(x)
    x = layers.Conv2D(64, 3, activation='relu', padding='same')(x)
    x = layers.MaxPooling2D(2, padding='same')(x)
    x = layers.Conv2D(128, 3, activation='relu', padding='same')(x)
    encoded = layers.MaxPooling2D(2, padding='same')(x)  # expected shape (8,8,128)

    x = layers.Conv2DTranspose(128, 3, strides=2, activation='relu', padding='same')(encoded)
    x = layers.Conv2DTranspose(64, 3, strides=2, activation='relu', padding='same')(x)
    x = layers.Conv2DTranspose(32, 3, strides=2, activation='relu', padding='same')(x)
    decoded = layers.Conv2D(3, 3, activation='sigmoid', padding='same')(x)

    autoencoder = models.Model(encoder_input, decoded, name="autoencoder")
    encoder = models.Model(encoder_input, encoded, name="encoder")

    encoded_input = layers.Input(shape=(8,8,128))
    d = layers.Conv2DTranspose(128, 3, strides=2, activation='relu', padding='same')(encoded_input)
    d = layers.Conv2DTranspose(64, 3, strides=2, activation='relu', padding='same')(d)
    d = layers.Conv2DTranspose(32, 3, strides=2, activation='relu', padding='same')(d)
    decoded_output = layers.Conv2D(3, 3, activation='sigmoid', padding='same')(d)
    decoder = models.Model(encoded_input, decoded_output, name="decoder")

    autoencoder.compile(optimizer='adam', loss='mse')
    return autoencoder, encoder, decoder

autoencoder, encoder, decoder = build_autoencoder(input_shape=(*IMG_SIZE, 3))
autoencoder.summary()

# -------------------------
# Training
# -------------------------
callbacks = [
    tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=5, restore_best_weights=True)
]

history = autoencoder.fit(
    train_ds,
    epochs=30,
    validation_data=val_ds,
    callbacks=callbacks,
    verbose=1
)

# -------------------------
# Visualization helper
# -------------------------
def display_images(model, x_samples, num_images=5):
    num_images = min(num_images, x_samples.shape[0])
    decoded = model.predict(x_samples[:num_images], verbose=0)
    fig, axes = plt.subplots(2, num_images, figsize=(num_images*3, 6))
    for i in range(num_images):
        axes[0,i].imshow(np.clip(x_samples[i], 0, 1))
        axes[0,i].axis('off')
        axes[1,i].imshow(np.clip(decoded[i], 0, 1))
        axes[1,i].axis('off')
    plt.tight_layout()
    plt.show()

display_images(autoencoder, x_test, num_images=min(5, x_test.shape[0]))

# -------------------------
# Save model
# -------------------------
autoencoder.save("demo_autoencoder_for_celeb.h5")
print("Saved autoencoder to demo_autoencoder_for_celeb.h5")

# -------------------------
# Optional: extract zip to folder (uncomment if you prefer extraction)
# -------------------------
# with zipfile.ZipFile(DATA_ZIP, 'r') as z:
#     extract_dir = r"C:\path\to\extract\folder"
#     z.extractall(extract_dir)
#     print("Extracted zip to", extract_dir)
