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)