如何使用 Python为你的在线会议创建一个假的摄像头

目录
  • 创建一个简单的假网络摄像头
  • 添加不同的模式
  • 优化过渡
  • 语音检测
  • 如何使用假网络摄像头

想象一下。你正在参加在线会议,出于某种原因,你并不想打开摄像头。但是如果你看到其他人都打开了,你觉得你也得打开,所以迅速整理自己的头发,确保衣着整洁,然后不情愿地打开相机。我们都经历过这种情况。

有一个好消息。在 Python 的帮助下,不再强制开启摄像头。将向你展示如何为你的在线会议创建一个假的摄像头,如下所示:

当然,这张脸不一定是比尔盖茨的,它也可以是你自己。

现在将向你展示如何在 Python 中编写代码。在文章的最后,将解释如何为自己使用这个假的摄像头。

创建一个简单的假网络摄像头

首先,我们将导入一些模块,尤其是 openCV。

import cv2
import numpy as np
import pickle
import pyaudio
import struct
import math
import argparse
import os

接下来我们将创建一个函数来从视频中提取所有帧:

def read_frames(file, video_folder):
    frames = []
    cap = cv2.VideoCapture(os.path.join('videos', video_folder, file))
    frame_rate = cap.get(cv2.CAP_PROP_FPS)
    if not cap.isOpened():
        print("Error opening video file")
    while cap.isOpened():
        ret, frame = cap.read()
        if ret:
            frames.append(frame)
        else:
            break
    cap.release()
    return frames, frame_rate

现在我们有了框架,我们可以创建一个循环,一个接一个地显示它们。当到达最后一帧时,我们向后播放视频,然后当我们到达第一帧时,我们将向前播放,我们将永远重复这个过程。这样就不会出现从最后一帧到第一帧的突然过渡。我们也会这样做,以便我们可以按“q”停止网络摄像头。

frames, frame_rate = read_frames('normal.mov', 'bill_gates')

def next_frame_index(i, reverse):
    if i == len(frames) - 1:
        reverse = True
    if i == 0:
        reverse = False
    if not reverse:
        i += 1
    else:
        i -= 1
    return i, reverse
rev = False
i = 0
while True:
    frame = frames[i]
    cv2.imshow('Webcam', frame)
    pressed_key = cv2.waitKey(int(1000/frame_rate)) & 0xFF
    if pressed_key == ord("q"):
        break
    i, rev = next_frame_index(i, mode, rev)

有了这个,我们就有了一个可以无缝播放的简单网络摄像头。

但我们并不止步于此。

添加不同的模式

如果我们的假网络摄像头头像可以做的不仅仅是被动地凝视,那将更有说服力。例如,有时在开会时,你需要点头表示同意、微笑、交谈或做其他事情。

所以我们希望我们的网络摄像头有多种“模式”,我们可以随时通过按下键盘上的一个键来切换。

为此,你需要为每种模式录制一个简短的录音,例如你只是微笑的录音。然后我们可以从每个视频中读取帧,并将它们存储在字典中。当我们检测到按键(例如,“s”切换到“微笑模式”)时,我们将活动模式更改为新模式并开始播放相应视频中的帧。

video_files = [file for file in os.listdir(os.path.join('videos', folder))
               if file not in ['transitions_dict.p', '.DS_Store']]
frames, frame_rates = {}, {}

for file in video_files:
    mode_name = file.split('.')[0]
    frames[mode_name], frame_rates[mode_name] = read_frames(file, folder)
modes = list(frames.keys())
commands = {mode[0]: mode for mode in modes if mode != 'normal'}

mode = "normal"
frame_rate = frame_rates[mode]
rev = False
i = 0
while True:
    frame = frames[mode][i]
    cv2.imshow('Webcam', frame)
    pressed_key = cv2.waitKey(int(1000/frame_rate)) & 0xFF
    if pressed_key == ord("q"):
        break
    for command, new_mode in commands.items():
        if pressed_key == ord(command):
            i, mode, frame_rate = change_mode(mode, new_mode, i)
    i, rev = next_frame_index(i, mode, rev)

