Arnaudding001 commited on
Commit
a4bc2b0
1 Parent(s): d1e62f2

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +280 -0
app.py ADDED
@@ -0,0 +1,280 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import pathlib
7
+ import torch
8
+ import gradio as gr
9
+
10
+ from vtoonify_model import Model
11
+
12
+ def parse_args() -> argparse.Namespace:
13
+ parser = argparse.ArgumentParser()
14
+ parser.add_argument('--device', type=str, default='cpu')
15
+ parser.add_argument('--theme', type=str)
16
+ parser.add_argument('--share', action='store_true')
17
+ parser.add_argument('--port', type=int)
18
+ parser.add_argument('--disable-queue',
19
+ dest='enable_queue',
20
+ action='store_false')
21
+ return parser.parse_args()
22
+
23
+ DESCRIPTION = '''
24
+ <div align=center>
25
+ <h1 style="font-weight: 900; margin-bottom: 7px;">
26
+ Portrait Style Transfer with <a href="https://github.com/williamyang1991/VToonify">VToonify</a>
27
+ </h1>
28
+ <video id="video" width=50% controls="" preload="none" poster="https://repository-images.githubusercontent.com/534480768/53715b0f-a2df-4daa-969c-0e74c102d339">
29
+ <source id="mp4" src="https://user-images.githubusercontent.com/18130694/189483939-0fc4a358-fb34-43cc-811a-b22adb820d57.mp4
30
+ " type="video/mp4">
31
+ </videos></div>
32
+ '''
33
+ FOOTER = '<div align=center><img id="visitor-badge" alt="visitor badge" src="https://visitor-badge.laobi.icu/badge?page_id=williamyang1991/VToonify" /></div>'
34
+
35
+ ARTICLE = r"""
36
+ If VToonify is helpful, please help to ⭐ the <a href='https://github.com/williamyang1991/VToonify' target='_blank'>Github Repo</a>. Thanks!
37
+ [![GitHub Stars](https://img.shields.io/github/stars/williamyang1991/VToonify?style=social)](https://github.com/williamyang1991/VToonify)
38
+ ---
39
+ 📝 **Citation**
40
+ If our work is useful for your research, please consider citing:
41
+ ```bibtex
42
+ @article{yang2022Vtoonify,
43
+ title={VToonify: Controllable High-Resolution Portrait Video Style Transfer},
44
+ author={Yang, Shuai and Jiang, Liming and Liu, Ziwei and Loy, Chen Change},
45
+ journal={ACM Transactions on Graphics (TOG)},
46
+ volume={41},
47
+ number={6},
48
+ articleno={203},
49
+ pages={1--15},
50
+ year={2022},
51
+ publisher={ACM New York, NY, USA},
52
+ doi={10.1145/3550454.3555437},
53
+ }
54
+ ```
55
+ 📋 **License**
56
+ This project is licensed under <a rel="license" href="https://github.com/williamyang1991/VToonify/blob/main/LICENSE.md">S-Lab License 1.0</a>.
57
+ Redistribution and use for non-commercial purposes should follow this license.
58
+ 📧 **Contact**
59
+ If you have any questions, please feel free to reach me out at <b>williamyang@pku.edu.cn</b>.
60
+ """
61
+
62
+ def update_slider(choice: str) -> dict:
63
+ if type(choice) == str and choice.endswith('-d'):
64
+ return gr.Slider.update(maximum=1, minimum=0, value=0.5)
65
+ else:
66
+ return gr.Slider.update(maximum=0.5, minimum=0.5, value=0.5)
67
+
68
+ def set_example_image(example: list) -> dict:
69
+ return gr.Image.update(value=example[0])
70
+
71
+ def set_example_video(example: list) -> dict:
72
+ return gr.Video.update(value=example[0]),
73
+
74
+ sample_video = ['./vtoonify/data/529_2.mp4','./vtoonify/data/7154235.mp4','./vtoonify/data/651.mp4','./vtoonify/data/908.mp4']
75
+ sample_vid = gr.Video(label='Video file') #for displaying the example
76
+ example_videos = gr.components.Dataset(components=[sample_vid], samples=[[path] for path in sample_video], type='values', label='Video Examples')
77
+
78
+ def main():
79
+ args = parse_args()
80
+ args.device = 'cuda' if torch.cuda.is_available() else 'cpu'
81
+ print('*** Now using %s.'%(args.device))
82
+ model = Model(device=args.device)
83
+
84
+ with gr.Blocks(theme=args.theme, css='style.css') as demo:
85
+
86
+ gr.Markdown(DESCRIPTION)
87
+
88
+ with gr.Box():
89
+ gr.Markdown('''## Step 1(Select Style)
90
+ - Select **Style Type**.
91
+ - Type with `-d` means it supports style degree adjustment.
92
+ - Type without `-d` usually has better toonification quality.
93
+ ''')
94
+ with gr.Row():
95
+ with gr.Column():
96
+ gr.Markdown('''Select Style Type''')
97
+ with gr.Row():
98
+ style_type = gr.Radio(label='Style Type',
99
+ choices=['cartoon1','cartoon1-d','cartoon2-d','cartoon3-d',
100
+ 'cartoon4','cartoon4-d','cartoon5-d','comic1-d',
101
+ 'comic2-d','arcane1','arcane1-d','arcane2', 'arcane2-d',
102
+ 'caricature1','caricature2','pixar','pixar-d',
103
+ 'illustration1-d', 'illustration2-d', 'illustration3-d', 'illustration4-d', 'illustration5-d',
104
+ ]
105
+ )
106
+ exstyle = gr.Variable()
107
+ with gr.Row():
108
+ loadmodel_button = gr.Button('Load Model')
109
+ with gr.Row():
110
+ load_info = gr.Textbox(label='Process Information', interactive=False, value='No model loaded.')
111
+ with gr.Column():
112
+ gr.Markdown('''Reference Styles
113
+ ![example](https://raw.githubusercontent.com/williamyang1991/tmpfile/master/vtoonify/style.jpg)''')
114
+
115
+
116
+ with gr.Box():
117
+ gr.Markdown('''## Step 2 (Preprocess Input Image / Video)
118
+ - Drop an image/video containing a near-frontal face to the **Input Image**/**Input Video**.
119
+ - Hit the **Rescale Image**/**Rescale First Frame** button.
120
+ - Rescale the input to make it best fit the model.
121
+ - The final image result will be based on this **Rescaled Face**. Use padding parameters to adjust the background space.
122
+ - **<font color=red>Solution to [Error: no face detected!]</font>**: VToonify uses dlib.get_frontal_face_detector but sometimes it fails to detect a face. You can try several times or use other images until a face is detected, then switch back to the original image.
123
+ - For video input, further hit the **Rescale Video** button.
124
+ - The final video result will be based on this **Rescaled Video**. To avoid overload, video is cut to at most **100/300** frames for CPU/GPU, respectively.
125
+ ''')
126
+ with gr.Row():
127
+ with gr.Box():
128
+ with gr.Column():
129
+ gr.Markdown('''Choose the padding parameters.
130
+ ![example](https://raw.githubusercontent.com/williamyang1991/tmpfile/master/vtoonify/rescale.jpg)''')
131
+ with gr.Row():
132
+ top = gr.Slider(128,
133
+ 256,
134
+ value=200,
135
+ step=8,
136
+ label='top')
137
+ with gr.Row():
138
+ bottom = gr.Slider(128,
139
+ 256,
140
+ value=200,
141
+ step=8,
142
+ label='bottom')
143
+ with gr.Row():
144
+ left = gr.Slider(128,
145
+ 256,
146
+ value=200,
147
+ step=8,
148
+ label='left')
149
+ with gr.Row():
150
+ right = gr.Slider(128,
151
+ 256,
152
+ value=200,
153
+ step=8,
154
+ label='right')
155
+ with gr.Box():
156
+ with gr.Column():
157
+ gr.Markdown('''Input''')
158
+ with gr.Row():
159
+ input_image = gr.Image(label='Input Image',
160
+ type='filepath')
161
+ with gr.Row():
162
+ preprocess_image_button = gr.Button('Rescale Image')
163
+ with gr.Row():
164
+ input_video = gr.Video(label='Input Video',
165
+ mirror_webcam=False,
166
+ type='filepath')
167
+ with gr.Row():
168
+ preprocess_video0_button = gr.Button('Rescale First Frame')
169
+ preprocess_video1_button = gr.Button('Rescale Video')
170
+
171
+ with gr.Box():
172
+ with gr.Column():
173
+ gr.Markdown('''View''')
174
+ with gr.Row():
175
+ input_info = gr.Textbox(label='Process Information', interactive=False, value='n.a.')
176
+ with gr.Row():
177
+ aligned_face = gr.Image(label='Rescaled Face',
178
+ type='numpy',
179
+ interactive=False)
180
+ instyle = gr.Variable()
181
+ with gr.Row():
182
+ aligned_video = gr.Video(label='Rescaled Video',
183
+ type='mp4',
184
+ interactive=False)
185
+ with gr.Row():
186
+ with gr.Column():
187
+ paths = ['./vtoonify/data/pexels-andrea-piacquadio-733872.jpg','./vtoonify/data/i5R8hbZFDdc.jpg','./vtoonify/data/yRpe13BHdKw.jpg','./vtoonify/data/ILip77SbmOE.jpg','./vtoonify/data/077436.jpg','./vtoonify/data/081680.jpg']
188
+ example_images = gr.Dataset(components=[input_image],
189
+ samples=[[path] for path in paths],
190
+ label='Image Examples')
191
+ with gr.Column():
192
+ #example_videos = gr.Dataset(components=[input_video], samples=[['./vtoonify/data/529.mp4']], type='values')
193
+ #to render video example on mouse hover/click
194
+ example_videos.render()
195
+ #to load sample video into input_video upon clicking on it
196
+ def load_examples(video):
197
+ #print("****** inside load_example() ******")
198
+ #print("in_video is : ", video[0])
199
+ return video[0]
200
+
201
+ example_videos.click(load_examples, example_videos, input_video)
202
+
203
+ with gr.Box():
204
+ gr.Markdown('''## Step 3 (Generate Style Transferred Image/Video)''')
205
+ with gr.Row():
206
+ with gr.Column():
207
+ gr.Markdown('''
208
+ - Adjust **Style Degree**.
209
+ - Hit **Toonify!** to toonify one frame. Hit **VToonify!** to toonify full video.
210
+ - Estimated time on 1600x1440 video of 300 frames: 1 hour (CPU); 2 mins (GPU)
211
+ ''')
212
+ style_degree = gr.Slider(0,
213
+ 1,
214
+ value=0.5,
215
+ step=0.05,
216
+ label='Style Degree')
217
+ with gr.Column():
218
+ gr.Markdown('''![example](https://raw.githubusercontent.com/williamyang1991/tmpfile/master/vtoonify/degree.jpg)
219
+ ''')
220
+ with gr.Row():
221
+ output_info = gr.Textbox(label='Process Information', interactive=False, value='n.a.')
222
+ with gr.Row():
223
+ with gr.Column():
224
+ with gr.Row():
225
+ result_face = gr.Image(label='Result Image',
226
+ type='numpy',
227
+ interactive=False)
228
+ with gr.Row():
229
+ toonify_button = gr.Button('Toonify!')
230
+ with gr.Column():
231
+ with gr.Row():
232
+ result_video = gr.Video(label='Result Video',
233
+ type='mp4',
234
+ interactive=False)
235
+ with gr.Row():
236
+ vtoonify_button = gr.Button('VToonify!')
237
+
238
+ gr.Markdown(ARTICLE)
239
+ gr.Markdown(FOOTER)
240
+
241
+ loadmodel_button.click(fn=model.load_model,
242
+ inputs=[style_type],
243
+ outputs=[exstyle, load_info])
244
+
245
+
246
+ style_type.change(fn=update_slider,
247
+ inputs=style_type,
248
+ outputs=style_degree)
249
+
250
+ preprocess_image_button.click(fn=model.detect_and_align_image,
251
+ inputs=[input_image, top, bottom, left, right],
252
+ outputs=[aligned_face, instyle, input_info])
253
+ preprocess_video0_button.click(fn=model.detect_and_align_video,
254
+ inputs=[input_video, top, bottom, left, right],
255
+ outputs=[aligned_face, instyle, input_info])
256
+ preprocess_video1_button.click(fn=model.detect_and_align_full_video,
257
+ inputs=[input_video, top, bottom, left, right],
258
+ outputs=[aligned_video, instyle, input_info])
259
+
260
+ toonify_button.click(fn=model.image_toonify,
261
+ inputs=[aligned_face, instyle, exstyle, style_degree, style_type],
262
+ outputs=[result_face, output_info])
263
+ vtoonify_button.click(fn=model.video_tooniy,
264
+ inputs=[aligned_video, instyle, exstyle, style_degree, style_type],
265
+ outputs=[result_video, output_info])
266
+
267
+
268
+ example_images.click(fn=set_example_image,
269
+ inputs=example_images,
270
+ outputs=example_images.components)
271
+
272
+ demo.launch(
273
+ enable_queue=args.enable_queue,
274
+ server_port=args.port,
275
+ share=args.share,
276
+ )
277
+
278
+
279
+ if __name__ == '__main__':
280
+ main()