alvinichi commited on
Commit
1a447e6
·
1 Parent(s): 7a842d4

update lib

Browse files
Files changed (3) hide show
  1. README.md +15 -18
  2. app.py +136 -136
  3. requirements.txt +8 -5
README.md CHANGED
@@ -1,30 +1,27 @@
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 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**: 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 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
 
1
  ---
2
+ title: First Order Motion Model Animation
3
+ emoji: 🎬
4
+ colorFrom: blue
5
+ colorTo: indigo
6
  sdk: gradio
7
  sdk_version: 4.0.2
8
  app_file: app.py
9
  pinned: false
10
  ---
11
 
12
+ # First Order Motion Model
13
 
14
+ Ứng dụng này sử dụng First Order Motion Model để 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 nguồn chứa người/đối tượng bạn muốn làm chuyển động
18
+ 2. Tải lên video tham chiếu chuyển động bạn muốn áp dụng
19
+ 3. Điều chỉnh các tùy chọn (tùy chọn)
20
+ 4. Nhấn "Tạo video" và chờ kết quả
21
 
22
+ ## hình được sử dụng
23
+ First Order Motion Model (FOMM) là một mô hình deep learning cho phép tạo chuyển động cho một đối tượng trong ảnh tĩnh dựa trên chuyển động từ video tham chiếu.
 
 
24
 