默认情况下,这样做是为了切换到指定模式,键盘命令是模式名称的第一个字母。现在我把这个'change_mode'函数作为一个黑盒子,稍后会解释它。

优化过渡

所以我们想从一个视频切换到另一个,比如说从正常模式到点头模式。如何以最佳方式从一个模式过渡到另一个模式(即过渡尽可能平滑)?

当我们进行过渡时,我们希望转到与我们当前所处的最相似的新模式的框架。

为此,我们可以首先定义图像之间的距离度量。这里使用一个简单的欧几里得距离,它查看两个图像的每个像素之间的差异。

有了这个距离,我们现在可以找到最接近我们当前的图像,并切换到这个。例如,如果我们想从普通模式过渡到点头模式,并且我们在普通视频的第 132 帧,我们将知道我们必须转到点头视频的第 86 帧才能获得最平滑的过渡。

我们可以为每一帧以及从每种模式到所有其他模式预先计算所有这些最佳转换。这样我们就不必在每次想要切换模式时都重新计算。还压缩了图像,以便计算执行时间更短。我们还将存储图像之间的最佳距离。

video_files = [file for file in os.listdir(os.path.join('videos', video_folder))
                       if file not in ['transitions_dict.p', '.DS_Store']]
frames = {}
for file in video_files:
    mode_name = file.split('.')[0]
    frames[mode_name] = read_frames(file, video_folder)
modes = list(frames.keys())

compression_ratio = 10
height, width = frames["normal"][0].shape[:2]
new_height, new_width = height // compression_ratio, width // compression_ratio, 

def compress_img(img):
    return cv2.resize(img.mean(axis=2), (new_width, new_height))

frames_compressed = {mode: np.array([compress_img(img) for img in frames[mode]]) for mode in modes}

transitions_dict = {mode:{} for mode in modes}

for i in range(len(modes)):
    for j in tqdm(range(i+1, len(modes))):
        mode_1, mode_2 = modes[i], modes[j]
        diff = np.expand_dims(frames_compressed[mode_1], axis=0) - np.expand_dims(frames_compressed[mode_2], axis=1)
        dists = np.linalg.norm(diff, axis=(2, 3))
        transitions_dict[mode_1][mode_2] = (dists.argmin(axis=0), dists.min(axis=0))
        transitions_dict[mode_2][mode_1] = (dists.argmin(axis=1), dists.min(axis=1))

pickle.dump(transitions_dict, open(os.path.join('videos', video_folder, 'transitions_dict.p'), 'wb'))

现在可以展示“change_mode”函数,该函数从预先计算的字典中检索要转换到的最佳帧。这样做是为了如果你按下例如“s”切换到微笑模式,再次按下它将切换回正常模式。

def change_mode(current_mode, toggled_mode, i):
    if current_mode == toggled_mode:
        toggled_mode = 'normal'

    new_i = transitions_dict[current_mode][toggled_mode][0][i]
    dist = transitions_dict[current_mode][toggled_mode][1][i]

    return new_i, toggled_mode, frame_rates[toggled_mode]

我们还可以添加另一项改进使我们的过渡更加无缝,不是总是立即切换模式,而是等待一段时间以获得更好的过渡。例如,如果我们的头像在点头,我们可以等到头部通过中间位置才转换到正常模式。为此,我们将引入一个时间窗口(这里我将其设置为 0.5 秒),这样我们将在切换模式之前等待在此窗口内转换的最佳时间。

switch_mode_max_delay_in_s = 0.5
def change_mode(current_mode, toggled_mode, i):
    if current_mode == toggled_mode:
        toggled_mode = 'normal'

    # Wait for the optimal frame to transition within acceptable window
    max_frames_delay = int(frame_rate * switch_mode_max_delay_in_s)
    global rev
    if rev:
        frames_to_wait = max_frames_delay-1 - transitions_dict[current_mode][toggled_mode][1][max(0, i+1 - max_frames_delay):i+1].argmin()
    else:
        frames_to_wait = transitions_dict[current_mode][toggled_mode][1][i:i + max_frames_delay].argmin()
    print(f'Wait {frames_to_wait} frames before transitioning')
    for _ in range(frames_to_wait):
        i, rev = next_frame_index(i, current_mode, rev)
        frame = frames[mode][i]
        cv2.imshow('Frame', frame)
        cv2.waitKey(int(1000 / frame_rate))
    new_i = transitions_dict[current_mode][toggled_mode][0][i]
    dist = transitions_dict[current_mode][toggled_mode][1][i]

    return new_i, toggled_mode, frame_rates[toggled_mode]

现在我们的过渡更加顺畅。但是,它们有时可能很明显。所以另一个想法是有目的地为视频添加冻结,就像那些在不稳定连接时可能发生的冻结一样(就是如果网络不稳定视频就卡住了),并使用它们来掩盖过渡(我们将使冻结持续时间与两个图像之间的距离成比例)。我们还将添加随机冻结,这样模式就不会变得明显。所以我们添加了这些新的代码:

# In the change_mode function:
    dist = transitions_dict[current_mode][toggled_mode][1][i]
    if freezes:
        freeze_duration = int(transition_freeze_duration_constant * dist)
        cv2.waitKey(freeze_duration)
# In the main loop:
    # Random freezes
    if freezes:
        if np.random.randint(frame_rate * 10) == 1:
            nb_frames_freeze = int(np.random.uniform(0.2, 1.5) * frame_rate)
            for _ in range(nb_frames_freeze):
                cv2.waitKey(int(1000 / frame_rate))
                i, rev = next_frame_index(i, mode, rev)

使用或不使用这些冻结保留为选项。

好的,现在我们已经真正涵盖了这些过渡的基础。我们还能为网络摄像头添加什么?

语音检测

另一件有趣的事情是添加语音检测,这样当我们说话时,视频里的“我”就会说话。

这是使用 pyaudio 完成的。感谢这个 stackoverflow 线程(https://stackoverflow.com/questions/4160175/detect-tap-with-pyaudio-from-live-mic)。

基本上,这个想法是查看一段时间内来自麦克风的声音的平均幅度,如果它足够高,可以认为我们一直在说话。最初这段代码是为了检测敲击噪音,但它也可以很好地检测语音。

AMPLITUDE_THRESHOLD = 0.010
FORMAT = pyaudio.paInt16
SHORT_NORMALIZE = (1.0/32768.0)
CHANNELS = 1
RATE = 44100
INPUT_BLOCK_TIME = 0.025
INPUT_FRAMES_PER_BLOCK = int(RATE*INPUT_BLOCK_TIME)
def get_rms(block):
    count = len(block)/2
    format = "%dh" % count
    shorts = struct.unpack(format, block)

    sum_squares = 0.0
    for sample in shorts:
        n = sample * SHORT_NORMALIZE
        sum_squares += n*n
    return math.sqrt( sum_squares / count )
pa = pyaudio.PyAudio()

stream = pa.open(format=FORMAT,
                 channels=CHANNELS,
                 rate=RATE,
                 input=True,
                 frames_per_buffer=INPUT_FRAMES_PER_BLOCK)
def detect_voice():
    error_count = 0
    voice_detected = False

    try:
        block = stream.read(INPUT_FRAMES_PER_BLOCK, exception_on_overflow=False)
    except (IOError, e):
        error_count += 1
        print("(%d) Error recording: %s" % (error_count, e))

    amplitude = get_rms(block)
    if amplitude > AMPLITUDE_THRESHOLD:
        voice_detected = True
    return voice_detected

现在我们可以将它添加到主循环中。这样做是为了在切换回正常模式之前,我们需要在一定数量的连续帧内检测到没有声音,这样我们就不会太频繁地切换。

# In the main loop:

  if voice_detection:
      if detect_voice():
          quiet_count = 0
          if mode != "talking":
              i, mode, frame_rate = change_mode(mode, "talking", i)
      else:
          if mode == "talking":
              quiet_count += 1
              if quiet_count > stop_talking_threshold:
                  quiet_count = 0
                  i, mode, frame_rate = change_mode(mode, "normal", i)

现在,当我们通过麦克风说话时,我们可以让我们的头像开始和停止说话。我这样做是为了通过按“v”来激活或停用语音检测。

这些都是迄今为止实现的所有功能。欢迎提出进一步改进的建议。

如何使用假网络摄像头

首先,从这里下载所有代码:https://github.com/FrancoisLeRoux1/Fake-webcam

你要做的是录制一些你自己的视频(在我的 Mac 上,为此使用了 Photo Booth 应用程序),并将它们放在“视频”文件夹内的一个新文件夹中。你将能够为不同的设置创建不同的文件夹,例如,你可以在其中穿不同的衬衫,或者让你的头发看起来不同。

这些视频可以而且应该很短(大约 10 秒的视频),否则如果你拍摄较长的视频,计算最佳过渡可能需要很长时间。你需要一个名为“normal”的视频,这将是你的默认模式。

然后,如果你想让你的化身说话,你必须录制一个名为“talking”的视频,你说的是随机的胡言乱语。

在此之后,你可以录制你想要的任何其他模式(例如,“微笑”、“点头”、“再见”……)。默认情况下,激活/停用这些模式的命令将是其名称的第一个字母(例如,对于“微笑”,请按“s”)。

然后你必须计算最佳转换。为此,只需运行脚本 compute-transitions.py

这应该需要几分钟。

然后当你完成后,你就可以启动你的假网络摄像头了。为此,请运行 fake-webcam.py 脚本。你需要指定视频所在的“视频”内的文件夹。你还可以指定是否要使用冻结。

所以现在你应该让你的假相机运行起来。接下来,你可以将其设置为在线会议的网络摄像头。为此,我使用了 OBS:https://obsproject.com/

选择正确的 Python 窗口作为源,然后单击 Start Virtual Camera。

你现在应该可以在你最喜欢的在线会议应用程序中选择此虚拟摄像头作为你的网络摄像头了!

到此这篇关于使用Python为你的在线会议创建一个假的摄像头的文章就介绍到这了,更多相关Python摄像头内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Python实现摄像头实时换脸详解

    目录 环境与效果 基本原理 完整源码 环境与效果 python3.9.6 pycharm 2021 库环境: dlib opencv-python 视频图片效果如下: 视频链接 摄像头实时换脸,老师都不认识我了!! 基本原理 使用dlib的shape_predictor_68_face_landmarks.dat模型获取一张有正脸的图片(1.png)和摄像头的自己的68个人脸特征点. 根据人脸特征点获取分别获取人脸掩模 对第一个图片仿射变换使其脸部对准摄像头图片中的脸部得到新的图片 对人脸掩模执

  • python通过opencv调用摄像头操作实例分析

    实例源码: #pip3 install opencv-python import cv2 from datetime import datetime FILENAME = 'myvideo.avi' WIDTH = 1280 HEIGHT = 720 FPS = 24.0 # 必须指定CAP_DSHOW(Direct Show)参数初始化摄像头,否则无法使用更高分辨率 cap = cv2.VideoCapture(0, cv2.CAP_DSHOW) # 设置摄像头设备分辨率 cap.set(cv

  • python 窃取摄像头照片的实现示例

    python窃取摄像头照片源码+获取授权码方法+py打包成exe 教你用python做一个属于自己的窃取摄像头照片的软件. 需要安装python3.5以上版本,在官网下载即可. 然后安装库opencv-python,安装方式为打开终端输入命令行. 可以在使用pip的时候加参数-i https://pypi.tuna.tsinghua.edu.cn/simple,这样就会从清华这边的镜像去安装需要的库,会快很多. pip install opencv-python -i https://pypi.

  • 基于python+opencv调用电脑摄像头实现实时人脸眼睛以及微笑识别

    本文教大家调用电脑摄像头进行实时人脸+眼睛识别+微笑识别,供大家参考,具体内容如下 一.调用电脑摄像头进行实时人脸+眼睛识别 # 调用电脑摄像头进行实时人脸+眼睛识别,可直接复制粘贴运行 import cv2 face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades+'haarcascade_frontalface_default.xml') eye_cascade = cv2.CascadeClassifier(cv2.data.ha

  • 如何使用Python控制摄像头录制视频

    导语: ​Python如何下载网页上的图片呢? 今天小编给大家分享另一个Python应用小程序,就是:用Python控制摄像头录制视频! 学会了也可以做一个属于自己的摄像头控制程序! 那么如何用Python编程来实现呢? 用Python代码实现照片阅读器功能,主要有7步: 第一步:导入需要的依赖库. 这里面主要用到三个库: (1)tkinter库:用于界面制作 (2)PIL库:用于图片处理 (3)cv2库:用于视频捕获 impor tcv2 impor ttkinter from PIL imp

  • python计算机视觉OpenCV库实现实时摄像头人脸检测示例

    目录 设备准备: 实现过程 调用模型库文件 打开摄像头 人脸检测 设置退出机制 程序运行 全部代码 OpenCV 是一个C++库,目前流行的计算机视觉编程库,用于实时处理计算机视觉方面的问题,它涵盖了很多计算机视觉领域的模块.在Python中常使用OpenCV库实现图像处理. 本文将介绍如何在Python3中使用OpenCV实现实时摄像头人脸检测: 设备准备: USB摄像头 接入PC电脑USB口,并调试正常打开视频.如果电脑内置了电脑摄像头,测试一下摄像头能否正常使用. 下载特征分类模型: XM

  • Python OpenCV超详细讲解读取图像视频和网络摄像头

    0.准备工作 右击新建的项目,选择Python File,新建一个Python文件,然后在开头import cv2导入cv2库. 1.读取图像调用imread()方法获取我们资源文件夹中的图片使用imshow()方法显示图片,窗口名称为OutputwaitKey(0)这句可以让窗口一直保持,如果去掉这句,窗口会一闪而过 我们来看下效果: 2.读取视频VideoCapture()方法的参数就是视频文件循环中通过read不断地去读视频的每一帧,再通过imshow显示出来最后if语句代表按q可以退出程

  • 如何使用 Python为你的在线会议创建一个假的摄像头

    目录 创建一个简单的假网络摄像头 添加不同的模式 优化过渡 语音检测 如何使用假网络摄像头 想象一下.你正在参加在线会议,出于某种原因,你并不想打开摄像头.但是如果你看到其他人都打开了,你觉得你也得打开,所以迅速整理自己的头发,确保衣着整洁,然后不情愿地打开相机.我们都经历过这种情况. 有一个好消息.在 Python 的帮助下,不再强制开启摄像头.将向你展示如何为你的在线会议创建一个假的摄像头,如下所示: 当然,这张脸不一定是比尔盖茨的,它也可以是你自己. 现在将向你展示如何在 Python 中

  • python使用Tkinter实现在线音乐播放器

    本文实例使用Tkinter实现在线音乐播放器的具体代码,供大家参考,具体内容如下 1.先使用Tkinter库写界面 2.写点击按钮触发的事件 (1).使用网易音乐的api,返回数据包装成json格式数据,解析数据 (2)涉及到多线程的问题未解决,一个软件默认打开一个线程,当播放歌曲时,显示界面就会卡掉,导致python停止工作 代码: #coding=utf-8 from Tkinter import * import tkMessageBox import urllib import json

  • python通过nmap扫描在线设备并尝试AAA登录(实例代码)

    如果管理网络设备很多,不可能靠人力每天去登录设备去查看是否在线.所以,可以利用python脚本通过每天扫描网络中的在线设备.可以部署在服务器上做成定时任务,每天发送AAA巡检报告. 下面是我写的一个python练手小程序.用来扫描一个网段中的在线主机,并尝试AAA去登录.统计一个大网段内可以成功aaa登录的主机. 注意: 该程序只是测试小程序,还有些小bug需要解决.不是通用的程序.主要提供一个大致思路. 主要用到了python-nmap, paramiko库. 程序大概思路: 利用nmap扫描

  • python 解决flask 图片在线浏览或者直接下载的问题

    目前是把图片存在mongodb数据库,实现一个方法,比如 访问 /get_pic/ID 能实现图片在浏览器打开,添加了一个状态,比如?filename=1.png,实现图片直接下载, 需要在读取图片函数中,给response 加上headers: 在 flask 中 response=make_response(f.read()) 需要下载就添加以下headers 当filename为中文时会报asicc编解码错误, 此时,import urllib (py3) filename=urllib.

  • 教你如何使Python爬取酷我在线音乐

    目录 前言 获取歌曲信息列表 请求参数分析 请求代码 获取歌曲下载链接 免费歌曲 付费歌曲 请求代码 后记 前言 写这篇博客的初衷是加深自己对网络请求发送和响应的理解,仅供学习使用,请勿用于非法用途!文明爬虫,从我做起.下面进入正题. 获取歌曲信息列表 在酷我的搜索框中输入关键词 aiko,回车之后可以看到所有和 aiko 相关的歌曲.打开开发者模式,在网络面板下按下 ctrl + f,搜索 二人,可以找到响应结果中包含 二人 的请求,这个请求就是用来获取歌曲信息列表的. 请求参数分析 请求的具

  • Python使用当前时间、随机数产生一个唯一数字的方法

    本文实例讲述了Python使用当前时间.随机数产生一个唯一数字的方法.分享给大家供大家参考,具体如下: Python生成当前时间很简单,比Java的代码简短多了,Java产生时间可参考<Java获取当前系统事件System.currentTimeMillis()方法> 具体代码如下: #-*-coding:utf-8-*- import datetime now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")

  • Python实战之用tkinter库做一个鼠标模拟点击器

    前言 用Python做一个鼠标模拟点击器,可以实现多位置,定时,定次数,定区域随机位置点击,对于一些比较肝的游戏(痒痒鼠之类的),挂机非常有帮助,解放双手;定区域随机点击可以一定程度上防止系统检测出有使用脚本开挂的行为 import tkinter as tk import random import pyautogui as mouse from tkinter.messagebox import * 安装库 首先是今天要用到的几个必要的库:tkinter,random,pyautogui 没

  • python中创建一个包并引用使用的操作方法

    一.Python包 python包在开发中十分常见,一般通过导入包含特定功能的python模块包进行使用.当然,也可以自己创建打包模块,然后发布,安装使用. 1.安装包 在线安装包:pip install 包名:安装第三方包:python setup.py  install (几乎每个python第三方包中都有这个setup.py文件,这个文件是作者打包时设置的文件,而安装第三方包时,也是要先进入到setup.py文件所在目录,然后执行python setup.py install) 2.dis

  • python创建一个最简单http webserver服务器的方法

    本文实例讲述了python创建一个最简单http webserver服务器的方法.分享给大家供大家参考.具体实现方法如下: import sys import BaseHTTPServer from SimpleHTTPServer import SimpleHTTPRequestHandler Handler = SimpleHTTPRequestHandler Server = BaseHTTPServer.HTTPServer Protocol = "HTTP/1.0" if s

  • 在Python的web框架中编写创建日志的程序的教程

    在Web开发中,后端代码写起来其实是相当容易的. 例如,我们编写一个REST API,用于创建一个Blog: @api @post('/api/blogs') def api_create_blog(): i = ctx.request.input(name='', summary='', content='') name = i.name.strip() summary = i.summary.strip() content = i.content.strip() if not name: r

随机推荐