では、過去記事二つのプログラムを使い、スマホアプリ「Snow」 みたく 同一写真上の二人の顔を入れ替えるプログラムを作ってみます。
プログラム書いてる人の技術力の問題で、めっちゃ雑ですけれども。
必要なモジュール
github.com
新しいめの Python用 OpenGLライブラリ。 今回はこちらを使ってみます
プログラム
fakeswap.py
from datetime import datetime
import numpy as np
import cv2
import moderngl
import facepoly
import facelandmark
import sys
def one2(x,y):
return 2*x-1,2*y-1
def mkbg(ctx):
vx=np.array([-1,1,1,-1],dtype=np.float)
vy=np.array([-1,-1,1,1],dtype=np.float)
tx=np.array([0,1,1,0],dtype=np.float)
ty=np.array([0,0,1,1],dtype=np.float)
index=np.array([0,1,2,0,2,3],dtype=np.int32)
bg=GLObj(ctx)
bg.setvert(vx,vy)
bg.setindex(index)
bg.tx=tx
bg.ty=ty
return bg
class GLRenderer(object):
def __init__(self):
#オフスクリーンレンダリング
self.ctx=moderngl.create_standalone_context()
def setframe(self,w,h):
self.W=w
self.H=h
self.fbo = self.ctx.simple_framebuffer((self.W,self.H))
self.fbo.use()
def mktex(self,im):
im2=cv2.cvtColor(im,cv2.COLOR_BGR2RGB)
h,w,c=im2.shape
tex = self.ctx.texture( (w,h) , 3, im2.tobytes())
return tex
def render(self,objlist):
self.ctx.clear(1.0, 1.0, 1.0)
#self.ctx.enable(moderngl.DEPTH_TEST)
self.fbo.clear(0.0, 0.0, 0.0, 1.0)
for obj in objlist:
obj.tex0.use(0)
obj.prog['Color0'].value = 0
obj.vao.render(moderngl.TRIANGLES)
im=np.fromstring(self.fbo.read(),dtype=np.uint8)
im=im.reshape(self.H,self.W,3)
cv2.cvtColor(im,cv2.COLOR_BGR2RGB,im)
#cv2.flip(im,0,im)
return im
class GLObj(object):
def __init__(self,ctx):
self.ctx=ctx
self.prog = self.ctx.program(
vertex_shader='''
#version 330
in vec2 in_vert;
in vec2 in_text;
out vec2 v_text;
void main() {
gl_Position = vec4(in_vert,0, 1.0);
v_text = in_text;
}
''',
fragment_shader='''
#version 330
uniform sampler2D Color0;
in vec2 v_text;
out vec4 f_color;
void main() {
vec3 color1 = texture(Color0, v_text).rgb;
f_color = vec4(color1, 1.0);
}
''',
)
def updatebuf(self):
vertices = np.dstack([self.vx, self.vy, self.tx,self.ty])
index =self.index
self.vbo = self.ctx.buffer(vertices.astype('f4').tobytes())
self.ibo = self.ctx.buffer(index.astype('i4').tobytes())
self.vao = self.ctx.simple_vertex_array(self.prog, self.vbo, 'in_vert', 'in_text',
index_buffer=self.ibo)
def setindex(self,index):
self.index=index
def setvert(self,vx,vy):
self.vx=vx
self.vy=vy
def settex(self,tex,tx,ty):
self.tex0=tex
self.tx=tx
self.ty=ty
def mkface(ctx):
fc=GLObj(ctx)
fcindex = facepoly.triangles
fc.setindex(fcindex)
return fc
if __name__=="__main__":
fn=sys.argv[1]
renderer=GLRenderer()
ctx=renderer.ctx
#
bg=mkbg(ctx)
fc0=mkface(ctx)
fc1=mkface(ctx)
im=cv2.imread(fn)
#顔検出
faces=facelandmark.landmark(im,nfaces=2)
tx0,ty0=faces[0]
tx1,ty1=faces[1]
tex=renderer.mktex(im)
#入れ替え
vx0,vy0=one2(tx1,ty1)
vx1,vy1=one2(tx0,ty0)
#フレームバッファ設定
h,w,c=im.shape
renderer.setframe(w,h)
#
fc0.settex(tex,tx0,ty0)
fc0.setvert(vx0,vy0)
fc1.settex(tex,tx1,ty1)
fc1.setvert(vx1,vy1)
#bg
bg.settex(tex,bg.tx, bg.ty)
objlist= [bg,fc0,fc1]
for obj in objlist:
obj.updatebuf()
im2=renderer.render(objlist)
cv2.imshow("faceswap",im2)
k=cv2.waitKey(1)
today=datetime.today()
fnout=today.strftime("%Y%m%d_%H%M%S.jpg")
cv2.imwrite(fnout,im2)
input("pause")
元画像
加工後
めっちゃ雑!