Jacob Logas
commited on
Update space for app
Browse files- .pre-commit-config.yaml +16 -0
- Dockerfile +0 -24
- README.md +0 -12
- app.py +105 -99
- requirements-dev.txt +2 -0
- requirements.txt +4 -71
.pre-commit-config.yaml
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
repos:
|
2 |
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
3 |
+
rev: v2.3.0
|
4 |
+
hooks:
|
5 |
+
- id: check-yaml
|
6 |
+
- id: end-of-file-fixer
|
7 |
+
- id: trailing-whitespace
|
8 |
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
9 |
+
# Ruff version.
|
10 |
+
rev: v0.5.2
|
11 |
+
hooks:
|
12 |
+
# Run the linter.
|
13 |
+
- id: ruff
|
14 |
+
args: [ --fix ]
|
15 |
+
# Run the formatter.
|
16 |
+
- id: ruff-format
|
Dockerfile
DELETED
@@ -1,24 +0,0 @@
|
|
1 |
-
# Stage 1: Build Dependencies
|
2 |
-
FROM python:slim as builder
|
3 |
-
|
4 |
-
RUN apt update && \
|
5 |
-
apt install --no-install-recommends -y build-essential gcc
|
6 |
-
|
7 |
-
COPY requirements.txt /requirements.txt
|
8 |
-
|
9 |
-
RUN pip install --upgrade pip && \
|
10 |
-
pip install --quiet --no-cache-dir --no-warn-script-location --user -r requirements.txt
|
11 |
-
|
12 |
-
# Stage 2: Runtime
|
13 |
-
FROM python:slim
|
14 |
-
ENV GRADIO_SERVER_NAME=0.0.0.0
|
15 |
-
|
16 |
-
RUN rm -rf /var/lib/apt/lists/*
|
17 |
-
|
18 |
-
COPY --from=builder /root/.local/lib/python3.11/site-packages /root/.local/lib/python3.11/site-packages
|
19 |
-
|
20 |
-
COPY raccoon_emoji.png raccoon_emoji.png
|
21 |
-
COPY app.py app.py
|
22 |
-
|
23 |
-
CMD [ "python" , "-u", "app.py" ]
|
24 |
-
EXPOSE 7860
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
README.md
CHANGED
@@ -1,12 +0,0 @@
|
|
1 |
-
---
|
2 |
-
title: Fawkes
|
3 |
-
emoji: 🌖
|
4 |
-
colorFrom: red
|
5 |
-
colorTo: purple
|
6 |
-
sdk: gradio
|
7 |
-
sdk_version: 3.0.20
|
8 |
-
app_file: app.py
|
9 |
-
pinned: false
|
10 |
-
license: gpl-3.0
|
11 |
-
python_version: 3.8.13
|
12 |
-
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app.py
CHANGED
@@ -5,111 +5,117 @@ from mtcnn_cv2 import MTCNN
|
|
5 |
|
6 |
detector = MTCNN()
|
7 |
|
|
|
8 |
def predict(img, selection):
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
|
30 |
def anonymize_face_pixelate(image, features, blocks=10):
|
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 |
def anonymize_face_emoji(img, features, name="smiley"):
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
|
66 |
-
|
67 |
-
|
|
|
|
|
68 |
|
69 |
-
return overlay_transparent(img, mask,
|
70 |
-
x - offset,
|
71 |
-
y - offset,
|
72 |
-
(mshape, mshape))
|
73 |
|
74 |
def overlay_transparent(background_img, img_to_overlay_t, x, y, overlay_size=None):
|
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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
|
6 |
detector = MTCNN()
|
7 |
|
8 |
+
|
9 |
def predict(img, selection):
|
10 |
+
faces = detector.detect_faces(img)
|
11 |
+
|
12 |
+
if selection == "Low":
|
13 |
+
opts = (anonymize_face_pixelate, 20)
|
14 |
+
elif selection == "Medium":
|
15 |
+
opts = (anonymize_face_pixelate, 10)
|
16 |
+
elif selection == "High":
|
17 |
+
opts = (anonymize_face_pixelate, 4)
|
18 |
+
elif selection == "Emoji":
|
19 |
+
opts = (anonymize_face_emoji, "smiley")
|
20 |
+
else:
|
21 |
+
raise Exception("I don't know how you did it but you chose something else.")
|
22 |
+
|
23 |
+
if len(faces) > 0:
|
24 |
+
for features in faces:
|
25 |
+
img = opts[0](img, features, opts[1])
|
26 |
+
else:
|
27 |
+
raise Exception("No faces detected")
|
28 |
+
return img
|
29 |
+
|
30 |
|
31 |
def anonymize_face_pixelate(image, features, blocks=10):
|
32 |
+
bb = features["box"]
|
33 |
+
face_crop = image[bb[1] : bb[1] + bb[3], bb[0] : bb[0] + bb[2]]
|
34 |
+
# Divide the input image into NxN blocks
|
35 |
+
(h, w) = face_crop.shape[:2]
|
36 |
+
xSteps = np.linspace(0, w, blocks + 1, dtype="int")
|
37 |
+
ySteps = np.linspace(0, h, blocks + 1, dtype="int")
|
38 |
+
|
39 |
+
# loop over the blocks in both x and y direction
|
40 |
+
for i in range(1, len(ySteps)):
|
41 |
+
for j in range(1, len(xSteps)):
|
42 |
+
# compute starting and ending (x, y)-coordinates
|
43 |
+
# for current block
|
44 |
+
startX = xSteps[j - 1]
|
45 |
+
startY = ySteps[i - 1]
|
46 |
+
endX = xSteps[j]
|
47 |
+
endY = ySteps[i]
|
48 |
+
|
49 |
+
# Extract the ROI using NumPy array slicing, compute the
|
50 |
+
# mean of the ROI, and then draw a rectangle with the
|
51 |
+
# mean RGB values over the ROI in teh original image
|
52 |
+
roi = face_crop[startY:endY, startX:endX]
|
53 |
+
(B, G, R) = [int(x) for x in cv2.mean(roi)[:3]]
|
54 |
+
cv2.rectangle(face_crop, (startX, startY), (endX, endY), (B, G, R), -1)
|
55 |
+
|
56 |
+
image[bb[1] : bb[1] + bb[3], bb[0] : bb[0] + bb[2]] = face_crop
|
57 |
+
return image
|
58 |
+
|
59 |
|
60 |
def anonymize_face_emoji(img, features, name="smiley"):
|
61 |
+
bb = features["box"]
|
62 |
+
(y, x) = (bb[1] + int(bb[3] / 2), bb[0] + int(bb[2] / 2))
|
63 |
+
(h, w) = (bb[3], bb[2])
|
64 |
+
# Get emoji with transparency
|
65 |
+
mask = cv2.imread("raccoon_emoji.png", -1)
|
66 |
|
67 |
+
mshape = max(h, w)
|
68 |
+
offset = int(mshape / 2)
|
69 |
+
|
70 |
+
return overlay_transparent(img, mask, x - offset, y - offset, (mshape, mshape))
|
71 |
|
|
|
|
|
|
|
|
|
72 |
|
73 |
def overlay_transparent(background_img, img_to_overlay_t, x, y, overlay_size=None):
|
74 |
+
"""
|
75 |
+
@brief Overlays a transparant PNG onto another image using CV2
|
76 |
+
|
77 |
+
@param background_img The background image
|
78 |
+
@param img_to_overlay_t The transparent image to overlay (has alpha channel)
|
79 |
+
@param x x location to place the top-left corner of our overlay
|
80 |
+
@param y y location to place the top-left corner of our overlay
|
81 |
+
@param overlay_size The size to scale our overlay to (tuple), no scaling if None
|
82 |
+
|
83 |
+
@return Background image with overlay on top
|
84 |
+
"""
|
85 |
+
|
86 |
+
bg_img = background_img.copy()
|
87 |
+
|
88 |
+
if overlay_size is not None:
|
89 |
+
img_to_overlay_t = cv2.resize(img_to_overlay_t.copy(), overlay_size)
|
90 |
+
|
91 |
+
# Extract the alpha mask of the RGBA image, convert to RGB
|
92 |
+
b, g, r, a = cv2.split(img_to_overlay_t)
|
93 |
+
overlay_color = cv2.merge((b, g, r))
|
94 |
+
|
95 |
+
# Apply some simple filtering to remove edge noise
|
96 |
+
mask = cv2.medianBlur(a, 5)
|
97 |
+
|
98 |
+
h, w, _ = overlay_color.shape
|
99 |
+
roi = bg_img[y : y + h, x : x + w]
|
100 |
+
|
101 |
+
# Black-out the area behind the logo in our original ROI
|
102 |
+
img1_bg = cv2.bitwise_and(roi.copy(), roi.copy(), mask=cv2.bitwise_not(mask))
|
103 |
+
|
104 |
+
# Mask out the logo from the logo image.
|
105 |
+
img2_fg = cv2.bitwise_and(overlay_color, overlay_color, mask=mask)
|
106 |
+
|
107 |
+
# Update the original image with our new ROI
|
108 |
+
bg_img[y : y + h, x : x + w] = cv2.add(img1_bg, img2_fg)
|
109 |
+
|
110 |
+
return bg_img
|
111 |
+
|
112 |
+
|
113 |
+
gr.Interface(
|
114 |
+
fn=predict,
|
115 |
+
inputs=[
|
116 |
+
gr.components.Image(type="numpy"),
|
117 |
+
gr.components.Radio(["Low", "Medium", "High", "Emoji"], value="Medium"),
|
118 |
+
],
|
119 |
+
outputs=gr.components.Image(type="pil"),
|
120 |
+
allow_flagging="never",
|
121 |
+
).launch(show_error=True, quiet=False)
|
requirements-dev.txt
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
ruff
|
2 |
+
pre-commit
|
requirements.txt
CHANGED
@@ -1,71 +1,4 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
anyio==3.6.2
|
6 |
-
async-timeout==4.0.2
|
7 |
-
attrs==22.1.0
|
8 |
-
bcrypt==4.0.1
|
9 |
-
certifi==2022.12.7
|
10 |
-
cffi==1.15.1
|
11 |
-
charset-normalizer==2.1.1
|
12 |
-
click==8.1.3
|
13 |
-
contourpy==1.0.6
|
14 |
-
cryptography==39.0.2
|
15 |
-
cycler==0.11.0
|
16 |
-
emoji==2.2.0
|
17 |
-
entrypoints==0.4
|
18 |
-
fastapi==0.86.0
|
19 |
-
ffmpy==0.3.0
|
20 |
-
filelock==3.9.1
|
21 |
-
fonttools==4.38.0
|
22 |
-
frozenlist==1.3.3
|
23 |
-
fsspec==2022.10.0
|
24 |
-
gradio==3.21.0
|
25 |
-
h11==0.12.0
|
26 |
-
httpcore==0.15.0
|
27 |
-
httpx==0.23.0
|
28 |
-
huggingface-hub==0.13.2
|
29 |
-
idna==3.4
|
30 |
-
Jinja2==3.1.2
|
31 |
-
jsonschema==4.17.3
|
32 |
-
kiwisolver==1.4.4
|
33 |
-
linkify-it-py==1.0.3
|
34 |
-
markdown-it-py==2.2.0
|
35 |
-
MarkupSafe==2.1.1
|
36 |
-
matplotlib==3.6.2
|
37 |
-
mdit-py-plugins==0.3.1
|
38 |
-
mdurl==0.1.2
|
39 |
-
mtcnn-opencv==1.0.2
|
40 |
-
multidict==6.0.2
|
41 |
-
numpy==1.23.4
|
42 |
-
opencv-contrib-python-headless==4.6.0.66
|
43 |
-
orjson==3.8.1
|
44 |
-
packaging==21.3
|
45 |
-
pandas==1.5.1
|
46 |
-
paramiko==2.12.0
|
47 |
-
Pillow==9.3.0
|
48 |
-
pycparser==2.21
|
49 |
-
pycryptodome==3.15.0
|
50 |
-
pydantic==1.10.2
|
51 |
-
pydub==0.25.1
|
52 |
-
PyNaCl==1.5.0
|
53 |
-
pyparsing==3.0.9
|
54 |
-
pyrsistent==0.19.3
|
55 |
-
python-dateutil==2.8.2
|
56 |
-
python-multipart==0.0.5
|
57 |
-
pytz==2022.6
|
58 |
-
PyYAML==6.0
|
59 |
-
requests==2.28.1
|
60 |
-
rfc3986==1.5.0
|
61 |
-
six==1.16.0
|
62 |
-
sniffio==1.3.0
|
63 |
-
starlette==0.20.4
|
64 |
-
toolz==0.12.0
|
65 |
-
tqdm==4.65.0
|
66 |
-
typing_extensions==4.4.0
|
67 |
-
uc-micro-py==1.0.1
|
68 |
-
urllib3==1.26.12
|
69 |
-
uvicorn==0.19.0
|
70 |
-
websockets==10.4
|
71 |
-
yarl==1.8.1
|
|
|
1 |
+
gradio>=4.38.1
|
2 |
+
numpy>=2.0.0
|
3 |
+
mtcnn-opencv>=1.0.2
|
4 |
+
opencv-python>=4.10.0.84
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|