Aadhithya commited on
Commit
6390e4a
·
1 Parent(s): b628cb1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +214 -68
app.py CHANGED
@@ -1,69 +1,215 @@
1
- from flask import Flask, render_template, request, redirect, url_for, send_from_directory
 
2
  import os
3
- import subprocess
4
- import uuid # Import the UUID module
5
- from werkzeug.utils import secure_filename
6
-
7
- app = Flask(__name__)
8
-
9
- # Configuration for file uploads and output
10
- UPLOAD_FOLDER = 'uploads'
11
- OUTPUT_FOLDER = 'output_files'
12
- ALLOWED_EXTENSIONS = {'jpg', 'jpeg', 'png', 'gif', 'mp4', 'avi', 'mov'}
13
-
14
- app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
15
- app.config['OUTPUT_FOLDER'] = OUTPUT_FOLDER
16
-
17
- def allowed_file(filename):
18
- return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
19
-
20
- @app.route('/', methods=['GET', 'POST'])
21
- def index():
22
- if request.method == 'POST':
23
- # Handle file uploads and processing options
24
- source_file = request.files['source']
25
- target_file = request.files['target']
26
- frame_processors = request.form.getlist('frame_processor')
27
-
28
- if source_file and allowed_file(source_file.filename) and target_file and allowed_file(target_file.filename):
29
- # Generate unique filenames with UUIDs for uploaded files
30
- source_filename = str(uuid.uuid4()) + '_' + secure_filename(source_file.filename)
31
- target_filename = str(uuid.uuid4()) + '_' + secure_filename(target_file.filename)
32
-
33
- # Save uploaded files
34
- source_path = os.path.join(app.config['UPLOAD_FOLDER'], source_filename)
35
- target_path = os.path.join(app.config['UPLOAD_FOLDER'], target_filename)
36
- source_file.save(source_path)
37
- target_file.save(target_path)
38
-
39
- # Determine output file name with UUID
40
- output_filename = str(uuid.uuid4()) + '.jpg' # Default output format is JPEG
41
-
42
- # Build and execute the processing command here
43
- processing_command = ['python', 'run.py', '-s', source_path, '-t', target_path, '-o', os.path.join(app.config['OUTPUT_FOLDER'], output_filename)]
44
- processing_command.extend(['--frame-processor', *frame_processors])
45
-
46
- try:
47
- # Execute the processing command using subprocess
48
- subprocess.run(processing_command, check=True)
49
-
50
- # Redirect to the output page
51
- return redirect(url_for('output', filename=output_filename))
52
- except subprocess.CalledProcessError:
53
- return render_template('error.html')
54
-
55
- return render_template('index.html')
56
-
57
- @app.route('/output/<filename>')
58
- def output(filename):
59
- return render_template('output.html', filename=filename)
60
-
61
- @app.route('/download/<filename>')
62
- def download(filename):
63
- return send_from_directory(app.config['OUTPUT_FOLDER'], filename, as_attachment=True)
64
-
65
- if __name__ == '__main__':
66
- os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
67
- os.makedirs(app.config['OUTPUT_FOLDER'], exist_ok=True)
68
- app.run(host="0.0.0.0", port=7860, debug=True)
69
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio
2
+ from huggingface_hub import Repository
3
  import os
