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

udpate lib

Browse files
Files changed (2) hide show
  1. app.py +126 -109
  2. requirements.txt +4 -7
app.py CHANGED
@@ -3,106 +3,131 @@ import torch
3
  import numpy as np
4
  import imageio
5
  import os
6
- import gdown
7
  import cv2
8
- from skimage.transform import resize
9
- from skimage import img_as_ubyte
10
- from first_order_model.demo import load_checkpoints, make_animation
11
 
12
- # Tải cài đặt hình
13
- def download_model():
14
- model_path = 'first_order_model/vox-cpk.pth.tar'
15
- if not os.path.exists(model_path):
16
- os.makedirs('first_order_model', exist_ok=True)
17
- url = 'https://drive.google.com/uc?id=1PyQJmkdCsAkOYwUyaj_l-l0as-iLDgeH'
18
- gdown.download(url, model_path, quiet=False)
19
 
20
- if not os.path.exists('first_order_model/config/vox-256.yaml'):
21
- os.makedirs('first_order_model/config', exist_ok=True)
22
- config_url = 'https://drive.google.com/uc?id=1PmYZrk1MLyfYFa5vgRy0HVfkWTR42NMj'
23
- gdown.download(config_url, 'first_order_model/config/vox-256.yaml', quiet=False)
 
 
 
 
 
 
 
 
 
24
 
25
  # Tạo video người chuyển động
26
- def animate_person(source_image, driving_video=None, movement_type="Mặc định"):
27
- if source_image is None:
28
- return None, "Vui lòng tải lên một hình ảnh người."
29
 
30
  try:
31
- # Tải hình
32
- download_model()
 
33
 
34
- # Chuẩn bị hình ảnh nguồn
35
- source_image_path = "source_image.jpg"
36
- cv2.imwrite(source_image_path, cv2.cvtColor(np.array(source_image), cv2.COLOR_RGB2BGR))
37
 
38
- # Chuẩn bị video tham chiếu
39
- if driving_video is None or movement_type != "Tùy chỉnh":
40
- # Sử dụng video mẫu dựa trên loại chuyển động
41
- driving_videos = {
42
- "Mặc định": "driving_videos/default.mp4",
43
- "Nói chuyện": "driving_videos/talking.mp4",
44
- "Quay đầu": "driving_videos/head_turning.mp4",
45
- "Cười": "driving_videos/smiling.mp4"
46
- }
47
-
48
- # Tạo thư mục cho video mẫu
49
- os.makedirs("driving_videos", exist_ok=True)
50
-
51
- # Tạo video mẫu đơn giản nếu chưa có
52
- if not os.path.exists(driving_videos[movement_type]):
53
- # Tạo một video mẫu đơn giản với OpenCV
54
- # Trong thực tế, bạn sẽ tải video mẫu từ nguồn khác
55
- video_path = driving_videos[movement_type]
56
- out = cv2.VideoWriter(video_path, cv2.VideoWriter_fourcc(*'mp4v'), 25, (256, 256))
57
-
58
- # Tạo 100 khung hình với chuyển động đơn giản
59
- for i in range(100):
60
- frame = np.zeros((256, 256, 3), dtype=np.uint8)
61
- if movement_type == "Nói chuyện":
62
- cv2.ellipse(frame, (128, 180), (30 + i % 10, 20), 0, 0, 360, (255, 255, 255), -1)
63
- elif movement_type == "Quay đầu":
64
- cv2.ellipse(frame, (128 + int(np.sin(i/10) * 30), 128), (60, 80), 0, 0, 360, (255, 255, 255), -1)
65
- elif movement_type == "Cười":
66
- cv2.ellipse(frame, (128, 128), (60, 80), 0, 0, 360, (255, 255, 255), -1)
67
- cv2.ellipse(frame, (128, 160 - i % 15), (40, 20), 0, 0, 180, (0, 0, 0), -1)
68
- else: # Mặc định
69
- cv2.ellipse(frame, (128, 128), (60, 80), 0, 0, 360, (255, 255, 255), -1)
70
- cv2.circle(frame, (110, 110), 10, (0, 0, 0), -1)
71
- cv2.circle(frame, (146, 110), 10, (0, 0, 0), -1)
72
-
73
- out.write(frame)
74
-
75
- out.release()
76
-
77
- driving_video_path = driving_videos[movement_type]
78
- else:
79
- # Sử dụng video do người dùng tải lên
80
- driving_video_path = "driving_video.mp4"
81
- # Lưu video tải lên
82
- with open(driving_video_path, 'wb') as f:
83
- f.write(driving_video)
84
 
