|
|
|
import streamlit as st |
|
import numpy as np |
|
import cv2 |
|
import insightface |
|
from insightface.app import FaceAnalysis |
|
import tempfile |
|
import os |
|
|
|
|
|
app = FaceAnalysis(name='buffalo_l') |
|
app.prepare(ctx_id=0, det_size=(640, 640)) |
|
|
|
|
|
swapper = insightface.model_zoo.get_model('inswapper_128.onnx', download=False, download_zip=False) |
|
|
|
def swap_faces_in_video(image, video, progress): |
|
""" |
|
Swaps faces from a source image with faces detected in a video and returns the path to the output video file. |
|
|
|
image: Source image (as an array) |
|
video: Path to the input video file |
|
progress: Streamlit progress object |
|
""" |
|
source_faces = app.get(image) |
|
|
|
if len(source_faces) == 0: |
|
st.error("No face detected in the source image.") |
|
return None |
|
|
|
source_face = source_faces[0] |
|
|
|
|
|
output_path = tempfile.mktemp(suffix='.avi') |
|
|
|
|
|
cap = cv2.VideoCapture(video) |
|
|
|
|
|
frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) |
|
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) |
|
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) |
|
fps = cap.get(cv2.CAP_PROP_FPS) |
|
|
|
|
|
fourcc = cv2.VideoWriter_fourcc(*'XVID') |
|
out = cv2.VideoWriter(output_path, fourcc, fps, (frame_width, frame_height)) |
|
|
|
for i in range(frame_count): |
|
ret, frame = cap.read() |
|
if not ret: |
|
break |
|
|
|
|
|
target_faces = app.get(frame) |
|
|
|
|
|
result_frame = frame.copy() |
|
|
|
|
|
for target_face in target_faces: |
|
result_frame = swapper.get(result_frame, target_face, source_face, paste_back=True) |
|
|
|
|
|
out.write(result_frame) |
|
|
|
|
|
progress.progress((i + 1) / frame_count) |
|
|
|
|
|
cap.release() |
|
out.release() |
|
|
|
return output_path |
|
|
|
|
|
st.title("Face Swapper in Video") |
|
st.write("Upload an image and a video to swap faces.") |
|
|
|
|
|
image_file = st.file_uploader("Upload Source Image", type=["jpg", "jpeg", "png"]) |
|
|
|
|
|
video_file = st.file_uploader("Upload Video", type=["mp4", "avi"]) |
|
|
|
if st.button("Swap Faces"): |
|
if image_file is not None and video_file is not None: |
|
|
|
source_image = cv2.imdecode(np.frombuffer(image_file.read(), np.uint8), cv2.IMREAD_COLOR) |
|
|
|
|
|
with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tmp_video: |
|
tmp_video.write(video_file.read()) |
|
tmp_video_path = tmp_video.name |
|
|
|
|
|
with st.spinner("Processing video..."): |
|
progress_bar = st.progress(0) |
|
output_video_path = swap_faces_in_video(source_image, tmp_video_path, progress_bar) |
|
|
|
if output_video_path: |
|
st.success("Face swapping completed!") |
|
|
|
st.video(output_video_path) |
|
|
|
|
|
with open(output_video_path, "rb") as f: |
|
st.download_button( |
|
label="Download Processed Video", |
|
data=f, |
|
file_name="output_swapped_video.avi", |
|
mime="video/x-msvideo" |
|
) |
|
|
|
|
|
os.remove(tmp_video_path) |
|
|
|
|
|
else: |
|
st.error("Please upload both an image and a video.") |
|
|