4
+
5
+ from utils.utils import norm_crop, estimate_norm, inverse_estimate_norm, transform_landmark_points, get_lm
6
+ from networks.layers import AdaIN, AdaptiveAttention
7
+ from tensorflow_addons.layers import InstanceNormalization
8
+ import numpy as np
9
+ import cv2
10
+ from scipy.ndimage import gaussian_filter
11
+
12
+ from tensorflow.keras.models import load_model
13
+ from options.swap_options import SwapOptions
14
+
15
+ # .
16
+ # token = os.environ['model_fetch']
17
+
18
+ opt = SwapOptions().parse()
19
+ token = os.environ['token']
20
+
21
+ retina_repo = Repository(local_dir="retina_models", clone_from="felixrosberg/RetinaFace")
22
+
23
+ from retinaface.models import *
24
+
25
+ RetinaFace = load_model("retina_models/RetinaFace-Res50.h5",
26
+ custom_objects={"FPN": FPN,
27
+ "SSH": SSH,
28
+ "BboxHead": BboxHead,
29
+ "LandmarkHead": LandmarkHead,
30
+ "ClassHead": ClassHead}
31
+ )
32
+
33
+ arc_repo = Repository(local_dir="arcface_model", clone_from="felixrosberg/ArcFace")
34
+ ArcFace = load_model("arcface_model/ArcFace-Res50.h5")
35
+ ArcFaceE = load_model("arcface_model/ArcFacePerceptual-Res50.h5")
36
+
37
+ g_repo = Repository(local_dir="g_model_c_hq", clone_from="felixrosberg/FaceDancer",use_auth_token=token)
38
+ G = load_model("g_model_c_hq/FaceDancer_config_c_HQ.h5", custom_objects={"AdaIN": AdaIN,
39
+ "AdaptiveAttention": AdaptiveAttention,
40
+ "InstanceNormalization": InstanceNormalization})
41
+
42
+ # r_repo = Repository(local_dir="reconstruction_attack", clone_from="felixrosberg/reconstruction_attack",
43
+ # private=True, use_auth_token=token)
44
+ # R = load_model("reconstruction_attack/reconstructor_42.h5", custom_objects={"AdaIN": AdaIN,
45
+ # "AdaptiveAttention": AdaptiveAttention,
46
+ # "InstanceNormalization": InstanceNormalization})
47
+
48
+ # permuter_repo = Repository(local_dir="identity_permuter", clone_from="felixrosberg/identitypermuter",
49
+ # private=True, use_auth_token=token, git_user="felixrosberg")
50
+
51
+ # from identity_permuter.id_permuter import identity_permuter
52
+
53
+ # IDP = identity_permuter(emb_size=32, min_arg=False)
54
+ # IDP.load_weights("identity_permuter/id_permuter.h5")
55
+
56
+ blend_mask_base = np.zeros(shape=(256, 256, 1))
57
+ blend_mask_base[80:244, 32:224] = 1
58
+ blend_mask_base = gaussian_filter(blend_mask_base, sigma=7)
59
+
60
+
61
+ def run_inference(target, source, slider, adv_slider, settings):
62
+ try:
63
+ source = np.array(source)
64
+ target = np.array(target)
65
+
66
+ # Prepare to load video
67
+ if "anonymize" not in settings:
68
+ source_a = RetinaFace(np.expand_dims(source, axis=0)).numpy()[0]
69
+ source_h, source_w, _ = source.shape
70
+ source_lm = get_lm(source_a, source_w, source_h)
71
+ source_aligned = norm_crop(source, source_lm, image_size=256)
72
+ source_z = ArcFace.predict(np.expand_dims(tf.image.resize(source_aligned, [112, 112]) / 255.0, axis=0))
73
+ else:
74
+ source_z = None
75
+
76
+ # read frame
77
+ im = target
78
+ im_h, im_w, _ = im.shape
79
+ im_shape = (im_w, im_h)
80
+
81
+ detection_scale = im_w // 640 if im_w > 640 else 1
82
+
83
+ faces = RetinaFace(np.expand_dims(cv2.resize(im,
84
+ (im_w // detection_scale,
85
+ im_h // detection_scale)), axis=0)).numpy()
86
+
87
+ total_img = im / 255.0
88
+ for annotation in faces:
89
+ lm_align = np.array([[annotation[4] * im_w, annotation[5] * im_h],
90
+ [annotation[6] * im_w, annotation[7] * im_h],
91
+ [annotation[8] * im_w, annotation[9] * im_h],
92
+ [annotation[10] * im_w, annotation[11] * im_h],
93
+ [annotation[12] * im_w, annotation[13] * im_h]],
94
+ dtype=np.float32)
95
+
96
+ # align the detected face
97
+ M, pose_index = estimate_norm(lm_align, 256, "arcface", shrink_factor=1.0)
98
+ im_aligned = (cv2.warpAffine(im, M, (256, 256), borderValue=0.0) - 127.5) / 127.5
99
+
100
+ if "adversarial defense" in settings:
101
+ eps = adv_slider / 200
102
+ X = tf.convert_to_tensor(np.expand_dims(im_aligned, axis=0))
103
+ with tf.GradientTape() as tape:
104
+ tape.watch(X)
105
+
106
+ X_z = ArcFaceE(tf.image.resize(X * 0.5 + 0.5, [112, 112]))
107
+ output = R([X, X_z])
108
+
109
+ loss = tf.reduce_mean(tf.abs(0 - output))
110
+
111
+ gradient = tf.sign(tape.gradient(loss, X))
112
+
113
+ adv_x = X + eps * gradient
114
+ im_aligned = tf.clip_by_value(adv_x, -1, 1)[0]
115
+
116
+ if "anonymize" in settings and "reconstruction attack" not in settings:
117
+ """source_z = ArcFace.predict(np.expand_dims(tf.image.resize(im_aligned, [112, 112]) / 255.0, axis=0))
118
+ anon_ratio = int(512 * (slider / 100))
119
+ anon_vector = np.ones(shape=(1, 512))
120
+ anon_vector[:, :anon_ratio] = -1
121
+ np.random.shuffle(anon_vector)
122
+ source_z *= anon_vector"""
123
+
124
+ slider_weight = slider / 100
125
+
126
+ target_z = ArcFace.predict(np.expand_dims(tf.image.resize(im_aligned, [112, 112]) * 0.5 + 0.5, axis=0))
127
+ # source_z = IDP.predict(target_z)
128
+
129
+ source_z = slider_weight * source_z + (1 - slider_weight) * target_z
130
+
131
+ if "reconstruction attack" in settings:
132
+ source_z = ArcFaceE.predict(np.expand_dims(tf.image.resize(im_aligned, [112, 112]) * 0.5 + 0.5, axis=0))
133
+
134
+ # face swap
135
+ if "reconstruction attack" not in settings:
136
+ changed_face_cage = G.predict([np.expand_dims(im_aligned, axis=0),
137
+ source_z])
138
+ changed_face = changed_face_cage[0] * 0.5 + 0.5
139
+
140
+ # get inverse transformation landmarks
141
+ transformed_lmk = transform_landmark_points(M, lm_align)
142
+
143
+ # warp image back
144
+ iM, _ = inverse_estimate_norm(lm_align, transformed_lmk, 256, "arcface", shrink_factor=1.0)
145
+ iim_aligned = cv2.warpAffine(changed_face, iM, im_shape, borderValue=0.0)
146
+
147
+ # blend swapped face with target image
148
+ blend_mask = cv2.warpAffine(blend_mask_base, iM, im_shape, borderValue=0.0)
149
+ blend_mask = np.expand_dims(blend_mask, axis=-1)
150
+ total_img = (iim_aligned * blend_mask + total_img * (1 - blend_mask))
151
+ else:
152
+ changed_face_cage = R.predict([np.expand_dims(im_aligned, axis=0),
153
+ source_z])
154
+ changed_face = changed_face_cage[0] * 0.5 + 0.5
155
+
156
+ # get inverse transformation landmarks
157
+ transformed_lmk = transform_landmark_points(M, lm_align)
158
+
159
+ # warp image back
160
+ iM, _ = inverse_estimate_norm(lm_align, transformed_lmk, 256, "arcface", shrink_factor=1.0)
161
+ iim_aligned = cv2.warpAffine(changed_face, iM, im_shape, borderValue=0.0)
162
+
163
+ # blend swapped face with target image
164
+ blend_mask = cv2.warpAffine(blend_mask_base, iM, im_shape, borderValue=0.0)
165
+ blend_mask = np.expand_dims(blend_mask, axis=-1)
166
+ total_img = (iim_aligned * blend_mask + total_img * (1 - blend_mask))
167
+
168
+ if "compare" in settings:
169
+ total_img = np.concatenate((im / 255.0, total_img), axis=1)
170
+
171
+ total_img = np.clip(total_img, 0, 1)
172
+ total_img *= 255.0
173
+ total_img = total_img.astype('uint8')
174
+
175
+ return total_img
176
+ except Exception as e:
177
+ print(e)
178
+ return None
179
+
180
+
181
+ description = "Performs subject agnostic identity transfer from a source face to all target faces. \n\n" \
182
+ "Implementation and demo of FaceDancer, accepted to WACV 2023. \n\n" \
183
+ "Pre-print: https://arxiv.org/abs/2210.10473 \n\n" \
184
+ "Code: https://github.com/felixrosberg/FaceDancer \n\n" \
185
+ "\n\n" \
186
+ "Options:\n\n" \
187
+ "-Compare returns the target image concatenated with the results.\n\n" \
188
+ "-Anonymize will ignore the source image and perform an identity permutation of target faces.\n\n" \
189
+ "-Reconstruction attack will attempt to invert the face swap or the anonymization.\n\n" \
190
+ "-Adversarial defense will add a permutation noise that disrupts the reconstruction attack.\n\n" \
191
+ "NOTE: There is no guarantees with the anonymization process currently.\n\n" \
192
+ "NOTE: source image with too high resolution may not work properly!"
193
+ examples = [["assets/rick.jpg", "assets/musk.jpg", 100, 10, ["compare"]],
194
+ ["assets/musk.jpg", "assets/musk.jpg", 100, 10, ["anonymize"]]]
195
+ article = """
196
+ Demo is based of recent research from my Ph.D work. Results expects to be published in the coming months.
197
+ """
198
+
199
+ iface = gradio.Interface(run_inference,
200
+ [gradio.Image(shape=None, type="pil", label='Target'),
201
+ gradio.Image(shape=None, type="pil", label='Source'),
202
+ gradio.Slider(0, 100, default=100, label="Anonymization ratio (%)"),
203
+ gradio.Slider(0, 100, default=100, label="Adversarial defense ratio (%)"),
204
+ gradio.CheckboxGroup(["compare",
205
+ "anonymize",
206
+ "reconstruction attack",
207
+ "adversarial defense"],
208
+ label='Options')],
209
+ "image",
210
+ title="Face Swap",
211
+ description=description,
212
+ examples=examples,
213
+ article=article,
214
+ layout="vertical")
215
+ iface.launch()