Compare commits

...

329 Commits

Author SHA1 Message Date
KRSHH 48c83151a4 size 2025-02-03 20:59:06 +05:30
KRSHH bb3502d9bd update branch
update branch
2025-01-31 22:32:47 +05:30
KRSHH a101a1f3f1 Reorganized switches 2025-01-30 20:20:04 +05:30
KRSHH 01ef955372 Improve eyebrow mask 2025-01-30 20:14:16 +05:30
KRSHH ab3b73631b Shift masking features to face_masking.py 2025-01-30 20:04:31 +05:30
KRSHH d8fc1ffa04 Eyebrow Mask 2025-01-30 19:58:15 +05:30
KRSHH 5dfd1c0ced Eye Mask 2025-01-30 19:20:58 +05:30
Kenneth Estanislao db594c0e7c Update README.md 2025-01-29 14:02:07 +08:00
Kenneth Estanislao 6a5b75ec45 Update README.md 2025-01-29 14:00:41 +08:00
Kenneth Estanislao 79e1ce5093 Update requirements.txt
update pillow

In _imagingcms.c in Pillow before 10.3.0, a buffer overflow exists because strcpy is used instead of strncpy.
2025-01-28 14:22:05 +08:00
KRSHH 59cd3be0f9 Simplify Privacy mode switch state 2025-01-27 00:47:34 +05:30
KRSHH ccb676ac17 FPS Switch re-enable 2025-01-26 23:41:44 +05:30
KRSHH f0c66732e7 Use Logo 2025-01-26 23:20:08 +05:30
KRSHH 8055d79daf Privacy Mode 2025-01-26 23:10:45 +05:30
KRSHH 3c7dd1a574 Hardcoded Keep FPS and Keep Frames 2025-01-23 18:45:43 +05:30
Kenneth Estanislao fda4878bfd Update README.md 2025-01-20 04:38:49 +08:00
Kenneth Estanislao 5ff922e2a4 Update README.md 2025-01-18 22:50:07 +08:00
Kenneth Estanislao 9ed5a72289 Update README.md 2025-01-18 22:33:30 +08:00
KRSHH 0c8e2d5794 Changes to TLDR 2025-01-18 19:59:02 +05:30
KRSHH a0aafbc97c Disclaimer TLDR 2025-01-18 19:57:46 +05:30
KRSHH f95b07423b Moved Disclaimer to top 2025-01-18 19:53:08 +05:30
KRSHH 3947053c89 Change img dimensions 2025-01-15 22:48:21 +05:30
KRSHH 0e6a6f84f5 Updated Features Section 2025-01-15 22:45:23 +05:30
KRSHH bb331a6db0 Add files via upload 2025-01-15 22:24:47 +05:30
KRSHH ec48b0048f Added Contacts 2025-01-15 01:07:16 +05:30
KRSHH acc4812551 Added Live Show Use Case 2025-01-15 00:33:02 +05:30
KRSHH 87ee05d7b3 Uploaded Live Show GIF 2025-01-15 00:29:22 +05:30
Kenneth Estanislao ce03dbf200 Update README.md 2025-01-14 03:32:43 +08:00
KRSHH 704aeb73b1 Added Command to install FFMPEG directly 2025-01-14 00:30:07 +05:30
KRSHH f5c8290e1c Update model URL 2025-01-14 00:26:03 +05:30
KRSHH f164d9234b Shifted Disclaimer to Bottom
Its pretty much standard in any repo
2025-01-12 16:35:11 +05:30
KRSHH 74009c1d5d Shift TL;DR under Packages 2025-01-11 21:03:26 +05:30
Kenneth Estanislao e6a1c8dd95 Update README.md 2025-01-07 19:03:21 +08:00
Kenneth Estanislao 0e3f2c8dc0 Update README.md 2025-01-07 19:02:46 +08:00
Kenneth Estanislao 464dc2a0aa Update README.md 2025-01-07 18:56:54 +08:00
Kenneth Estanislao a05754fb28 Update README.md 2025-01-07 18:55:21 +08:00
Kenneth Estanislao 9727f34923 Update README.md 2025-01-07 18:52:24 +08:00
Kenneth Estanislao a86544a4b4 Update README.md 2025-01-07 18:48:03 +08:00
Kenneth Estanislao 979da7aa1d Update README.md 2025-01-07 18:33:22 +08:00
Kenneth Estanislao 4a37bb2a97 Update README.md 2025-01-07 18:32:52 +08:00
Kenneth Estanislao 21d3c8766a Merge pull request #879 from hacksider/premain
Premain
2025-01-07 18:12:47 +08:00
Kenneth Estanislao ee19c5158a Merge pull request #877 from qitianai/add-lang
Add multi language UI
2025-01-07 17:57:10 +08:00
qitianai 693c9bb268 Merge pull request #1 from hacksider/main
merge from source main branch
2025-01-07 15:01:00 +08:00
qitian 5132f86cdc add mutil language 2025-01-07 14:04:18 +08:00
Kenneth Estanislao cab2efa200 Update README.md
added qitianai on the credits
2025-01-07 13:48:42 +08:00
qitian 6e29e4061b merge from the source and little change 2025-01-07 13:46:17 +08:00
KRSHH 2a7ae010a8 Raised img Res 2025-01-06 23:53:18 +05:30
KRSHH a834811974 Add URL to buttons
Forgot to add before (regarded)
2025-01-06 23:23:19 +05:30
KRSHH d2aaf46e69 Change buttons 2025-01-06 23:13:57 +05:30
Makaru d07d4a6a26 Update ui.py
I pushed it to premain
2025-01-07 01:15:05 +08:00
KRSHH 09f0343639 Shifted features section under Quick start 2025-01-06 18:16:44 +05:30
KRSHH 75913c513e Decreased Disclaimer's Font Size 2025-01-06 18:02:51 +05:30
KRSHH 7f38539508 Fix Grammar in README 2025-01-06 17:51:00 +05:30
Kenneth Estanislao b38831dfdf Revert "Merge pull request #868 from kier007/main"
This reverts commit c03f697729, reversing
changes made to d8a5cdbc19.
2025-01-06 14:14:21 +08:00
Kenneth Estanislao b518f4337d Revert "Merge pull request #869 from kier007/patch-1"
This reverts commit b38ef62447, reversing
changes made to c03f697729.
2025-01-06 14:14:04 +08:00
KRSHH 7def969831 Add download buttons for Windows and Mac
Add download buttons for Windows and Mac
2025-01-05 23:03:11 +05:30
KRSHH 6bf503e669 Add download buttons for Windows and Mac 2025-01-05 23:02:41 +05:30
Kenneth Estanislao 28513d6c1f Update metadata.py 2025-01-06 00:27:45 +08:00
Kenneth Estanislao f6abe502b6 Update README.md 2025-01-06 00:26:55 +08:00
Kenneth Estanislao b38ef62447 Merge pull request #869 from kier007/patch-1
Update the UI to close the face mapper when disabled
2025-01-06 00:23:49 +08:00
Makaru a3469b7bd4 Update ui.py
Added:
- If you happen to turn off the map faces switch while the Source x Target Mapper window is open, the Source x Target Mapper window will close.
2025-01-06 00:10:53 +08:00
Kenneth Estanislao c03f697729 Merge pull request #868 from kier007/main
Update ui.py
2025-01-05 20:33:49 +08:00
Makaru 742bcab130 Update ui.py
Added:
- try-finally Block: This makes sure the camera.release() is called no matter how the while loops end.
- Resource Cleanup: The finally block takes care of cleaning up resources to keep the application stable.
2025-01-05 20:19:36 +08:00
Makaru 22940d1b99 Update ui.py
The following changes have been implemented:
-A "clear" button has been incorporated.
-The Source x Target Mapper window has been retained following the submission of data via the "submit" button.
2025-01-05 18:29:01 +08:00
KRSHH d8a5cdbc19 removed comment from requirements.txt 2025-01-03 19:21:39 +05:30
Kenneth Estanislao 6219da4b1b Update README.md 2025-01-03 21:12:07 +08:00
Kenneth Estanislao 22e1110ec4 Merge pull request #862 from kier007/main
Update requirements.txt for CUDA 12.1 compatibility
2025-01-03 21:07:32 +08:00
Makaru 82d5d34912 Update requirements.txt 2025-01-03 20:42:38 +08:00
Makaru 60e82ea200 Update requirements.txt 2025-01-03 20:26:54 +08:00
KRSHH 8be7368949 Added URL to official website 2024-12-30 15:51:46 +05:30
KRSHH 5003c04386 Added IShowSpeed's Testimonial 2024-12-29 22:00:25 +05:30
KRSHH aed933c1db Update branches
Update Branches
2024-12-29 21:44:57 +05:30
KRSHH a50ea98bc2 Fixed Sentence Formatting 2024-12-29 03:14:02 +05:30
KRSHH 6a9bf2acfb Deleted unused MP4 Demo 2024-12-29 03:11:41 +05:30
KRSHH 395cecf11d Features Header Change 2024-12-29 03:08:42 +05:30
KRSHH ebf4e95c3a Readme Changes 2024-12-29 03:07:31 +05:30
KRSHH 5974ba2a68 Fix Grammar 2024-12-29 03:06:10 +05:30
KRSHH 75c53ac7aa Readme Changes 2024-12-29 03:02:54 +05:30
KRSHH 8aeb406ea2 Rename run-laptop-gpu.bat to run-directml.bat 2024-12-26 20:38:01 +05:30
KRSHH 8b3bd734cf Delete run_with_chocolatey.bat 2024-12-26 20:35:09 +05:30
KRSHH b0aac8bd04 Merge pull request #851 from mehdico/mouth-mask-arg
Added the --mouth-mask argument to the CLI
2024-12-26 20:30:48 +05:30
KRSHH 9dc3c3e9c2 Merge pull request #854 from hacksider/premain
Make main up to date with premain branch
2024-12-26 20:16:34 +05:30
KRSHH 21989d4a49 Added PR checklist 2024-12-26 20:15:51 +05:30
KRSHH b97185d2bf Merge branch 'main' into premain 2024-12-26 20:07:26 +05:30
Mehdi Mousavi 81da9a23ca Fix mouth mask description 2024-12-24 09:51:32 +03:30
Mehdi Mousavi 007867a6f6 Add support for --mouth-mask argument 2024-12-24 09:40:06 +03:30
KRSHH 7ec9d61608 Removed default limits
User should add limits according their needs
2024-12-24 01:26:20 +05:30
KRSHH eeff1a87fa Remove Unused Directory and Images 2024-12-24 01:23:50 +05:30
KRSHH bc1149cd80 Remove Unused Directory and Images 2024-12-24 01:23:24 +05:30
KRSHH 11c10b354f docs: changed testing branch to premain 2024-12-24 00:45:57 +05:30
KRSHH 71aae3fe07 docs: changed testing branch to premain 2024-12-24 00:42:12 +05:30
KRSHH b995eca033 Update premain
updating premain
2024-12-24 00:36:59 +05:30
KRSHH b17e52dea2 Mac Webcam Serial No. Management 2024-12-23 22:45:41 +05:30
Kenneth Estanislao 3a858847e3 Merge pull request #846 from pedrodanielsantos/main
Fix "Update face_enhancer.py"
2024-12-23 17:45:10 +08:00
KRSHH 77c19d1073 FaceTime Camera Index to 0 2024-12-23 14:58:43 +05:30
Pedro Santos 7472dfb694 fix: add match statement
Added for optimization

Co-Authored-By: Zephira <zephira58@protonmail.com>
2024-12-23 06:29:36 +00:00
Pedro Santos 41c6916273 Revert "Update face_enhancer.py"
This reverts commit ed7a21687c.
2024-12-23 06:08:45 +00:00
Kenneth Estanislao ed7a21687c Update face_enhancer.py
change if from before statement to elif, also fix conditional ladder
2024-12-23 12:45:53 +08:00
KRSHH 5ce991651d Formatting
Moved Windows only modules, to top too.
2024-12-23 09:46:59 +05:30
KRSHH 432984b3b6 Mac Fix
Pygrabber Module import only on windows
2024-12-23 09:41:17 +05:30
KRSHH 47c8f7acc0 PR #844 - Pygrabber + Mac fix
Pygrabber + Mac fix
2024-12-22 18:34:32 +05:30
KRSHH 606137c58f Merge branch 'main' into premain 2024-12-22 18:32:38 +05:30
KRSHH 76b94ac034 Changed Metadata to GitHub Edition 2024-12-22 18:28:38 +05:30
KRSHH 84ca1dc2f2 Make Face Enhancer Model device Conditional
Added Co-Author