25
+ ## Paper & Code
26
+ - Paper: [First Order Motion Model for Image Animation](https://arxiv.org/abs/2003.00196)
27
+ - Code gốc: [AliaksandrSiarohin/first-order-model](https://github.com/AliaksandrSiarohin/first-order-model)
 
app.py CHANGED
@@ -1,156 +1,151 @@
1
  import gradio as gr
2
- import torch
3
  import numpy as np
 
4
  import imageio
5
- import os
6
- from PIL import Image
7
- import cv2
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
- # Hàm tách đối tượng khỏi nền
10
- def segment_person(image):
11
- # Trong thực tế, bạn sẽ sử dụng một mô hình phân đoạn như U2Net
12
- # Đây là một phiên bản đơn giản sử dụng phân ngưỡng màu
 
 
 
 
 
13
 
14
- # Chuyển sang không gian màu HSV
15
- image_cv = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2HSV)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
- # Tạo mặt nạ đơn giản (trong thực tế cần mô hình phân đoạn thật)
18
- # Giả sử nền sáng hơn đối tượng
19
- _, mask = cv2.threshold(image_cv[:, :, 2], 127, 255, cv2.THRESH_BINARY_INV)
20
 
21
- # Xử mặt nạ
22
- kernel = np.ones((5, 5), np.uint8)
23
- mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
24
- mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
25
 
26
- return mask
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
- # Tạo video người chuyển động
29
- def animate_person(image, movement_type, num_frames=24):
30
- if image is None:
31
- return None, "Vui lòng tải lên một hình ảnh."
32
 
33
  try:
34
- # Đảm bảo hình ảnh định dạng RGB
35
- if image.mode != "RGB":
36
- image = image.convert("RGB")
37
-
38
- # Thay đổi kích thước hình ảnh
39
- image = image.resize((512, 512))
40
- image_array = np.array(image)
41
 
42
- # Tách người từ nền
43
- mask = segment_person(image)
44
 
45
- # Tạo ảnh nền và ảnh người
46
- background = image_array.copy()
47
- person = image_array.copy()
48
 
49
- # Áp dụng mặt nạ
50
- person_mask = np.stack([mask, mask, mask], axis=2) / 255.0
51
- person = person * person_mask
52
- background = background * (1 - person_mask)
53
-
54
- # Tạo frames dựa vào loại chuyển động
55
- frames = []
56
-
57
- if movement_type == "Đi bộ":
58
- # Mô phỏng đi bộ - di chuyển lên xuống và sang ngang
59
- for i in range(num_frames):
60
- y_offset = int(np.sin(i/8 * 2 * np.pi) * 10)
61
- x_offset = i % 4 - 2 # Nhịp bước nhỏ
62
-
63
- # Tạo frame mới với nền tĩnh
64
- frame = background.copy()
65
-
66
- # Thêm người với offset
67
- M = np.float32([[1, 0, x_offset], [0, 1, y_offset]])
68
- moved_person = cv2.warpAffine(person, M, (512, 512))
69
-
70
- # Kết hợp nền và người
71
- frame = frame + moved_person
72
- frames.append(frame.astype(np.uint8))
73
-
74
- elif movement_type == "Vẫy tay":
75
- # Mô phỏng vẫy tay - xoay nhẹ phần trên
76
- for i in range(num_frames):
77
- angle = np.sin(i/6 * 2 * np.pi) * 5 # Xoay ±5 độ
78
-
79
- # Tạo ma trận xoay
80
- center = (256, 200) # Giả sử tâm xoay ở phần trên của người
81
- M = cv2.getRotationMatrix2D(center, angle, 1.0)
82
-
83
- # Xoay người
84
- rotated_person = cv2.warpAffine(person, M, (512, 512))
85
-
86
- # Kết hợp nền và người đã xoay
87
- frame = background.copy() + rotated_person
88
- frames.append(frame.astype(np.uint8))
89
-
90
- elif movement_type == "Nhảy múa":
91
- # Mô phỏng nhảy múa - kết hợp chuyển động
92
- for i in range(num_frames):
93
- y_offset = int(np.sin(i/6 * 2 * np.pi) * 15)
94
- x_offset = int(np.sin(i/4 * 2 * np.pi) * 10)
95
- angle = np.sin(i/8 * 2 * np.pi) * 3
96
-
97
- # Xoay người
98
- center = (256, 256)
99
- M_rot = cv2.getRotationMatrix2D(center, angle, 1.0)
100
- rotated_person = cv2.warpAffine(person, M_rot, (512, 512))
101
-
102
- # Di chuyển người đã xoay
103
- M_trans = np.float32([[1, 0, x_offset], [0, 1, y_offset]])
104
- moved_person = cv2.warpAffine(rotated_person, M_trans, (512, 512))
105
-
106
- # Kết hợp nền và người đã di chuyển
107
- frame = background.copy() + moved_person
108
- frames.append(frame.astype(np.uint8))
109
-
110
- else: # Chuyển động nhẹ
111
- for i in range(num_frames):
112
- angle = np.sin(i/12 * 2 * np.pi) * 2
113
- y_offset = int(np.sin(i/10 * 2 * np.pi) * 5)
114
-
115
- # Xoay người
116
- center = (256, 256)
117
- M_rot = cv2.getRotationMatrix2D(center, angle, 1.0)
118
- rotated_person = cv2.warpAffine(person, M_rot, (512, 512))
119
-
120
- # Di chuyển người đã xoay
121
- M_trans = np.float32([[1, 0, 0], [0, 1, y_offset]])
122
- moved_person = cv2.warpAffine(rotated_person, M_trans, (512, 512))
123
-
124
- # Kết hợp nền và người đã di chuyển
125
- frame = background.copy() + moved_person
126
- frames.append(frame.astype(np.uint8))
127
-
128
- # Lưu video
129
- output_path = "animated_person.mp4"
130
- imageio.mimsave(output_path, frames, fps=8)
131
-
132
- return output_path, "Video được tạo thành công!"
133
 
 
134
  except Exception as e:
135
  return None, f"Lỗi: {str(e)}"
136
 
137
  # Tạo giao diện Gradio
138
- with gr.Blocks(title="Ứng dụng tạo chuyển động cho người trong ảnh") as demo:
139
- gr.Markdown("# Tạo video người chuyển động từ ảnh")
140
- gr.Markdown("Tạo video trong đó chỉ người trong ảnh chuyển động, nền vẫn giữ nguyên")
141
 
142
  with gr.Row():
143
  with gr.Column():
144
- image_input = gr.Image(type="pil", label="Tải lên ảnh người")
145
- movement_type = gr.Radio(
146
- ["Đi bộ", "Vẫy tay", "Nhảy múa", "Chuyển động nhẹ"],
147
- label="Loại chuyển động",
148
- value="Chuyển động nhẹ"
149
- )
150
- num_frames = gr.Slider(
151
- minimum=12, maximum=36, value=24, step=4,
152
- label="Số khung hình"
153
- )
154
  submit_btn = gr.Button("Tạo video")
155
 
156
  with gr.Column():
@@ -158,14 +153,19 @@ with gr.Blocks(title="Ứng dụng tạo chuyển động cho người trong ả
158
  output_message = gr.Textbox(label="Thông báo")
159
 
160
  submit_btn.click(
161
- fn=animate_person,
162
- inputs=[image_input, movement_type, num_frames],
163
  outputs=[output_video, output_message]
164
  )
165
 
 
 
 
 
 
166
  gr.Markdown("### Lưu ý")
167
- gr.Markdown("- Sử dụng ảnhngười trên nền đơn giản để kết quả tốt nhất")
168
- gr.Markdown("- Phương pháp này tách ngườinền, chỉ làm chuyển động người")
169
- gr.Markdown("- Đây phiên bản đơn giản, kết quả thực tế sẽ phụ thuộc vào chất lượng hình ảnh")
170
 
171
  demo.launch()
 
1
  import gradio as gr
2
+ import os
3
  import numpy as np
4
+ import torch
5
  import imageio
6
+ import subprocess
7
+ from skimage.transform import resize
8
+ from skimage import img_as_ubyte
9
+
10
+ # Clone repo nếu chưa có
11
+ if not os.path.exists('first-order-model'):
12
+ subprocess.call(['git', 'clone', 'https://github.com/AliaksandrSiarohin/first-order-model.git'])
13
+ os.rename('first-order-model', 'first_order_model')
14
+
15
+ # Thêm đường dẫn vào PYTHONPATH
16
+ import sys
17
+ sys.path.append('first_order_model')
18
+
19
+ # Import các module cần thiết từ repo
20
+ from first_order_model.demo import load_checkpoints
21
+ from first_order_model.animate import normalize_kp
22
 
23
+ # Tải hình pre-trained
24
+ def download_model():
25
+ model_path = 'checkpoints/vox-cpk.pth.tar'
26
+ if not os.path.exists(model_path):
27
+ os.makedirs('checkpoints', exist_ok=True)
28
+ subprocess.call([
29
+ 'wget', 'https://drive.google.com/uc?export=download&id=1PyQJmkdCsAkOYwUyaj_l-l0as-iLDgeH',
30
+ '-O', model_path
31
+ ])
32
 
33
+ config_path = 'first_order_model/config/vox-256.yaml'
34
+ if not os.path.exists(config_path):
35
+ os.makedirs('first_order_model/config', exist_ok=True)
36
+ subprocess.call([
37
+ 'wget', 'https://drive.google.com/uc?export=download&id=1pZUMNRjkBiuBEM68oj9nskuWgJR-5QMn',
38
+ '-O', config_path
39
+ ])
40
+
41
+ return config_path, model_path
42
+
43
+ # Hàm tạo animation
44
+ def make_animation(source_image, driving_video, relative=True, adapt_movement_scale=True):
45
+ config_path, checkpoint_path = download_model()
46
+
47
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
48
+
49
+ # Tải mô hình và cấu hình
50
+ generator, kp_detector = load_checkpoints(config_path, checkpoint_path, device=device)
51
+
52
+ # Đọc source_image và driving_video
53
+ source = imageio.imread(source_image)
54
+ reader = imageio.get_reader(driving_video)
55
+ fps = reader.get_meta_data()['fps']
56
+ driving = []
57
+ try:
58
+ for im in reader:
59
+ driving.append(im)
60
+ except RuntimeError:
61
+ pass
62
+ reader.close()
63
 
64
+ # Tiền xử
65
+ source = resize(source, (256, 256))[..., :3]
66
+ driving = [resize(frame, (256, 256))[..., :3] for frame in driving]
67
 
68
+ # Chuyển đổi thành tensor
69
+ source = torch.tensor(source[np.newaxis].astype(np.float32)).permute(0, 3, 1, 2).to(device)
70
+ driving = torch.tensor(np.array(driving).astype(np.float32)).permute(0, 3, 1, 2).to(device)
 
71
 
72
+ # Trích xuất keypoints
73
+ kp_source = kp_detector(source)
74
+ kp_driving_initial = kp_detector(driving[0:1])
75
+
76
+ # Tạo animation
77
+ with torch.no_grad():
78
+ predictions = []
79
+ for frame_idx in range(driving.shape[0]):
80
+ driving_frame = driving[frame_idx:frame_idx+1]
81
+ kp_driving = kp_detector(driving_frame)
82
+
83
+ # Chuẩn hóa keypoints
84
+ if relative:
85
+ kp_norm = normalize_kp(
86
+ kp_source=kp_source,
87
+ kp_driving=kp_driving,
88
+ kp_driving_initial=kp_driving_initial,
89
+ use_relative_movement=relative,
90
+ use_relative_jacobian=relative,
91
+ adapt_movement_scale=adapt_movement_scale
92
+ )
93
+ else:
94
+ kp_norm = kp_driving
95
+
96
+ # Tạo frame
97
+ out = generator(source, kp_source=kp_source, kp_driving=kp_norm)
98
+ predictions.append(np.transpose(out['prediction'].data.cpu().numpy(), [0, 2, 3, 1])[0])
99
+
100
+ # Lưu video kết quả
101
+ output_path = 'result.mp4'
102
+ imageio.mimsave(output_path, [img_as_ubyte(frame) for frame in predictions], fps=fps)
103
+
104
+ return output_path
105
 
106
+ # Định nghĩa giao diện Gradio
107
+ def animate_fomm(source_image, driving_video, relative=True, adapt_scale=True):
108
+ if source_image is None or driving_video is None:
109
+ return None, "Vui lòng tải lên cả ảnh nguồn và video tham chiếu."
110
 
111
  try:
112
+ # Lưu tạm ảnh video tải lên
113
+ source_path = "source_image.jpg"
114
+ driving_path = "driving_video.mp4"
 
 
 
 
115
 
116
+ # Lưu ảnh nguồn
117
+ source_image.save(source_path)
118
 
119
+ # Lưu video tham chiếu
120
+ with open(driving_path, 'wb') as f:
121
+ f.write(driving_video)
122
 
123
+ # Tạo animation
124
+ result_path = make_animation(
125
+ source_path,
126
+ driving_path,
127
+ relative=relative,
128
+ adapt_movement_scale=adapt_scale
129
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
 
131
+ return result_path, "Video được tạo thành công!"
132
  except Exception as e:
133
  return None, f"Lỗi: {str(e)}"
134
 
135
  # Tạo giao diện Gradio
136
+ with gr.Blocks(title="First Order Motion Model - Tạo video người chuyển động") as demo:
137
+ gr.Markdown("# First Order Motion Model")
138
+ gr.Markdown("Tạo video người chuyển động từ một ảnh tĩnh video tham chiếu")
139
 
140
  with gr.Row():
141
  with gr.Column():
142
+ source_image = gr.Image(type="pil", label="Tải lên ảnh nguồn")
143
+ driving_video = gr.Video(label="Tải lên video tham chiếu")
144
+
145
+ with gr.Row():
146
+ relative = gr.Checkbox(value=True, label="Chuyển động tương đối")
147
+ adapt_scale = gr.Checkbox(value=True, label="Điều chỉnh tỷ lệ chuyển động")
148
+
 
 
 
149
  submit_btn = gr.Button("Tạo video")
150
 
151
  with gr.Column():
 
153
  output_message = gr.Textbox(label="Thông báo")
154
 
155
  submit_btn.click(
156
+ fn=animate_fomm,
157
+ inputs=[source_image, driving_video, relative, adapt_scale],
158
  outputs=[output_video, output_message]
159
  )
160
 
161
+ gr.Markdown("### Cách sử dụng")
162
+ gr.Markdown("1. Tải lên **ảnh nguồn** - ảnh chứa người/đối tượng bạn muốn làm chuyển động")
163
+ gr.Markdown("2. Tải lên **video tham chiếu** - video có chuyển động bạn muốn áp dụng")
164
+ gr.Markdown("3. Nhấn **Tạo video** và chờ kết quả")
165
+
166
  gr.Markdown("### Lưu ý")
167
+ gr.Markdown("- Ảnh nguồn video tham chiếu nên đối tượng tương tự (người với người, mặt với mặt)")
168
+ gr.Markdown("- Đối tượng nên vị trí tương tự trong cả ảnh nguồn khung đầu tiên của video tham chiếu")
169
+ gr.Markdown("- Quá trình tạo video thể mất vài phút")
170
 
171
  demo.launch()
requirements.txt CHANGED
@@ -1,7 +1,10 @@
1
  gradio==4.0.2
2
- torch
 
3
  numpy
4
- Pillow
5
- imageio==2.31.1
6
- imageio-ffmpeg
7
- opencv-python
 
 
 
1
  gradio==4.0.2
2
+ torch==1.13.1
3
+ torchvision==0.14.1
4
  numpy
5
+ imageio==2.9.0
6
+ imageio-ffmpeg==0.4.5
7
+ scikit-image==0.19.3
8
+ matplotlib
9
+ PyYAML==5.3.1
10
+ face-alignment==1.3.5