SpoutはZoom等のテレビ会議システムからカメラとして選択できるので、Webカメラ→Spout(Pythonでゴニョゴニョ)→Zoomなどとすれば、在宅勤務用時に、顔をそのまま出したくないが、表情を見せたい時など、顔にイフェクトをかけたり、逆に顔以外の背景を消したりなど簡単にできます。
「簡単に」と書きましたが、実はオリジナルの記事が古いので、まともに動かすのは各モジュールのバージョンの相性が悪いと動かないので、その塩梅がノウハウです。
先ず、Spout本家ははこちら、https://spout.zeal.co/
こちらから、Spoutをインストールします。
次に、以下からSpout for Python をダウンロードします。
このSpout-for-Python-master内のExample内の各コードが動作すれば、Libs内のSpoutSDK.pydがそのまま使えるということになりますが、動作しなければ、自分でbuildする必要があります。
Python用にbuildする場合は以下のサイトが参考になります。上のオリジナルに従うと、
Python以外の他のライブラリをすべてbuildしますので、えらく時間がかかります。
その場合の動くバージョンの組み合わせの一つは以下の通りです。これはすべてのプラットフォーム
で動くかどうかは不明です。実際手持ちのPCで動く場合と動く場合があります。特にopencvなどがまともに動かない場合があります。
動作バージョンのPythonフォルダを動かないほうのPCコピーすれば動きます。
Python 3.74
PyOpenGL 3.15
pygame 1.18.2
opencv_python 4.2.0.34
ここで、buildして、SpoutSDK.dll ができ、それをSpoutSDK.pyd とリネームしたものが
Pythonからimport SpoutSDK で利用できます。
WebCamを備えたPCで以下のコードが動けばひとまずオーケーです。
つまり、SpoutのDEMOフォルダ内のSpoutReceiveでWebCamからの映像が受信できる
かチェックしてください。受信できていれば、ZoomなどからSpoutをカメラとして
選択すると、テレビ会議にその映像を送ることができます。
これにどのようにしてイフェクトをかけるかは次のポストで紹介します。
import sys
sys.path.append('../Library')
import cv2
import numpy as np
import SpoutSDK
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
def main():
# window details
width = 640
height = 480
display = (width,height)
# window setup
pygame.init()
pygame.display.set_caption('Spout Python Sender')
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
pygame.display.gl_set_attribute(pygame.GL_ALPHA_SIZE, 8)
cap = cv2.VideoCapture(0)
if cap.isOpened() is False:
raise("IO Error")
cap.set(cv2.CAP_PROP_FPS, 30)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
cap.set(3, width)
cap.set(4, height)
# OpenGL init
glMatrixMode(GL_PROJECTION)
glOrtho(0,width,height,0,1,-1)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glDisable(GL_DEPTH_TEST)
glClearColor(0.0,0.0,0.0,0.0)
glEnable(GL_TEXTURE_2D)
# init spout sender
spoutSender = SpoutSDK.SpoutSender()
spoutSenderWidth = width
spoutSenderHeight = height
# Its signature in c++ looks like this: bool CreateSender(const char *Sendername, unsigned int width, unsigned int height, DWORD dwFormat = 0);
spoutSender.CreateSender('Spout for Python Webcam Sender Example', width, height, 0)
# create texture id for use with Spout
senderTextureID = glGenTextures(1)
# initalise our sender texture
glBindTexture(GL_TEXTURE_2D, senderTextureID)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glBindTexture(GL_TEXTURE_2D, 0)
# loop
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
ret, frame = cap.read() #read camera image
#img = cv2.imread('image.png') # if use the image file
frame = cv2.cvtColor(frame,cv2.COLOR_BGR2RGB) #BGR-->RGB
h, w = frame.shape[:2]
glBindTexture(GL_TEXTURE_2D, senderTextureID)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, frame)
spoutSender.SendTexture(senderTextureID, GL_TEXTURE_2D, spoutSenderWidth, spoutSenderHeight, False, 0)
#glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
# Clear screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )
# reset the drawing perspective
glLoadIdentity()
# Draw texture to screen
glBegin(GL_QUADS)
##
glTexCoord(0,0)
glVertex2f(0,0)
#
glTexCoord(1,0)
glVertex2f(width,0)
#
glTexCoord(1,1)
glVertex2f(width,height)
#
glTexCoord(0,1)
glVertex2f(0,height)
##
glEnd()
pygame.display.flip()
# unbind our sender texture
glBindTexture(GL_TEXTURE_2D, 0)
# pygame.time.wait(10)
if __name__ == '__main__':
main()