sayedM commited on
Commit
6dfbcaa
·
verified ·
1 Parent(s): 66014bf

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +130 -0
app.py ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import io
2
+ import datetime
3
+
4
+ import gradio as gr
5
+ from PIL import Image, ImageFilter, ImageDraw, ImageFont
6
+ import numpy as np
7
+
8
+
9
+ def modern_to_nokia_pil(
10
+ img,
11
+ jpeg_quality=15,
12
+ noise_std=12,
13
+ color_levels=32,
14
+ blur_radius=0.6,
15
+ gamma=1.3,
16
+ add_date_stamp=True,
17
+ ):
18
+ # Ensure RGB
19
+ img = img.convert("RGB")
20
+
21
+ # --- Crop to 4:3 like old phones ---
22
+ w, h = img.size
23
+ target_ratio = 4 / 3
24
+ current_ratio = w / h
25
+
26
+ if current_ratio > target_ratio:
27
+ # too wide: crop width
28
+ new_w = int(h * target_ratio)
29
+ left = (w - new_w) // 2
30
+ img = img.crop((left, 0, left + new_w, h))
31
+ else:
32
+ # too tall: crop height
33
+ new_h = int(w / target_ratio)
34
+ top = (h - new_h) // 2
35
+ img = img.crop((0, top, w, top + new_h))
36
+
37
+ # --- Resize down to ~0.3 MP (640x480) ---
38
+ img = img.resize((640, 480), resample=Image.BILINEAR)
39
+
40
+ # --- Slight blur for soft lens ---
41
+ img = img.filter(ImageFilter.GaussianBlur(radius=blur_radius))
42
+
43
+ # --- Reduce color depth (posterization) ---
44
+ arr = np.array(img, dtype=np.uint8)
45
+ if color_levels < 2:
46
+ color_levels = 2
47
+ step = max(1, 256 // int(color_levels)) # step size
48
+ arr = (arr // step) * step
49
+ img = Image.fromarray(arr, mode="RGB")
50
+
51
+ # --- Add noise ---
52
+ arr = np.array(img, dtype=np.int16)
53
+ noise = np.random.normal(0, noise_std, arr.shape)
54
+ arr = arr + noise
55
+ arr = np.clip(arr, 0, 255).astype(np.uint8)
56
+ img = Image.fromarray(arr, mode="RGB")
57
+
58
+ # --- Crush dynamic range (gamma curve) ---
59
+ arr = np.array(img, dtype=np.float32) / 255.0
60
+ arr = np.power(arr, gamma) # gamma >1 = darker mids
61
+ arr = np.clip(arr * 255, 0, 255).astype(np.uint8)
62
+ img = Image.fromarray(arr, mode="RGB")
63
+
64
+ # --- Optional yellow date stamp in corner ---
65
+ if add_date_stamp:
66
+ draw = ImageDraw.Draw(img)
67
+ font = ImageFont.load_default()
68
+ now = datetime.datetime.now()
69
+ text = now.strftime("%d-%m-%y %H:%M") # Nokia-style
70
+ # text size
71
+ text_w, text_h = draw.textsize(text, font=font)
72
+ margin = 4
73
+ x = img.width - text_w - margin
74
+ y = img.height - text_h - margin
75
+ # black box behind text
76
+ draw.rectangle(
77
+ [x - 2, y - 2, x + text_w + 2, y + text_h + 2],
78
+ fill=(0, 0, 0),
79
+ )
80
+ # yellow-ish text
81
+ draw.text((x, y), text, font=font, fill=(255, 255, 0))
82
+
83
+ # --- Save with low JPEG quality to get artifacts ---
84
+ buffer = io.BytesIO()
85
+ img.save(
86
+ buffer,
87
+ format="JPEG",
88
+ quality=int(jpeg_quality),
89
+ optimize=False,
90
+ progressive=False,
91
+ )
92
+ buffer.seek(0)
93
+ img = Image.open(buffer)
94
+
95
+ return img
96
+
97
+
98
+ def convert_fn(image, jpeg_quality, noise_std, color_levels, blur_radius, gamma, add_date_stamp):
99
+ if image is None:
100
+ return None
101
+ return modern_to_nokia_pil(
102
+ image,
103
+ jpeg_quality=jpeg_quality,
104
+ noise_std=noise_std,
105
+ color_levels=color_levels,
106
+ blur_radius=blur_radius,
107
+ gamma=gamma,
108
+ add_date_stamp=add_date_stamp,
109
+ )
110
+
111
+
112
+ demo = gr.Interface(
113
+ fn=convert_fn,
114
+ inputs=[
115
+ gr.Image(type="pil", label="Input image"),
116
+ gr.Slider(5, 40, value=15, step=1, label="JPEG quality (lower = more Nokia)"),
117
+ gr.Slider(0, 40, value=12, step=1, label="Noise amount"),
118
+ gr.Slider(2, 64, value=32, step=2, label="Color levels per channel"),
119
+ gr.Slider(0.0, 3.0, value=0.6, step=0.1, label="Blur radius"),
120
+ gr.Slider(0.5, 2.5, value=1.3, step=0.1, label="Gamma (contrast curve)"),
121
+ gr.Checkbox(True, label="Add date stamp"),
122
+ ],
123
+ outputs=gr.Image(type="pil", label="Nokia-style image"),
124
+ title="0.3 MP Nokia Camera Filter",
125
+ description="Upload a modern photo and turn it into an old-school 0.3 MP Nokia-style photo.",
126
+ )
127
+
128
+
129
+ if __name__ == "__main__":
130
+ demo.launch()