Compare commits

...

27 Commits

Author SHA1 Message Date
rehanbgmi e9f0006702
Merge 5db23597e9 into 9086072b8e 2025-06-24 21:41:03 +02:00
google-labs-jules[bot] 5db23597e9 fix: More robust handling of feathered_mask normalization
This commit provides a more robust fix for the RuntimeWarning
(invalid value encountered in divide/cast) that could occur in
the `apply_mouth_area` function within
`modules/processors/frame/face_swapper.py`.

The previous check for `feathered_mask.max() == 0` was not
sufficient for all floating point edge cases.

The updated logic now:
- Checks if `feathered_mask.max()` is less than a small epsilon (1e-6).
- If true, it logs a warning and explicitly sets `feathered_mask`
  to an all-zero `uint8` array of the correct shape.
- Otherwise, it proceeds with the normalization and casting to `uint8`.

This ensures that division by zero or by extremely small numbers is
prevented, and the `feathered_mask` is always in a valid state for
subsequent blending operations.
2025-06-23 20:45:41 +00:00
google-labs-jules[bot] 84ae5810bf Fix issues 2025-06-23 20:38:28 +00:00
google-labs-jules[bot] ebc30b1cac fix: Address code review feedback from previous PR
This commit implements changes based on the code review feedback
for the recent face swap enhancement features.

Key changes include:

1.  **Error Handling for Color Transfer:**
    *   Wrapped the `apply_color_transfer` call in `swap_face` (within `face_swapper.py`) in a try-except block. If color transfer fails, an error is logged, and the system falls back to using the uncorrected swapped face ROI, preventing pipeline crashes.

2.  **GaussianBlur Kernel Size Validation:**
    *   Added validation logic in `face_swapper.py` for `mouth_mask_blur_kernel_size` and `face_mask_blur_kernel_size`.
    *   A helper function `_validate_kernel_size` ensures that kernel dimensions are positive odd integers. If invalid values are provided via global settings, a warning is logged, and the functions fall back to safe default kernel sizes (e.g., (9,9) for mouth, (5,5) for face).

3.  **Configurable GFPGAN Upscale Factor:**
    *   The `upscale` factor for `GFPGANer` in `face_enhancer.py` is now configurable via `getattr(modules.globals, 'gfpgan_upscale_factor', 2)`, allowing you to adjust this parameter.

4.  **Clarification on Mouth Mask Blur Default:**
    *   Added a comment in `face_swapper.py` explaining that the new default `(9,9)` for `mouth_mask_blur_kernel_size` is a deliberate performance/quality trade-off and that this setting is configurable.

