Compare commits
No commits in common. "a90c4facc585caf3c928f834d5bd57f4c84ecd0d" and "f9768854565634db03f9ee51a068862276162325" have entirely different histories.
a90c4facc5
...
f976885456
|
|
@ -142,7 +142,6 @@ Just follow the clicks on the screenshot
|
||||||
Just use your favorite screencapture to stream like OBS
|
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).
|
> Note: In case you want to change your face, just select another picture, the preview mode will then restart (so just wait a bit).
|
||||||
|
|
||||||
You can now use the virtual camera output (uses pyvirtualcam) by turning on the `Virtual Cam Output (OBS)` toggle which should output to the OBS Virtual Camera. Note: this may not work on macOS. You will get a preview as before, but now you will also have a virtual camera output which can be used in applications like Zoom.
|
|
||||||
|
|
||||||
Additional command line arguments are given below. To learn out what they do, check [this guide](https://github.com/s0md3v/roop/wiki/Advanced-Options).
|
Additional command line arguments are given below. To learn out what they do, check [this guide](https://github.com/s0md3v/roop/wiki/Advanced-Options).
|
||||||
|
|
||||||
|
|
@ -159,8 +158,6 @@ options:
|
||||||
--many-faces process every face
|
--many-faces process every face
|
||||||
--video-encoder {libx264,libx265,libvpx-vp9} adjust output video encoder
|
--video-encoder {libx264,libx265,libvpx-vp9} adjust output video encoder
|
||||||
--video-quality [0-51] adjust output video quality
|
--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
|
--max-memory MAX_MEMORY maximum amount of RAM in GB
|
||||||
--execution-provider {cpu} [{cpu} ...] available execution provider (choices: cpu, ...)
|
--execution-provider {cpu} [{cpu} ...] available execution provider (choices: cpu, ...)
|
||||||
--execution-threads EXECUTION_THREADS number of execution threads
|
--execution-threads EXECUTION_THREADS number of execution threads
|
||||||
|
|
|
||||||
|
|
@ -60,10 +60,6 @@ def parse_args() -> None:
|
||||||
choices=['libx264', 'libx265', 'libvpx-vp9'])
|
choices=['libx264', 'libx265', 'libvpx-vp9'])
|
||||||
program.add_argument('--video-quality', help='Adjust output video quality', dest='video_quality', type=int, default=18,
|
program.add_argument('--video-quality', help='Adjust output video quality', dest='video_quality', type=int, default=18,
|
||||||
choices=range(52), metavar='[0-51]')
|
choices=range(52), metavar='[0-51]')
|
||||||
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,
|
program.add_argument('--max-memory', help='Maximum amount of RAM in GB', dest='max_memory', type=int,
|
||||||
default=suggest_max_memory())
|
default=suggest_max_memory())
|
||||||
program.add_argument('--execution-provider', help='Execution provider', dest='execution_provider', default=['cpu'],
|
program.add_argument('--execution-provider', help='Execution provider', dest='execution_provider', default=['cpu'],
|
||||||
|
|
@ -93,8 +89,6 @@ def parse_args() -> None:
|
||||||
modules.globals.many_faces = args.many_faces
|
modules.globals.many_faces = args.many_faces
|
||||||
modules.globals.video_encoder = args.video_encoder
|
modules.globals.video_encoder = args.video_encoder
|
||||||
modules.globals.video_quality = args.video_quality
|
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.max_memory = args.max_memory
|
||||||
modules.globals.execution_providers = decode_execution_providers(args.execution_provider)
|
modules.globals.execution_providers = decode_execution_providers(args.execution_provider)
|
||||||
modules.globals.execution_threads = args.execution_threads
|
modules.globals.execution_threads = args.execution_threads
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,6 @@ keep_frames = None
|
||||||
many_faces = None
|
many_faces = None
|
||||||
video_encoder = None
|
video_encoder = None
|
||||||
video_quality = None
|
video_quality = None
|
||||||
live_mirror = None
|
|
||||||
live_resizable = None
|
|
||||||
max_memory = None
|
max_memory = None
|
||||||
execution_providers: List[str] = []
|
execution_providers: List[str] = []
|
||||||
execution_threads = None
|
execution_threads = None
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,6 @@ ROOT_WIDTH = 600
|
||||||
PREVIEW = None
|
PREVIEW = None
|
||||||
PREVIEW_MAX_HEIGHT = 700
|
PREVIEW_MAX_HEIGHT = 700
|
||||||
PREVIEW_MAX_WIDTH = 1200
|
PREVIEW_MAX_WIDTH = 1200
|
||||||
PREVIEW_DEFAULT_WIDTH = 960
|
|
||||||
PREVIEW_DEFAULT_HEIGHT = 540
|
|
||||||
|
|
||||||
RECENT_DIRECTORY_SOURCE = None
|
RECENT_DIRECTORY_SOURCE = None
|
||||||
RECENT_DIRECTORY_TARGET = None
|
RECENT_DIRECTORY_TARGET = None
|
||||||
|
|
@ -44,7 +42,6 @@ status_label = None
|
||||||
|
|
||||||
img_ft, vid_ft = modules.globals.file_types
|
img_ft, vid_ft = modules.globals.file_types
|
||||||
|
|
||||||
camera = None
|
|
||||||
|
|
||||||
def check_camera_permissions():
|
def check_camera_permissions():
|
||||||
"""Check and request camera access permission on macOS."""
|
"""Check and request camera access permission on macOS."""
|
||||||
|
|
@ -187,7 +184,7 @@ def create_preview(parent: ctk.CTk) -> ctk.CTkToplevel:
|
||||||
preview.withdraw()
|
preview.withdraw()
|
||||||
preview.title('Preview')
|
preview.title('Preview')
|
||||||
preview.protocol('WM_DELETE_WINDOW', toggle_preview)
|
preview.protocol('WM_DELETE_WINDOW', toggle_preview)
|
||||||
preview.resizable(width=True, height=True)
|
preview.resizable(width=False, height=False)
|
||||||
|
|
||||||
preview_label = ctk.CTkLabel(preview, text=None)
|
preview_label = ctk.CTkLabel(preview, text=None)
|
||||||
preview_label.pack(fill='both', expand=True)
|
preview_label.pack(fill='both', expand=True)
|
||||||
|
|
@ -284,11 +281,6 @@ def toggle_preview() -> None:
|
||||||
init_preview()
|
init_preview()
|
||||||
update_preview()
|
update_preview()
|
||||||
PREVIEW.deiconify()
|
PREVIEW.deiconify()
|
||||||
global camera
|
|
||||||
if PREVIEW.state() == 'withdrawn':
|
|
||||||
if camera and camera.isOpened():
|
|
||||||
camera.release()
|
|
||||||
camera = None
|
|
||||||
|
|
||||||
|
|
||||||
def init_preview() -> None:
|
def init_preview() -> None:
|
||||||
|
|
@ -318,27 +310,21 @@ def update_preview(frame_number: int = 0) -> None:
|
||||||
image = ctk.CTkImage(image, size=image.size)
|
image = ctk.CTkImage(image, size=image.size)
|
||||||
preview_label.configure(image=image)
|
preview_label.configure(image=image)
|
||||||
|
|
||||||
def webcam_preview_loop(camera: cv2.VideoCapture, source_image: Any, frame_processors: List[ModuleType], virtual_cam: pyvirtualcam.Camera = None) -> bool:
|
def webcam_preview_loop(cap: cv2.VideoCapture, source_image: Any, frame_processors: List[ModuleType], virtual_cam: pyvirtualcam.Camera = None) -> bool:
|
||||||
global preview_label, PREVIEW
|
global preview_label, PREVIEW
|
||||||
|
|
||||||
ret, frame = camera.read()
|
ret, frame = cap.read()
|
||||||
if not ret:
|
if not ret:
|
||||||
update_status(f"Error: Frame not received from camera.")
|
update_status(f"Error: Frame not received from camera.")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
temp_frame = frame.copy()
|
temp_frame = frame.copy()
|
||||||
|
|
||||||
if modules.globals.live_mirror:
|
|
||||||
temp_frame = cv2.flip(temp_frame, 1) # horizontal flipping
|
|
||||||
|
|
||||||
if modules.globals.live_resizable:
|
|
||||||
temp_frame = fit_image_to_size(temp_frame, PREVIEW.winfo_width(), PREVIEW.winfo_height())
|
|
||||||
|
|
||||||
for frame_processor in frame_processors:
|
for frame_processor in frame_processors:
|
||||||
temp_frame = frame_processor.process_frame(source_image, temp_frame)
|
temp_frame = frame_processor.process_frame(source_image, temp_frame)
|
||||||
|
|
||||||
image = Image.fromarray(cv2.cvtColor(temp_frame, cv2.COLOR_BGR2RGB))
|
image = Image.fromarray(cv2.cvtColor(temp_frame, cv2.COLOR_BGR2RGB))
|
||||||
image = ImageOps.contain(image, (temp_frame.shape[1], temp_frame.shape[0]), Image.LANCZOS)
|
image = ImageOps.contain(image, (PREVIEW_MAX_WIDTH, PREVIEW_MAX_HEIGHT), Image.LANCZOS)
|
||||||
image = ctk.CTkImage(image, size=image.size)
|
image = ctk.CTkImage(image, size=image.size)
|
||||||
preview_label.configure(image=image)
|
preview_label.configure(image=image)
|
||||||
if virtual_cam:
|
if virtual_cam:
|
||||||
|
|
@ -351,20 +337,6 @@ def webcam_preview_loop(camera: cv2.VideoCapture, source_image: Any, frame_proce
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def fit_image_to_size(image, width: int, height: int):
|
|
||||||
if width is None and height is None:
|
|
||||||
return image
|
|
||||||
h, w, _ = image.shape
|
|
||||||
ratio_h = 0.0
|
|
||||||
ratio_w = 0.0
|
|
||||||
if width > height:
|
|
||||||
ratio_h = height / h
|
|
||||||
else:
|
|
||||||
ratio_w = width / w
|
|
||||||
ratio = max(ratio_w, ratio_h)
|
|
||||||
new_size = (int(ratio * w), int(ratio * h))
|
|
||||||
return cv2.resize(image, dsize=new_size)
|
|
||||||
|
|
||||||
def webcam_preview(camera_name: str, virtual_cam_output: bool):
|
def webcam_preview(camera_name: str, virtual_cam_output: bool):
|
||||||
if modules.globals.source_path is None:
|
if modules.globals.source_path is None:
|
||||||
return
|
return
|
||||||
|
|
@ -384,21 +356,20 @@ def webcam_preview(camera_name: str, virtual_cam_output: bool):
|
||||||
# Use OpenCV's camera index for cross-platform compatibility
|
# Use OpenCV's camera index for cross-platform compatibility
|
||||||
camera_index = get_camera_index_by_name(camera_name)
|
camera_index = get_camera_index_by_name(camera_name)
|
||||||
|
|
||||||
global camera
|
cap = cv2.VideoCapture(camera_index)
|
||||||
camera = cv2.VideoCapture(camera_index)
|
|
||||||
|
|
||||||
if not camera.isOpened():
|
if not cap.isOpened():
|
||||||
update_status(f"Error: Could not open camera {camera_name}")
|
update_status(f"Error: Could not open camera {camera_name}")
|
||||||
return
|
return
|
||||||
|
|
||||||
camera.set(cv2.CAP_PROP_FRAME_WIDTH, WIDTH)
|
cap.set(cv2.CAP_PROP_FRAME_WIDTH, WIDTH)
|
||||||
camera.set(cv2.CAP_PROP_FRAME_HEIGHT, HEIGHT)
|
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, HEIGHT)
|
||||||
camera.set(cv2.CAP_PROP_FPS, FPS)
|
cap.set(cv2.CAP_PROP_FPS, FPS)
|
||||||
|
|
||||||
PREVIEW_MAX_WIDTH = WIDTH
|
PREVIEW_MAX_WIDTH = WIDTH
|
||||||
PREVIEW_MAX_HEIGHT = HEIGHT
|
PREVIEW_MAX_HEIGHT = HEIGHT
|
||||||
|
|
||||||
preview_label.configure(width=PREVIEW_DEFAULT_WIDTH, height=PREVIEW_DEFAULT_HEIGHT)
|
preview_label.configure(image=None)
|
||||||
PREVIEW.deiconify()
|
PREVIEW.deiconify()
|
||||||
|
|
||||||
frame_processors = get_frame_processors_modules(modules.globals.frame_processors)
|
frame_processors = get_frame_processors_modules(modules.globals.frame_processors)
|
||||||
|
|
@ -409,12 +380,14 @@ def webcam_preview(camera_name: str, virtual_cam_output: bool):
|
||||||
if virtual_cam_output:
|
if virtual_cam_output:
|
||||||
with pyvirtualcam.Camera(width=WIDTH, height=HEIGHT, fps=FPS, fmt=pyvirtualcam.PixelFormat.BGR) as virtual_cam:
|
with pyvirtualcam.Camera(width=WIDTH, height=HEIGHT, fps=FPS, fmt=pyvirtualcam.PixelFormat.BGR) as virtual_cam:
|
||||||
while preview_running:
|
while preview_running:
|
||||||
preview_running = webcam_preview_loop(camera, source_image, frame_processors, virtual_cam)
|
preview_running = webcam_preview_loop(cap, source_image, frame_processors, virtual_cam)
|
||||||
|
|
||||||
while preview_running:
|
while preview_running:
|
||||||
preview_running = webcam_preview_loop(camera, source_image, frame_processors)
|
preview_running = webcam_preview_loop(cap, source_image, frame_processors)
|
||||||
|
|
||||||
if camera: camera.release()
|
|
||||||
|
|
||||||
|
cap.release()
|
||||||
PREVIEW.withdraw()
|
PREVIEW.withdraw()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -447,19 +420,8 @@ def get_available_cameras():
|
||||||
elif device.deviceType() == "AVCaptureDeviceTypeContinuityCamera":
|
elif device.deviceType() == "AVCaptureDeviceTypeContinuityCamera":
|
||||||
print(f"Skipping Continuity Camera: {device.localizedName()}")
|
print(f"Skipping Continuity Camera: {device.localizedName()}")
|
||||||
elif platform.system() == 'Windows' or platform.system() == 'Linux':
|
elif platform.system() == 'Windows' or platform.system() == 'Linux':
|
||||||
try:
|
|
||||||
devices = FilterGraph().get_input_devices()
|
|
||||||
except Exception as e:
|
|
||||||
# Use OpenCV to detect camera indexes
|
# Use OpenCV to detect camera indexes
|
||||||
index = 0
|
devices = FilterGraph().get_input_devices()
|
||||||
devices = []
|
|
||||||
while True:
|
|
||||||
cap = cv2.VideoCapture(index)
|
|
||||||
if not cap.isOpened():
|
|
||||||
break
|
|
||||||
devices.append(f"Camera {index}")
|
|
||||||
cap.release()
|
|
||||||
index += 1
|
|
||||||
|
|
||||||
available_cameras = devices
|
available_cameras = devices
|
||||||
return available_cameras
|
return available_cameras
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue