naohiro701 commited on
Commit
6afef35
·
verified ·
1 Parent(s): 784bebe

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +217 -0
app.py ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+
3
+ import streamlit as st
4
+ from PIL import Image, ImageOps, ImageEnhance, ImageFilter, ImageDraw, ImageChops
5
+ import random
6
+ import os
7
+ import io
8
+ import time
9
+ import numpy as np
10
+
11
+ # Title
12
+ st.title("Unique Generative Photo Editor")
13
+
14
+ # Record the start time
15
+ start_time = time.time()
16
+
17
+ # Image Upload
18
+ uploaded_file = st.file_uploader("Upload an image...", type=["jpg", "jpeg", "png"])
19
+
20
+ if uploaded_file is not None:
21
+ # Display the uploaded image
22
+ input_image = Image.open(uploaded_file).convert("RGB")
23
+ st.image(input_image, caption='Uploaded Image', use_column_width=True)
24
+
25
+ # Get original image size
26
+ original_width, original_height = input_image.size
27
+
28
+ # Sidebar for parameter adjustments
29
+ st.sidebar.title("Parameter Adjustments")
30
+
31
+ # Image scale (size) adjustment
32
+ scale_factor = st.sidebar.slider("Image Scale (Size)", 0.1, 1.0, 1.0, 0.01)
33
+ new_width = int(original_width * scale_factor)
34
+ new_height = int(original_height * scale_factor)
35
+ input_image = input_image.resize((new_width, new_height), resample=Image.LANCZOS)
36
+ st.write(f"Resized Image: {input_image.size}")
37
+
38
+ # Contrast adjustment
39
+ contrast_factor = st.sidebar.slider("Contrast Strength", 0.5, 3.0, 1.5, 0.1)
40
+
41
+ # Brightness adjustment
42
+ brightness_factor = st.sidebar.slider("Brightness", 0.5, 3.0, 1.0, 0.1)
43
+
44
+ # Sharpness adjustment
45
+ sharpness_factor = st.sidebar.slider("Sharpness", 0.0, 5.0, 1.0, 0.1)
46
+
47
+ # Sepia depth
48
+ sepia_depth = st.sidebar.slider("Sepia Depth", 0, 100, 30, 1)
49
+
50
+ # Vignette effect strength
51
+ vignette_strength = st.sidebar.slider("Vignette Strength", 0.0, 1.0, 0.5, 0.01)
52
+
53
+ # Noise level
54
+ noise_level = st.sidebar.slider("Noise Level", 0, 100, 30, 1)
55
+
56
+ # Generate a unique seed
57
+ seed = random.randint(0, 2**32 - 1)
58
+ st.write(f"Unique Seed Value: {seed}")
59
+
60
+ # Seed file to record used seeds
61
+ seed_file = "used_seeds.txt"
62
+
63
+ # Load used seeds
64
+ if os.path.exists(seed_file):
65
+ with open(seed_file, 'r') as f:
66
+ used_seeds = set(int(line.strip()) for line in f)
67
+ else:
68
+ used_seeds = set()
69
+
70
+ if seed in used_seeds:
71
+ st.error("This seed value has already been used. Please try again.")
72
+ else:
73
+ # Save the seed value
74
+ with open(seed_file, 'a') as f:
75
+ f.write(f"{seed}\n")
76
+
77
+ # Image processing
78
+ with st.spinner('Processing image...'):
79
+ try:
80
+ def apply_unique_effect(image, seed, contrast_factor, brightness_factor, sharpness_factor,
81
+ sepia_depth, vignette_strength, noise_level):
82
+ # Set the seed values
83
+ np.random.seed(seed)
84
+ random.seed(seed)
85
+
86
+ # Step 1: Convert to grayscale
87
+ image = ImageOps.grayscale(image)
88
+
89
+ # Step 2: Adjust contrast
90
+ enhancer = ImageEnhance.Contrast(image)
91
+ image = enhancer.enhance(contrast_factor)
92
+
93
+ # Step 3: Adjust brightness
94
+ enhancer = ImageEnhance.Brightness(image)
95
+ image = enhancer.enhance(brightness_factor)
96
+
97
+ # Step 4: Adjust sharpness
98
+ enhancer = ImageEnhance.Sharpness(image)
99
+ image = enhancer.enhance(sharpness_factor)
100
+
101
+ # Step 5: Apply sepia tone
102
+ sepia_image = np.array(image).astype(np.float64)
103
+ sepia_image = sepia_image / 255.0
104
+
105
+ sepia_filter = np.array([[1.0, 0.95, 0.82]]) # Sepia color
106
+ sepia_image = sepia_image[..., np.newaxis] * sepia_filter
107
+
108
+ sepia_image = np.clip(sepia_image * (1 + sepia_depth / 100), 0, 1)
109
+ sepia_image = (sepia_image * 255).astype(np.uint8)
110
+
111
+ image = Image.fromarray(sepia_image, mode='RGB')
112
+
113
+ # Step 6: Add vignette effect
114
+ width, height = image.size
115
+ x = np.linspace(-1, 1, width)
116
+ y = np.linspace(-1, 1, height)
117
+ xx, yy = np.meshgrid(x, y)
118
+ gradient = np.sqrt(xx**2 + yy**2)
119
+ mask = (1 - gradient / gradient.max())
120
+ mask = np.clip(mask, 0, 1)
121
+ mask = mask ** (vignette_strength * 10) # Adjust strength
122
+
123
+ alpha = (mask * 255).astype(np.uint8)
124
+ vignette = Image.fromarray(alpha, mode='L')
125
+ image.putalpha(vignette)
126
+
127
+ # Step 7: Add noise
128
+ noise_array = np.random.randint(0, noise_level, (height, width), dtype='uint8')
129
+ noise_image = Image.fromarray(noise_array, mode='L')
130
+ noise_image = noise_image.convert('RGBA')
131
+
132
+ # Combine image and noise
133
+ r, g, b, a = image.split()
134
+ noise_r, noise_g, noise_b, noise_a = noise_image.split()
135
+
136
+ r = ImageChops.add(r, noise_r)
137
+ g = ImageChops.add(g, noise_g)
138
+ b = ImageChops.add(b, noise_b)
139
+
140
+ image = Image.merge('RGBA', (r, g, b, a))
141
+
142
+ # Step 8: Remove alpha channel if necessary
143
+ image = image.convert("RGB")
144
+
145
+ # Check processing time
146
+ processing_time = time.time() - start_time
147
+ if processing_time > 30:
148
+ raise TimeoutError("Processing timed out. Please try again with a smaller image size.")
149
+
150
+ return image
151
+
152
+ # Apply the effect
153
+ output_image = apply_unique_effect(
154
+ input_image,
155
+ seed,
156
+ contrast_factor,
157
+ brightness_factor,
158
+ sharpness_factor,
159
+ sepia_depth,
160
+ vignette_strength,
161
+ noise_level
162
+ )
163
+
164
+ # Check total processing time
165
+ total_time = time.time() - start_time
166
+ st.write(f"Processing Time: {total_time:.2f} seconds")
167
+
168
+ st.image(output_image, caption='Transformed Image', use_column_width=True)
169
+
170
+ # Download button
171
+ buffered = io.BytesIO()
172
+ output_image.save(buffered, format="PNG")
173
+ img_data = buffered.getvalue()
174
+
175
+ st.download_button(
176
+ label="Download Image",
177
+ data=img_data,
178
+ file_name="transformed_image.png",
179
+ mime="image/png"
180
+ )
181
+ except TimeoutError as e:
182
+ st.error(str(e))
183
+
184
+
185
+ # Original Concept Explanation
186
+ markdown_text = """
187
+ # Unique Generative Photo Editor
188
+
189
+ 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.
190
+
191
+ ## Features
192
+
193
+ - **Uniqueness Guaranteed:** Uses a random seed for each transformation, so every image is one-of-a-kind.
194
+ - **User Control:** Adjust various parameters like image scale, contrast, brightness, sharpness, sepia depth, vignette strength, and noise level to customize the effect.
195
+ - **Vintage Effects:** Emulates the ambiance of classic photography techniques through digital image processing.
196
+
197
+ ## How to Use
198
+
199
+ 1. **Upload an Image:** Select the image you want to transform.
200
+ 2. **Adjust Parameters:** Use the sliders to fine-tune the effects to your liking.
201
+ 3. **Unique Seed Generation:** A unique seed value is generated for each transformation to ensure uniqueness.
202
+ 4. **Image Processing:** The app applies the effects based on your settings and the unique seed.
203
+ 5. **View and Download:** Preview the transformed image and download it if you're satisfied.
204
+
205
+ ## Notes
206
+
207
+ - The uniqueness of each image is based on the random seed and your chosen parameters.
208
+ - Images are processed locally and are not saved on the server.
209
+ - Experiment with different settings to create your own unique piece of art.
210
+
211
+ ## Reference
212
+
213
+ [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)
214
+ """
215
+
216
+ # Display the Markdown Explanation
217
+ st.markdown(markdown_text)