These changes improve the robustness, configurability, and clarity of the recently added features.
2025-06-23 18:02:56 +00:00
Kenneth Estanislao 9086072b8e
Update README.md 2025-06-23 17:06:34 +08:00
KRSHH 12fda0a3ed
fix formatting 2025-06-17 18:42:36 +05:30
KRSHH d963430854
Add techlinked link 2025-06-17 18:42:10 +05:30
KRSHH 5855d15c09
Removed outdated links 2025-06-17 18:35:24 +05:30
KRSHH fcc73d0add
Update Download Button 2025-06-16 14:37:41 +05:30
KRSHH 8d4a386a27
Upgrade prebuilt to 2.1 2025-06-15 22:19:49 +05:30
Chittimalla Krish b98c5234d8
Revert 8bdc14a 2025-06-15 20:08:43 +05:30
Chittimalla Krish 8bdc14a789
Update prebuilt version 2025-06-15 17:50:38 +05:30
Kenneth Estanislao f121083bc8
Update README.md
RTX 50xx support
2025-06-15 02:22:00 +08:00
Kenneth Estanislao 745d449ca6
Update README.md
support for RTX 50xx
2025-06-09 00:34:26 +08:00
Kenneth Estanislao ec6d7d2995
Merge pull request #1327 from zjy-dev/fix/add-cudnn-installation-docs
docs: add cuDNN installation guidance for CUDA
2025-06-01 12:05:04 +08:00
zjy-dev e791f2f18a docs: add cuDNN installation guidance for CUDA 2025-06-01 00:40:29 +08:00
KRSHH 3795e41fd7
Merge pull request #1307 from Neurofix/main
ADD locale ko.json
2025-05-28 08:09:02 +05:30
KRSHH ab8a1c82c1
Merge pull request #1310 from Jocund96/main
Add Russian locale file: ru.json
2025-05-26 02:34:03 +05:30
Jasurbek Odilov e1842ae0ba
Merge pull request #1 from Jocund96/Jocund96-patch-1
Add locale Russian
2025-05-25 21:28:57 +02:00
Jasurbek Odilov 989106e914
Add files via upload 2025-05-25 21:28:07 +02:00
Neurofix de27fb8a81
Create ko.json
Add korean
2025-05-25 14:49:54 +09:00
KRSHH 28109e93bb
Merge pull request #1297 from j-hewett/main
Add Spanish translation
2025-05-21 21:44:03 +05:30
Jonah Hewett fc312516e3
Add Spanish translation 2025-05-21 16:35:37 +01:00
Chou Chamnan 72049f3e91
Add khmer translation (#1291)
* Add khmer language

* Fix khmer language

---------

Co-authored-by: Chamnan dev
2025-05-18 23:03:53 +05:30
inwchamp1337 6cb5de01f8
Added a Thai translation (#1284)
* Added a Thai translation

* Update th.json
2025-05-18 23:03:19 +05:30
KRSHH 0bcf340217
Merge pull request #1281 from Giovannapls/add/pt-br-translate
[Added] pt br translate
2025-05-18 23:01:00 +05:30
Giovanna 994a63c546 [Added] pt br translate 2025-05-14 19:24:13 -03:00
11 changed files with 348 additions and 37 deletions

View File

@ -30,13 +30,13 @@ By using this software, you agree to these terms and commit to using it in a man
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. 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.
## Exclusive v2.0 Quick Start - Pre-built (Windows) ## Exclusive v2.1 Quick Start - Pre-built (Windows/Mac Silicon)
<a href="https://deeplivecam.net/index.php/quickstart"> <img src="media/Download.png" width="285" height="77" /> <a href="https://deeplivecam.net/index.php/quickstart"> <img src="media/Download.png" width="285" height="77" />
##### This is the fastest build you can get if you have a discrete NVIDIA or AMD GPU. ##### This is the fastest build you can get if you have a discrete NVIDIA or AMD GPU or Mac Silicon, And you'll receive special priority support.
###### These Pre-builts are perfect for non-technical users or those who don't 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. This will be 60 days ahead on the open source version. ###### These Pre-builts are perfect for non-technical users or those who don't 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 ## TLDR; Live Deepfake in just 3 Clicks
![easysteps](https://github.com/user-attachments/assets/af825228-852c-411b-b787-ffd9aac72fc6) ![easysteps](https://github.com/user-attachments/assets/af825228-852c-411b-b787-ffd9aac72fc6)
@ -187,12 +187,16 @@ pip install -r requirements.txt
**CUDA Execution Provider (Nvidia)** **CUDA Execution Provider (Nvidia)**
1. Install [CUDA Toolkit 11.8.0](https://developer.nvidia.com/cuda-11-8-0-download-archive) 1. Install [CUDA Toolkit 12.8.0](https://developer.nvidia.com/cuda-12-8-0-download-archive)
2. Install dependencies: 2. Install [cuDNN v8.9.7 for CUDA 12.x](https://developer.nvidia.com/rdp/cudnn-archive) (required for onnxruntime-gpu):
- Download cuDNN v8.9.7 for CUDA 12.x
- Make sure the cuDNN bin directory is in your system PATH
3. Install dependencies:
```bash ```bash
pip install -U torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu128
pip uninstall onnxruntime onnxruntime-gpu pip uninstall onnxruntime onnxruntime-gpu
pip install onnxruntime-gpu==1.16.3 pip install onnxruntime-gpu==1.21.0
``` ```
3. Usage: 3. Usage:
@ -300,19 +304,6 @@ python run.py --execution-provider openvino
- Use a screen capture tool like OBS to stream. - Use a screen capture tool like OBS to stream.
- To change the face, select a new source image. - To change the face, select a new source image.
## Tips and Tricks
Check out these helpful guides to get the most out of Deep-Live-Cam:
- [Unlocking the Secrets to the Perfect Deepfake Image](https://deeplivecam.net/index.php/blog/tips-and-tricks/unlocking-the-secrets-to-the-perfect-deepfake-image) - Learn how to create the best deepfake with full head coverage
- [Video Call with DeepLiveCam](https://deeplivecam.net/index.php/blog/tips-and-tricks/video-call-with-deeplivecam) - Make your meetings livelier by using DeepLiveCam with OBS and meeting software
- [Have a Special Guest!](https://deeplivecam.net/index.php/blog/tips-and-tricks/have-a-special-guest) - Tutorial on how to use face mapping to add special guests to your stream
- [Watch Deepfake Movies in Realtime](https://deeplivecam.net/index.php/blog/tips-and-tricks/watch-deepfake-movies-in-realtime) - See yourself star in any video without processing the video
- [Better Quality without Sacrificing Speed](https://deeplivecam.net/index.php/blog/tips-and-tricks/better-quality-without-sacrificing-speed) - Tips for achieving better results without impacting performance
- [Instant Vtuber!](https://deeplivecam.net/index.php/blog/tips-and-tricks/instant-vtuber) - Create a new persona/vtuber easily using Metahuman Creator
Visit our [official blog](https://deeplivecam.net/index.php/blog/tips-and-tricks) for more tips and tutorials.
## Command Line Arguments (Unmaintained) ## Command Line Arguments (Unmaintained)
``` ```
@ -356,6 +347,8 @@ Looking for a CLI mode? Using the -s/--source argument will make the run program
- [*"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 - [*"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 - [*"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 - [*"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
- [*"They do a pretty good job matching poses, expression and even the lighting"*](https://www.youtube.com/watch?v=wnCghLjqv3s&t=551s) - TechLinked (LTT)
## Credits ## Credits

46
locales/es.json 100644
View File

@ -0,0 +1,46 @@
{
"Source x Target Mapper": "Mapeador de fuente x destino",
"select a source image": "Seleccionar imagen fuente",
"Preview": "Vista previa",
"select a target image or video": "elegir un video o una imagen fuente",
"save image output file": "guardar imagen final",
"save video output file": "guardar video final",
"select a target image": "elegir una imagen objetiva",
"source": "fuente",
"Select a target": "Elegir un destino",
"Select a face": "Elegir una cara",
"Keep audio": "Mantener audio original",
"Face Enhancer": "Potenciador de caras",
"Many faces": "Varias caras",
"Show FPS": "Mostrar fps",
"Keep fps": "Mantener fps",
"Keep frames": "Mantener frames",
"Fix Blueish Cam": "Corregir tono azul de video",
"Mouth Mask": "Máscara de boca",
"Show Mouth Mask Box": "Mostrar área de la máscara de boca",
"Start": "Iniciar",
"Live": "En vivo",
"Destroy": "Borrar",
"Map faces": "Mapear caras",
"Processing...": "Procesando...",
"Processing succeed!": "¡Proceso terminado con éxito!",
"Processing ignored!": "¡Procesamiento omitido!",
"Failed to start camera": "No se pudo iniciar la cámara",
"Please complete pop-up or close it.": "Complete o cierre el pop-up",
"Getting unique faces": "Buscando caras únicas",
"Please select a source image first": "Primero, seleccione una imagen fuente",
"No faces found in target": "No se encontró una cara en el destino",
"Add": "Agregar",
"Clear": "Limpiar",
"Submit": "Enviar",
"Select source image": "Seleccionar imagen fuente",
"Select target image": "Seleccionar imagen destino",
"Please provide mapping!": "Por favor, proporcione un mapeo",
"At least 1 source with target is required!": "Se requiere al menos una fuente con un destino.",
"At least 1 source with target is required!": "Se requiere al menos una fuente con un destino.",
"Face could not be detected in last upload!": "¡No se pudo encontrar una cara en el último video o imagen!",
"Select Camera:": "Elegir cámara:",
"All mappings cleared!": "¡Todos los mapeos fueron borrados!",
"Mappings successfully submitted!": "Mapeos enviados con éxito!",
"Source x Target Mapper is already open.": "El mapeador de fuente x destino ya está abierto."
}

45
locales/km.json 100644
View File

@ -0,0 +1,45 @@
{
"Source x Target Mapper": "ប្រភប x បន្ថែម Mapper",
"select a source image": "ជ្រើសរើសប្រភពរូបភាព",
"Preview": "បង្ហាញ",
"select a target image or video": "ជ្រើសរើសគោលដៅរូបភាពឬវីដេអូ",
"save image output file": "រក្សាទុកលទ្ធផលឯកសាររូបភាព",
"save video output file": "រក្សាទុកលទ្ធផលឯកសារវីដេអូ",
"select a target image": "ជ្រើសរើសគោលដៅរូបភាព",
"source": "ប្រភព",
"Select a target": "ជ្រើសរើសគោលដៅ",
"Select a face": "ជ្រើសរើសមុខ",
"Keep audio": "រម្លងសម្លេង",
"Face Enhancer": "ឧបករណ៍ពង្រឹងមុខ",
"Many faces": "ទម្រង់មុខច្រើន",
"Show FPS": "បង្ហាញ FPS",
"Keep fps": "រម្លង fps",
"Keep frames": "រម្លងទម្រង់",
"Fix Blueish Cam": "ជួសជុល Cam Blueish",
"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!": "សូមផ្ដល់នៅផែនទី",
"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 Target Mapper បានបើករួចហើយ។"
}

45
locales/ko.json 100644
View File

@ -0,0 +1,45 @@
{
"Source x Target Mapper": "소스 x 타겟 매퍼",
"select a source image": "소스 이미지 선택",
"Preview": "미리보기",
"select a target image or video": "타겟 이미지 또는 영상 선택",
"save image output file": "이미지 출력 파일 저장",
"save video output file": "영상 출력 파일 저장",
"select a target image": "타겟 이미지 선택",
"source": "소스",
"Select a target": "타겟 선택",
"Select a face": "얼굴 선택",
"Keep audio": "오디오 유지",
"Face Enhancer": "얼굴 향상",
"Many faces": "여러 얼굴",
"Show FPS": "FPS 표시",
"Keep fps": "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!": "매핑을 입력해주세요!",
"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 타겟 매퍼가 이미 열려 있습니다."
}

46
locales/pt-br.json 100644
View File

@ -0,0 +1,46 @@
{
"Source x Target Mapper": "Mapeador de Origem x Destino",
"select an source image": "Escolha uma imagem de origem",
"Preview": "Prévia",
"select an target image or video": "Escolha uma imagem ou vídeo de destino",
"save image output file": "Salvar imagem final",
"save video output file": "Salvar vídeo final",
"select an target image": "Escolha uma imagem de destino",
"source": "Origem",
"Select a target": "Escolha o destino",
"Select a face": "Escolha um rosto",
"Keep audio": "Manter o áudio original",
"Face Enhancer": "Melhorar rosto",
"Many faces": "Vários rostos",
"Show FPS": "Mostrar FPS",
"Keep fps": "Manter FPS",
"Keep frames": "Manter frames",
"Fix Blueish Cam": "Corrigir tom azulado da câmera",
"Mouth Mask": "Máscara da boca",
"Show Mouth Mask Box": "Mostrar área da máscara da boca",
"Start": "Começar",
"Live": "Ao vivo",
"Destroy": "Destruir",
"Map faces": "Mapear rostos",
"Processing...": "Processando...",
"Processing succeed!": "Tudo certo!",
"Processing ignored!": "Processamento ignorado!",
"Failed to start camera": "Não foi possível iniciar a câmera",
"Please complete pop-up or close it.": "Finalize ou feche o pop-up",
"Getting unique faces": "Buscando rostos diferentes",
"Please select a source image first": "Selecione primeiro uma imagem de origem",
"No faces found in target": "Nenhum rosto encontrado na imagem de destino",
"Add": "Adicionar",
"Clear": "Limpar",
"Submit": "Enviar",
"Select source image": "Escolha a imagem de origem",
"Select target image": "Escolha a imagem de destino",
"Please provide mapping!": "Você precisa realizar o mapeamento!",
"Atleast 1 source with target is required!": "É necessária pelo menos uma origem com um destino!",
"At least 1 source with target is required!": "É necessária pelo menos uma origem com um destino!",
"Face could not be detected in last upload!": "Não conseguimos detectar o rosto na última imagem!",
"Select Camera:": "Escolher câmera:",
"All mappings cleared!": "Todos os mapeamentos foram removidos!",
"Mappings successfully submitted!": "Mapeamentos enviados com sucesso!",
"Source x Target Mapper is already open.": "O Mapeador de Origem x Destino já está aberto."
}

45
locales/ru.json 100644
View File

@ -0,0 +1,45 @@
{
"Source x Target Mapper": "Сопоставитель Источник x Цель",
"select a source image": "выберите исходное изображение",
"Preview": "Предпросмотр",
"select a target image or video": "выберите целевое изображение или видео",
"save image output file": "сохранить выходной файл изображения",
"save video output file": "сохранить выходной файл видео",
"select a target image": "выберите целевое изображение",
"source": "источник",
"Select a target": "Выберите целевое изображение",
"Select a face": "Выберите лицо",
"Keep audio": "Сохранить аудио",
"Face Enhancer": "Улучшение лица",
"Many faces": "Несколько лиц",
"Show FPS": "Показать FPS",
"Keep fps": "Сохранить 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!": "Пожалуйста, укажите сопоставление!",
"At least 1 source with target is required!": "Требуется хотя бы 1 источник с целью!",
"Face could not be detected in last upload!": "Лицо не обнаружено в последнем загруженном изображении!",
"Select Camera:": "Выберите камеру:",
"All mappings cleared!": "Все сопоставления очищены!",
"Mappings successfully submitted!": "Сопоставления успешно отправлены!",
"Source x Target Mapper is already open.": "Сопоставитель Источник-Цель уже открыт."
}

45
locales/th.json 100644
View File

@ -0,0 +1,45 @@
{
"Source x Target Mapper": "ตัวจับคู่ต้นทาง x ปลายทาง",
"select a source image": "เลือกรูปภาพต้นฉบับ",
"Preview": "ตัวอย่าง",
"select a target image or video": "เลือกรูปภาพหรือวิดีโอเป้าหมาย",
"save image output file": "บันทึกไฟล์รูปภาพ",
"save video output file": "บันทึกไฟล์วิดีโอ",
"select a target image": "เลือกรูปภาพเป้าหมาย",
"source": "ต้นฉบับ",
"Select a target": "เลือกเป้าหมาย",
"Select a face": "เลือกใบหน้า",
"Keep audio": "เก็บเสียง",
"Face Enhancer": "ปรับปรุงใบหน้า",
"Many faces": "หลายใบหน้า",
"Show FPS": "แสดง FPS",
"Keep fps": "คงค่า 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!": "โปรดระบุการจับคู่!",
"At least 1 source with target is required!": "ต้องมีการจับคู่ต้นฉบับกับเป้าหมายอย่างน้อย 1 คู่!",
"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.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

@ -2,6 +2,7 @@ import os
import shutil import shutil
from typing import Any from typing import Any
import insightface import insightface
import logging # Added logging import
import cv2 import cv2
import numpy as np import numpy as np
@ -25,18 +26,27 @@ def get_face_analyser() -> Any:
def get_one_face(frame: Frame) -> Any: def get_one_face(frame: Frame) -> Any:
face = get_face_analyser().get(frame) faces = get_face_analyser().get(frame)
if not faces:
logging.debug("Face_analyser: get_one_face: No faces found by insightface.")
return None
try: try:
return min(face, key=lambda x: x.bbox[0]) return min(faces, key=lambda x: x.bbox[0])
except ValueError: except ValueError:
logging.debug("Face_analyser: get_one_face: ValueError, likely no faces after all.")
return None return None
def get_many_faces(frame: Frame) -> Any: def get_many_faces(frame: Frame) -> Any:
try: faces = get_face_analyser().get(frame)
return get_face_analyser().get(frame) if not faces: # Check if faces is None or an empty list
except IndexError: logging.debug("Face_analyser: get_many_faces: No faces found by insightface.")
return None # Depending on what insightface returns for no faces,
# you might return None or an empty list.
# If .get() returns an empty list for no faces, this check is sufficient.
# If .get() returns None, this is also fine.
return faces # Return original (None or empty list)
return faces
def has_valid_map() -> bool: def has_valid_map() -> bool:
for map in modules.globals.source_target_map: for map in modules.globals.source_target_map:

View File

@ -82,7 +82,8 @@ def get_face_enhancer() -> Any:
selected_device = torch.device("cpu") selected_device = torch.device("cpu")
device_priority.append("CPU") device_priority.append("CPU")
FACE_ENHANCER = gfpgan.GFPGANer(model_path=model_path, upscale=2, device=selected_device) upscale_factor = getattr(modules.globals, 'gfpgan_upscale_factor', 2)
FACE_ENHANCER = gfpgan.GFPGANer(model_path=model_path, upscale=upscale_factor, device=selected_device)
# for debug: # for debug:
print(f"Selected device: {selected_device} and device priority: {device_priority}") print(f"Selected device: {selected_device} and device priority: {device_priority}")

View File

@ -21,6 +21,16 @@ FACE_SWAPPER = None
THREAD_LOCK = threading.Lock() THREAD_LOCK = threading.Lock()
NAME = "DLC.FACE-SWAPPER" NAME = "DLC.FACE-SWAPPER"
def _validate_kernel_size(kernel_tuple, default_kernel_tuple):
if isinstance(kernel_tuple, tuple) and len(kernel_tuple) == 2 and \
isinstance(kernel_tuple[0], int) and kernel_tuple[0] > 0 and kernel_tuple[0] % 2 == 1 and \
isinstance(kernel_tuple[1], int) and kernel_tuple[1] > 0 and kernel_tuple[1] % 2 == 1:
return kernel_tuple
else:
logging.warning(f"Invalid kernel size {kernel_tuple} received. Must be a tuple of two positive odd integers. Falling back to default {default_kernel_tuple}.")
return default_kernel_tuple
abs_dir = os.path.dirname(os.path.abspath(__file__)) abs_dir = os.path.dirname(os.path.abspath(__file__))
models_dir = os.path.join( models_dir = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(abs_dir))), "models" os.path.dirname(os.path.dirname(os.path.dirname(abs_dir))), "models"
@ -83,8 +93,12 @@ def swap_face(source_face: Face, target_face: Face, temp_frame: Frame) -> Frame:
if original_target_face_roi.size > 0: if original_target_face_roi.size > 0:
swapped_face_roi = swapped_frame[y1:y2, x1:x2].copy() swapped_face_roi = swapped_frame[y1:y2, x1:x2].copy()
if swapped_face_roi.size > 0: if swapped_face_roi.size > 0:
corrected_swapped_face_roi = apply_color_transfer(swapped_face_roi, original_target_face_roi) try:
swapped_frame[y1:y2, x1:x2] = corrected_swapped_face_roi corrected_swapped_face_roi = apply_color_transfer(swapped_face_roi, original_target_face_roi)
swapped_frame[y1:y2, x1:x2] = corrected_swapped_face_roi
except Exception as e:
logging.error(f"Failed to apply statistical color transfer: {e}. Using original swapped ROI.")
# swapped_frame already contains the uncorrected swapped_face_roi in this region
else: else:
# Apply the face swap without statistical color correction # Apply the face swap without statistical color correction
swapped_frame = face_swapper.get( swapped_frame = face_swapper.get(
@ -122,16 +136,26 @@ def process_frame(source_face: Face, temp_frame: Frame) -> Frame:
many_faces = get_many_faces(temp_frame) many_faces = get_many_faces(temp_frame)
if many_faces: if many_faces:
for target_face in many_faces: for target_face in many_faces:
if source_face and target_face: if source_face and target_face: # target_face from many_faces will always be valid here
temp_frame = swap_face(source_face, target_face, temp_frame) temp_frame = swap_face(source_face, target_face, temp_frame)
else: elif not source_face: # Check source_face specifically
print("Face detection failed for target/source.") logging.error("Source face is not available or no face detected in source image. Skipping swap for this target face.")
# Optionally `continue` or `break` if source_face is essential for all
elif not source_face : # if many_faces is empty AND source_face is also an issue
logging.error("Source face is not available AND no faces detected in target frame.")
else: # many_faces is empty, but source_face is ok
logging.info(f"No faces detected in the current target frame for 'many_faces' mode.")
else: else:
target_face = get_one_face(temp_frame) target_face = get_one_face(temp_frame)
if target_face and source_face: if target_face and source_face:
temp_frame = swap_face(source_face, target_face, temp_frame) temp_frame = swap_face(source_face, target_face, temp_frame)
else: else:
logging.error("Face detection failed for target or source.") if not source_face:
logging.error("Source face is not available or no face detected in source image.")
elif not target_face:
logging.error(f"No face detected in the current target frame.")
else: # Should not happen if logic is right, but as a fallback
logging.error("Face detection failed for an unknown reason concerning target or source.")
return temp_frame return temp_frame
@ -383,8 +407,12 @@ def create_lower_mouth_mask(
cv2.fillPoly(mask_roi, [expanded_landmarks - [min_x, min_y]], 255) cv2.fillPoly(mask_roi, [expanded_landmarks - [min_x, min_y]], 255)
# Apply Gaussian blur to soften the mask edges # Apply Gaussian blur to soften the mask edges
kernel_size_mouth = getattr(modules.globals, 'mouth_mask_blur_kernel_size', (9, 9)) # Default kernel size for mouth mask blur is (9,9) as a balance between performance and smoothing.
mask_roi = cv2.GaussianBlur(mask_roi, kernel_size_mouth, 0) # Larger values (e.g., (15,15) - the previous hardcoded value) provide more smoothing but are slower.
# This is configurable via modules.globals.mouth_mask_blur_kernel_size.
kernel_size_mouth_config = getattr(modules.globals, 'mouth_mask_blur_kernel_size', (9, 9))
valid_kernel_mouth = _validate_kernel_size(kernel_size_mouth_config, (9, 9))
mask_roi = cv2.GaussianBlur(mask_roi, valid_kernel_mouth, 0)
# Place the mask ROI in the full-sized mask # Place the mask ROI in the full-sized mask
mask[min_y:max_y, min_x:max_x] = mask_roi mask[min_y:max_y, min_x:max_x] = mask_roi
@ -525,7 +553,13 @@ def apply_mouth_area(
feathered_mask = cv2.GaussianBlur( feathered_mask = cv2.GaussianBlur(
polygon_mask.astype(float), (0, 0), feather_amount polygon_mask.astype(float), (0, 0), feather_amount
) )
feathered_mask = feathered_mask / feathered_mask.max()
mask_max_value = feathered_mask.max()
if mask_max_value < 1e-6: # Check if max is effectively zero
logging.warning("Mouth mask's feathered_mask is all zeros or near-zeros after blur. Resulting mask will be black.")
feathered_mask = np.zeros_like(polygon_mask, dtype=np.uint8)
else:
feathered_mask = (feathered_mask / mask_max_value * 255).astype(np.uint8)
face_mask_roi = face_mask[min_y:max_y, min_x:max_x] face_mask_roi = face_mask[min_y:max_y, min_x:max_x]
combined_mask = feathered_mask * (face_mask_roi / 255.0) combined_mask = feathered_mask * (face_mask_roi / 255.0)
@ -613,8 +647,9 @@ def create_face_mask(face: Face, frame: Frame) -> np.ndarray:
cv2.fillConvexPoly(mask, hull_padded, 255) cv2.fillConvexPoly(mask, hull_padded, 255)
# Smooth the mask edges # Smooth the mask edges
kernel_size_face = getattr(modules.globals, 'face_mask_blur_kernel_size', (5, 5)) kernel_size_face_config = getattr(modules.globals, 'face_mask_blur_kernel_size', (5, 5))
mask = cv2.GaussianBlur(mask, kernel_size_face, 0) valid_kernel_face = _validate_kernel_size(kernel_size_face_config, (5, 5))
mask = cv2.GaussianBlur(mask, valid_kernel_face, 0)
return mask return mask