85
- # Tải hình và cấu hình
86
- generator, kp_detector = load_checkpoints(
87
- config_path='first_order_model/config/vox-256.yaml',
88
- checkpoint_path='first_order_model/vox-cpk.pth.tar',
89
- device=torch.device('cuda' if torch.cuda.is_available() else 'cpu')
90
- )
91
 
92
- # Tạo animation
93
- predictions = make_animation(
94
- source_image=source_image_path,
95
- driving_video=driving_video_path,
96
- generator=generator,
97
- kp_detector=kp_detector,
98
- relative=True,
99
- adapt_movement_scale=True,
100
- device=torch.device('cuda' if torch.cuda.is_available() else 'cpu')
101
- )
102
 
103
- # Lưu video kết quả
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  output_path = "animated_person.mp4"
105
- imageio.mimsave(output_path, [img_as_ubyte(frame) for frame in predictions], fps=25)
106
 
107
  return output_path, "Video được tạo thành c��ng!"
108
 
@@ -112,23 +137,20 @@ def animate_person(source_image, driving_video=None, movement_type="Mặc địn
112
  # Tạo giao diện Gradio
113
  with gr.Blocks(title="Ứng dụng tạo chuyển động cho người trong ảnh") as demo:
114
  gr.Markdown("# Tạo video người chuyển động từ ảnh")
115
- gr.Markdown("Tạo video trong đó người/khuôn mặt trong ảnh của bạn chuyển động tự nhiên")
116
 
117
  with gr.Row():
118
  with gr.Column():
119
- source_image = gr.Image(type="numpy", label="Tải lên ảnh người")
120
-
121
- with gr.Row():
122
- movement_choice = gr.Radio(
123
- ["Mặc định", "Nói chuyện", "Quay đầu", "Cười", "Tùy chỉnh"],
124
- label="Chọn kiểu chuyển động",
125
- value="Mặc định"
126
- )
127
-
128
- driving_video = gr.Video(
129
- label="Tải lên video tham chiếu (chỉ khi chọn 'Tùy chỉnh')"
130
  )
131
-
132
  submit_btn = gr.Button("Tạo video")
133
 
134
  with gr.Column():
@@ -137,18 +159,13 @@ with gr.Blocks(title="Ứng dụng tạo chuyển động cho người trong ả
137
 
138
  submit_btn.click(
139
  fn=animate_person,
140
- inputs=[source_image, driving_video, movement_choice],
141
  outputs=[output_video, output_message]
142
  )
143
 
144
- gr.Markdown("### Cách thức hoạt động")
145
- gr.Markdown("1. Ứng dụng sử dụng mô hình First Order Motion Model để phân tích chuyển động")
146
- gr.Markdown("2. Mô hình áp dụng chuyển động từ video tham chiếu vào đối tượng trong ảnh của bạn")
147
- gr.Markdown("3. Kết quả là một video với người/đối tượng trong ảnh của bạn chuyển động tự nhiên")
148
-
149
  gr.Markdown("### Lưu ý")
150
- gr.Markdown("- Kết quả tốt nhất với ảnh chụp chính diện, nền đơn giản")
151
- gr.Markdown("- Khuôn mặt/người cần ràngkhông bị che khuất")
152
- gr.Markdown("- Nếu bạn chọn 'Tùy chỉnh', hãy tải lên video chuyển động bạn muốn áp dụng")
153
 
154
  demo.launch()
 
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ử lý 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 là đị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
 
 
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():
 
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 ảnh người trên nền đơn giản để có 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()
requirements.txt CHANGED
@@ -1,10 +1,7 @@
1
  gradio==4.0.2
2
- torch==1.7.1
3
- torchvision==0.8.2
4
  numpy
5
- imageio==2.9.0
 
6
  imageio-ffmpeg
7
- scikit-image
8
- opencv-python
9
- gdown
10
- pyyaml
 
1
  gradio==4.0.2
2
+ torch
 
3
  numpy
4
+ Pillow
5
+ imageio==2.31.1
6
  imageio-ffmpeg
7
+ opencv-python