Skip to content
This repository has been archived by the owner on Nov 13, 2024. It is now read-only.

Commit

Permalink
added module: Face Swap (Insight)
Browse files Browse the repository at this point in the history
  • Loading branch information
iperov committed Jul 9, 2023
1 parent c747863 commit c4511db
Show file tree
Hide file tree
Showing 33 changed files with 568 additions and 76 deletions.
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

<tr><td colspan=2 align="center">

## Face Swapper
## Face Swap (DFM)

You can swap your face from a webcam or the face in the video using trained face models.

Expand Down Expand Up @@ -242,6 +242,21 @@ Here is an <a href="https://www.tiktok.com/@arnoldschwarzneggar/video/6995538782

<tr><td colspan=2 align="center">

## Face Swap (Insight)

You can swap your face from a webcam or the face in the video using your own single photo.

<img src="doc/lukashenko.png" width=128></img>

<img src="doc/insight_faceswap_example.gif"></img>

</td></tr>

</table>
<table align="center" border="0">

<tr><td colspan=2 align="center">

## Face Animator

There is also a Face Animator module in DeepFaceLive app. You can control a static face picture using video or your own face from the camera. The quality is not the best, and requires fine face matching and tuning parameters for every face pair, but enough for funny videos and memes or real-time streaming at 25 fps using 35 TFLOPS GPU.
Expand Down
22 changes: 12 additions & 10 deletions apps/DeepFaceLive/DeepFaceLiveApp.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,19 @@
from . import backend
from .ui.QCameraSource import QCameraSource
from .ui.QFaceAligner import QFaceAligner
from .ui.QFaceAnimator import QFaceAnimator
from .ui.QFaceDetector import QFaceDetector
from .ui.QFaceMarker import QFaceMarker
from .ui.QFaceMerger import QFaceMerger
from .ui.QFaceAnimator import QFaceAnimator
from .ui.QFaceSwapper import QFaceSwapper
from .ui.QFaceSwapInsight import QFaceSwapInsight
from .ui.QFaceSwapDFM import QFaceSwapDFM
from .ui.QFileSource import QFileSource
from .ui.QFrameAdjuster import QFrameAdjuster
from .ui.QStreamOutput import QStreamOutput
from .ui.widgets.QBCFaceAlignViewer import QBCFaceAlignViewer
from .ui.widgets.QBCFaceSwapViewer import QBCFaceSwapViewer
from .ui.widgets.QBCMergedFrameViewer import QBCMergedFrameViewer
from .ui.widgets.QBCFrameViewer import QBCFrameViewer
from .ui.widgets.QBCMergedFrameViewer import QBCMergedFrameViewer


