File size: 8,574 Bytes
6afef35 |
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 |
# app.py
import streamlit as st
from PIL import Image, ImageOps, ImageEnhance, ImageFilter, ImageDraw, ImageChops
import random
import os
import io
import time
import numpy as np
# Title
st.title("Unique Generative Photo Editor")
# Record the start time
start_time = time.time()
# Image Upload
uploaded_file = st.file_uploader("Upload an image...", type=["jpg", "jpeg", "png"])
if uploaded_file is not None:
# Display the uploaded image
input_image = Image.open(uploaded_file).convert("RGB")
st.image(input_image, caption='Uploaded Image', use_column_width=True)
# Get original image size
original_width, original_height = input_image.size
# Sidebar for parameter adjustments
st.sidebar.title("Parameter Adjustments")
# Image scale (size) adjustment
scale_factor = st.sidebar.slider("Image Scale (Size)", 0.1, 1.0, 1.0, 0.01)
new_width = int(original_width * scale_factor)
new_height = int(original_height * scale_factor)
input_image = input_image.resize((new_width, new_height), resample=Image.LANCZOS)
st.write(f"Resized Image: {input_image.size}")
# Contrast adjustment
contrast_factor = st.sidebar.slider("Contrast Strength", 0.5, 3.0, 1.5, 0.1)
# Brightness adjustment
brightness_factor = st.sidebar.slider("Brightness", 0.5, 3.0, 1.0, 0.1)
# Sharpness adjustment
sharpness_factor = st.sidebar.slider("Sharpness", 0.0, 5.0, 1.0, 0.1)
# Sepia depth
sepia_depth = st.sidebar.slider("Sepia Depth", 0, 100, 30, 1)
# Vignette effect strength
vignette_strength = st.sidebar.slider("Vignette Strength", 0.0, 1.0, 0.5, 0.01)
# Noise level
noise_level = st.sidebar.slider("Noise Level", 0, 100, 30, 1)
# Generate a unique seed
seed = random.randint(0, 2**32 - 1)
st.write(f"Unique Seed Value: {seed}")
# Seed file to record used seeds
seed_file = "used_seeds.txt"
# Load used seeds
if os.path.exists(seed_file):
with open(seed_file, 'r') as f:
used_seeds = set(int(line.strip()) for line in f)
else:
used_seeds = set()
if seed in used_seeds:
st.error("This seed value has already been used. Please try again.")
else:
# Save the seed value
with open(seed_file, 'a') as f:
f.write(f"{seed}\n")
# Image processing
with st.spinner('Processing image...'):
try:
def apply_unique_effect(image, seed, contrast_factor, brightness_factor, sharpness_factor,
sepia_depth, vignette_strength, noise_level):
# Set the seed values
np.random.seed(seed)
random.seed(seed)
# Step 1: Convert to grayscale
image = ImageOps.grayscale(image)
# Step 2: Adjust contrast
enhancer = ImageEnhance.Contrast(image)
image = enhancer.enhance(contrast_factor)
# Step 3: Adjust brightness
enhancer = ImageEnhance.Brightness(image)
image = enhancer.enhance(brightness_factor)
# Step 4: Adjust sharpness
enhancer = ImageEnhance.Sharpness(image)
image = enhancer.enhance(sharpness_factor)
# Step 5: Apply sepia tone
sepia_image = np.array(image).astype(np.float64)
sepia_image = sepia_image / 255.0
sepia_filter = np.array([[1.0, 0.95, 0.82]]) # Sepia color
sepia_image = sepia_image[..., np.newaxis] * sepia_filter
sepia_image = np.clip(sepia_image * (1 + sepia_depth / 100), 0, 1)
sepia_image = (sepia_image * 255).astype(np.uint8)
image = Image.fromarray(sepia_image, mode='RGB')
# Step 6: Add vignette effect
width, height = image.size
x = np.linspace(-1, 1, width)
y = np.linspace(-1, 1, height)
xx, yy = np.meshgrid(x, y)
gradient = np.sqrt(xx**2 + yy**2)
mask = (1 - gradient / gradient.max())
mask = np.clip(mask, 0, 1)
mask = mask ** (vignette_strength * 10) # Adjust strength
alpha = (mask * 255).astype(np.uint8)
vignette = Image.fromarray(alpha, mode='L')
image.putalpha(vignette)
# Step 7: Add noise
noise_array = np.random.randint(0, noise_level, (height, width), dtype='uint8')
noise_image = Image.fromarray(noise_array, mode='L')
noise_image = noise_image.convert('RGBA')
# Combine image and noise
r, g, b, a = image.split()
noise_r, noise_g, noise_b, noise_a = noise_image.split()
r = ImageChops.add(r, noise_r)
g = ImageChops.add(g, noise_g)
b = ImageChops.add(b, noise_b)
image = Image.merge('RGBA', (r, g, b, a))
# Step 8: Remove alpha channel if necessary
image = image.convert("RGB")
# Check processing time
processing_time = time.time() - start_time
if processing_time > 30:
raise TimeoutError("Processing timed out. Please try again with a smaller image size.")
return image
# Apply the effect
output_image = apply_unique_effect(
input_image,
seed,
contrast_factor,
brightness_factor,
sharpness_factor,
sepia_depth,
vignette_strength,
noise_level
)
# Check total processing time
total_time = time.time() - start_time
st.write(f"Processing Time: {total_time:.2f} seconds")
st.image(output_image, caption='Transformed Image', use_column_width=True)
# Download button
buffered = io.BytesIO()
output_image.save(buffered, format="PNG")
img_data = buffered.getvalue()
st.download_button(
label="Download Image",
data=img_data,
file_name="transformed_image.png",
mime="image/png"
)
except TimeoutError as e:
st.error(str(e))
# Original Concept Explanation
markdown_text = """
This application allows you to apply unique, artistic effects to your images, emulating a vintage style. Each image transformation is guaranteed to be unique due to the use of a random seed, ensuring that the same effect cannot be reproduced.
## Features
- **Uniqueness Guaranteed:** Uses a random seed for each transformation, so every image is one-of-a-kind.
- **User Control:** Adjust various parameters like image scale, contrast, brightness, sharpness, sepia depth, vignette strength, and noise level to customize the effect.
- **Vintage Effects:** Emulates the ambiance of classic photography techniques through digital image processing.
## How to Use
1. **Upload an Image:** Select the image you want to transform.
2. **Adjust Parameters:** Use the sliders to fine-tune the effects to your liking.
3. **Unique Seed Generation:** A unique seed value is generated for each transformation to ensure uniqueness.
4. **Image Processing:** The app applies the effects based on your settings and the unique seed.
5. **View and Download:** Preview the transformed image and download it if you're satisfied.
## Notes
- The uniqueness of each image is based on the random seed and your chosen parameters.
- Images are processed locally and are not saved on the server.
- Experiment with different settings to create your own unique piece of art.
## Reference
[1] Chinatsu Ozawa, Tatsuya Minagawa, and Yoichi Ochiai. 2024. Can AI Generated Ambrotype Chain the Aura of Alternative Process? In *SIGGRAPH Asia 2024 Art Papers (SA Art Papers '24)*, December 03–06, 2024, Tokyo, Japan. ACM, New York, NY, USA, 13 Pages. [https://doi.org/10.1145/3680530.3695434](https://doi.org/10.1145/3680530.3695434)
"""
# Display the Markdown Explanation
st.markdown(markdown_text) |