Spaces:
Running
Running
Deepro Bardhan
commited on
Commit
·
2c0a9f6
1
Parent(s):
72e0b27
AddedSingleSrcMultiVideo
Browse files- .gitignore +1 -0
- app.py +127 -0
.gitignore
CHANGED
|
@@ -8,6 +8,7 @@ MultiSrcMultiDst/
|
|
| 8 |
SingleSrcMultiDst/
|
| 9 |
CustomSwap/
|
| 10 |
CustomVideoSwap/
|
|
|
|
| 11 |
__pycache__/*
|
| 12 |
.gradio/
|
| 13 |
|
|
|
|
| 8 |
SingleSrcMultiDst/
|
| 9 |
CustomSwap/
|
| 10 |
CustomVideoSwap/
|
| 11 |
+
SingleSrcMultiVideo/
|
| 12 |
__pycache__/*
|
| 13 |
.gradio/
|
| 14 |
|
app.py
CHANGED
|
@@ -693,6 +693,118 @@ def swap_video_custom_mapping(src_imgs, video, mapping_str, delete_frames_dir=Tr
|
|
| 693 |
log += f"Elapsed time: {elapsed:.2f} seconds\n"
|
| 694 |
return final_output_path, log
|
| 695 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 696 |
|
| 697 |
# Gradio UI
|
| 698 |
with gr.Blocks() as demo:
|
|
@@ -810,6 +922,21 @@ with gr.Blocks() as demo:
|
|
| 810 |
gr.Textbox(label="Log Output", lines=8, interactive=False)
|
| 811 |
],
|
| 812 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 813 |
|
| 814 |
|
| 815 |
if __name__ == "__main__":
|
|
|
|
| 693 |
log += f"Elapsed time: {elapsed:.2f} seconds\n"
|
| 694 |
return final_output_path, log
|
| 695 |
|
| 696 |
+
def swap_single_src_multi_video(src_img, dst_videos, dst_indices, delete_frames_dir=True, add_audio=True, progress=gr.Progress(track_tqdm=True)):
|
| 697 |
+
"""
|
| 698 |
+
Swaps a single source image onto multiple videos, with a mapping for destination face indices.
|
| 699 |
+
Each video is processed one by one.
|
| 700 |
+
"""
|
| 701 |
+
log = ""
|
| 702 |
+
results = []
|
| 703 |
+
start_time = time.time()
|
| 704 |
+
base_dir = "SingleSrcMultiVideo"
|
| 705 |
+
dst_dir = os.path.join(base_dir, "dst")
|
| 706 |
+
frames_dir = os.path.join(base_dir, "video_frames")
|
| 707 |
+
swapped_dir = os.path.join(base_dir, "swap_frames")
|
| 708 |
+
output_dir = os.path.join(base_dir, "output")
|
| 709 |
+
os.makedirs(dst_dir, exist_ok=True)
|
| 710 |
+
os.makedirs(frames_dir, exist_ok=True)
|
| 711 |
+
os.makedirs(swapped_dir, exist_ok=True)
|
| 712 |
+
os.makedirs(output_dir, exist_ok=True)
|
| 713 |
+
|
| 714 |
+
# Parse indices
|
| 715 |
+
if isinstance(dst_indices, str):
|
| 716 |
+
dst_indices_list = [int(idx.strip()) for idx in dst_indices.split(",") if idx.strip().isdigit()]
|
| 717 |
+
else:
|
| 718 |
+
dst_indices_list = [int(idx) for idx in dst_indices]
|
| 719 |
+
|
| 720 |
+
# Save source image
|
| 721 |
+
src_path = os.path.join(base_dir, "data_src.jpg")
|
| 722 |
+
src_img_bgr = cv2.cvtColor(src_img, cv2.COLOR_RGB2BGR)
|
| 723 |
+
cv2.imwrite(src_path, src_img_bgr)
|
| 724 |
+
log += f"Saved source image to {src_path}\n"
|
| 725 |
+
|
| 726 |
+
from VideoSwapping import extract_frames, frames_to_video
|
| 727 |
+
|
| 728 |
+
for i, video in enumerate(dst_videos):
|
| 729 |
+
dst_idx = dst_indices_list[i] if i < len(dst_indices_list) else 1
|
| 730 |
+
video_name = f"video_{i}.mp4"
|
| 731 |
+
dst_video_path = os.path.join(dst_dir, video_name)
|
| 732 |
+
output_video_path = os.path.join(output_dir, f"output_{i}.mp4")
|
| 733 |
+
output_video_with_audio = os.path.join(output_dir, f"output_with_audio_{i}.mp4")
|
| 734 |
+
|
| 735 |
+
# Copy video to dst_dir
|
| 736 |
+
if isinstance(video, str) and os.path.exists(video):
|
| 737 |
+
shutil.copy(video, dst_video_path)
|
| 738 |
+
log += f"Copied video {video} to {dst_video_path}\n"
|
| 739 |
+
else:
|
| 740 |
+
dst_video_path = video
|
| 741 |
+
|
| 742 |
+
# Extract frames
|
| 743 |
+
frame_paths = extract_frames(dst_video_path, frames_dir)
|
| 744 |
+
log += f"Extracted {len(frame_paths)} frames from {dst_video_path} to {frames_dir}\n"
|
| 745 |
+
progress(i / len(dst_videos), desc=f"Processing video {i+1}/{len(dst_videos)}")
|
| 746 |
+
|
| 747 |
+
swapped_files = set(os.listdir(swapped_dir))
|
| 748 |
+
total_frames = len(frame_paths)
|
| 749 |
+
temp_frame_path = os.path.join(swapped_dir, "temp.jpg")
|
| 750 |
+
start_loop_time = time.time()
|
| 751 |
+
|
| 752 |
+
for idx, frame_path in enumerate(frame_paths):
|
| 753 |
+
swapped_name = f"swapped_{idx:05d}.jpg"
|
| 754 |
+
out_path = os.path.join(swapped_dir, swapped_name)
|
| 755 |
+
if swapped_name in swapped_files and os.path.exists(out_path):
|
| 756 |
+
continue
|
| 757 |
+
try:
|
| 758 |
+
shutil.copy(frame_path, temp_frame_path)
|
| 759 |
+
try:
|
| 760 |
+
swapped_img = swapper.swap_faces(src_path, 1, temp_frame_path, int(dst_idx))
|
| 761 |
+
cv2.imwrite(temp_frame_path, swapped_img)
|
| 762 |
+
except Exception as e:
|
| 763 |
+
log += f"Failed to swap face in frame {idx} of video {i}: {e}\n"
|
| 764 |
+
shutil.copy(temp_frame_path, out_path)
|
| 765 |
+
if os.path.exists(temp_frame_path):
|
| 766 |
+
os.remove(temp_frame_path)
|
| 767 |
+
except Exception as e:
|
| 768 |
+
cv2.imwrite(out_path, cv2.imread(frame_path))
|
| 769 |
+
log += f"Failed to swap frame {idx} of video {i}: {e}\n"
|
| 770 |
+
|
| 771 |
+
# Combine frames to video
|
| 772 |
+
cap = cv2.VideoCapture(dst_video_path)
|
| 773 |
+
fps = cap.get(cv2.CAP_PROP_FPS)
|
| 774 |
+
cap.release()
|
| 775 |
+
frames_to_video(swapped_dir, output_video_path, fps)
|
| 776 |
+
log += f"Combined swapped frames into video {output_video_path}\n"
|
| 777 |
+
|
| 778 |
+
# Mux audio if requested
|
| 779 |
+
if add_audio:
|
| 780 |
+
ok, audio_log = add_audio_to_video(dst_video_path, output_video_path, output_video_with_audio)
|
| 781 |
+
if ok:
|
| 782 |
+
log += f"Added audio to {output_video_with_audio}\n"
|
| 783 |
+
results.append(output_video_with_audio)
|
| 784 |
+
else:
|
| 785 |
+
log += f"Audio muxing failed for video {i}: {audio_log}\n"
|
| 786 |
+
results.append(output_video_path)
|
| 787 |
+
else:
|
| 788 |
+
results.append(output_video_path)
|
| 789 |
+
log += f"Audio was not added for video {i} as per user request.\n"
|
| 790 |
+
|
| 791 |
+
# Cleanup frames for next video
|
| 792 |
+
if delete_frames_dir and os.path.exists(frames_dir):
|
| 793 |
+
shutil.rmtree(frames_dir)
|
| 794 |
+
os.makedirs(frames_dir, exist_ok=True)
|
| 795 |
+
log += f"Deleted video_frames directory after video {i}.\n"
|
| 796 |
+
elif not delete_frames_dir:
|
| 797 |
+
log += f"Kept video_frames directory after video {i} as requested.\n"
|
| 798 |
+
if os.path.exists(swapped_dir):
|
| 799 |
+
shutil.rmtree(swapped_dir)
|
| 800 |
+
os.makedirs(swapped_dir, exist_ok=True)
|
| 801 |
+
log += f"Cleared swap_frames directory after video {i}.\n"
|
| 802 |
+
|
| 803 |
+
elapsed = time.time() - start_time
|
| 804 |
+
log += f"Elapsed time: {elapsed:.2f} seconds\n"
|
| 805 |
+
return results, log
|
| 806 |
+
|
| 807 |
+
|
| 808 |
|
| 809 |
# Gradio UI
|
| 810 |
with gr.Blocks() as demo:
|
|
|
|
| 922 |
gr.Textbox(label="Log Output", lines=8, interactive=False)
|
| 923 |
],
|
| 924 |
)
|
| 925 |
+
with gr.Tab("SingleSrcMultiVideo"):
|
| 926 |
+
gr.Interface(
|
| 927 |
+
fn=swap_single_src_multi_video,
|
| 928 |
+
inputs=[
|
| 929 |
+
gr.Image(label="Source Image"),
|
| 930 |
+
gr.File(label="Target Videos (select multiple)", file_count="multiple", type="filepath"),
|
| 931 |
+
gr.Textbox(label="Destination Face Indices (comma-separated, e.g. 1,2,1)"),
|
| 932 |
+
gr.Checkbox(label="Delete video_frames directory after processing", value=True),
|
| 933 |
+
gr.Checkbox(label="Add audio from original video", value=True)
|
| 934 |
+
],
|
| 935 |
+
outputs=[
|
| 936 |
+
gr.Gallery(label="Swapped Videos", type="filepath"),
|
| 937 |
+
gr.Textbox(label="Log Output", lines=8, interactive=False)
|
| 938 |
+
],
|
| 939 |
+
)
|
| 940 |
|
| 941 |
|
| 942 |
if __name__ == "__main__":
|