mirror of
https://github.com/alew3/faceit_live3
synced 2024-11-10 01:11:01 +00:00
285 lines
8.9 KiB
Python
285 lines
8.9 KiB
Python
import imageio
|
|
import numpy as np
|
|
import pandas as pd
|
|
from skimage.transform import resize
|
|
import warnings
|
|
import sys
|
|
import cv2
|
|
import time
|
|
import PIL.Image as Image
|
|
import PIL.ImageFilter
|
|
import io
|
|
from io import BytesIO
|
|
import pyautogui
|
|
import os
|
|
import glob
|
|
from argparse import Namespace
|
|
import argparse
|
|
import timeit
|
|
import torch
|
|
warnings.filterwarnings("ignore")
|
|
|
|
############## setup ####
|
|
stream = True
|
|
media_path = './media/'
|
|
model_path = 'model/'
|
|
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('--webcam_id', type = int, default = 0)
|
|
parser.add_argument('--stream_id', type = int, default = 1)
|
|
parser.add_argument('--gpu_id', type = int, default = 0)
|
|
parser.add_argument('--system', type = str, default = "win")
|
|
|
|
args = parser.parse_args()
|
|
webcam_id = args.webcam_id
|
|
gpu_id = args.gpu_id
|
|
stream_id = args.stream_id
|
|
system = args.system
|
|
|
|
webcam_height = 480
|
|
webcam_width = 640
|
|
screen_width, screen_height = pyautogui.size()
|
|
img_shape = [256, 256, 0]
|
|
|
|
if system=="linux":
|
|
print("Linux version, importing FakeWebCam")
|
|
import pyfakewebcam
|
|
|
|
|
|
first_order_path = 'first-order-model/'
|
|
sys.path.insert(0,first_order_path)
|
|
reset = True
|
|
|
|
# import methods from first-order-model
|
|
import demo
|
|
from demo import load_checkpoints, make_animation, tqdm
|
|
|
|
# prevent tqdm from outputting to console
|
|
demo.tqdm = lambda *i, **kwargs: i[0]
|
|
|
|
print("CUDA is available: ",torch.cuda.is_available())
|
|
if (torch.cuda.is_available()):
|
|
torch.cuda.device("cuda:" + str(gpu_id))
|
|
print("Device Name:",torch.cuda.get_device_name(gpu_id))
|
|
print("Device Count:",torch.cuda.device_count())
|
|
print("CUDA: ",torch.version.cuda)
|
|
print("cuDNN",torch.backends.cudnn.version())
|
|
print("Device",torch.cuda.current_device())
|
|
|
|
|
|
img_list = []
|
|
print("Scanning /media folder for images to use...")
|
|
for filename in os.listdir(media_path):
|
|
if filename.endswith(".jpg") or filename.endswith(".jpeg") or filename.endswith(".png"):
|
|
img_list.append(os.path.join(media_path, filename))
|
|
print(os.path.join(media_path, filename))
|
|
|
|
#print(img_list, len(img_list))
|
|
|
|
############## end setup ####
|
|
|
|
def main():
|
|
global source_image
|
|
source_image = readnextimage(0)
|
|
|
|
# start streaming
|
|
if system=="linux":
|
|
camera = pyfakewebcam.FakeWebcam(f'/dev/video{stream_id}', webcam_width, webcam_height)
|
|
camera.print_capabilities()
|
|
print(f"Fake webcam created on /dev/video{stream_id}. Use Firefox and join a Google Meeting to test.")
|
|
|
|
# capture webcam
|
|
video_capture = cv2.VideoCapture(webcam_id)
|
|
time.sleep(1)
|
|
width = video_capture.get(3) # float
|
|
height = video_capture.get(4) # float
|
|
print("webcam dimensions = {} x {}".format(width,height))
|
|
|
|
# load models
|
|
net = load_face_model()
|
|
generator, kp_detector = demo.load_checkpoints(config_path=f'{first_order_path}config/vox-adv-256.yaml', checkpoint_path=f'{model_path}/vox-adv-cpk.pth.tar')
|
|
|
|
|
|
# create windows
|
|
cv2.namedWindow('Face', cv2.WINDOW_GUI_NORMAL) # extracted face
|
|
cv2.moveWindow('Face', int(screen_width//2)-150, 100)
|
|
cv2.resizeWindow('Face', 256,256)
|
|
|
|
cv2.namedWindow('DeepFake', cv2.WINDOW_GUI_NORMAL) # face transformation
|
|
cv2.moveWindow('DeepFake', int(screen_width//2)+150, 100)
|
|
cv2.resizeWindow('DeepFake', 256, 256)
|
|
|
|
cv2.namedWindow('Stream', cv2.WINDOW_GUI_NORMAL) # rendered to fake webcam
|
|
cv2.moveWindow('Stream', int(screen_width//2)-int(webcam_width//2), 400)
|
|
cv2.resizeWindow('Stream', webcam_width,webcam_height)
|
|
|
|
|
|
print("Press C to center Webcam, Press B/N for previous/next image in media directory, T to alter between relative and absolute transformation, Q to quit")
|
|
x1,y1,x2,y2 = [0,0,0,0]
|
|
relative = True
|
|
previous = None
|
|
|
|
while True:
|
|
ret, frame = video_capture.read()
|
|
frame = cv2.resize(frame, (640, 480))
|
|
frame = cv2.flip(frame,1)
|
|
|
|
if (previous is None or reset is True):
|
|
x1,y1,x2,y2 = find_face_cut(net,frame)
|
|
previous = cut_face_window(x1,y1,x2,y2,frame)
|
|
reset = False
|
|
#img_shape = source_image.shape
|
|
#cv2.resizeWindow('DeepFake', int(img_shape[1] // img_shape[0] * 256), 256)
|
|
#cv2.imshow('Previous',previous)
|
|
|
|
|
|
curr_face = cut_face_window(x1,y1,x2,y2,frame.copy())
|
|
# cv2.imshow('Previous',previous)
|
|
# cv2.imshow('Curr Face',curr_face)
|
|
# cv2.imshow('Source Image',source_image)
|
|
|
|
deep_fake = process_image(source_image,previous,curr_face,net, generator, kp_detector, relative)
|
|
#print("deep_fake",deep_fake.shape)
|
|
|
|
deep_fake = cv2.cvtColor(deep_fake, cv2.COLOR_RGB2BGR)
|
|
|
|
rgb = cv2.resize(deep_fake,(int(source_image.shape[0] // source_image.shape[1] * 480),480))
|
|
|
|
# pad image
|
|
x_border = int((640-(img_shape[1] // img_shape[0] * 480))//2)
|
|
#y_border = int((480-(img_shape[0] // img_shape[1] * 640))//2)
|
|
|
|
stream_v = cv2.copyMakeBorder(rgb, 0, 0, x_border if x_border >=0 else 0, x_border if x_border >=0 else 0, cv2.BORDER_CONSTANT)
|
|
|
|
#cv2.imshow('Webcam', frame)
|
|
cv2.imshow('Face', curr_face)
|
|
cv2.imshow('DeepFake', deep_fake)
|
|
#cv2.imshow('Previous', previous)
|
|
#cv2.imshow('RGB', rgb)
|
|
#cv2.imshow('Source Image', source_image)
|
|
#time.sleep(1/30.0)
|
|
|
|
cv2.imshow('Stream',stream_v)
|
|
|
|
# stream to fakewebcam
|
|
if system=="linux":
|
|
stream_v = cv2.flip(stream_v,1)
|
|
stream_v = cv2.cvtColor(stream_v, cv2.COLOR_BGR2RGB)
|
|
stream_v = (stream_v*255).astype(np.uint8)
|
|
#print("output to fakecam")
|
|
camera.schedule_frame(stream_v)
|
|
|
|
k = cv2.waitKey(1)
|
|
# Hit 'q' on the keyboard to quit!
|
|
if k & 0xFF == ord('q'):
|
|
print("Quiting")
|
|
video_capture.release()
|
|
break
|
|
elif k==ord('c'):
|
|
# center
|
|
print("Centering the image")
|
|
reset = True
|
|
elif k==ord('b'):
|
|
# previous image
|
|
print("Loading previous image")
|
|
source_image = readpreviousimage()
|
|
reset = True
|
|
elif k==ord('n'):
|
|
# next image
|
|
print("Loading next image")
|
|
source_image = readnextimage()
|
|
reset = True
|
|
elif k==ord('t'):
|
|
# rotate
|
|
relative = not relative
|
|
print("Changing transform mode")
|
|
|
|
|
|
cv2.destroyAllWindows()
|
|
exit()
|
|
|
|
|
|
# transform face with first-order-model
|
|
def process_image(source_image,base,current,net, generator,kp_detector,relative):
|
|
predictions = make_animation(source_image, [base,current], generator, kp_detector, relative=relative, adapt_movement_scale=False)
|
|
return predictions[1]
|
|
|
|
def load_face_model():
|
|
modelFile = f"{model_path}/res10_300x300_ssd_iter_140000.caffemodel"
|
|
configFile = f"{model_path}./deploy.prototxt.txt"
|
|
net = cv2.dnn.readNetFromCaffe(configFile, modelFile)
|
|
return net
|
|
|
|
def cut_face_window(x1,y1,x2,y2,frame):
|
|
frame = frame.copy()
|
|
frame = frame[y1:y2,x1:x2]
|
|
face = resize(frame, (256, 256))[..., :3]
|
|
return face
|
|
|
|
# find the face in webcam stream and center a 256x256 window
|
|
def find_face_cut(net,face):
|
|
blob = cv2.dnn.blobFromImage(face, 1.0, (300, 300), [104, 117, 123], False, False)
|
|
frameWidth = 640
|
|
frameHeight = 480
|
|
net.setInput(blob)
|
|
detections = net.forward()
|
|
bboxes = []
|
|
face_found = False
|
|
for i in range(detections.shape[2]):
|
|
#print(i)
|
|
confidence = detections[0, 0, i, 2]
|
|
if confidence > 0.9:
|
|
x1 = (int(detections[0, 0, i, 3] * frameWidth)//2)*2
|
|
y1 = (int(detections[0, 0, i, 4] * frameHeight)//2)*2
|
|
x2 = (int(detections[0, 0, i, 5] * frameWidth)//2)*2
|
|
y2 = (int(detections[0, 0, i, 6] * frameHeight)//2)*2
|
|
|
|
face_margin_w = int(256 - (abs(x1-x2)))
|
|
face_margin_h = int(256 - (abs(y1-y2)))
|
|
|
|
cut_x1 = x1 - int(face_margin_w//2)
|
|
cut_y1 = y1 - int(2*face_margin_h//3)
|
|
|
|
cut_x2 = x2 + int(face_margin_w//2)
|
|
cut_y2 = y2 + face_margin_h - int(2*face_margin_h//3)
|
|
|
|
face_found = True
|
|
break
|
|
|
|
if not face_found:
|
|
print("No face detected in video")
|
|
# let's just use the middle section of the image
|
|
cut_x1,cut_y1,cut_x2,cut_y2 = 112,192,368,448
|
|
else:
|
|
print(f'Found face at: ({x1,y1}) ({x2},{y2} width:{(x2-x1)} height: {(y2-y1)})')
|
|
print(f'Cutting at: ({cut_x1,cut_y1}) ({cut_x2},{cut_y2} width:{(cut_x2-cut_x1)} height: {(cut_y2-cut_y1)})')
|
|
|
|
|
|
return cut_x1,cut_y1,cut_x2,cut_y2
|
|
|
|
def readimage():
|
|
global img_list,img_shape
|
|
img = imageio.imread(img_list[pos])
|
|
img = resize(img, (256, 256))[..., :3]
|
|
return img
|
|
|
|
def readpreviousimage():
|
|
global pos
|
|
if pos<len(img_list)-1:
|
|
pos=pos-1
|
|
else:
|
|
pos=0
|
|
return readimage()
|
|
|
|
def readnextimage(position=-1):
|
|
global pos
|
|
if (position != -1):
|
|
pos = position
|
|
else:
|
|
if pos<len(img_list)-1:
|
|
pos=pos+1
|
|
else:
|
|
pos=0
|
|
return readimage()
|
|
|
|
main() |