Spaces:
Running
Running
update
Browse files- README.md +16 -16
- app.py +78 -99
- requirements.txt +3 -4
README.md
CHANGED
@@ -1,30 +1,30 @@
|
|
1 |
---
|
2 |
-
title:
|
3 |
-
emoji:
|
4 |
-
colorFrom:
|
5 |
colorTo: purple
|
6 |
sdk: gradio
|
7 |
sdk_version: 4.0.2
|
8 |
app_file: app.py
|
9 |
pinned: false
|
10 |
---
|
11 |
-
# Ứng dụng tạo video từ hình ảnh
|
12 |
|
13 |
-
Ứng dụng
|
14 |
|
15 |
-
|
16 |
|
17 |
-
|
18 |
-
|
|
|
19 |
3. Điều chỉnh các tham số (tùy chọn)
|
20 |
4. Nhấn "Tạo video"
|
21 |
-
5. Đợi quá trình xử lý hoàn tất và tải xuống video
|
22 |
-
|
23 |
-
## Mô hình được sử dụng
|
24 |
-
|
25 |
-
Ứng dụng này sử dụng mô hình AnimateDiff để tạo hoạt ảnh từ hình ảnh tĩnh.
|
26 |
|
27 |
-
##
|
|
|
|
|
|
|
28 |
|
29 |
-
|
30 |
-
-
|
|
|
|
|
|
1 |
---
|
2 |
+
title: Animate Person From Image
|
3 |
+
emoji: 🎭
|
4 |
+
colorFrom: pink
|
5 |
colorTo: purple
|
6 |
sdk: gradio
|
7 |
sdk_version: 4.0.2
|
8 |
app_file: app.py
|
9 |
pinned: false
|
10 |
---
|
|
|
11 |
|
12 |
+
# Ứng dụng tạo video người chuyển động từ ảnh
|
13 |
|
14 |
+
Ứng dụng này sử dụng AI để tạo video người chuyển động từ một ảnh tĩnh.
|
15 |
|
16 |
+
## Cách sử dụng
|
17 |
+
1. Tải lên ảnh chứa người
|
18 |
+
2. Nhập mô tả cho kiểu chuyển động mong muốn
|
19 |
3. Điều chỉnh các tham số (tùy chọn)
|
20 |
4. Nhấn "Tạo video"
|
|
|
|
|
|
|
|
|
|
|
21 |
|
22 |
+
## Các tham số
|
23 |
+
- **Mô tả chuyển động**: Mô tả bằng lời cách người sẽ chuyển động
|
24 |
+
- **Mức độ chuyển động**: Điều chỉnh cường độ chuyển động (1-255)
|
25 |
+
- **FPS**: Số khung hình mỗi giây của video kết quả
|
26 |
|
27 |
+
## Mẹo sử dụng
|
28 |
+
- Ảnh nên có nền đơn giản để có kết quả tốt nhất
|
29 |
+
- Người trong ảnh nên ở tư thế tự nhiên, không quá phức tạp
|
30 |
+
- Thử nghiệm với các mô tả khác nhau để có hiệu quả tốt nhất
|
app.py
CHANGED
@@ -1,130 +1,109 @@
|
|
1 |
import gradio as gr
|
2 |
-
import torch
|
3 |
import os
|
4 |
-
|
5 |
import numpy as np
|
6 |
-
import
|
7 |
-
import
|
|
|
8 |
|
9 |
-
#
|
10 |
-
|
11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
|
13 |
-
# Hàm tạo video
|
14 |
-
def
|
15 |
if image is None:
|
16 |
-
return None, "Vui lòng tải lên một hình ảnh"
|
17 |
-
|
18 |
-
# Đảm bảo hình ảnh là định dạng RGB
|
19 |
-
if image.mode != "RGB":
|
20 |
-
image = image.convert("RGB")
|
21 |
-
|
22 |
-
# Thay đổi kích thước hình ảnh về 512x512
|
23 |
-
image = image.resize((512, 512))
|
24 |
|
25 |
try:
|
26 |
-
#
|
27 |
-
|
28 |
-
|
29 |
-
if effect_type == "zoom-in":
|
30 |
-
# Hiệu ứng zoom-in
|
31 |
-
for i in range(num_frames):
|
32 |
-
zoom_factor = 1.0 + (i / num_frames) * (effect_strength / 10)
|
33 |
-
img_copy = image.copy()
|
34 |
-
|
35 |
-
size = int(img_copy.width / zoom_factor)
|
36 |
-
left = (img_copy.width - size) // 2
|
37 |
-
top = (img_copy.height - size) // 2
|
38 |
-
right = left + size
|
39 |
-
bottom = top + size
|
40 |
-
|
41 |
-
cropped = img_copy.crop((left, top, right, bottom))
|
42 |
-
frame = cropped.resize((512, 512))
|
43 |
-
frames.append(np.array(frame))
|
44 |
-
|
45 |
-
elif effect_type == "pan-right":
|
46 |
-
# Hiệu ứng pan từ trái sang phải
|
47 |
-
width, height = image.size
|
48 |
-
for i in range(num_frames):
|
49 |
-
offset = int((i / num_frames) * width * (effect_strength / 10))
|
50 |
-
img_copy = image.copy()
|
51 |
-
|
52 |
-
# Tạo hiệu ứng pan
|
53 |
-
if offset > 0:
|
54 |
-
# Lấy phần hình ảnh từ offset đến cuối
|
55 |
-
right_part = img_copy.crop((offset, 0, width, height))
|
56 |
-
# Lấy phần còn lại từ đầu
|
57 |
-
left_part = img_copy.crop((0, 0, offset, height))
|
58 |
-
# Tạo hình ảnh mới
|
59 |
-
new_img = Image.new('RGB', (width, height))
|
60 |
-
new_img.paste(right_part, (0, 0))
|
61 |
-
new_img.paste(left_part, (width - offset, 0))
|
62 |
-
frames.append(np.array(new_img))
|
63 |
-
else:
|
64 |
-
frames.append(np.array(img_copy))
|
65 |
-
|
66 |
-
elif effect_type == "fade":
|
67 |
-
# Hiệu ứng fade in/out
|
68 |
-
base_frame = np.array(image)
|
69 |
-
for i in range(num_frames):
|
70 |
-
# Tính toán độ mờ
|
71 |
-
if i < num_frames / 2:
|
72 |
-
# Fade in
|
73 |
-
alpha = i / (num_frames / 2)
|
74 |
-
else:
|
75 |
-
# Fade out
|
76 |
-
alpha = 2.0 - (i / (num_frames / 2))
|
77 |
-
|
78 |
-
# Áp dụng độ mờ
|
79 |
-
frame = (base_frame * alpha * (effect_strength / 5)).astype(np.uint8)
|
80 |
-
frames.append(frame)
|
81 |
|
|
|
|
|
|
|
|
|
82 |
else:
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
frame = (np.array(image) * brightness).clip(0, 255).astype(np.uint8)
|
87 |
-
frames.append(frame)
|
88 |
|
89 |
-
# Tạo
|
90 |
-
|
91 |
-
imageio.mimsave(output_path, frames, fps=8)
|
92 |
|
93 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
94 |
except Exception as e:
|
95 |
return None, f"Lỗi: {str(e)}"
|
96 |
|
97 |
# Tạo giao diện Gradio
|
98 |
-
with gr.Blocks(title="
|
99 |
-
gr.Markdown("# Tạo video từ
|
100 |
-
gr.Markdown("Tải lên
|
101 |
|
102 |
with gr.Row():
|
103 |
with gr.Column():
|
104 |
-
image_input = gr.Image(type="pil", label="Tải lên
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
value="
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
109 |
)
|
110 |
-
num_frames = gr.Slider(minimum=10, maximum=30, value=16, step=2, label="Số khung hình")
|
111 |
-
effect_strength = gr.Slider(minimum=1.0, maximum=10.0, value=5.0, step=0.5, label="Độ mạnh của hiệu ứng")
|
112 |
submit_btn = gr.Button("Tạo video")
|
113 |
-
|
114 |
with gr.Column():
|
115 |
output_video = gr.Video(label="Video kết quả")
|
116 |
output_message = gr.Textbox(label="Thông báo")
|
117 |
|
118 |
submit_btn.click(
|
119 |
-
fn=
|
120 |
-
inputs=[image_input,
|
121 |
outputs=[output_video, output_message]
|
122 |
)
|
123 |
|
124 |
-
gr.Markdown("###
|
125 |
-
gr.Markdown("-
|
126 |
-
gr.Markdown("-
|
127 |
-
gr.Markdown("-
|
128 |
-
gr.Markdown("- **Pulse**: Hiệu ứng thay đổi độ sáng theo nhịp")
|
129 |
|
130 |
demo.launch()
|
|
|
1 |
import gradio as gr
|
|
|
2 |
import os
|
3 |
+
import torch
|
4 |
import numpy as np
|
5 |
+
from PIL import Image
|
6 |
+
from diffusers import DiffusionPipeline, DDIMScheduler
|
7 |
+
from diffusers.utils import export_to_video
|
8 |
|
9 |
+
# Khởi tạo mô hình
|
10 |
+
def load_model():
|
11 |
+
pipe = DiffusionPipeline.from_pretrained(
|
12 |
+
"guoyww/animatediff-motion-adapter-v1-5",
|
13 |
+
torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32
|
14 |
+
)
|
15 |
+
pipe.scheduler = DDIMScheduler.from_config(pipe.scheduler.config)
|
16 |
+
pipe = pipe.to("cuda" if torch.cuda.is_available() else "cpu")
|
17 |
+
return pipe
|
18 |
|
19 |
+
# Hàm xử lý chính để tạo video từ ảnh
|
20 |
+
def animate_person(image, prompt, motion_bucket_id=127, fps=8):
|
21 |
if image is None:
|
22 |
+
return None, "Vui lòng tải lên một hình ảnh."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
|
24 |
try:
|
25 |
+
# Xử lý và chuẩn bị hình ảnh
|
26 |
+
if image.mode != "RGB":
|
27 |
+
image = image.convert("RGB")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
|
29 |
+
# Resize hình ảnh để phù hợp với mô hình
|
30 |
+
w, h = image.size
|
31 |
+
if w > h:
|
32 |
+
new_w, new_h = 512, int(h * 512 / w)
|
33 |
else:
|
34 |
+
new_w, new_h = int(w * 512 / h), 512
|
35 |
+
|
36 |
+
image = image.resize((new_w, new_h))
|
|
|
|
|
37 |
|
38 |
+
# Tạo mặt nạ để tập trung vào chủ thể (người)
|
39 |
+
# Mặt nạ đơn giản - trong thực tế có thể cần mô hình phân đoạn người phức tạp hơn
|
|
|
40 |
|
41 |
+
# Tải mô hình
|
42 |
+
pipe = load_model()
|
43 |
+
|
44 |
+
# Tạo video
|
45 |
+
if not prompt:
|
46 |
+
prompt = "A person moving naturally, photorealistic, high quality"
|
47 |
+
|
48 |
+
# Thêm hướng dẫn về chuyển động người để có kết quả tốt hơn
|
49 |
+
full_prompt = f"{prompt}, person in motion, smooth movement, natural pose, high quality, detailed"
|
50 |
+
|
51 |
+
# Sinh video
|
52 |
+
output = pipe(
|
53 |
+
prompt=full_prompt,
|
54 |
+
image=image,
|
55 |
+
negative_prompt="blurry, low quality, distorted, disfigured, bad anatomy",
|
56 |
+
num_frames=24,
|
57 |
+
guidance_scale=7.5,
|
58 |
+
num_inference_steps=50,
|
59 |
+
motion_bucket_id=motion_bucket_id
|
60 |
+
)
|
61 |
+
|
62 |
+
# Xuất video
|
63 |
+
video_path = "animated_person.mp4"
|
64 |
+
frames = output.frames[0]
|
65 |
+
export_to_video(frames, video_path, fps=fps)
|
66 |
+
|
67 |
+
return video_path, "Video được tạo thành công!"
|
68 |
except Exception as e:
|
69 |
return None, f"Lỗi: {str(e)}"
|
70 |
|
71 |
# Tạo giao diện Gradio
|
72 |
+
with gr.Blocks(title="Tạo video người chuyển động từ ảnh") as demo:
|
73 |
+
gr.Markdown("# Tạo video người chuyển động từ ảnh")
|
74 |
+
gr.Markdown("Tải lên ảnh người và xem họ chuyển động tự nhiên trong video")
|
75 |
|
76 |
with gr.Row():
|
77 |
with gr.Column():
|
78 |
+
image_input = gr.Image(type="pil", label="Tải lên ảnh người")
|
79 |
+
prompt_input = gr.Textbox(
|
80 |
+
label="Mô tả chuyển động",
|
81 |
+
placeholder="Mô tả cách người trong ảnh sẽ chuyển động...",
|
82 |
+
value="Person walking naturally, photorealistic"
|
83 |
+
)
|
84 |
+
motion_input = gr.Slider(
|
85 |
+
minimum=1, maximum=255, value=127, step=1,
|
86 |
+
label="Mức độ chuyển động (1-255)"
|
87 |
+
)
|
88 |
+
fps_input = gr.Slider(
|
89 |
+
minimum=6, maximum=30, value=8, step=1,
|
90 |
+
label="Số khung hình mỗi giây (FPS)"
|
91 |
)
|
|
|
|
|
92 |
submit_btn = gr.Button("Tạo video")
|
93 |
+
|
94 |
with gr.Column():
|
95 |
output_video = gr.Video(label="Video kết quả")
|
96 |
output_message = gr.Textbox(label="Thông báo")
|
97 |
|
98 |
submit_btn.click(
|
99 |
+
fn=animate_person,
|
100 |
+
inputs=[image_input, prompt_input, motion_input, fps_input],
|
101 |
outputs=[output_video, output_message]
|
102 |
)
|
103 |
|
104 |
+
gr.Markdown("### Lưu ý")
|
105 |
+
gr.Markdown("- Quá trình tạo video có thể mất vài phút")
|
106 |
+
gr.Markdown("- Kết quả tốt nhất với ảnh người rõ nét, chụp thẳng")
|
107 |
+
gr.Markdown("- Sử dụng prompt cụ thể để điều khiển kiểu chuyển động")
|
|
|
108 |
|
109 |
demo.launch()
|
requirements.txt
CHANGED
@@ -1,7 +1,6 @@
|
|
1 |
gradio==4.0.2
|
2 |
torch
|
3 |
torchvision
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
imageio-ffmpeg
|
|
|
1 |
gradio==4.0.2
|
2 |
torch
|
3 |
torchvision
|
4 |
+
diffusers>=0.24.0
|
5 |
+
transformers>=4.31.0
|
6 |
+
accelerate
|
|