class QLiveSwap(qtx.QXWidget):
Expand Down Expand Up @@ -58,21 +59,22 @@ def __init__(self, userdata_path : Path,
face_marker = self.face_marker = backend.FaceMarker (weak_heap=backend_weak_heap, reemit_frame_signal=reemit_frame_signal, bc_in=face_detector_bc_out, bc_out=face_marker_bc_out, backend_db=backend_db)
face_aligner = self.face_aligner = backend.FaceAligner (weak_heap=backend_weak_heap, reemit_frame_signal=reemit_frame_signal, bc_in=face_marker_bc_out, bc_out=face_aligner_bc_out, backend_db=backend_db )
face_animator = self.face_animator = backend.FaceAnimator (weak_heap=backend_weak_heap, reemit_frame_signal=reemit_frame_signal, bc_in=face_aligner_bc_out, bc_out=face_merger_bc_out, animatables_path=animatables_path, backend_db=backend_db )

face_swapper = self.face_swapper = backend.FaceSwapper (weak_heap=backend_weak_heap, reemit_frame_signal=reemit_frame_signal, bc_in=face_aligner_bc_out, bc_out=face_swapper_bc_out, dfm_models_path=dfm_models_path, backend_db=backend_db )
face_swap_insight = self.face_swap_insight = backend.FaceSwapInsight (weak_heap=backend_weak_heap, reemit_frame_signal=reemit_frame_signal, bc_in=face_aligner_bc_out, bc_out=face_swapper_bc_out, faces_path=animatables_path, backend_db=backend_db )
face_swap_dfm = self.face_swap_dfm = backend.FaceSwapDFM (weak_heap=backend_weak_heap, reemit_frame_signal=reemit_frame_signal, bc_in=face_aligner_bc_out, bc_out=face_swapper_bc_out, dfm_models_path=dfm_models_path, backend_db=backend_db )
frame_adjuster = self.frame_adjuster = backend.FrameAdjuster(weak_heap=backend_weak_heap, reemit_frame_signal=reemit_frame_signal, bc_in=face_swapper_bc_out, bc_out=frame_adjuster_bc_out, backend_db=backend_db )
face_merger = self.face_merger = backend.FaceMerger (weak_heap=backend_weak_heap, reemit_frame_signal=reemit_frame_signal, bc_in=frame_adjuster_bc_out, bc_out=face_merger_bc_out, backend_db=backend_db )
stream_output = self.stream_output = backend.StreamOutput (weak_heap=backend_weak_heap, reemit_frame_signal=reemit_frame_signal, bc_in=face_merger_bc_out, save_default_path=userdata_path, backend_db=backend_db)

self.all_backends : List[backend.BackendHost] = [file_source, camera_source, face_detector, face_marker, face_aligner, face_animator, face_swapper, frame_adjuster, face_merger, stream_output]
self.all_backends : List[backend.BackendHost] = [file_source, camera_source, face_detector, face_marker, face_aligner, face_animator, face_swap_insight, face_swap_dfm, frame_adjuster, face_merger, stream_output]

self.q_file_source = QFileSource(self.file_source)
self.q_camera_source = QCameraSource(self.camera_source)
self.q_face_detector = QFaceDetector(self.face_detector)
self.q_face_marker = QFaceMarker(self.face_marker)
self.q_face_aligner = QFaceAligner(self.face_aligner)
self.q_face_animator = QFaceAnimator(self.face_animator, animatables_path=animatables_path)
self.q_face_swapper = QFaceSwapper(self.face_swapper, dfm_models_path=dfm_models_path)
self.q_face_swap_insight = QFaceSwapInsight(self.face_swap_insight, faces_path=animatables_path)
self.q_face_swap_dfm = QFaceSwapDFM(self.face_swap_dfm, dfm_models_path=dfm_models_path)
self.q_frame_adjuster = QFrameAdjuster(self.frame_adjuster)
self.q_face_merger = QFaceMerger(self.face_merger)
self.q_stream_output = QStreamOutput(self.stream_output)
Expand All @@ -83,8 +85,8 @@ def __init__(self, userdata_path : Path,
self.q_ds_merged_frame_viewer = QBCMergedFrameViewer(backend_weak_heap, face_merger_bc_out)

q_nodes = qtx.QXWidgetHBox([ qtx.QXWidgetVBox([self.q_file_source, self.q_camera_source], spacing=5, fixed_width=256),
qtx.QXWidgetVBox([self.q_face_detector, self.q_face_aligner,], spacing=5, fixed_width=256),
qtx.QXWidgetVBox([self.q_face_marker, self.q_face_animator, self.q_face_swapper], spacing=5, fixed_width=256),
qtx.QXWidgetVBox([self.q_face_detector, self.q_face_aligner, ], spacing=5, fixed_width=256),
qtx.QXWidgetVBox([self.q_face_marker, self.q_face_animator, self.q_face_swap_insight, self.q_face_swap_dfm], spacing=5, fixed_width=256),
qtx.QXWidgetVBox([self.q_frame_adjuster, self.q_face_merger, self.q_stream_output], spacing=5, fixed_width=256),
], spacing=5, size_policy=('fixed', 'fixed') )

Expand Down Expand Up @@ -112,7 +114,7 @@ def clear_backend_db(self):
def initialize(self):
for bcknd in self.all_backends:
default_state = True
if isinstance(bcknd, (backend.CameraSource, backend.FaceAnimator) ):
if isinstance(bcknd, (backend.CameraSource, backend.FaceAnimator, backend.FaceSwapInsight) ):
default_state = False
bcknd.restore_on_off_state(default_state=default_state)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@
BackendWorkerState)


class FaceSwapper(BackendHost):
class FaceSwapDFM(BackendHost):
def __init__(self, weak_heap : BackendWeakHeap, reemit_frame_signal : BackendSignal, bc_in : BackendConnection, bc_out : BackendConnection, dfm_models_path : Path, backend_db : BackendDB = None,
id : int = 0):
self._id = id
super().__init__(backend_db=backend_db,
sheet_cls=Sheet,
worker_cls=FaceSwapperWorker,
worker_cls=FaceSwapDFMWorker,
worker_state_cls=WorkerState,
worker_start_args=[weak_heap, reemit_frame_signal, bc_in, bc_out, dfm_models_path])

Expand All @@ -29,7 +29,7 @@ def get_control_sheet(self) -> 'Sheet.Host': return super().get_control_sheet()
def _get_name(self):
return super()._get_name()# + f'{self._id}'

class FaceSwapperWorker(BackendWorker):
class FaceSwapDFMWorker(BackendWorker):
def get_state(self) -> 'WorkerState': return super().get_state()
def get_control_sheet(self) -> 'Sheet.Worker': return super().get_control_sheet()

Expand Down Expand Up @@ -218,7 +218,7 @@ def on_tick(self):
if events.new_status_downloading:
self.set_busy(False)
cs.model_dl_progress.enable()
cs.model_dl_progress.set_config( lib_csw.Progress.Config(title='@FaceSwapper.downloading_model') )
cs.model_dl_progress.set_config( lib_csw.Progress.Config(title='@FaceSwapDFM.downloading_model') )
cs.model_dl_progress.set_progress(0)

elif events.new_status_initialized:
Expand All @@ -229,12 +229,12 @@ def on_tick(self):

cs.model_info_label.enable()
cs.model_info_label.set_config( lib_csw.InfoLabel.Config(info_icon=True,
info_lines=[f'@FaceSwapper.model_information',
info_lines=[f'@FaceSwapDFM.model_information',
'',
f'@FaceSwapper.filename',
f'@FaceSwapDFM.filename',
f'{self.dfm_model.get_model_path().name}',
'',
f'@FaceSwapper.resolution',
f'@FaceSwapDFM.resolution',
f'{model_width}x{model_height}']) )

cs.swap_all_faces.enable()
Expand Down
Loading

0 comments on commit c4511db

Please sign in to comment.