Co-Authored-By: Rishon <rishon@rishon.me>
2024-12-19 21:18:28 +05:30
KRSHH 681c20dbbd Revert "Make Face Enhancer Model device Conditional"
This reverts commit c240f6e31c.
2024-12-19 21:16:56 +05:30
KRSHH c240f6e31c Make Face Enhancer Model device Conditional 2024-12-19 21:12:57 +05:30
Kenneth Estanislao ba9d58e04e Update metadata.py 2024-12-19 13:08:25 +08:00
KRSHH 4bb979faf0 Update metadata.py 2024-12-18 22:45:58 +05:30
KRSHH eae69c4b47 Removed bat file 2024-12-18 22:45:28 +05:30
KRSHH f7823906d1 Update metadata.py 2024-12-18 22:44:20 +05:30
Kenneth Estanislao a1d9b73742 Revert "Merge pull request #829 from RishonLi/patch-1"
This reverts commit 5f5fe8890a, reversing
changes made to a9e8f27360.
2024-12-16 22:46:39 +08:00
Kenneth Estanislao 5f5fe8890a Merge pull request #829 from RishonLi/patch-1
Update face_enhancer.py for apple silicon mps
2024-12-16 22:30:50 +08:00
KRSHH a9e8f27360 Pygrabber only for Windows 2024-12-16 18:41:39 +05:30
Rishon de4f765878 Update face_enhancer.py for apple silicon mps 2024-12-14 16:47:07 +08:00
KRSHH c72582506d Adding Pygrabber as Cam manager 2024-12-13 19:49:11 +05:30
KRSHH 7fb6b54c0b Add Pygrabber 2024-12-13 19:05:38 +05:30
KRSHH d6236a0eed Update README.md 2024-11-30 23:37:38 +05:30
KRSHH 6171141505 Detection Benchmarks 2024-11-17 23:53:04 +05:30
KRSHH 08adb53b8f Add files via upload 2024-11-17 23:48:38 +05:30
Kenneth Estanislao 9e5446582e Merge branch 'main' of https://github.com/hacksider/Deep-Live-Cam 2024-11-17 22:24:04 +08:00
Kenneth Estanislao b9c7c0db6f Update .gitignore 2024-11-17 21:52:41 +08:00
Kenneth Estanislao cab8b9afcb Update README.md 2024-11-14 19:47:35 +08:00
Kenneth Estanislao 4d8ba6396a Merge pull request #773 from NeuroDonu/main
fix for GfpGAN and inswapper model path retrieval bug
2024-11-12 13:21:34 +08:00
NeuroDonu e4761e4d66 fix path for download and use model 2024-11-09 16:43:35 +03:00
NeuroDonu a840986159 fix path for model 2024-11-09 16:43:13 +03:00
KRSHH 4874282642 Making issue template mandatory 2024-11-08 23:21:30 +05:30
KRSHH 71c33437fc Update bug_report.md 2024-11-02 12:59:33 +05:30
KRSHH a39b2e8d81 Update bug_report.md 2024-11-01 10:31:44 +05:30
KRSHH a7e775f918 Removed Link of a disabled repo
For avoiding ToS violation strike on this
2024-10-30 18:05:42 +05:30
KRSHH 5919995fa1 Update bug_report.md
Added this because of too many amateurs not following the obvious common steps before opening an issue.
2024-10-30 11:41:24 +05:30
Kenneth Estanislao 8746c9bd36 Update metadata.py
1.7
2024-10-30 00:25:06 +08:00
KRSHH 6a9ac5b70a Merge pull request #743 from theogbob/patch-1
Fix ui.py
2024-10-27 10:33:53 +05:30
theogbob 916c2f82d8 Fix ui.py
Add command to "mouth_mask": modules.globals.mouth_mask which fixes the error "SyntaxError: invalid syntax. Perhaps you forgot a comma?"
2024-10-26 14:40:03 -04:00
KRSHH 80f6ea9e65 Save Mouth Mask Switch states 2024-10-26 17:54:45 +05:30
Kenneth Estanislao 9e24281a94 Delete media/mouth.gif 2024-10-26 14:32:16 +08:00
Kenneth Estanislao 82b527487a Update README.md
ohhh... bad example during political times 😝
2024-10-26 14:31:24 +08:00
Kenneth Estanislao abde84ea57 Merge pull request #740 from KRSHH/main
BOUNTY: Mouth Mask Feature
2024-10-26 14:12:20 +08:00
KRSHH c599bb3e34 Mouth Masking Example 2024-10-25 22:47:53 +05:30
KRSHH 39db53abd6 Update README.md
Describes better.
2024-10-25 21:34:52 +05:30
KRSHH 29c9c119d3 Add Mouth Mask Feature 2024-10-25 20:59:30 +05:30
KRSHH fad626e84c Revert "Implement mouth mask"
This reverts commit 5ef255c3c3.
2024-10-25 20:55:21 +05:30
KRSHH 5ef255c3c3 Implement mouth mask 2024-10-25 20:53:31 +05:30
KRSHH 6f6f93a4ad Added Links to Models in Instructions 2024-10-22 18:16:10 +05:30
KRSHH c75f941716 Removed Package Repetition 2024-10-22 17:24:06 +05:30
KRSHH e4af521592 Delete Media from main 2024-10-21 19:02:59 +05:30
KRSHH 6d40560c92 Add files via upload 2024-10-21 19:00:10 +05:30
KRSHH 570648efd0 Upload images to media folder 2024-10-21 18:56:36 +05:30
KRSHH 2dc429440e Shift Images to a folder 2024-10-21 18:50:07 +05:30
Kenneth Estanislao 240995bbe4 Update README.md 2024-10-21 16:14:39 +08:00
KRSHH fe8e54ddc1 Update README.md - Fix Text position 2024-10-20 22:37:30 +05:30
Kenneth Estanislao 1462ee9aeb Update README.md
included instructions to watch movies in realtime!
2024-10-20 22:46:38 +08:00
KRSHH 3da987340b Fix Enhancer for Map Faces 2024-10-15 13:08:03 +05:30
Kenneth Estanislao a4216bf9ec Update README.md
added tips and links
2024-10-14 19:54:21 +08:00
KRSHH ab26413ce8 on/off enhancer during inference and improve FPS counter 2024-10-13 13:16:21 +05:30
KRSHH 94b0b63b3b Update README.md 2024-10-09 21:46:59 +05:30
KRSHH 53d473164b remember/save switch states 2024-10-09 19:51:04 +05:30
KRSHH 673439d47c Update globals.py for Default states 2024-10-09 19:50:20 +05:30
KRSHH bbad5e08bb Update globals.py 2024-10-06 20:36:57 +05:30
KRSHH 88164c6303 Show FPS Switch 2024-10-05 17:39:41 +05:30
KRSHH a49d3fc6e5 Face Mapping fix 2024-10-05 15:00:00 +05:30
Kenneth Estanislao e531f6f26e improved performance enhancement
improved performance
2024-10-05 01:42:40 +08:00
Kenneth Estanislao c39f6ac33b Update metadata.py 2024-10-05 01:38:01 +08:00
KRSHH 5812ef3cc9 Webcam selection 2024-10-05 01:37:19 +08:00
KRSHH b9aac85635 Merge pull request #694 from KRSHH/main
Hotswap Source image - switch faces without closing live
2024-10-04 18:27:33 +05:30
KRSHH 75decc5838 Hotswap Source image - switch faces without closing live 2024-10-04 18:17:22 +05:30
Kenneth Estanislao f38ebb485a Update ui.py
removed opacity, will work on it later to optimize
2024-10-04 15:39:08 +08:00
Kenneth Estanislao 95742c8fd5 Merge pull request #686 from GhoulBoii/main
BOUNTY - Webcam Merged (tested)
2024-10-04 14:46:06 +08:00
Kenneth Estanislao 60e27f4755 Revert "Merge pull request #685 from KRSHH/main"
This reverts commit d4e5b8078d, reversing
changes made to c08bec22e3.
2024-10-03 14:51:38 +08:00
KRSHH 3d741bd269 Update README.md 2024-10-02 18:38:37 +05:30
KRSHH d4e5b8078d Merge pull request #685 from KRSHH/main
Live faceswap opacity slider
2024-10-02 15:24:53 +05:30
KRSHH 61b51fc5d4 Move the slider from live to root 2024-10-02 14:37:19 +05:30
KRSHH f19e425143 Update ui.py 2024-10-02 14:20:56 +05:30
KRSHH 7d6bdad086 Default opacity global 2024-10-02 13:24:23 +05:30
KRSHH 12c0a7ac86 Faceswap live opacity slider 2024-10-02 13:23:39 +05:30
Kenneth Estanislao c08bec22e3 Update issue templates 2024-10-01 14:26:03 +08:00
KRSHH bdd7c593e1 Update README.md 2024-09-28 20:53:29 +05:30
KRSHH 6e618baf34 Update README.md 2024-09-28 17:22:21 +05:30
KRSHH 0edcaae713 Merge pull request #650 from KRSHH/main
Preview video Frame by Frame using left and right arrow keys
2024-09-28 12:37:40 +05:30
KRSHH dff6cec2f9 Comment Indention fix 2024-09-27 20:59:48 +05:30
KRSHH 4d1d2c86af Preview video Frame by Frame using left and right arrow keys 2024-09-27 20:40:32 +05:30
KRSHH e00c398825 Merge branch 'hacksider:main' into main 2024-09-27 20:20:22 +05:30
KRSHH 0e481609ea Update README.md 2024-09-27 19:59:13 +05:30
KRSHH 683481804c Delete outdated docs directory 2024-09-26 11:03:46 +05:30
KRSHH 5845b9c480 Update README.md 2024-09-26 00:57:11 +05:30
Kenneth Estanislao 71cf39fd98 Update metadata.py
changes of version from 1.4 to 1.5 (UI modified)
2024-09-26 00:57:45 +08:00
KRSHH 92db20eba4 Merge pull request #632 from KRSHH/main
Unreverting New UI after Fixes, Unreverted README
2024-09-25 17:51:30 +05:30
KRSHH f1e365799e Updated README, (Images - TBU) 2024-09-25 17:42:09 +05:30
KRSHH 6d1238212a New Fixed UI 2024-09-25 17:36:50 +05:30
Kenneth Estanislao 92a0994f01 Update README.md 2024-09-21 19:56:00 +08:00
Kenneth Estanislao cad40b25dc Update face_swapper.py
added the missing ' , my bad on this...
2024-09-19 21:00:29 +08:00
Kenneth Estanislao 1b4c0ce43e Update face_swapper.py
should fix issues for those who dont have nvidia cards
2024-09-19 17:43:05 +08:00
Kenneth Estanislao fd4e3f546d reverted to the old version
fixing the issue #597
2024-09-19 17:38:02 +08:00
Kenneth Estanislao 5bcd6dabde Update ui.py 2024-09-19 15:54:57 +08:00
Kenneth Estanislao 3e1f333e5e Revert "Merge pull request #594 from KRSHH/main"
This reverts commit 2641f9e344, reversing
changes made to 9bf2080ac8.
2024-09-19 02:36:35 +08:00
Kenneth Estanislao 1f71d274b5 Revert "Merge pull request #599 from KRSHH/main"
This reverts commit 80de3dc32e, reversing
changes made to 375d4ae620.
2024-09-19 02:01:47 +08:00
Kenneth Estanislao bbfdf83267 Update requirements.txt 2024-09-19 00:38:41 +08:00
Kenneth Estanislao 88254c3952 Merge pull request #604 from bkosowski/bugfix/fix_onnxruntime_version
Downgrade onnxruntime version to 1.16.0 to fix requirements installation
2024-09-19 00:33:05 +08:00
bkosowski 069e9b46e6 Downgrade onnxruntime version to 1.16.0 to fix requirements installation 2024-09-18 15:58:50 +02:00
Kenneth Estanislao 80de3dc32e Merge pull request #599 from KRSHH/main
Update README.md
2024-09-17 21:47:44 +08:00
KRSHH 911148cc6b README.md Update
Thanks to all the contributors
2024-09-17 19:03:06 +05:30
KRSHH b229545454 Update README.md
Fix formatting, structure etc.
2024-09-17 18:24:43 +05:30
Kenneth Estanislao 375d4ae620 Update README.md
added KRSHH
2024-09-17 20:27:27 +08:00
Kenneth Estanislao bcfb9f24ea Merge pull request #598 from KRSHH/main
Fixed the Face mapper issue in Live Cam - New UI PR
2024-09-17 20:25:33 +08:00
KRSHH a905d161e5 Add files via upload 2024-09-17 20:25:08 +08:00
KRSHH d78df54721 Fixed the Face Mapper issue on live cam 2024-09-17 20:20:14 +08:00
KRSHH 4067d24c26 Fix Popup Live width 2024-09-17 20:18:59 +08:00
KRSHH 9c22e63d7b Fix Popup Live width 2024-09-17 17:46:14 +05:30
KRSHH 0350f23519 Fixed the Face Mapper issue on live cam 2024-09-17 16:51:28 +05:30
KRSHH d1ec0a17b2 Minor Fixes 2024-09-16 21:58:24 +05:30
KRSHH bd8ed6e7eb Add files via upload 2024-09-16 21:48:13 +05:30
Kenneth Estanislao ea7bbd49fe Revert "Merge pull request #592 from KRSHH/main"
This reverts commit 2f29d323d9.
2024-09-16 23:34:35 +08:00
Kenneth Estanislao 2f29d323d9 Merge pull request #592 from KRSHH/main
Better UI
2024-09-16 23:32:39 +08:00
Kenneth Estanislao c6e00796c8 Merge pull request #588 from KRSHH/main
Enhance UI with drag and drop, modern look using customtkinter, and improved webcam mapping
2024-09-16 23:30:12 +08:00
Kenneth Estanislao 2641f9e344 Merge pull request #594 from KRSHH/main
UI Change
2024-09-16 23:26:29 +08:00
KRSHH 5dd621b2b0 Fixed Typo 2024-09-16 20:47:02 +05:30
KRSHH 05413cc989 Update README.md
For avoiding ToS violation
2024-09-16 20:38:56 +05:30
KRSHH c49d0e0e3c Bug fixes 2024-09-16 20:36:28 +05:30
unknown 88e3274d96 Backk 2024-09-16 20:24:04 +05:30
Kenneth Estanislao 9bf2080ac8 Revert "Merge pull request #588 from KRSHH/main"
This reverts commit 8c6d0134a8, reversing
changes made to 621c3f035e.
2024-09-16 22:18:59 +08:00
Kenneth Estanislao 5ab00388b7 Revert "Merge pull request #592 from KRSHH/main"
This reverts commit 4768488653, reversing
changes made to 8c6d0134a8.
2024-09-16 22:18:53 +08:00
Kenneth Estanislao 4768488653 Merge pull request #592 from KRSHH/main
Better UI
2024-09-16 22:10:42 +08:00
KRSHH 569c9ca25a Resizable Root window 2024-09-16 19:13:54 +05:30
KRSHH c9f8537a15 Switch alignment 2024-09-16 18:53:19 +05:30
KRSHH 2d99e392ff Vertical switches 2024-09-16 18:48:05 +05:30
KRSHH 1725ba95e9 Accurate Average PC Performance GIF 2024-09-16 18:32:29 +05:30
KRSHH abe1e67c0e adding avg pc performance demo 2024-09-16 18:31:18 +05:30
KRSHH 2b9d10f182 Donation button, close option button 2024-09-16 16:54:49 +05:30
K 674f584895 UI Change
Changes in UI
2024-09-16 13:31:20 +05:30
K 325187b513 Fix Text
Font Change, Larger, Bolder
2024-09-16 11:22:38 +05:30
Kenneth Estanislao 8c6d0134a8 Merge pull request #588 from KRSHH/main
Enhance UI with drag and drop, modern look using customtkinter, and improved webcam mapping
2024-09-16 12:21:39 +08:00
K d2f57fa4dd Minor UI Fixes 2024-09-16 01:46:40 +05:30
K 2f2380b98d Delete modules/ui.json 2024-09-16 01:00:03 +05:30
K e5c29749bb UI Redone 2024-09-16 00:37:34 +05:30
K b505ae7b90 Add customtkinter in requirements.txt 2024-09-16 00:33:49 +05:30
CH. Krish 373134cfa1 Add tkinterdnd2 to requirements.txt 2024-09-15 23:02:25 +05:30
CH. Krish 523d80550d Adding Drag and Drop feature to Face Mapper and Source and Target 2024-09-15 23:00:28 +05:30
Kenneth Estanislao 621c3f035e Update README.md
fixed the gumroad link
2024-09-15 19:15:02 +08:00
Vic P. 83529c8ca8 Update README.md 2024-09-15 14:57:31 +07:00
Kenneth Estanislao d38a816b55 Update README.md 2024-09-14 02:17:34 +08:00
Kenneth Estanislao 9fccb069df Update README.md 2024-09-14 02:15:51 +08:00
Kenneth Estanislao 1829d5650b easy installer link 2024-09-14 02:08:33 +08:00
Kenneth Estanislao be36016a69 Update metadata.py 2024-09-14 01:58:34 +08:00
Kenneth Estanislao 26e764c842 Create gumroad.png 2024-09-14 01:56:27 +08:00
Kenneth Estanislao 08b7d56b47 Update README.md 2024-09-13 16:57:46 +08:00
Kenneth Estanislao 969c8796d5 Update README.md 2024-09-13 16:57:09 +08:00
Kenneth Estanislao 0d8fe7f930 Merge branch 'main' of https://github.com/hacksider/Deep-Live-Cam 2024-09-13 16:53:16 +08:00
Kenneth Estanislao 7be92ac3e5 Update face_mapping2.png 2024-09-13 16:52:59 +08:00
Kenneth Estanislao 24414e8d75 Update README.md 2024-09-13 16:40:45 +08:00
Kenneth Estanislao c6309136ad Update README.md 2024-09-13 16:39:34 +08:00
Kenneth Estanislao cec588f1c1 Update README.md
added features
2024-09-13 16:38:47 +08:00
Kenneth Estanislao e899707542 facemapping data
demo data for facemapping
2024-09-13 16:30:44 +08:00
Kenneth Estanislao 336ce2d0d6 Update README.md 2024-09-13 15:49:03 +08:00
Kenneth Estanislao 3f58bdc714 Create resizable.gif 2024-09-13 15:48:47 +08:00
Kenneth Estanislao a2d2f20b5a Update README.md 2024-09-13 14:27:22 +08:00
Kenneth Estanislao 1415493327 Update README.md 2024-09-13 14:16:28 +08:00
Kenneth Estanislao c8851038fa Update README.md 2024-09-13 14:15:51 +08:00
Kenneth Estanislao e74b6ebe42 Update README.md
completed multiple face feature, thanks to @pereiraroland26 for this
2024-09-13 14:12:45 +08:00
Kenneth Estanislao b2fa95e2fc Merge pull request #572 from pereiraroland26/main
Updates to multiple face support (webcam scenario)
2024-09-12 22:27:07 +08:00
Roland Pereira f133d48f60 handled webcam scenario where detected faces are greater than maps provided 2024-09-11 21:42:38 +05:30
Kenneth Estanislao e1a01cfba2 Merge pull request #568 from cyf1r3/main
Update README.md
2024-09-11 13:24:10 +08:00
Anant Singh 06e5e76797 Update README.md
Changed the keyword 'roop' to 'Deep-Live-Cam'.
2024-09-11 10:37:11 +05:30
Kenneth Estanislao 16c1b44927 Revert "recommit webcam option"
This reverts commit 49d3f9a3cc.
2024-09-11 02:49:53 +08:00
Kenneth Estanislao 229375465d Update README.md
added some credits
2024-09-11 00:05:06 +08:00
Kenneth Estanislao 49d3f9a3cc recommit webcam option 2024-09-11 00:02:45 +08:00
Kenneth Estanislao 39238ee80f Merge pull request #566 from pereiraroland26/main
Added support for multiple faces
2024-09-10 23:35:19 +08:00
Roland Pereira d7c6226eb7 updated button widths on popup 2024-09-10 18:53:25 +05:30
Roland Pereira eb140e59c2 commiting gitignore 2024-09-10 16:00:24 +05:30
pereiraroland26 f122006024 updated README.md and created variables for pop dimensions 2024-09-10 14:28:33 +05:30
Roland Pereira 0a144ec57f Merge branch 'hacksider:main' into main 2024-09-10 13:48:40 +05:30
Kenneth Estanislao 9acf77b6ed Revert "Merge pull request #556 from Highpressure/main"
This reverts commit fd07185043, reversing
changes made to f762b61a12.
2024-09-10 14:59:05 +08:00
Kenneth Estanislao fd07185043 Merge pull request #556 from Highpressure/main
multi camera device support
2024-09-10 13:47:43 +08:00
pereiraroland26 da3498c36f Merge branch 'main' of https://github.com/pereiraroland26/Deep-Live-Cam_v2.0 2024-09-10 05:41:46 +05:30
pereiraroland26@gmail.com 53fc65ca7c Added ability to map faces 2024-09-10 05:40:55 +05:30
james 397c84fa8b Added ability to map faces 2024-09-10 04:37:58 +05:30
Highpressure 6381f63722 Update ui.py
option switches went missing in last commit
2024-09-06 21:56:13 +02:00
Highpressure 83ca917c66 Update capturer.py
added change to support multi camera device support as my device 0 is a virtual cam for iphone redirection, device 1 is obs and device 2 is my real camera
2024-09-06 20:59:35 +02:00
Highpressure 2d34201cfc Update ui.py
added dropdown for multi camera device selection
2024-09-06 20:58:38 +02:00
Kenneth Estanislao f762b61a12 Update README.md 2024-09-05 16:09:31 +08:00
Kenneth Estanislao 14625dbfde Update README.md
includes licensing of insightface
2024-09-05 16:01:11 +08:00
Vic P. dc8563372d Update README.md to collapse optional sections for better readability 2024-09-01 01:29:57 +07:00
Vic P. 5dcd30e587 Merge pull request #507 from duhow/patch-1
Update README.md to add an additional model file for the face swapper function
2024-09-01 00:55:36 +07:00
Vic P. e84369862e Update README.md 2024-09-01 00:47:45 +07:00
Vic P. a9f869e491 Merge pull request #510 from underlines/feature/color_space_conversion
Feature/color space conversion
2024-09-01 00:34:46 +07:00
underlines 03fb6bf619 Update readme.md with Windows 11 WSL2 Ubuntu tutorial for Webcams 2024-08-30 23:49:14 +02:00
underlines c91ab8bbd2 add toggle button for blueish cam fix (Force OpenCV2 BGR2RGB) 2024-08-30 22:02:23 +02:00
underlines 79c6615a68 use mjpeg and convert bgr to rgb 2024-08-30 21:49:01 +02:00
David Girón 3c708b0fcb fix model face-swapper 2024-08-30 16:21:57 +02:00
Kenneth Estanislao 3107f74165 Merge pull request #506 from duhow/patch-1
fix: requirements ResolutionImpossible
2024-08-30 19:09:02 +08:00
David Girón 99704f3a18 fix: requirements ResolutionImpossible 2024-08-30 09:07:40 +02:00
Kenneth Estanislao 40598daea9 Merge pull request #455 from barongello/main
Adding a swap faces button to easily swap source/target images
2024-08-27 12:29:55 +08:00
barongello 528c30e3ba Adding a swap faces button to easily swap source/target images 2024-08-25 12:25:19 -03:00
Kenneth Estanislao 446487a70c Update ui.py
Disable NSFW in accordance to github rules
2024-08-24 17:38:49 +08:00
Vic P. 7f95b69bc5 Add TODO to README.md 2024-08-24 00:45:14 +07:00
Kenneth Estanislao 540dad346e Update README.md 2024-08-23 01:56:13 +08:00
Vic P. aa94f2ae7e Merge pull request #429 from vic4key/main
@refer to the PR https://github.com/hacksider/Deep-Live-Cam/pull/293 in the `experimental` branch.
2024-08-22 00:54:10 +07:00
Vic P 3755198ecd Update codes following the comments of @sourcery-ai.
Signed-off-by: Vic P <vic4key@gmail.com>
2024-08-22 00:50:14 +07:00
Vic P 4f62119c2e Support the following options:
- The live camera display as you see it in the front-facing camera frame (like iPhone's Mirror Front Camera).
- The live camera frame is resizable.
Note: These options are turned off by default. Enabling both options may reduce performance by ~2%.

Signed-off-by: Vic P <vic4key@gmail.com>
2024-08-22 00:35:05 +07:00
Vic P. 42b54ef330 Merge pull request #421 from vic4key/main
Re-enabled the NSFW function (turn-off by default) with its bug fixes at PR https://github.com/hacksider/Deep-Live-Cam/pull/237.
2024-08-21 02:22:12 +07:00
Vic P 6d28a52869 Update codes following the comments of @sourcery-ai.
Signed-off-by: Vic P <vic4key@gmail.com>
2024-08-21 02:16:06 +07:00
Vic P 7313a332c8 Re-enabled the NSFW function (turn-off by default).
@refer to the PR #237 in the `experimental` branch.

Signed-off-by: Vic P <vic4key@gmail.com>
2024-08-21 02:02:00 +07:00
Kenneth Estanislao e4b494174d Merge pull request #324 from vietjovi/main
Update README.md to address the issue with the GTK package on MAC OS
2024-08-18 13:47:57 +08:00
Kenneth Estanislao 69d863b44a Revert "Merge remote-tracking branch 'parent/experimental' into experimental"
This reverts commit df99f6ca17.
2024-08-16 21:03:14 +08:00
Kenneth Estanislao d10314c8d6 Revert "Update ui.py"
This reverts commit 9d20e04336.
2024-08-16 21:03:07 +08:00
Kenneth Estanislao 9d20e04336 Update ui.py
Hides NSFW
2024-08-16 20:29:55 +08:00
Aleksandr Spiridonov df99f6ca17 Merge remote-tracking branch 'parent/experimental' into experimental 2024-08-16 20:28:57 +08:00
Kenneth Estanislao 22abb8c25f Revert "Merge pull request #293 from vic4key/experimental"
This reverts commit eab5ba7027.
2024-08-16 13:47:12 +08:00
Kenneth Estanislao eab5ba7027 Merge pull request #293 from vic4key/experimental
To fix bugs and support more options for the Live function (see details in Commits tab)
2024-08-15 14:21:58 +08:00
Viet Nguyen c288d82713 Fix spelling 'package' 2024-08-15 02:36:01 +07:00
Viet Nguyen c8d526157a Update README.md 2024-08-15 02:22:06 +07:00
Kenneth Estanislao 4324b41b9e Update ui.py
hides NSFW button
2024-08-15 03:03:57 +08:00
Kenneth Estanislao a6e00211f0 Merge pull request #321 from gianpaj/stop-live-mode-if-preview-is-closed
Stop live mode when the preview window is closed
2024-08-15 03:01:37 +08:00
Gianfranco Palumbo 99214c7ab1 Stop live mode the preview window is closed 2024-08-14 17:52:42 +02:00
Kenneth Estanislao 080d6f5110 Merge pull request #282 from jasonkneen/main-macos-metal-gpu-optimisation
macOS optimisations for Silicon Macs for GPU / Metal usage (reduced CPU load from 600% to 150%)
2024-08-13 20:30:26 +08:00
Jason Kneen 155546b937 Update .gitignore 2024-08-13 13:23:13 +01:00
Kenneth Estanislao 79fbb7998c Merge pull request #281 from snewell92/patch-1 2024-08-13 20:09:04 +08:00
Sean Newell 5ce2fd298b sourcery update
Grammar updates

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2024-08-13 14:03:05 +02:00
Sean Newell 740410dd73 Strengthen ethical consideration
Nothing we say is legally binding in here, but it
behooves us to be stronger in our language - getting consent
to be digitally reproduced should be required
and standard procedure.
2024-08-13 13:50:02 +02:00
Kenneth Estanislao cbc7c22f1c Create CONTRIBUTING.md 2024-08-13 03:12:58 +08:00
Kenneth Estanislao a31e81fa66 Update README.md
https://www.reddit.com/r/singularity/comments/1eo4sne/comment/lhl7odv/
2024-08-11 21:59:31 +08:00
Kenneth Estanislao e8a8acca9f Update README.md 2024-08-11 21:17:04 +08:00
Kenneth Estanislao a9d4564726 Update README.md
relinking this to the old repo
2024-08-11 21:08:38 +08:00
Kenneth Estanislao fc47cffb18 Update README.md 2024-08-11 16:35:38 +08:00
Kenneth Estanislao fff3009c80 Merge pull request #152 from Saharsha-N/patch-1
Update README.md
2024-08-10 22:08:08 +08:00
Saharsha-N 84c10400b9 Update README.md
Fixed a typo.
2024-08-10 09:55:36 -04:00
Kenneth Estanislao 9f58dfeee1 Merge pull request #140 from rahulbansal16/main
Fix this cyclic dependency issue which was coming while installing rquirements
2024-08-10 20:29:59 +08:00
Rahul Bansal 04e72a85c3 Fix this cyclic dependency issue which was coming while doing the pip install requirements. Now the code is working. You are able to run it on your Windows machine. 2024-08-10 17:43:39 +05:30
Kenneth Estanislao 6a17297e2f Update README.md 2024-08-10 14:19:20 +08:00
Kenneth Estanislao ddd19474da Merge pull request #115 from hacksider/revert-88-main
Revert "Enable to choose a camera device in UI" Will put it on experimental as of this moment
2024-08-10 13:57:37 +08:00
Kenneth Estanislao d49a77b3a3 Revert "Enable to choose a camera device in UI" 2024-08-10 13:54:12 +08:00
42 changed files with 3018 additions and 456 deletions
+26
View File
@@ -0,0 +1,26 @@
***[Remove this]The issue would be closed without notice and be considered spam if the template is not followed.***
**Describe the bug**
A clear and concise description of what the bug is.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Error Message**
`<The error message in terminal>`
**Desktop (please complete the following information):**
- OS: [e.g. Windows]
- Version [e.g. 22]
- GPU
- CPU
**Additional context**
Add any other context about the problem here.
**Confirmation (Mandatory)**
- [ ] I have followed the template
- [ ] This is not a query about how to increase performance
- [ ] I have checked the issues page, and this is not a duplicate
+6 -1
View File
@@ -6,17 +6,22 @@ __pycache__/
.todo
*.log
*.backup
tf_env/
*.png
*.mp4
*.mkv
.tmp/
temp/
.venv/
venv/
env/
workflow/
gfpgan/
models/inswapper_128.onnx
models/GFPGANv1.4.pth
*.onnx
models/DMDNet.pth
faceswap/
.vscode/
switch_states.json
+1
View File
@@ -0,0 +1 @@
3.10.0
+38
View File
@@ -0,0 +1,38 @@
# Collaboration Guidelines and Codebase Quality Standards
To ensure smooth collaboration and maintain the high quality of our codebase, please adhere to the following guidelines:
## Branching Strategy
* **`premain`**:
* Always push your changes to the `premain` branch initially.
* This safeguards the `main` branch from unintentional disruptions.
* All tests will be performed on the `premain` branch.
* Changes will only be merged into `main` after several hours or days of rigorous testing.
* **`experimental`**:
* For large or potentially disruptive changes, use the `experimental` branch.
* This allows for thorough discussion and review before considering a merge into `main`.
## Pre-Pull Request Checklist
Before creating a Pull Request (PR), ensure you have completed the following tests:
### Functionality
* **Realtime Faceswap**:
* Test with face enhancer **enabled** and **disabled**.
* **Map Faces**:
* Test with both options (**enabled** and **disabled**).
* **Camera Listing**:
* Verify that all cameras are listed accurately.
### Stability
* **Realtime FPS**:
* Confirm that there is no drop in real-time frames per second (FPS).
* **Boot Time**:
* Changes should not negatively impact the boot time of either the application or the real-time faceswap feature.
* **GPU Overloading**:
* Test for a minimum of 15 minutes to guarantee no GPU overloading, which could lead to crashes.
* **App Performance**:
* The application should remain responsive and not exhibit any lag.
+225 -83
View File
@@ -1,163 +1,264 @@
![demo-gif](demo.gif)
<h1 align="center">Deep-Live-Cam</h1>
<p align="center">
Real-time face swap and video deepfake with a single click and only a single image.
</p>
<p align="center">
<a href="https://trendshift.io/repositories/11395" target="_blank"><img src="https://trendshift.io/api/badge/repositories/11395" alt="hacksider%2FDeep-Live-Cam | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
</p>
<p align="center">
<img src="media/demo.gif" alt="Demo GIF" width="800">
</p>
## Disclaimer
This deepfake software is designed to be a productive tool for the AI-generated media industry. It can assist artists in animating custom characters, creating engaging content, and even using models for clothing design.
We are aware of the potential for unethical applications and are committed to preventative measures. A built-in check prevents the program from processing inappropriate media (nudity, graphic content, sensitive material like war footage, etc.). We will continue to develop this project responsibly, adhering to the law and ethics. We may shut down the project or add watermarks if legally required.
- Ethical Use: Users are expected to use this software responsibly and legally. If using a real person's face, obtain their consent and clearly label any output as a deepfake when sharing online.
- Content Restrictions: The software includes built-in checks to prevent processing inappropriate media, such as nudity, graphic content, or sensitive material.
- Legal Compliance: We adhere to all relevant laws and ethical guidelines. If legally required, we may shut down the project or add watermarks to the output.
- User Responsibility: We are not responsible for end-user actions. Users must ensure their use of the software aligns with ethical standards and legal requirements.
By using this software, you agree to these terms and commit to using it in a manner that respects the rights and dignity of others.
Users are expected to use this software responsibly and legally. If using a real person's face, obtain their consent and clearly label any output as a deepfake when sharing online. We are not responsible for end-user actions.
## Disclaimer
This software is meant to be a productive contribution to the rapidly growing AI-generated media industry. It will help artists with tasks such as animating a custom character or using the character as a model for clothing etc.
## Quick Start - Pre-built (Windows / Nvidia)
The developers of this software are aware of its possible unethical applications and are committed to take preventative measures against them. It has a built-in check which prevents the program from working on inappropriate media including but not limited to nudity, graphic content, sensitive material such as war footage etc. We will continue to develop this project in the positive direction while adhering to law and ethics. This project may be shut down or include watermarks on the output if requested by law.
<a href="https://hacksider.gumroad.com/l/vccdmm"> <img src="https://github.com/user-attachments/assets/7d993b32-e3e8-4cd3-bbfb-a549152ebdd5" width="285" height="77" />
Users of this software are expected to use this software responsibly while abiding the local law. If face of a real person is being used, users are suggested to get consent from the concerned person and clearly mention that it is a deepfake when posting content online. Developers of this software will not be responsible for actions of end-users.
##### This is the fastest build you can get if you have a discrete NVIDIA GPU.
## How do I install it?
## Quick Start - Pre-built (Mac / Silicon)
<a href="https://krshh.gumroad.com/l/Deep-Live-Cam-Mac"> <img src="https://github.com/user-attachments/assets/d5d913b5-a7de-4609-96b9-979a5749a703" width="285" height="77" />
###### These Pre-builts are perfect for non-technical users or those who dont have time to, or can't manually install all the requirements. Just a heads-up: this is an open-source project, so you can also install it manually.
## TLDR; Live Deepfake in just 3 Clicks
![easysteps](https://github.com/user-attachments/assets/af825228-852c-411b-b787-ffd9aac72fc6)
1. Select a face
2. Select which camera to use
3. Press live!
## Features & Uses - Everything is real-time
### Mouth Mask
**Retain your original mouth for accurate movement using Mouth Mask**
<p align="center">
<img src="media/ludwig.gif" alt="resizable-gif">
</p>
### Face Mapping
**Use different faces on multiple subjects simultaneously**
<p align="center">
<img src="media/streamers.gif" alt="face_mapping_source">
</p>
### Your Movie, Your Face
**Watch movies with any face in real-time**
<p align="center">
<img src="media/movie.gif" alt="movie">
</p>
### Live Show
**Run Live shows and performances**
<p align="center">
<img src="media/live_show.gif" alt="show">
</p>
### Memes
**Create Your most viral meme yet**
<p align="center">
<img src="media/meme.gif" alt="show" width="450">
<br>
<sub>Created using Many Faces feature in Deep-Live-Cam</sub>
</p>
### Basic: It is more likely to work on your computer but it will also be very slow. You can follow instructions for the basic install (This usually runs via **CPU**)
#### 1.Setup your platform
- python (3.10 recommended)
## Installation (Manual)
**Please be aware that the installation requires technical skills and is not for beginners. Consider downloading the prebuilt version.**
<details>
<summary>Click to see the process</summary>
### Installation
This is more likely to work on your computer but will be slower as it utilizes the CPU.
**1. Set up Your Platform**
- Python (3.10 recommended)
- pip
- git
- [ffmpeg](https://www.youtube.com/watch?v=OlNWCpFdVMA)
- [visual studio 2022 runtimes (windows)](https://visualstudio.microsoft.com/visual-cpp-build-tools/)
#### 2. Clone Repository
https://github.com/hacksider/Deep-Live-Cam.git
- [ffmpeg](https://www.youtube.com/watch?v=OlNWCpFdVMA) - ```iex (irm ffmpeg.tc.ht)```
- [Visual Studio 2022 Runtimes (Windows)](https://visualstudio.microsoft.com/visual-cpp-build-tools/)
#### 3. Download Models
**2. Clone the Repository**
1. [GFPGANv1.4](https://huggingface.co/hacksider/deep-live-cam/resolve/main/GFPGANv1.4.pth)
2. [inswapper_128_fp16.onnx](https://huggingface.co/hacksider/deep-live-cam/resolve/main/inswapper_128_fp16.onnx)
Then put those 2 files on the "**models**" folder
#### 4. Install dependency
We highly recommend to work with a `venv` to avoid issues.
```bash
https://github.com/hacksider/Deep-Live-Cam.git
```
**3. Download the Models**
1. [GFPGANv1.4](https://huggingface.co/hacksider/deep-live-cam/resolve/main/GFPGANv1.4.pth)
2. [inswapper\_128\_fp16.onnx](https://huggingface.co/hacksider/deep-live-cam/resolve/main/inswapper_128_fp16.onnx)
Place these files in the "**models**" folder.
**4. Install Dependencies**
We highly recommend using a `venv` to avoid issues.
```bash
pip install -r requirements.txt
```
##### DONE!!! If you dont have any GPU, You should be able to run roop using `python run.py` command. Keep in mind that while running the program for first time, it will download some models which can take time depending on your network connection.
### *Proceed if you want to use GPU Acceleration
### CUDA Execution Provider (Nvidia)*
1. Install [CUDA Toolkit 11.8](https://developer.nvidia.com/cuda-11-8-0-download-archive)
2. Install dependencies:
**For macOS:** Install or upgrade the `python-tk` package:
```bash
brew install python-tk@3.10
```
**Run:** If you don't have a GPU, you can run Deep-Live-Cam using `python run.py`. Note that initial execution will download models (~300MB).
### GPU Acceleration
**CUDA Execution Provider (Nvidia)**
1. Install [CUDA Toolkit 11.8](https://developer.nvidia.com/cuda-11-8-0-download-archive) or [CUDA Toolkit 12.1.1](https://developer.nvidia.com/cuda-12-1-1-download-archive)
2. Install dependencies:
```bash
pip uninstall onnxruntime onnxruntime-gpu
pip install onnxruntime-gpu==1.16.3
```
3. Usage in case the provider is available:
3. Usage:
```
```bash
python run.py --execution-provider cuda
```
### [](https://github.com/s0md3v/roop/wiki/2.-Acceleration#coreml-execution-provider-apple-silicon)CoreML Execution Provider (Apple Silicon)
**CoreML Execution Provider (Apple Silicon)**
1. Install dependencies:
1. Install dependencies:
```
```bash
pip uninstall onnxruntime onnxruntime-silicon
pip install onnxruntime-silicon==1.13.1
```
2. Usage in case the provider is available:
2. Usage:
```
```bash
python run.py --execution-provider coreml
```
### [](https://github.com/s0md3v/roop/wiki/2.-Acceleration#coreml-execution-provider-apple-legacy)CoreML Execution Provider (Apple Legacy)
**CoreML Execution Provider (Apple Legacy)**
1. Install dependencies:
1. Install dependencies:
```
```bash
pip uninstall onnxruntime onnxruntime-coreml
pip install onnxruntime-coreml==1.13.1
```
2. Usage in case the provider is available:
2. Usage:
```
```bash
python run.py --execution-provider coreml
```
### [](https://github.com/s0md3v/roop/wiki/2.-Acceleration#directml-execution-provider-windows)DirectML Execution Provider (Windows)
**DirectML Execution Provider (Windows)**
1. Install dependencies:
1. Install dependencies:
```
```bash
pip uninstall onnxruntime onnxruntime-directml
pip install onnxruntime-directml==1.15.1
```
2. Usage in case the provider is available:
2. Usage:
```
```bash
python run.py --execution-provider directml
```
### [](https://github.com/s0md3v/roop/wiki/2.-Acceleration#openvino-execution-provider-intel)OpenVINO™ Execution Provider (Intel)
**OpenVINO™ Execution Provider (Intel)**
1. Install dependencies:
1. Install dependencies:
```
```bash
pip uninstall onnxruntime onnxruntime-openvino
pip install onnxruntime-openvino==1.15.0
```
2. Usage in case the provider is available:
2. Usage:
```
```bash
python run.py --execution-provider openvino
```
## How do I use it?
> Note: When you run this program for the first time, it will download some models ~300MB in size.
</details>
Executing `python run.py` command will launch this window:
![gui-demo](instruction.png)
## Usage
Choose a face (image with desired face) and the target image/video (image/video in which you want to replace the face) and click on `Start`. Open file explorer and navigate to the directory you select your output to be in. You will find a directory named `<video_title>` where you can see the frames being swapped in realtime. Once the processing is done, it will create the output file. That's it.
**1. Image/Video Mode**
## For the webcam mode
Just follow the clicks on the screenshot
1. Select a face
2. Click live
3. Wait for a few second (it takes a longer time, usually 10 to 30 seconds before the preview shows up)
- Execute `python run.py`.
- Choose a source face image and a target image/video.
- Click "Start".
- The output will be saved in a directory named after the target video.
![demo-gif](demo.gif)
**2. Webcam Mode**
Just use your favorite screencapture to stream like OBS
> Note: In case you want to change your face, just select another picture, the preview mode will then restart (so just wait a bit).
- Execute `python run.py`.
- Select a source face image.
- Click "Live".
- Wait for the preview to appear (10-30 seconds).
- Use a screen capture tool like OBS to stream.
- To change the face, select a new source image.
Additional command line arguments are given below. To learn out what they do, check [this guide](https://github.com/s0md3v/roop/wiki/Advanced-Options).
## Command Line Arguments (Unmaintained)
```
options:
-h, --help show this help message and exit
-s SOURCE_PATH, --source SOURCE_PATH select an source image
-t TARGET_PATH, --target TARGET_PATH select an target image or video
-s SOURCE_PATH, --source SOURCE_PATH select a source image
-t TARGET_PATH, --target TARGET_PATH select a target image or video
-o OUTPUT_PATH, --output OUTPUT_PATH select output file or directory
--frame-processor FRAME_PROCESSOR [FRAME_PROCESSOR ...] frame processors (choices: face_swapper, face_enhancer, ...)
--keep-fps keep original fps
--keep-audio keep original audio
--keep-frames keep temporary frames
--many-faces process every face
--map-faces map source target faces
--mouth-mask mask the mouth region
--video-encoder {libx264,libx265,libvpx-vp9} adjust output video encoder
--video-quality [0-51] adjust output video quality
--live-mirror the live camera display as you see it in the front-facing camera frame
--live-resizable the live camera frame is resizable
--max-memory MAX_MEMORY maximum amount of RAM in GB
--execution-provider {cpu} [{cpu} ...] available execution provider (choices: cpu, ...)
--execution-threads EXECUTION_THREADS number of execution threads
@@ -166,10 +267,51 @@ options:
Looking for a CLI mode? Using the -s/--source argument will make the run program in cli mode.
## Press
**We are always open to criticism and are ready to improve, that's why we didn't cherry-pick anything.**
- [*"Deep-Live-Cam goes viral, allowing anyone to become a digital doppelganger"*](https://arstechnica.com/information-technology/2024/08/new-ai-tool-enables-real-time-face-swapping-on-webcams-raising-fraud-concerns/) - Ars Technica
- [*"Thanks Deep Live Cam, shapeshifters are among us now"*](https://dataconomy.com/2024/08/15/what-is-deep-live-cam-github-deepfake/) - Dataconomy
- [*"This free AI tool lets you become anyone during video-calls"*](https://www.newsbytesapp.com/news/science/deep-live-cam-ai-impersonation-tool-goes-viral/story) - NewsBytes
- [*"OK, this viral AI live stream software is truly terrifying"*](https://www.creativebloq.com/ai/ok-this-viral-ai-live-stream-software-is-truly-terrifying) - Creative Bloq
- [*"Deepfake AI Tool Lets You Become Anyone in a Video Call With Single Photo"*](https://petapixel.com/2024/08/14/deep-live-cam-deepfake-ai-tool-lets-you-become-anyone-in-a-video-call-with-single-photo-mark-zuckerberg-jd-vance-elon-musk/) - PetaPixel
- [*"Deep-Live-Cam Uses AI to Transform Your Face in Real-Time, Celebrities Included"*](https://www.techeblog.com/deep-live-cam-ai-transform-face/) - TechEBlog
- [*"An AI tool that "makes you look like anyone" during a video call is going viral online"*](https://telegrafi.com/en/a-tool-that-makes-you-look-like-anyone-during-a-video-call-is-going-viral-on-the-Internet/) - Telegrafi
- [*"This Deepfake Tool Turning Images Into Livestreams is Topping the GitHub Charts"*](https://decrypt.co/244565/this-deepfake-tool-turning-images-into-livestreams-is-topping-the-github-charts) - Emerge
- [*"New Real-Time Face-Swapping AI Allows Anyone to Mimic Famous Faces"*](https://www.digitalmusicnews.com/2024/08/15/face-swapping-ai-real-time-mimic/) - Digital Music News
- [*"This real-time webcam deepfake tool raises alarms about the future of identity theft"*](https://www.diyphotography.net/this-real-time-webcam-deepfake-tool-raises-alarms-about-the-future-of-identity-theft/) - DIYPhotography
- [*"That's Crazy, Oh God. That's Fucking Freaky Dude... That's So Wild Dude"*](https://www.youtube.com/watch?time_continue=1074&v=py4Tc-Y8BcY) - SomeOrdinaryGamers
- [*"Alright look look look, now look chat, we can do any face we want to look like chat"*](https://www.youtube.com/live/mFsCe7AIxq8?feature=shared&t=2686) - IShowSpeed
## Credits
- [henryruhs](https://github.com/henryruhs): for being an irreplaceable contributor to the project
- [ffmpeg](https://ffmpeg.org/): for making video related operations easy
- [deepinsight](https://github.com/deepinsight): for their [insightface](https://github.com/deepinsight/insightface) project which provided a well-made library and models.
- [havok2-htwo](https://github.com/havok2-htwo) : for sharing the code for webcam
- [GosuDRM](https://github.com/GosuDRM/nsfw-roop) : for uncensoring roop
- and all developers behind libraries used in this project.
- [ffmpeg](https://ffmpeg.org/): for making video-related operations easy
- [deepinsight](https://github.com/deepinsight): for their [insightface](https://github.com/deepinsight/insightface) project which provided a well-made library and models. Please be reminded that the [use of the model is for non-commercial research purposes only](https://github.com/deepinsight/insightface?tab=readme-ov-file#license).
- [havok2-htwo](https://github.com/havok2-htwo): for sharing the code for webcam
- [GosuDRM](https://github.com/GosuDRM): for the open version of roop
- [pereiraroland26](https://github.com/pereiraroland26): Multiple faces support
- [vic4key](https://github.com/vic4key): For supporting/contributing to this project
- [kier007](https://github.com/kier007): for improving the user experience
- [qitianai](https://github.com/qitianai): for multi-lingual support
- and [all developers](https://github.com/hacksider/Deep-Live-Cam/graphs/contributors) behind libraries used in this project.
- Footnote: Please be informed that the base author of the code is [s0md3v](https://github.com/s0md3v/roop)
- All the wonderful users who helped make this project go viral by starring the repo ❤️
[![Stargazers](https://reporoster.com/stars/hacksider/Deep-Live-Cam)](https://github.com/hacksider/Deep-Live-Cam/stargazers)
## Contributions
![Alt](https://repobeats.axiom.co/api/embed/fec8e29c45dfdb9c5916f3a7830e1249308d20e1.svg "Repobeats analytics image")
## Stars to the Moon 🚀
<a href="https://star-history.com/#hacksider/deep-live-cam&Date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=hacksider/deep-live-cam&type=Date&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=hacksider/deep-live-cam&type=Date" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=hacksider/deep-live-cam&type=Date" />
</picture>
</a>
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 MiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

+46
View File
@@ -0,0 +1,46 @@
{
"Source x Target Mapper": "Source x Target Mapper",
"select an source image": "选择一个源图像",
"Preview": "预览",
"select an target image or video": "选择一个目标图像或视频",
"save image output file": "保存图像输出文件",
"save video output file": "保存视频输出文件",
"select an target image": "选择一个目标图像",
"source": "源",
"Select a target": "选择一个目标",
"Select a face": "选择一张脸",
"Keep audio": "保留音频",
"Face Enhancer": "面纹增强器",
"Many faces": "多脸",
"Show FPS": "显示帧率",
"Keep fps": "保持帧率",
"Keep frames": "保持帧数",
"Fix Blueish Cam": "修复偏蓝的摄像头",
"Mouth Mask": "口罩",
"Show Mouth Mask Box": "显示口罩盒",
"Start": "开始",
"Live": "直播",
"Destroy": "结束",
"Map faces": "识别人脸",
"Processing...": "处理中...",
"Processing succeed!": "处理成功!",
"Processing ignored!": "处理被忽略!",
"Failed to start camera": "启动相机失败",
"Please complete pop-up or close it.": "请先完成弹出窗口或者关闭它",
"Getting unique faces": "获取独特面部",
"Please select a source image first": "请先选择一个源图像",
"No faces found in target": "目标图像中没有人脸",
"Add": "添加",
"Clear": "清除",
"Submit": "确认",
"Select source image": "请选取源图像",
"Select target image": "请选取目标图像",
"Please provide mapping!": "请提供映射",
"Atleast 1 source with target is required!": "至少需要一个来源图像与目标图像相关!",
"At least 1 source with target is required!": "至少需要一个来源图像与目标图像相关!",
"Face could not be detected in last upload!": "最近上传的图像中没有检测到人脸!",
"Select Camera:": "选择摄像头",
"All mappings cleared!": "所有映射均已清除!",
"Mappings successfully submitted!": "成功提交映射!",
"Source x Target Mapper is already open.": "源 x 目标映射器已打开。"
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

View File

Before

Width:  |  Height:  |  Size: 11 MiB

After

Width:  |  Height:  |  Size: 11 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 MiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 MiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 MiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 MiB

+4 -1
View File
@@ -1 +1,4 @@
just put the models in this folder
just put the models in this folder -
https://huggingface.co/hacksider/deep-live-cam/resolve/main/inswapper_128_fp16.onnx?download=true
https://github.com/TencentARC/GFPGAN/releases/download/v1.3.4/GFPGANv1.4.pth
+15 -3
View File
@@ -1,16 +1,28 @@
from typing import Any
import cv2
import modules.globals # Import the globals to check the color correction toggle
def get_video_frame(video_path: str, frame_number: int = 0) -> Any:
capture = cv2.VideoCapture(video_path)
# Set MJPEG format to ensure correct color space handling
capture.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*'MJPG'))
# Only force RGB conversion if color correction is enabled
if modules.globals.color_correction:
capture.set(cv2.CAP_PROP_CONVERT_RGB, 1)
frame_total = capture.get(cv2.CAP_PROP_FRAME_COUNT)
capture.set(cv2.CAP_PROP_POS_FRAMES, min(frame_total, frame_number - 1))
has_frame, frame = capture.read()
if has_frame and modules.globals.color_correction:
# Convert the frame color if necessary
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
capture.release()
if has_frame:
return frame
return None
return frame if has_frame else None
def get_video_frame_total(video_path: str) -> int:
+32
View File
@@ -0,0 +1,32 @@
import numpy as np
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
from typing import Any
def find_cluster_centroids(embeddings, max_k=10) -> Any:
inertia = []
cluster_centroids = []
K = range(1, max_k+1)
for k in K:
kmeans = KMeans(n_clusters=k, random_state=0)
kmeans.fit(embeddings)
inertia.append(kmeans.inertia_)
cluster_centroids.append({"k": k, "centroids": kmeans.cluster_centers_})
diffs = [inertia[i] - inertia[i+1] for i in range(len(inertia)-1)]
optimal_centroids = cluster_centroids[diffs.index(max(diffs)) + 1]['centroids']
return optimal_centroids
def find_closest_centroid(centroids: list, normed_face_embedding) -> list:
try:
centroids = np.array(centroids)
normed_face_embedding = np.array(normed_face_embedding)
similarities = np.dot(centroids, normed_face_embedding)
closest_centroid_index = np.argmax(similarities)
return closest_centroid_index, centroids[closest_centroid_index]
except ValueError:
return None
+35 -23
View File
@@ -20,6 +20,7 @@ import modules.metadata
import modules.ui as ui
from modules.processors.frame.core import get_frame_processors_modules
from modules.utilities import has_image_extension, is_image, is_video, detect_fps, create_video, extract_frames, get_temp_frame_paths, restore_audio, create_temp, move_temp, clean_temp, normalize_output_path
from modules.fake_face_handler import cleanup_fake_face
if 'ROCMExecutionProvider' in modules.globals.execution_providers:
del torch
@@ -35,12 +36,16 @@ def parse_args() -> None:
program.add_argument('-t', '--target', help='select an target image or video', dest='target_path')
program.add_argument('-o', '--output', help='select output file or directory', dest='output_path')
program.add_argument('--frame-processor', help='pipeline of frame processors', dest='frame_processor', default=['face_swapper'], choices=['face_swapper', 'face_enhancer'], nargs='+')
program.add_argument('--keep-fps', help='keep original fps', dest='keep_fps', action='store_true', default=False)
program.add_argument('--keep-audio', help='keep original audio', dest='keep_audio', action='store_true', default=True)
program.add_argument('--keep-frames', help='keep temporary frames', dest='keep_frames', action='store_true', default=False)
program.add_argument('--many-faces', help='process every face', dest='many_faces', action='store_true', default=False)
program.add_argument('--nsfw-filter', help='filter the NSFW image or video', dest='nsfw_filter', action='store_true', default=False)
program.add_argument('--map-faces', help='map source target faces', dest='map_faces', action='store_true', default=False)
program.add_argument('--mouth-mask', help='mask the mouth region', dest='mouth_mask', action='store_true', default=False)
program.add_argument('--video-encoder', help='adjust output video encoder', dest='video_encoder', default='libx264', choices=['libx264', 'libx265', 'libvpx-vp9'])
program.add_argument('--video-quality', help='adjust output video quality', dest='video_quality', type=int, default=18, choices=range(52), metavar='[0-51]')
program.add_argument('-l', '--lang', help='Ui language', default="en")
program.add_argument('--live-mirror', help='The live camera display as you see it in the front-facing camera frame', dest='live_mirror', action='store_true', default=False)
program.add_argument('--live-resizable', help='The live camera frame is resizable', dest='live_resizable', action='store_true', default=False)
program.add_argument('--max-memory', help='maximum amount of RAM in GB', dest='max_memory', type=int, default=suggest_max_memory())
program.add_argument('--execution-provider', help='execution provider', dest='execution_provider', default=['cpu'], choices=suggest_execution_providers(), nargs='+')
program.add_argument('--execution-threads', help='number of execution threads', dest='execution_threads', type=int, default=suggest_execution_threads())
@@ -59,23 +64,27 @@ def parse_args() -> None:
modules.globals.output_path = normalize_output_path(modules.globals.source_path, modules.globals.target_path, args.output_path)
modules.globals.frame_processors = args.frame_processor
modules.globals.headless = args.source_path or args.target_path or args.output_path
modules.globals.keep_fps = args.keep_fps
modules.globals.keep_fps = True
modules.globals.keep_frames = True
modules.globals.keep_audio = args.keep_audio
modules.globals.keep_frames = args.keep_frames
modules.globals.many_faces = args.many_faces
modules.globals.mouth_mask = args.mouth_mask
modules.globals.nsfw_filter = args.nsfw_filter
modules.globals.map_faces = args.map_faces
modules.globals.video_encoder = args.video_encoder
modules.globals.video_quality = args.video_quality
modules.globals.live_mirror = args.live_mirror
modules.globals.live_resizable = args.live_resizable
modules.globals.max_memory = args.max_memory
modules.globals.execution_providers = decode_execution_providers(args.execution_provider)
modules.globals.execution_threads = args.execution_threads
modules.globals.lang = args.lang
#for ENHANCER tumbler:
if 'face_enhancer' in args.frame_processor:
modules.globals.fp_ui['face_enhancer'] = True
else:
modules.globals.fp_ui['face_enhancer'] = False
modules.globals.nsfw = False
# translate deprecated args
if args.source_path_deprecated:
@@ -165,18 +174,19 @@ def update_status(message: str, scope: str = 'DLC.CORE') -> None:
if not modules.globals.headless:
ui.update_status(message)
def start() -> None:
for frame_processor in get_frame_processors_modules(modules.globals.frame_processors):
if not frame_processor.pre_start():
return
update_status('Processing...')
# process image to image
if has_image_extension(modules.globals.target_path):
if modules.globals.nsfw == False:
from modules.predicter import predict_image
if predict_image(modules.globals.target_path):
destroy()
shutil.copy2(modules.globals.target_path, modules.globals.output_path)
if modules.globals.nsfw_filter and ui.check_and_ignore_nsfw(modules.globals.target_path, destroy):
return
try:
shutil.copy2(modules.globals.target_path, modules.globals.output_path)
except Exception as e:
print("Error copying file:", str(e))
for frame_processor in get_frame_processors_modules(modules.globals.frame_processors):
update_status('Progressing...', frame_processor.NAME)
frame_processor.process_image(modules.globals.source_path, modules.globals.output_path, modules.globals.output_path)
@@ -187,14 +197,15 @@ def start() -> None:
update_status('Processing to image failed!')
return
# process image to videos
if modules.globals.nsfw == False:
from modules.predicter import predict_video
if predict_video(modules.globals.target_path):
destroy()
update_status('Creating temp resources...')
create_temp(modules.globals.target_path)
update_status('Extracting frames...')
extract_frames(modules.globals.target_path)
if modules.globals.nsfw_filter and ui.check_and_ignore_nsfw(modules.globals.target_path, destroy):
return
if not modules.globals.map_faces:
update_status('Creating temp resources...')
create_temp(modules.globals.target_path)
update_status('Extracting frames...')
extract_frames(modules.globals.target_path)
temp_frame_paths = get_temp_frame_paths(modules.globals.target_path)
for frame_processor in get_frame_processors_modules(modules.globals.frame_processors):
update_status('Progressing...', frame_processor.NAME)
@@ -226,10 +237,11 @@ def start() -> None:
update_status('Processing to video failed!')
def destroy() -> None:
def destroy(to_quit=True) -> None:
if modules.globals.target_path:
clean_temp(modules.globals.target_path)
quit()
cleanup_fake_face()
if to_quit: quit()
def run() -> None:
@@ -243,5 +255,5 @@ def run() -> None:
if modules.globals.headless:
start()
else:
window = ui.init(start, destroy)
window = ui.init(start, destroy, modules.globals.lang)
window.mainloop()
Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

+158
View File
@@ -1,8 +1,16 @@
import os
import shutil
from typing import Any
import insightface
import cv2
import numpy as np
import modules.globals
from tqdm import tqdm
from modules.typing import Frame
from modules.cluster_analysis import find_cluster_centroids, find_closest_centroid
from modules.utilities import get_temp_directory_path, create_temp, extract_frames, clean_temp, get_temp_frame_paths
from pathlib import Path
FACE_ANALYSER = None
@@ -29,3 +37,153 @@ def get_many_faces(frame: Frame) -> Any:
return get_face_analyser().get(frame)
except IndexError:
return None
def has_valid_map() -> bool:
for map in modules.globals.souce_target_map:
if "source" in map and "target" in map:
return True
return False
def default_source_face() -> Any:
for map in modules.globals.souce_target_map:
if "source" in map:
return map['source']['face']
return None
def simplify_maps() -> Any:
centroids = []
faces = []
for map in modules.globals.souce_target_map:
if "source" in map and "target" in map:
centroids.append(map['target']['face'].normed_embedding)
faces.append(map['source']['face'])
modules.globals.simple_map = {'source_faces': faces, 'target_embeddings': centroids}
return None
def add_blank_map() -> Any:
try:
max_id = -1
if len(modules.globals.souce_target_map) > 0:
max_id = max(modules.globals.souce_target_map, key=lambda x: x['id'])['id']
modules.globals.souce_target_map.append({
'id' : max_id + 1
})
except ValueError:
return None
def get_unique_faces_from_target_image() -> Any:
try:
modules.globals.souce_target_map = []
target_frame = cv2.imread(modules.globals.target_path)
many_faces = get_many_faces(target_frame)
i = 0
for face in many_faces:
x_min, y_min, x_max, y_max = face['bbox']
modules.globals.souce_target_map.append({
'id' : i,
'target' : {
'cv2' : target_frame[int(y_min):int(y_max), int(x_min):int(x_max)],
'face' : face
}
})
i = i + 1
except ValueError:
return None
def get_unique_faces_from_target_video() -> Any:
try:
modules.globals.souce_target_map = []
frame_face_embeddings = []
face_embeddings = []
print('Creating temp resources...')
clean_temp(modules.globals.target_path)
create_temp(modules.globals.target_path)
print('Extracting frames...')
extract_frames(modules.globals.target_path)
temp_frame_paths = get_temp_frame_paths(modules.globals.target_path)
i = 0
for temp_frame_path in tqdm(temp_frame_paths, desc="Extracting face embeddings from frames"):
temp_frame = cv2.imread(temp_frame_path)
many_faces = get_many_faces(temp_frame)
for face in many_faces:
face_embeddings.append(face.normed_embedding)
frame_face_embeddings.append({'frame': i, 'faces': many_faces, 'location': temp_frame_path})
i += 1
centroids = find_cluster_centroids(face_embeddings)
for frame in frame_face_embeddings:
for face in frame['faces']:
closest_centroid_index, _ = find_closest_centroid(centroids, face.normed_embedding)
face['target_centroid'] = closest_centroid_index
for i in range(len(centroids)):
modules.globals.souce_target_map.append({
'id' : i
})
temp = []
for frame in tqdm(frame_face_embeddings, desc=f"Mapping frame embeddings to centroids-{i}"):
temp.append({'frame': frame['frame'], 'faces': [face for face in frame['faces'] if face['target_centroid'] == i], 'location': frame['location']})
modules.globals.souce_target_map[i]['target_faces_in_frame'] = temp
# dump_faces(centroids, frame_face_embeddings)
default_target_face()
except ValueError:
return None
def default_target_face():
for map in modules.globals.souce_target_map:
best_face = None
best_frame = None
for frame in map['target_faces_in_frame']:
if len(frame['faces']) > 0:
best_face = frame['faces'][0]
best_frame = frame
break
for frame in map['target_faces_in_frame']:
for face in frame['faces']:
if face['det_score'] > best_face['det_score']:
best_face = face
best_frame = frame
x_min, y_min, x_max, y_max = best_face['bbox']
target_frame = cv2.imread(best_frame['location'])
map['target'] = {
'cv2' : target_frame[int(y_min):int(y_max), int(x_min):int(x_max)],
'face' : best_face
}
def dump_faces(centroids: Any, frame_face_embeddings: list):
temp_directory_path = get_temp_directory_path(modules.globals.target_path)
for i in range(len(centroids)):
if os.path.exists(temp_directory_path + f"/{i}") and os.path.isdir(temp_directory_path + f"/{i}"):
shutil.rmtree(temp_directory_path + f"/{i}")
Path(temp_directory_path + f"/{i}").mkdir(parents=True, exist_ok=True)
for frame in tqdm(frame_face_embeddings, desc=f"Copying faces to temp/./{i}"):
temp_frame = cv2.imread(frame['location'])
j = 0
for face in frame['faces']:
if face['target_centroid'] == i:
x_min, y_min, x_max, y_max = face['bbox']
if temp_frame[int(y_min):int(y_max), int(x_min):int(x_max)].size > 0:
cv2.imwrite(temp_directory_path + f"/{i}/{frame['frame']}_{j}.png", temp_frame[int(y_min):int(y_max), int(x_min):int(x_max)])
j += 1
+120
View File
@@ -0,0 +1,120 @@
import os
import requests
import tempfile
from pathlib import Path
import cv2
import numpy as np
import modules.globals
def add_padding_to_face(image, padding_ratio=0.3):
"""Add padding around the face image
Args:
image: The input face image
padding_ratio: Amount of padding to add as a ratio of image dimensions
Returns:
Padded image with background padding added
"""
if image is None:
return None
height, width = image.shape[:2]
pad_x = int(width * padding_ratio)
pad_y = int(height * padding_ratio)
# Create larger image with padding
padded_height = height + 2 * pad_y
padded_width = width + 2 * pad_x
padded_image = np.zeros((padded_height, padded_width, 3), dtype=np.uint8)
# Fill padded area with blurred and darkened edge pixels
edge_color = cv2.blur(image, (15, 15))
edge_color = (edge_color * 0.6).astype(np.uint8) # Darken the padding
# Fill the padded image with original face
padded_image[pad_y:pad_y+height, pad_x:pad_x+width] = image
# Fill padding areas with edge color
# Top padding - repeat first row
top_edge = edge_color[0, :, :]
for i in range(pad_y):
padded_image[i, pad_x:pad_x+width] = top_edge
# Bottom padding - repeat last row
bottom_edge = edge_color[-1, :, :]
for i in range(pad_y):
padded_image[pad_y+height+i, pad_x:pad_x+width] = bottom_edge
# Left padding - repeat first column
left_edge = edge_color[:, 0, :]
for i in range(pad_x):
padded_image[pad_y:pad_y+height, i] = left_edge
# Right padding - repeat last column
right_edge = edge_color[:, -1, :]
for i in range(pad_x):
padded_image[pad_y:pad_y+height, pad_x+width+i] = right_edge
# Fill corners with nearest edge colors
# Top-left corner
padded_image[:pad_y, :pad_x] = edge_color[0, 0, :]
# Top-right corner
padded_image[:pad_y, pad_x+width:] = edge_color[0, -1, :]
# Bottom-left corner
padded_image[pad_y+height:, :pad_x] = edge_color[-1, 0, :]
# Bottom-right corner
padded_image[pad_y+height:, pad_x+width:] = edge_color[-1, -1, :]
return padded_image
def get_fake_face() -> str:
"""Fetch a face from thispersondoesnotexist.com and save it temporarily"""
try:
# Create temp directory if it doesn't exist
temp_dir = Path(tempfile.gettempdir()) / "deep-live-cam"
temp_dir.mkdir(parents=True, exist_ok=True)
# Generate temp file path
temp_file = temp_dir / "fake_face.jpg"
# Basic headers to mimic a browser request
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
# Fetch the image
response = requests.get('https://thispersondoesnotexist.com', headers=headers)
if response.status_code == 200:
# Read image from response
image_array = np.asarray(bytearray(response.content), dtype=np.uint8)
image = cv2.imdecode(image_array, cv2.IMREAD_COLOR)
# Add padding around the face
padded_image = add_padding_to_face(image)
# Save the padded image
cv2.imwrite(str(temp_file), padded_image)
return str(temp_file)
else:
print(f"Failed to fetch fake face: {response.status_code}")
return None
except Exception as e:
print(f"Error fetching fake face: {str(e)}")
return None
def cleanup_fake_face():
"""Clean up the temporary fake face image"""
try:
if modules.globals.fake_face_path and os.path.exists(modules.globals.fake_face_path):
os.remove(modules.globals.fake_face_path)
modules.globals.fake_face_path = None
except Exception as e:
print(f"Error cleaning up fake face: {str(e)}")
def refresh_fake_face():
"""Refresh the fake face image"""
cleanup_fake_face()
modules.globals.fake_face_path = get_fake_face()
return modules.globals.fake_face_path is not None
+26
View File
@@ -0,0 +1,26 @@
import json
from pathlib import Path
class LanguageManager:
def __init__(self, default_language="en"):
self.current_language = default_language
self.translations = {}
self.load_language(default_language)
def load_language(self, language_code) -> bool:
"""load language file"""
if language_code == "en":
return True
try:
file_path = Path(__file__).parent.parent / f"locales/{language_code}.json"
with open(file_path, "r", encoding="utf-8") as file:
self.translations = json.load(file)
self.current_language = language_code
return True
except FileNotFoundError:
print(f"Language file not found: {language_code}")
return False
def _(self, key, default=None) -> str:
"""get translate text"""
return self.translations.get(key, default if default else key)
+34 -12
View File
@@ -1,30 +1,52 @@
import os
from typing import List, Dict
from typing import List, Dict, Any
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
WORKFLOW_DIR = os.path.join(ROOT_DIR, 'workflow')
WORKFLOW_DIR = os.path.join(ROOT_DIR, "workflow")
file_types = [
('Image', ('*.png','*.jpg','*.jpeg','*.gif','*.bmp')),
('Video', ('*.mp4','*.mkv'))
("Image", ("*.png", "*.jpg", "*.jpeg", "*.gif", "*.bmp")),
("Video", ("*.mp4", "*.mkv")),
]
souce_target_map = []
simple_map = {}
source_path = None
target_path = None
output_path = None
frame_processors: List[str] = []
keep_fps = None
keep_audio = None
keep_frames = None
many_faces = None
keep_fps = True
keep_audio = True
keep_frames = False
many_faces = False
map_faces = False
color_correction = False
nsfw_filter = False
video_encoder = None
video_quality = None
live_mirror = False
live_resizable = True
max_memory = None
execution_providers: List[str] = []
execution_threads = None
headless = None
log_level = 'error'
fp_ui: Dict[str, bool] = {}
nsfw = None
log_level = "error"
fp_ui: Dict[str, bool] = {"face_enhancer": False}
camera_input_combobox = None
webcam_preview_running = False
webcam_preview_running = False
show_fps = False
mouth_mask = False
show_mouth_mask_box = False
mask_feather_ratio = 8
mask_down_size = 0.50
mask_size = 1
mouth_mask_size = 1.0
eyes_mask = False
show_eyes_mask_box = False
eyebrows_mask = False
show_eyebrows_mask_box = False
eyes_mask_size = 1.0
eyebrows_mask_size = 1.0
use_fake_face = False
fake_face_path = None
+3 -3
View File
@@ -1,3 +1,3 @@
name = 'Deep Live Cam'
version = '1.3.0'
edition = 'Portable'
name = 'Deep-Live-Cam'
version = '1.8'
edition = 'GitHub Edition'
+12 -1
View File
@@ -1,16 +1,27 @@
import numpy
import opennsfw2
from PIL import Image
import cv2 # Add OpenCV import
import modules.globals # Import globals to access the color correction toggle
from modules.typing import Frame
MAX_PROBABILITY = 0.85
# Preload the model once for efficiency
model = None
def predict_frame(target_frame: Frame) -> bool:
# Convert the frame to RGB before processing if color correction is enabled
if modules.globals.color_correction:
target_frame = cv2.cvtColor(target_frame, cv2.COLOR_BGR2RGB)
image = Image.fromarray(target_frame)
image = opennsfw2.preprocess_image(image, opennsfw2.Preprocessing.YAHOO)
model = opennsfw2.make_open_nsfw_model()
global model
if model is None:
model = opennsfw2.make_open_nsfw_model()
views = numpy.expand_dims(image, axis=0)
_, probability = model.predict(views)[0]
return probability > MAX_PROBABILITY
+47 -17
View File
@@ -9,23 +9,41 @@ import modules.processors.frame.core
from modules.core import update_status
from modules.face_analyser import get_one_face
from modules.typing import Frame, Face
from modules.utilities import conditional_download, resolve_relative_path, is_image, is_video
import platform
import torch
from modules.utilities import (
conditional_download,
is_image,
is_video,
)
FACE_ENHANCER = None
THREAD_SEMAPHORE = threading.Semaphore()
THREAD_LOCK = threading.Lock()
NAME = 'DLC.FACE-ENHANCER'
NAME = "DLC.FACE-ENHANCER"
abs_dir = os.path.dirname(os.path.abspath(__file__))
models_dir = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(abs_dir))), "models"
)
def pre_check() -> bool:
download_directory_path = resolve_relative_path('..\models')
conditional_download(download_directory_path, ['https://github.com/TencentARC/GFPGAN/releases/download/v1.3.4/GFPGANv1.4.pth'])
download_directory_path = models_dir
conditional_download(
download_directory_path,
[
"https://github.com/TencentARC/GFPGAN/releases/download/v1.3.4/GFPGANv1.4.pth"
],
)
return True
def pre_start() -> bool:
if not is_image(modules.globals.target_path) and not is_video(modules.globals.target_path):
update_status('Select an image or video for target path.', NAME)
if not is_image(modules.globals.target_path) and not is_video(
modules.globals.target_path
):
update_status("Select an image or video for target path.", NAME)
return False
return True
@@ -35,21 +53,24 @@ def get_face_enhancer() -> Any:
with THREAD_LOCK:
if FACE_ENHANCER is None:
if os.name == 'nt':
model_path = resolve_relative_path('..\models\GFPGANv1.4.pth')
# todo: set models path https://github.com/TencentARC/GFPGAN/issues/399
else:
model_path = resolve_relative_path('../models/GFPGANv1.4.pth')
FACE_ENHANCER = gfpgan.GFPGANer(model_path=model_path, upscale=1) # type: ignore[attr-defined]
model_path = os.path.join(models_dir, "GFPGANv1.4.pth")
match platform.system():
case "Darwin": # Mac OS
if torch.backends.mps.is_available():
mps_device = torch.device("mps")
FACE_ENHANCER = gfpgan.GFPGANer(model_path=model_path, upscale=1, device=mps_device) # type: ignore[attr-defined]
else:
FACE_ENHANCER = gfpgan.GFPGANer(model_path=model_path, upscale=1) # type: ignore[attr-defined]
case _: # Other OS
FACE_ENHANCER = gfpgan.GFPGANer(model_path=model_path, upscale=1) # type: ignore[attr-defined]
return FACE_ENHANCER
def enhance_face(temp_frame: Frame) -> Frame:
with THREAD_SEMAPHORE:
_, _, temp_frame = get_face_enhancer().enhance(
temp_frame,
paste_back=True
)
_, _, temp_frame = get_face_enhancer().enhance(temp_frame, paste_back=True)
return temp_frame
@@ -60,7 +81,9 @@ def process_frame(source_face: Face, temp_frame: Frame) -> Frame:
return temp_frame
def process_frames(source_path: str, temp_frame_paths: List[str], progress: Any = None) -> None:
def process_frames(
source_path: str, temp_frame_paths: List[str], progress: Any = None
) -> None:
for temp_frame_path in temp_frame_paths:
temp_frame = cv2.imread(temp_frame_path)
result = process_frame(None, temp_frame)
@@ -77,3 +100,10 @@ def process_image(source_path: str, target_path: str, output_path: str) -> None:
def process_video(source_path: str, temp_frame_paths: List[str]) -> None:
modules.processors.frame.core.process_video(None, temp_frame_paths, process_frames)
def process_frame_v2(temp_frame: Frame) -> Frame:
target_face = get_one_face(temp_frame)
if target_face:
temp_frame = enhance_face(temp_frame)
return temp_frame
+634
View File
@@ -0,0 +1,634 @@
import cv2
import numpy as np
from modules.typing import Face, Frame
import modules.globals
def apply_color_transfer(source, target):
"""
Apply color transfer from target to source image
"""
source = cv2.cvtColor(source, cv2.COLOR_BGR2LAB).astype("float32")
target = cv2.cvtColor(target, cv2.COLOR_BGR2LAB).astype("float32")
source_mean, source_std = cv2.meanStdDev(source)
target_mean, target_std = cv2.meanStdDev(target)
# Reshape mean and std to be broadcastable
source_mean = source_mean.reshape(1, 1, 3)
source_std = source_std.reshape(1, 1, 3)
target_mean = target_mean.reshape(1, 1, 3)
target_std = target_std.reshape(1, 1, 3)
# Perform the color transfer
source = (source - source_mean) * (target_std / source_std) + target_mean
return cv2.cvtColor(np.clip(source, 0, 255).astype("uint8"), cv2.COLOR_LAB2BGR)
def create_face_mask(face: Face, frame: Frame) -> np.ndarray:
mask = np.zeros(frame.shape[:2], dtype=np.uint8)
landmarks = face.landmark_2d_106
if landmarks is not None:
# Convert landmarks to int32
landmarks = landmarks.astype(np.int32)
# Extract facial features
right_side_face = landmarks[0:16]
left_side_face = landmarks[17:32]
right_eye = landmarks[33:42]
right_eye_brow = landmarks[43:51]
left_eye = landmarks[87:96]
left_eye_brow = landmarks[97:105]
# Calculate forehead extension
right_eyebrow_top = np.min(right_eye_brow[:, 1])
left_eyebrow_top = np.min(left_eye_brow[:, 1])
eyebrow_top = min(right_eyebrow_top, left_eyebrow_top)
face_top = np.min([right_side_face[0, 1], left_side_face[-1, 1]])
forehead_height = face_top - eyebrow_top
extended_forehead_height = int(forehead_height * 5.0) # Extend by 50%
# Create forehead points
forehead_left = right_side_face[0].copy()
forehead_right = left_side_face[-1].copy()
forehead_left[1] -= extended_forehead_height
forehead_right[1] -= extended_forehead_height
# Combine all points to create the face outline
face_outline = np.vstack(
[
[forehead_left],
right_side_face,
left_side_face[::-1], # Reverse left side to create a continuous outline
[forehead_right],
]
)
# Calculate padding
padding = int(
np.linalg.norm(right_side_face[0] - left_side_face[-1]) * 0.05
) # 5% of face width
# Create a slightly larger convex hull for padding
hull = cv2.convexHull(face_outline)
hull_padded = []
for point in hull:
x, y = point[0]
center = np.mean(face_outline, axis=0)
direction = np.array([x, y]) - center
direction = direction / np.linalg.norm(direction)
padded_point = np.array([x, y]) + direction * padding
hull_padded.append(padded_point)
hull_padded = np.array(hull_padded, dtype=np.int32)
# Fill the padded convex hull
cv2.fillConvexPoly(mask, hull_padded, 255)
# Smooth the mask edges
mask = cv2.GaussianBlur(mask, (5, 5), 3)
return mask
def create_lower_mouth_mask(
face: Face, frame: Frame
) -> (np.ndarray, np.ndarray, tuple, np.ndarray):
mask = np.zeros(frame.shape[:2], dtype=np.uint8)
mouth_cutout = None
landmarks = face.landmark_2d_106
if landmarks is not None:
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
lower_lip_order = [
65,
66,
62,
70,
69,
18,
19,
20,
21,
22,
23,
24,
0,
8,
7,
6,
5,
4,
3,
2,
65,
]
lower_lip_landmarks = landmarks[lower_lip_order].astype(
np.float32
) # Use float for precise calculations
# Calculate the center of the landmarks
center = np.mean(lower_lip_landmarks, axis=0)
# Expand the landmarks outward using the mouth_mask_size
expansion_factor = (
1 + modules.globals.mask_down_size * modules.globals.mouth_mask_size
) # Adjust expansion based on slider
expanded_landmarks = (lower_lip_landmarks - center) * expansion_factor + center
# Extend the top lip part
toplip_indices = [
20,
0,
1,
2,
3,
4,
5,
] # Indices for landmarks 2, 65, 66, 62, 70, 69, 18
toplip_extension = (
modules.globals.mask_size * modules.globals.mouth_mask_size * 0.5
) # Adjust extension based on slider
for idx in toplip_indices:
direction = expanded_landmarks[idx] - center
direction = direction / np.linalg.norm(direction)
expanded_landmarks[idx] += direction * toplip_extension
# Extend the bottom part (chin area)
chin_indices = [
11,
12,
13,
14,
15,
16,
] # Indices for landmarks 21, 22, 23, 24, 0, 8
chin_extension = 2 * 0.2 # Adjust this factor to control the extension
for idx in chin_indices:
expanded_landmarks[idx][1] += (
expanded_landmarks[idx][1] - center[1]
) * chin_extension
# Convert back to integer coordinates
expanded_landmarks = expanded_landmarks.astype(np.int32)
# Calculate bounding box for the expanded lower mouth
min_x, min_y = np.min(expanded_landmarks, axis=0)
max_x, max_y = np.max(expanded_landmarks, axis=0)
# Add some padding to the bounding box
padding = int((max_x - min_x) * 0.1) # 10% padding
min_x = max(0, min_x - padding)
min_y = max(0, min_y - padding)
max_x = min(frame.shape[1], max_x + padding)
max_y = min(frame.shape[0], max_y + padding)
# Ensure the bounding box dimensions are valid
if max_x <= min_x or max_y <= min_y:
if (max_x - min_x) <= 1:
max_x = min_x + 1
if (max_y - min_y) <= 1:
max_y = min_y + 1
# Create the mask
mask_roi = np.zeros((max_y - min_y, max_x - min_x), dtype=np.uint8)
cv2.fillPoly(mask_roi, [expanded_landmarks - [min_x, min_y]], 255)
# Apply Gaussian blur to soften the mask edges
mask_roi = cv2.GaussianBlur(mask_roi, (15, 15), 5)
# Place the mask ROI in the full-sized mask
mask[min_y:max_y, min_x:max_x] = mask_roi
# Extract the masked area from the frame
mouth_cutout = frame[min_y:max_y, min_x:max_x].copy()
# Return the expanded lower lip polygon in original frame coordinates
lower_lip_polygon = expanded_landmarks
return mask, mouth_cutout, (min_x, min_y, max_x, max_y), lower_lip_polygon
def create_eyes_mask(face: Face, frame: Frame) -> (np.ndarray, np.ndarray, tuple, np.ndarray):
mask = np.zeros(frame.shape[:2], dtype=np.uint8)
eyes_cutout = None
landmarks = face.landmark_2d_106
if landmarks is not None:
# Left eye landmarks (87-96) and right eye landmarks (33-42)
left_eye = landmarks[87:96]
right_eye = landmarks[33:42]
# Calculate centers and dimensions for each eye
left_eye_center = np.mean(left_eye, axis=0).astype(np.int32)
right_eye_center = np.mean(right_eye, axis=0).astype(np.int32)
# Calculate eye dimensions with size adjustment
def get_eye_dimensions(eye_points):
x_coords = eye_points[:, 0]
y_coords = eye_points[:, 1]
width = int((np.max(x_coords) - np.min(x_coords)) * (1 + modules.globals.mask_down_size * modules.globals.eyes_mask_size))
height = int((np.max(y_coords) - np.min(y_coords)) * (1 + modules.globals.mask_down_size * modules.globals.eyes_mask_size))
return width, height
left_width, left_height = get_eye_dimensions(left_eye)
right_width, right_height = get_eye_dimensions(right_eye)
# Add extra padding
padding = int(max(left_width, right_width) * 0.2)
# Calculate bounding box for both eyes
min_x = min(left_eye_center[0] - left_width//2, right_eye_center[0] - right_width//2) - padding
max_x = max(left_eye_center[0] + left_width//2, right_eye_center[0] + right_width//2) + padding
min_y = min(left_eye_center[1] - left_height//2, right_eye_center[1] - right_height//2) - padding
max_y = max(left_eye_center[1] + left_height//2, right_eye_center[1] + right_height//2) + padding
# Ensure coordinates are within frame bounds
min_x = max(0, min_x)
min_y = max(0, min_y)
max_x = min(frame.shape[1], max_x)
max_y = min(frame.shape[0], max_y)
# Create mask for the eyes region
mask_roi = np.zeros((max_y - min_y, max_x - min_x), dtype=np.uint8)
# Draw ellipses for both eyes
left_center = (left_eye_center[0] - min_x, left_eye_center[1] - min_y)
right_center = (right_eye_center[0] - min_x, right_eye_center[1] - min_y)
# Calculate axes lengths (half of width and height)
left_axes = (left_width//2, left_height//2)
right_axes = (right_width//2, right_height//2)
# Draw filled ellipses
cv2.ellipse(mask_roi, left_center, left_axes, 0, 0, 360, 255, -1)
cv2.ellipse(mask_roi, right_center, right_axes, 0, 0, 360, 255, -1)
# Apply Gaussian blur to soften mask edges
mask_roi = cv2.GaussianBlur(mask_roi, (15, 15), 5)
# Place the mask ROI in the full-sized mask
mask[min_y:max_y, min_x:max_x] = mask_roi
# Extract the masked area from the frame
eyes_cutout = frame[min_y:max_y, min_x:max_x].copy()
# Create polygon points for visualization
def create_ellipse_points(center, axes):
t = np.linspace(0, 2*np.pi, 32)
x = center[0] + axes[0] * np.cos(t)
y = center[1] + axes[1] * np.sin(t)
return np.column_stack((x, y)).astype(np.int32)
# Generate points for both ellipses
left_points = create_ellipse_points((left_eye_center[0], left_eye_center[1]), (left_width//2, left_height//2))
right_points = create_ellipse_points((right_eye_center[0], right_eye_center[1]), (right_width//2, right_height//2))
# Combine points for both eyes
eyes_polygon = np.vstack([left_points, right_points])
return mask, eyes_cutout, (min_x, min_y, max_x, max_y), eyes_polygon
def create_curved_eyebrow(points):
if len(points) >= 5:
# Sort points by x-coordinate
sorted_idx = np.argsort(points[:, 0])
sorted_points = points[sorted_idx]
# Calculate dimensions
x_min, y_min = np.min(sorted_points, axis=0)
x_max, y_max = np.max(sorted_points, axis=0)
width = x_max - x_min
height = y_max - y_min
# Create more points for smoother curve
num_points = 50
x = np.linspace(x_min, x_max, num_points)
# Fit quadratic curve through points for more natural arch
coeffs = np.polyfit(sorted_points[:, 0], sorted_points[:, 1], 2)
y = np.polyval(coeffs, x)
# Increased offsets to create more separation
top_offset = height * 0.5 # Increased from 0.3 to shift up more
bottom_offset = height * 0.2 # Increased from 0.1 to shift down more
# Create smooth curves
top_curve = y - top_offset
bottom_curve = y + bottom_offset
# Create curved endpoints with more pronounced taper
end_points = 5
start_x = np.linspace(x[0] - width * 0.15, x[0], end_points) # Increased taper
end_x = np.linspace(x[-1], x[-1] + width * 0.15, end_points) # Increased taper
# Create tapered ends
start_curve = np.column_stack((
start_x,
np.linspace(bottom_curve[0], top_curve[0], end_points)
))
end_curve = np.column_stack((
end_x,
np.linspace(bottom_curve[-1], top_curve[-1], end_points)
))
# Combine all points to form a smooth contour
contour_points = np.vstack([
start_curve,
np.column_stack((x, top_curve)),
end_curve,
np.column_stack((x[::-1], bottom_curve[::-1]))
])
# Add slight padding for better coverage
center = np.mean(contour_points, axis=0)
vectors = contour_points - center
padded_points = center + vectors * 1.2 # Increased padding slightly
return padded_points
return points
def create_eyebrows_mask(face: Face, frame: Frame) -> (np.ndarray, np.ndarray, tuple, np.ndarray):
mask = np.zeros(frame.shape[:2], dtype=np.uint8)
eyebrows_cutout = None
landmarks = face.landmark_2d_106
if landmarks is not None:
# Left eyebrow landmarks (97-105) and right eyebrow landmarks (43-51)
left_eyebrow = landmarks[97:105].astype(np.float32)
right_eyebrow = landmarks[43:51].astype(np.float32)
# Calculate centers and dimensions for each eyebrow
left_center = np.mean(left_eyebrow, axis=0)
right_center = np.mean(right_eyebrow, axis=0)
# Calculate bounding box with padding adjusted by size
all_points = np.vstack([left_eyebrow, right_eyebrow])
padding_factor = modules.globals.eyebrows_mask_size
min_x = np.min(all_points[:, 0]) - 25 * padding_factor
max_x = np.max(all_points[:, 0]) + 25 * padding_factor
min_y = np.min(all_points[:, 1]) - 20 * padding_factor
max_y = np.max(all_points[:, 1]) + 15 * padding_factor
# Ensure coordinates are within frame bounds
min_x = max(0, int(min_x))
min_y = max(0, int(min_y))
max_x = min(frame.shape[1], int(max_x))
max_y = min(frame.shape[0], int(max_y))
# Create mask for the eyebrows region
mask_roi = np.zeros((max_y - min_y, max_x - min_x), dtype=np.uint8)
try:
# Convert points to local coordinates
left_local = left_eyebrow - [min_x, min_y]
right_local = right_eyebrow - [min_x, min_y]
def create_curved_eyebrow(points):
if len(points) >= 5:
# Sort points by x-coordinate
sorted_idx = np.argsort(points[:, 0])
sorted_points = points[sorted_idx]
# Calculate dimensions
x_min, y_min = np.min(sorted_points, axis=0)
x_max, y_max = np.max(sorted_points, axis=0)
width = x_max - x_min
height = y_max - y_min
# Create more points for smoother curve
num_points = 50
x = np.linspace(x_min, x_max, num_points)
# Fit quadratic curve through points for more natural arch
coeffs = np.polyfit(sorted_points[:, 0], sorted_points[:, 1], 2)
y = np.polyval(coeffs, x)
# Increased offsets to create more separation
top_offset = height * 0.5 # Increased from 0.3 to shift up more
bottom_offset = height * 0.2 # Increased from 0.1 to shift down more
# Create smooth curves
top_curve = y - top_offset
bottom_curve = y + bottom_offset
# Create curved endpoints with more pronounced taper
end_points = 5
start_x = np.linspace(x[0] - width * 0.15, x[0], end_points) # Increased taper
end_x = np.linspace(x[-1], x[-1] + width * 0.15, end_points) # Increased taper
# Create tapered ends
start_curve = np.column_stack((
start_x,
np.linspace(bottom_curve[0], top_curve[0], end_points)
))
end_curve = np.column_stack((
end_x,
np.linspace(bottom_curve[-1], top_curve[-1], end_points)
))
# Combine all points to form a smooth contour
contour_points = np.vstack([
start_curve,
np.column_stack((x, top_curve)),
end_curve,
np.column_stack((x[::-1], bottom_curve[::-1]))
])
# Add slight padding for better coverage
center = np.mean(contour_points, axis=0)
vectors = contour_points - center
padded_points = center + vectors * 1.2 # Increased padding slightly
return padded_points
return points
# Generate and draw eyebrow shapes
left_shape = create_curved_eyebrow(left_local)
right_shape = create_curved_eyebrow(right_local)
# Apply multi-stage blurring for natural feathering
# First, strong Gaussian blur for initial softening
mask_roi = cv2.GaussianBlur(mask_roi, (21, 21), 7)
# Second, medium blur for transition areas
mask_roi = cv2.GaussianBlur(mask_roi, (11, 11), 3)
# Finally, light blur for fine details
mask_roi = cv2.GaussianBlur(mask_roi, (5, 5), 1)
# Normalize mask values
mask_roi = cv2.normalize(mask_roi, None, 0, 255, cv2.NORM_MINMAX)
# Place the mask ROI in the full-sized mask
mask[min_y:max_y, min_x:max_x] = mask_roi
# Extract the masked area from the frame
eyebrows_cutout = frame[min_y:max_y, min_x:max_x].copy()
# Combine points for visualization
eyebrows_polygon = np.vstack([
left_shape + [min_x, min_y],
right_shape + [min_x, min_y]
]).astype(np.int32)
except Exception as e:
# Fallback to simple polygons if curve fitting fails
left_local = left_eyebrow - [min_x, min_y]
right_local = right_eyebrow - [min_x, min_y]
cv2.fillPoly(mask_roi, [left_local.astype(np.int32)], 255)
cv2.fillPoly(mask_roi, [right_local.astype(np.int32)], 255)
mask_roi = cv2.GaussianBlur(mask_roi, (21, 21), 7)
mask[min_y:max_y, min_x:max_x] = mask_roi
eyebrows_cutout = frame[min_y:max_y, min_x:max_x].copy()
eyebrows_polygon = np.vstack([left_eyebrow, right_eyebrow]).astype(np.int32)
return mask, eyebrows_cutout, (min_x, min_y, max_x, max_y), eyebrows_polygon
def apply_mask_area(
frame: np.ndarray,
cutout: np.ndarray,
box: tuple,
face_mask: np.ndarray,
polygon: np.ndarray,
) -> np.ndarray:
min_x, min_y, max_x, max_y = box
box_width = max_x - min_x
box_height = max_y - min_y
if (
cutout is None
or box_width is None
or box_height is None
or face_mask is None
or polygon is None
):
return frame
try:
resized_cutout = cv2.resize(cutout, (box_width, box_height))
roi = frame[min_y:max_y, min_x:max_x]
if roi.shape != resized_cutout.shape:
resized_cutout = cv2.resize(
resized_cutout, (roi.shape[1], roi.shape[0])
)
color_corrected_area = apply_color_transfer(resized_cutout, roi)
# Create mask for the area
polygon_mask = np.zeros(roi.shape[:2], dtype=np.uint8)
# Split points for left and right parts if needed
if len(polygon) > 50: # Arbitrary threshold to detect if we have multiple parts
mid_point = len(polygon) // 2
left_points = polygon[:mid_point] - [min_x, min_y]
right_points = polygon[mid_point:] - [min_x, min_y]
cv2.fillPoly(polygon_mask, [left_points], 255)
cv2.fillPoly(polygon_mask, [right_points], 255)
else:
adjusted_polygon = polygon - [min_x, min_y]
cv2.fillPoly(polygon_mask, [adjusted_polygon], 255)
# Apply strong initial feathering
polygon_mask = cv2.GaussianBlur(polygon_mask, (21, 21), 7)
# Apply additional feathering
feather_amount = min(
30,
box_width // modules.globals.mask_feather_ratio,
box_height // modules.globals.mask_feather_ratio,
)
feathered_mask = cv2.GaussianBlur(
polygon_mask.astype(float), (0, 0), feather_amount
)
feathered_mask = feathered_mask / feathered_mask.max()
# Apply additional smoothing to the mask edges
feathered_mask = cv2.GaussianBlur(feathered_mask, (5, 5), 1)
face_mask_roi = face_mask[min_y:max_y, min_x:max_x]
combined_mask = feathered_mask * (face_mask_roi / 255.0)
combined_mask = combined_mask[:, :, np.newaxis]
blended = (
color_corrected_area * combined_mask + roi * (1 - combined_mask)
).astype(np.uint8)
# Apply face mask to blended result
face_mask_3channel = (
np.repeat(face_mask_roi[:, :, np.newaxis], 3, axis=2) / 255.0
)
final_blend = blended * face_mask_3channel + roi * (1 - face_mask_3channel)
frame[min_y:max_y, min_x:max_x] = final_blend.astype(np.uint8)
except Exception as e:
pass
return frame
def draw_mask_visualization(
frame: Frame,
mask_data: tuple,
label: str,
draw_method: str = "polygon"
) -> Frame:
mask, cutout, (min_x, min_y, max_x, max_y), polygon = mask_data
vis_frame = frame.copy()
# Ensure coordinates are within frame bounds
height, width = vis_frame.shape[:2]
min_x, min_y = max(0, min_x), max(0, min_y)
max_x, max_y = min(width, max_x), min(height, max_y)
if draw_method == "ellipse" and len(polygon) > 50: # For eyes
# Split points for left and right parts
mid_point = len(polygon) // 2
left_points = polygon[:mid_point]
right_points = polygon[mid_point:]
try:
# Fit ellipses to points - need at least 5 points
if len(left_points) >= 5 and len(right_points) >= 5:
# Convert points to the correct format for ellipse fitting
left_points = left_points.astype(np.float32)
right_points = right_points.astype(np.float32)
# Fit ellipses
left_ellipse = cv2.fitEllipse(left_points)
right_ellipse = cv2.fitEllipse(right_points)
# Draw the ellipses
cv2.ellipse(vis_frame, left_ellipse, (0, 255, 0), 2)
cv2.ellipse(vis_frame, right_ellipse, (0, 255, 0), 2)
except Exception as e:
# If ellipse fitting fails, draw simple rectangles as fallback
left_rect = cv2.boundingRect(left_points)
right_rect = cv2.boundingRect(right_points)
cv2.rectangle(vis_frame,
(left_rect[0], left_rect[1]),
(left_rect[0] + left_rect[2], left_rect[1] + left_rect[3]),
(0, 255, 0), 2)
cv2.rectangle(vis_frame,
(right_rect[0], right_rect[1]),
(right_rect[0] + right_rect[2], right_rect[1] + right_rect[3]),
(0, 255, 0), 2)
else: # For mouth and eyebrows
# Draw the polygon
if len(polygon) > 50: # If we have multiple parts
mid_point = len(polygon) // 2
left_points = polygon[:mid_point]
right_points = polygon[mid_point:]
cv2.polylines(vis_frame, [left_points], True, (0, 255, 0), 2, cv2.LINE_AA)
cv2.polylines(vis_frame, [right_points], True, (0, 255, 0), 2, cv2.LINE_AA)
else:
cv2.polylines(vis_frame, [polygon], True, (0, 255, 0), 2, cv2.LINE_AA)
# Add label
cv2.putText(
vis_frame,
label,
(min_x, min_y - 10),
cv2.FONT_HERSHEY_SIMPLEX,
0.5,
(255, 255, 255),
1,
)
return vis_frame
+249 -32
View File
@@ -2,34 +2,62 @@ from typing import Any, List
import cv2
import insightface
import threading
import numpy as np
import modules.globals
import modules.processors.frame.core
from modules.core import update_status
from modules.face_analyser import get_one_face, get_many_faces
from modules.face_analyser import get_one_face, get_many_faces, default_source_face
from modules.typing import Face, Frame
from modules.utilities import conditional_download, resolve_relative_path, is_image, is_video
from modules.utilities import (
conditional_download,
is_image,
is_video,
)
from modules.cluster_analysis import find_closest_centroid
from modules.processors.frame.face_masking import (
create_face_mask,
create_lower_mouth_mask,
create_eyes_mask,
create_eyebrows_mask,
apply_mask_area,
draw_mask_visualization
)
import os
FACE_SWAPPER = None
THREAD_LOCK = threading.Lock()
NAME = 'DLC.FACE-SWAPPER'
NAME = "DLC.FACE-SWAPPER"
abs_dir = os.path.dirname(os.path.abspath(__file__))
models_dir = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(abs_dir))), "models"
)
def pre_check() -> bool:
download_directory_path = resolve_relative_path('../models')
conditional_download(download_directory_path, ['https://huggingface.co/hacksider/deep-live-cam/blob/main/inswapper_128_fp16.onnx'])
download_directory_path = abs_dir
conditional_download(
download_directory_path,
[
"https://huggingface.co/hacksider/deep-live-cam/blob/main/inswapper_128_fp16.onnx"
],
)
return True
def pre_start() -> bool:
if not is_image(modules.globals.source_path):
update_status('Select an image for source path.', NAME)
if not modules.globals.map_faces and not is_image(modules.globals.source_path):
update_status("Select an image for source path.", NAME)
return False
elif not get_one_face(cv2.imread(modules.globals.source_path)):
update_status('No face in source path detected.', NAME)
elif not modules.globals.map_faces and not get_one_face(
cv2.imread(modules.globals.source_path)
):
update_status("No face in source path detected.", NAME)
return False
if not is_image(modules.globals.target_path) and not is_video(modules.globals.target_path):
update_status('Select an image or video for target path.', NAME)
if not is_image(modules.globals.target_path) and not is_video(
modules.globals.target_path
):
update_status("Select an image or video for target path.", NAME)
return False
return True
@@ -39,16 +67,86 @@ def get_face_swapper() -> Any:
with THREAD_LOCK:
if FACE_SWAPPER is None:
model_path = resolve_relative_path('../models/inswapper_128_fp16.onnx')
FACE_SWAPPER = insightface.model_zoo.get_model(model_path, providers=modules.globals.execution_providers)
model_path = os.path.join(models_dir, "inswapper_128_fp16.onnx")
FACE_SWAPPER = insightface.model_zoo.get_model(
model_path, providers=modules.globals.execution_providers
)
return FACE_SWAPPER
def swap_face(source_face: Face, target_face: Face, temp_frame: Frame) -> Frame:
return get_face_swapper().get(temp_frame, target_face, source_face, paste_back=True)
face_swapper = get_face_swapper()
# Apply the face swap
swapped_frame = face_swapper.get(
temp_frame, target_face, source_face, paste_back=True
)
# Create face mask for both mouth and eyes masking
face_mask = create_face_mask(target_face, temp_frame)
if modules.globals.mouth_mask:
# Create and apply mouth mask
mouth_mask_data = create_lower_mouth_mask(target_face, temp_frame)
swapped_frame = apply_mask_area(
swapped_frame,
mouth_mask_data[1], # mouth_cutout
mouth_mask_data[2], # mouth_box
face_mask,
mouth_mask_data[3] # mouth_polygon
)
if modules.globals.show_mouth_mask_box:
swapped_frame = draw_mask_visualization(
swapped_frame,
mouth_mask_data,
"Lower Mouth Mask"
)
if modules.globals.eyes_mask:
# Create and apply eyes mask
eyes_mask_data = create_eyes_mask(target_face, temp_frame)
swapped_frame = apply_mask_area(
swapped_frame,
eyes_mask_data[1], # eyes_cutout
eyes_mask_data[2], # eyes_box
face_mask,
eyes_mask_data[3] # eyes_polygon
)
if modules.globals.show_eyes_mask_box:
swapped_frame = draw_mask_visualization(
swapped_frame,
eyes_mask_data,
"Eyes Mask",
draw_method="ellipse"
)
if modules.globals.eyebrows_mask:
# Create and apply eyebrows mask
eyebrows_mask_data = create_eyebrows_mask(target_face, temp_frame)
swapped_frame = apply_mask_area(
swapped_frame,
eyebrows_mask_data[1], # eyebrows_cutout
eyebrows_mask_data[2], # eyebrows_box
face_mask,
eyebrows_mask_data[3] # eyebrows_polygon
)
if modules.globals.show_eyebrows_mask_box:
swapped_frame = draw_mask_visualization(
swapped_frame,
eyebrows_mask_data,
"Eyebrows Mask"
)
return swapped_frame
def process_frame(source_face: Face, temp_frame: Frame) -> Frame:
if modules.globals.color_correction:
temp_frame = cv2.cvtColor(temp_frame, cv2.COLOR_BGR2RGB)
if modules.globals.many_faces:
many_faces = get_many_faces(temp_frame)
if many_faces:
@@ -61,26 +159,145 @@ def process_frame(source_face: Face, temp_frame: Frame) -> Frame:
return temp_frame
def process_frames(source_path: str, temp_frame_paths: List[str], progress: Any = None) -> None:
source_face = get_one_face(cv2.imread(source_path))
for temp_frame_path in temp_frame_paths:
temp_frame = cv2.imread(temp_frame_path)
try:
result = process_frame(source_face, temp_frame)
cv2.imwrite(temp_frame_path, result)
except Exception as exception:
print(exception)
pass
if progress:
progress.update(1)
def process_frame_v2(temp_frame: Frame, temp_frame_path: str = "") -> Frame:
if is_image(modules.globals.target_path):
if modules.globals.many_faces:
source_face = default_source_face()
for map in modules.globals.souce_target_map:
target_face = map["target"]["face"]
temp_frame = swap_face(source_face, target_face, temp_frame)
elif not modules.globals.many_faces:
for map in modules.globals.souce_target_map:
if "source" in map:
source_face = map["source"]["face"]
target_face = map["target"]["face"]
temp_frame = swap_face(source_face, target_face, temp_frame)
elif is_video(modules.globals.target_path):
if modules.globals.many_faces:
source_face = default_source_face()
for map in modules.globals.souce_target_map:
target_frame = [
f
for f in map["target_faces_in_frame"]
if f["location"] == temp_frame_path
]
for frame in target_frame:
for target_face in frame["faces"]:
temp_frame = swap_face(source_face, target_face, temp_frame)
elif not modules.globals.many_faces:
for map in modules.globals.souce_target_map:
if "source" in map:
target_frame = [
f
for f in map["target_faces_in_frame"]
if f["location"] == temp_frame_path
]
source_face = map["source"]["face"]
for frame in target_frame:
for target_face in frame["faces"]:
temp_frame = swap_face(source_face, target_face, temp_frame)
else:
detected_faces = get_many_faces(temp_frame)
if modules.globals.many_faces:
if detected_faces:
source_face = default_source_face()
for target_face in detected_faces:
temp_frame = swap_face(source_face, target_face, temp_frame)
elif not modules.globals.many_faces:
if detected_faces:
if len(detected_faces) <= len(
modules.globals.simple_map["target_embeddings"]
):
for detected_face in detected_faces:
closest_centroid_index, _ = find_closest_centroid(
modules.globals.simple_map["target_embeddings"],
detected_face.normed_embedding,
)
temp_frame = swap_face(
modules.globals.simple_map["source_faces"][
closest_centroid_index
],
detected_face,
temp_frame,
)
else:
detected_faces_centroids = []
for face in detected_faces:
detected_faces_centroids.append(face.normed_embedding)
i = 0
for target_embedding in modules.globals.simple_map[
"target_embeddings"
]:
closest_centroid_index, _ = find_closest_centroid(
detected_faces_centroids, target_embedding
)
temp_frame = swap_face(
modules.globals.simple_map["source_faces"][i],
detected_faces[closest_centroid_index],
temp_frame,
)
i += 1
return temp_frame
def process_frames(
source_path: str, temp_frame_paths: List[str], progress: Any = None
) -> None:
if not modules.globals.map_faces:
source_face = get_one_face(cv2.imread(source_path))
for temp_frame_path in temp_frame_paths:
temp_frame = cv2.imread(temp_frame_path)
try:
result = process_frame(source_face, temp_frame)
cv2.imwrite(temp_frame_path, result)
except Exception as exception:
print(exception)
pass
if progress:
progress.update(1)
else:
for temp_frame_path in temp_frame_paths:
temp_frame = cv2.imread(temp_frame_path)
try:
result = process_frame_v2(temp_frame, temp_frame_path)
cv2.imwrite(temp_frame_path, result)
except Exception as exception:
print(exception)
pass
if progress:
progress.update(1)
def process_image(source_path: str, target_path: str, output_path: str) -> None:
source_face = get_one_face(cv2.imread(source_path))
target_frame = cv2.imread(target_path)
result = process_frame(source_face, target_frame)
cv2.imwrite(output_path, result)
if not modules.globals.map_faces:
source_face = get_one_face(cv2.imread(source_path))
target_frame = cv2.imread(target_path)
result = process_frame(source_face, target_frame)
cv2.imwrite(output_path, result)
else:
if modules.globals.many_faces:
update_status(
"Many faces enabled. Using first source image. Progressing...", NAME
)
target_frame = cv2.imread(output_path)
result = process_frame_v2(target_frame)
cv2.imwrite(output_path, result)
def process_video(source_path: str, temp_frame_paths: List[str]) -> None:
modules.processors.frame.core.process_video(source_path, temp_frame_paths, process_frames)
if modules.globals.map_faces and modules.globals.many_faces:
update_status(
"Many faces enabled. Using first source image. Progressing...", NAME
)
modules.processors.frame.core.process_video(
source_path, temp_frame_paths, process_frames
)
+1117 -118
View File
File diff suppressed because it is too large Load Diff
+87 -19
View File
@@ -12,16 +12,23 @@ from tqdm import tqdm
import modules.globals
TEMP_FILE = 'temp.mp4'
TEMP_DIRECTORY = 'temp'
TEMP_FILE = "temp.mp4"
TEMP_DIRECTORY = "temp"
# monkey patch ssl for mac
if platform.system().lower() == 'darwin':
if platform.system().lower() == "darwin":
ssl._create_default_https_context = ssl._create_unverified_context
def run_ffmpeg(args: List[str]) -> bool:
commands = ['ffmpeg', '-hide_banner', '-hwaccel', 'auto', '-loglevel', modules.globals.log_level]
commands = [
"ffmpeg",
"-hide_banner",
"-hwaccel",
"auto",
"-loglevel",
modules.globals.log_level,
]
commands.extend(args)
try:
subprocess.check_output(commands, stderr=subprocess.STDOUT)
@@ -32,8 +39,19 @@ def run_ffmpeg(args: List[str]) -> bool:
def detect_fps(target_path: str) -> float:
command = ['ffprobe', '-v', 'error', '-select_streams', 'v:0', '-show_entries', 'stream=r_frame_rate', '-of', 'default=noprint_wrappers=1:nokey=1', target_path]
output = subprocess.check_output(command).decode().strip().split('/')
command = [
"ffprobe",
"-v",
"error",
"-select_streams",
"v:0",
"-show_entries",
"stream=r_frame_rate",
"-of",
"default=noprint_wrappers=1:nokey=1",
target_path,
]
output = subprocess.check_output(command).decode().strip().split("/")
try:
numerator, denominator = map(int, output)
return numerator / denominator
@@ -44,25 +62,65 @@ def detect_fps(target_path: str) -> float:
def extract_frames(target_path: str) -> None:
temp_directory_path = get_temp_directory_path(target_path)
run_ffmpeg(['-i', target_path, '-pix_fmt', 'rgb24', os.path.join(temp_directory_path, '%04d.png')])
run_ffmpeg(
[
"-i",
target_path,
"-pix_fmt",
"rgb24",
os.path.join(temp_directory_path, "%04d.png"),
]
)
def create_video(target_path: str, fps: float = 30.0) -> None:
temp_output_path = get_temp_output_path(target_path)
temp_directory_path = get_temp_directory_path(target_path)
run_ffmpeg(['-r', str(fps), '-i', os.path.join(temp_directory_path, '%04d.png'), '-c:v', modules.globals.video_encoder, '-crf', str(modules.globals.video_quality), '-pix_fmt', 'yuv420p', '-vf', 'colorspace=bt709:iall=bt601-6-625:fast=1', '-y', temp_output_path])
run_ffmpeg(
[
"-r",
str(fps),
"-i",
os.path.join(temp_directory_path, "%04d.png"),
"-c:v",
modules.globals.video_encoder,
"-crf",
str(modules.globals.video_quality),
"-pix_fmt",
"yuv420p",
"-vf",
"colorspace=bt709:iall=bt601-6-625:fast=1",
"-y",
temp_output_path,
]
)
def restore_audio(target_path: str, output_path: str) -> None:
temp_output_path = get_temp_output_path(target_path)
done = run_ffmpeg(['-i', temp_output_path, '-i', target_path, '-c:v', 'copy', '-map', '0:v:0', '-map', '1:a:0', '-y', output_path])
done = run_ffmpeg(
[
"-i",
temp_output_path,
"-i",
target_path,
"-c:v",
"copy",
"-map",
"0:v:0",
"-map",
"1:a:0",
"-y",
output_path,
]
)
if not done:
move_temp(target_path, output_path)
def get_temp_frame_paths(target_path: str) -> List[str]:
temp_directory_path = get_temp_directory_path(target_path)
return glob.glob((os.path.join(glob.escape(temp_directory_path), '*.png')))
return glob.glob((os.path.join(glob.escape(temp_directory_path), "*.png")))
def get_temp_directory_path(target_path: str) -> str:
@@ -81,7 +139,9 @@ def normalize_output_path(source_path: str, target_path: str, output_path: str)
source_name, _ = os.path.splitext(os.path.basename(source_path))
target_name, target_extension = os.path.splitext(os.path.basename(target_path))
if os.path.isdir(output_path):
return os.path.join(output_path, source_name + '-' + target_name + target_extension)
return os.path.join(
output_path, source_name + "-" + target_name + target_extension
)
return output_path
@@ -108,20 +168,20 @@ def clean_temp(target_path: str) -> None:
def has_image_extension(image_path: str) -> bool:
return image_path.lower().endswith(('png', 'jpg', 'jpeg'))
return image_path.lower().endswith(("png", "jpg", "jpeg"))
def is_image(image_path: str) -> bool:
if image_path and os.path.isfile(image_path):
mimetype, _ = mimetypes.guess_type(image_path)
return bool(mimetype and mimetype.startswith('image/'))
return bool(mimetype and mimetype.startswith("image/"))
return False
def is_video(video_path: str) -> bool:
if video_path and os.path.isfile(video_path):
mimetype, _ = mimetypes.guess_type(video_path)
return bool(mimetype and mimetype.startswith('video/'))
return bool(mimetype and mimetype.startswith("video/"))
return False
@@ -129,12 +189,20 @@ def conditional_download(download_directory_path: str, urls: List[str]) -> None:
if not os.path.exists(download_directory_path):
os.makedirs(download_directory_path)
for url in urls:
download_file_path = os.path.join(download_directory_path, os.path.basename(url))
download_file_path = os.path.join(
download_directory_path, os.path.basename(url)
)
if not os.path.exists(download_file_path):
request = urllib.request.urlopen(url) # type: ignore[attr-defined]
total = int(request.headers.get('Content-Length', 0))
with tqdm(total=total, desc='Downloading', unit='B', unit_scale=True, unit_divisor=1024) as progress:
urllib.request.urlretrieve(url, download_file_path, reporthook=lambda count, block_size, total_size: progress.update(block_size)) # type: ignore[attr-defined]
request = urllib.request.urlopen(url) # type: ignore[attr-defined]
total = int(request.headers.get("Content-Length", 0))
with tqdm(
total=total,
desc="Downloading",
unit="B",
unit_scale=True,
unit_divisor=1024,
) as progress:
urllib.request.urlretrieve(url, download_file_path, reporthook=lambda count, block_size, total_size: progress.update(block_size)) # type: ignore[attr-defined]
def resolve_relative_path(path: str) -> str:
+94
View File
@@ -0,0 +1,94 @@
import cv2
import numpy as np
from typing import Optional, Tuple, Callable
import platform
import threading
# Only import Windows-specific library if on Windows
if platform.system() == "Windows":
from pygrabber.dshow_graph import FilterGraph
class VideoCapturer:
def __init__(self, device_index: int):
self.device_index = device_index
self.frame_callback = None
self._current_frame = None
self._frame_ready = threading.Event()
self.is_running = False
self.cap = None
# Initialize Windows-specific components if on Windows
if platform.system() == "Windows":
self.graph = FilterGraph()
# Verify device exists
devices = self.graph.get_input_devices()
if self.device_index >= len(devices):
raise ValueError(
f"Invalid device index {device_index}. Available devices: {len(devices)}"
)
def start(self, width: int = 960, height: int = 540, fps: int = 60) -> bool:
"""Initialize and start video capture"""
try:
if platform.system() == "Windows":
# Windows-specific capture methods
capture_methods = [
(self.device_index, cv2.CAP_DSHOW), # Try DirectShow first
(self.device_index, cv2.CAP_ANY), # Then try default backend
(-1, cv2.CAP_ANY), # Try -1 as fallback
(0, cv2.CAP_ANY), # Finally try 0 without specific backend
]
for dev_id, backend in capture_methods:
try:
self.cap = cv2.VideoCapture(dev_id, backend)
if self.cap.isOpened():
break
self.cap.release()
except Exception:
continue
else:
# Unix-like systems (Linux/Mac) capture method
self.cap = cv2.VideoCapture(self.device_index)
if not self.cap or not self.cap.isOpened():
raise RuntimeError("Failed to open camera")
# Configure format
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
self.cap.set(cv2.CAP_PROP_FPS, fps)
self.is_running = True
return True
except Exception as e:
print(f"Failed to start capture: {str(e)}")
if self.cap:
self.cap.release()
return False
def read(self) -> Tuple[bool, Optional[np.ndarray]]:
"""Read a frame from the camera"""
if not self.is_running or self.cap is None:
return False, None
ret, frame = self.cap.read()
if ret:
self._current_frame = frame
if self.frame_callback:
self.frame_callback(frame)
return True, frame
return False, None
def release(self) -> None:
"""Stop capture and release resources"""
if self.is_running and self.cap is not None:
self.cap.release()
self.is_running = False
self.cap = None
def set_frame_callback(self, callback: Callable[[np.ndarray], None]) -> None:
"""Set callback for frame processing"""
self.frame_callback = callback
+7 -6
View File
@@ -1,23 +1,24 @@
--extra-index-url https://download.pytorch.org/whl/cu118
numpy==1.23.5
opencv-python==4.8.1.78
numpy>=1.23.5,<2
opencv-python==4.10.0.84
cv2_enumerate_cameras==1.1.15
onnx==1.16.0
insightface==0.7.3
psutil==5.9.8
tk==0.1.0
customtkinter==5.2.2
pillow==9.5.0
pillow==11.1.0
torch==2.0.1+cu118; sys_platform != 'darwin'
torch==2.0.1; sys_platform == 'darwin'
torchvision==0.15.2+cu118; sys_platform != 'darwin'
torchvision==0.15.2; sys_platform == 'darwin'
onnxruntime==1.18.0; sys_platform == 'darwin' and platform_machine != 'arm64'
onnxruntime-silicon==1.16.3; sys_platform == 'darwin' and platform_machine == 'arm64'
onnxruntime-gpu==1.18.0; sys_platform != 'darwin'
tensorflow==2.13.0rc1; sys_platform == 'darwin'
onnxruntime-gpu==1.16.3; sys_platform != 'darwin'
tensorflow==2.12.1; sys_platform != 'darwin'
opennsfw2==0.10.2
protobuf==4.23.2
tqdm==4.66.4
gfpgan==1.3.8
tkinterdnd2==0.4.2
pygrabber==0.2
+1 -1
View File
@@ -1 +1 @@
python run.py --execution-provider cuda --execution-threads 60 --max-memory 60
python run.py --execution-provider cuda
+1
View File
@@ -0,0 +1 @@
python run.py --execution-provider dml
-1
View File
@@ -1 +0,0 @@
python run.py --execution-provider dml
-13
View File
@@ -1,13 +0,0 @@
@echo off
:: Installing Microsoft Visual C++ Runtime - all versions 1.0.1 if it's not already installed
choco install vcredist-all
:: Installing CUDA if it's not already installed
choco install cuda
:: Inatalling ffmpeg if it's not already installed
choco install ffmpeg
:: Installing Python if it's not already installed
choco install python -y
:: Assuming successful installation, we ensure pip is upgraded
python -m ensurepip --upgrade
:: Use pip to install the packages listed in 'requirements.txt'
pip install -r requirements.txt
-122
View File
@@ -1,122 +0,0 @@
@echo off
setlocal EnableDelayedExpansion
:: 1. Setup your platform
echo Setting up your platform...
:: Python
where python >nul 2>&1
if %ERRORLEVEL% neq 0 (
echo Python is not installed. Please install Python 3.10 or later.
pause
exit /b
)
:: Pip
where pip >nul 2>&1
if %ERRORLEVEL% neq 0 (
echo Pip is not installed. Please install Pip.
pause
exit /b
)
:: Git
where git >nul 2>&1
if %ERRORLEVEL% neq 0 (
echo Git is not installed. Installing Git...
winget install --id Git.Git -e --source winget
)
:: FFMPEG
where ffmpeg >nul 2>&1
if %ERRORLEVEL% neq 0 (
echo FFMPEG is not installed. Installing FFMPEG...
winget install --id Gyan.FFmpeg -e --source winget
)
:: Visual Studio 2022 Runtimes
echo Installing Visual Studio 2022 Runtimes...
winget install --id Microsoft.VC++2015-2022Redist-x64 -e --source winget
:: 2. Clone Repository
if exist Deep-Live-Cam (
echo Deep-Live-Cam directory already exists.
set /p overwrite="Do you want to overwrite? (Y/N): "
if /i "%overwrite%"=="Y" (
rmdir /s /q Deep-Live-Cam
git clone https://github.com/hacksider/Deep-Live-Cam.git
) else (
echo Skipping clone, using existing directory.
)
) else (
git clone https://github.com/hacksider/Deep-Live-Cam.git
)
cd Deep-Live-Cam
:: 3. Download Models
echo Downloading models...
mkdir models
curl -L -o models/GFPGANv1.4.pth https://path.to.model/GFPGANv1.4.pth
curl -L -o models/inswapper_128_fp16.onnx https://path.to.model/inswapper_128_fp16.onnx
:: 4. Install dependencies
echo Creating a virtual environment...
python -m venv venv
call venv\Scripts\activate
echo Installing required Python packages...
pip install --upgrade pip
pip install -r requirements.txt
echo Setup complete. You can now run the application.
:: GPU Acceleration Options
echo.
echo Choose the GPU Acceleration Option if applicable:
echo 1. CUDA (Nvidia)
echo 2. CoreML (Apple Silicon)
echo 3. CoreML (Apple Legacy)
echo 4. DirectML (Windows)
echo 5. OpenVINO (Intel)
echo 6. None
set /p choice="Enter your choice (1-6): "
if "%choice%"=="1" (
echo Installing CUDA dependencies...
pip uninstall -y onnxruntime onnxruntime-gpu
pip install onnxruntime-gpu==1.16.3
set exec_provider="cuda"
) else if "%choice%"=="2" (
echo Installing CoreML (Apple Silicon) dependencies...
pip uninstall -y onnxruntime onnxruntime-silicon
pip install onnxruntime-silicon==1.13.1
set exec_provider="coreml"
) else if "%choice%"=="3" (
echo Installing CoreML (Apple Legacy) dependencies...
pip uninstall -y onnxruntime onnxruntime-coreml
pip install onnxruntime-coreml==1.13.1
set exec_provider="coreml"
) else if "%choice%"=="4" (
echo Installing DirectML dependencies...
pip uninstall -y onnxruntime onnxruntime-directml
pip install onnxruntime-directml==1.15.1
set exec_provider="directml"
) else if "%choice%"=="5" (
echo Installing OpenVINO dependencies...
pip uninstall -y onnxruntime onnxruntime-openvino
pip install onnxruntime-openvino==1.15.0
set exec_provider="openvino"
) else (
echo Skipping GPU acceleration setup.
)
:: Run the application
if defined exec_provider (
echo Running the application with %exec_provider% execution provider...
python run.py --execution-provider %exec_provider%
) else (
echo Running the application...
python run.py
)
pause