Rupesx007 commited on
Commit
82a4714
·
verified ·
1 Parent(s): 7b287e7

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +192 -32
src/streamlit_app.py CHANGED
@@ -1,40 +1,200 @@
1
- import altair as alt
2
  import numpy as np
3
- import pandas as pd
4
  import streamlit as st
 
 
5
 
6
- """
7
- # Welcome to Streamlit!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
 
12
 
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
 
 
 
15
 
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
 
 
 
 
 
 
 
 
18
 
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
1
+ import cv2
2
  import numpy as np
 
3
  import streamlit as st
4
+ from PIL import Image
5
+ import io
6
 
7
+ class FaceAnonymizer:
8
+ def __init__(self):
9
+ # loads harcascade for facial detecition
10
+ self.face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
11
+
12
+ def detect_faces(self, image):
13
+ """
14
+ input : takes an image
15
+ output : returns list of rectangles, each rectangle represent a face
16
+ [[(100, 50, 80, 80), (250, 60, 85, 85)] : means two faces were detected.
17
+ """
18
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
19
+ faces = self.face_cascade.detectMultiScale(
20
+ gray,
21
+ scaleFactor=1.1,
22
+ minNeighbors=5,
23
+ minSize=(30, 30)
24
+ )
25
+ return faces
26
+
27
+ def pixelate_area(self, image, x, y, w, h, pixel_size=15):
28
+ """
29
+ input : image,
30
+ (x,y) is the top-left corner of the rectangle
31
+ (w,h) is the width and height of the rectangle
32
+ output : returns the image with the selected area pixelated.
33
+ """
34
+ reason_of_interest = image[y:y+h, x:x+w]
35
+ downscaled_roi = cv2.resize(reason_of_interest, (pixel_size, pixel_size), interpolation=cv2.INTER_LINEAR)
36
+ pixelated = cv2.resize(downscaled_roi, (w, h), interpolation=cv2.INTER_NEAREST)
37
+ image[y:y+h, x:x+w] = pixelated
38
+ return image
39
+
40
+ def blur_area(self, image, x, y, w, h, blur_strength=25):
41
+ """Apply gaussian blur to a specific area"""
42
+ roi = image[y:y+h, x:x+w]
43
+ # Ensure blur strength is odd
44
+ if blur_strength % 2 == 0:
45
+ blur_strength += 1
46
+ blurred = cv2.GaussianBlur(roi, (blur_strength, blur_strength), 0)
47
+ image[y:y+h, x:x+w] = blurred
48
+ return image
49
+
50
+ def process_image(self, image, method='blur', pixel_size=15, blur_strength=25, padding=10):
51
+ """Process an image to anonymize faces"""
52
+ result = image.copy()
53
+ faces = self.detect_faces(image)
54
+
55
+ for (x, y, w, h) in faces:
56
+ # Add padding around the face
57
+ x = max(0, x - padding)
58
+ y = max(0, y - padding)
59
+ w = min(image.shape[1] - x, w + 2 * padding)
60
+ h = min(image.shape[0] - y, h + 2 * padding)
61
+
62
+ if method == 'pixelate':
63
+ result = self.pixelate_area(result, x, y, w, h, pixel_size)
64
+ elif method == 'blur':
65
+ result = self.blur_area(result, x, y, w, h, blur_strength)
66
+
67
+ return result, len(faces)
68
 
69
+ # helper functions to convert PIL to CV2
70
+ def pil_to_cv2(pil_image):
71
+ open_cv_image = np.array(pil_image.convert('RGB'))
72
+ return cv2.cvtColor(open_cv_image, cv2.COLOR_RGB2BGR)
73
 
74
+ # helper functions to convert CV2 to PIL
75
+ def cv2_to_pil(cv2_image):
76
+ """Convert OpenCV image to PIL format"""
77
+ rgb_image = cv2.cvtColor(cv2_image, cv2.COLOR_BGR2RGB)
78
+ return Image.fromarray(rgb_image)
79
 
80
+ def main():
81
+ st.set_page_config(
82
+ page_title="Face Anonymizer",
83
+ page_icon="🙈",
84
+ layout="wide"
85
+ )
86
+
87
+ st.title("Face Anonymizer")
88
+ st.markdown("Upload an image and automatically blur or pixelate faces for privacy protection")
89
+
90
 
91
+ if 'anonymizer' not in st.session_state:
92
+ st.session_state.anonymizer = FaceAnonymizer()
93
+
94
+ st.sidebar.header("Settings")
95
+
96
+ method = st.sidebar.selectbox(
97
+ "Anonymization Method",
98
+ ["blur", "pixelate"],
99
+ help="Choose between blur or pixelation effect"
100
+ )
101
+
102
+ if method == "blur":
103
+ blur_strength = st.sidebar.slider(
104
+ "Blur Strength",
105
+ min_value=5,
106
+ max_value=99,
107
+ value=25,
108
+ step=2,
109
+ help="Higher values = more blur (must be odd)"
110
+ )
111
+
112
+ if blur_strength % 2 == 0:
113
+ blur_strength += 1
114
+ else:
115
+ pixel_size = st.sidebar.slider(
116
+ "Pixel Size",
117
+ min_value=5,
118
+ max_value=50,
119
+ value=15,
120
+ help="Lower values = more pixelated"
121
+ )
122
+
123
+ padding = st.sidebar.slider(
124
+ "Face Padding",
125
+ min_value=0,
126
+ max_value=50,
127
+ value=10,
128
+ help="Adds an extra padding around detected faces"
129
+ )
130
+
131
+ # upload a file
132
+ uploaded_file = st.file_uploader(
133
+ "Choose an image file",
134
+ type=['jpg', 'jpeg', 'png'],
135
+ help="Upload a JPG, PNG or image"
136
+ )
137
+
138
+ if uploaded_file is not None:
139
+ # if image is uploaded open and display the image
140
+ pil_image = Image.open(uploaded_file)
141
+
142
+ col1, col2 = st.columns(2)
143
+
144
+ with col1:
145
+ st.subheader("📸 Original Image")
146
+ st.image(pil_image, use_column_width=True)
147
+
148
+ # process the image
149
+ with st.spinner("detecting and anonymizing faces"):
150
+ # convert PIL to cv2 format
151
+ cv2_image = pil_to_cv2(pil_image)
152
+
153
+ # process based on selected method
154
+ if method == "blur":
155
+ processed_image, face_count = st.session_state.anonymizer.process_image(
156
+ cv2_image, method=method, blur_strength=blur_strength, padding=padding
157
+ )
158
+ else:
159
+ processed_image, face_count = st.session_state.anonymizer.process_image(
160
+ cv2_image, method=method, pixel_size=pixel_size, padding=padding
161
+ )
162
+
163
+ # convert back to PIL for display
164
+ result_pil = cv2_to_pil(processed_image)
165
+
166
+ with col2:
167
+ st.subheader("Anonymized Image")
168
+ st.image(result_pil, use_column_width=True)
169
+
170
+ # Show results info
171
+ if face_count > 0:
172
+ st.success(f"Successfully anonymized {face_count} face(s) using {method}")
173
+ else:
174
+ st.warning("No faces detected in the image")
175
+
176
+
177
+ img_buffer = io.BytesIO()
178
+ result_pil.save(img_buffer, format='PNG')
179
+ img_buffer.seek(0)
180
+
181
+ st.download_button(
182
+ label="Download Anonymized Image",
183
+ data=img_buffer.getvalue(),
184
+ file_name=f"anonymized_{uploaded_file.name}",
185
+ mime="image/png",
186
+ use_container_width=True
187
+ )
188
+
189
+ # Settings info
190
+ with st.expander("ℹ️ Processing Details"):
191
+ st.write(f"**Method:** {method.title()}")
192
+ if method == "blur":
193
+ st.write(f"**Blur Strength:** {blur_strength}")
194
+ else:
195
+ st.write(f"**Pixel Size:** {pixel_size}")
196
+ st.write(f"**Face Padding:** {padding}px")
197
+
198
 
199
+ if __name__ == "__main__":
200
+ main()