顔のポリゴン分割自動生成

前回からの続きです。 最終的には Snowみたく 顔を入れ替えるプログラムになる予定です
boxheadroom.hatenablog.com

dlibで取得したfacelandmark (を水増して おでこを追加したもの)を cv2.Subdiv2Dを使ってドロネー三角形に分割します

直下に フォルダ名 faceを作り、 適当に顔画像を入れておき、何度か facepoy.py を実行して 一番気に入った分割になった時点でやめます。
少し 口を開けた写真のほうが 口のまわりの分割がうまくいくんじゃないかと思います。 

(正直に書くと、 自分は 最初 前回の記事で作成した 頂点番号の画像を印刷 → エンピツで三角形を書いて 手で入力しました)

facepoly.py



import numpy as np
triangles=np.loadtxt("facepoly.txt",dtype=np.int32).flatten()

if __name__=="__main__":
import os
import cv2
import csv
import glob

from facelandmark import landmark
flist=glob.glob("face/*.jpg")
np.random.shuffle(flist)
fn=np.random.choice(flist)

im=cv2.imread(fn)
faces=landmark(im,zero2one=False)
px,py=faces[0]
vlist=[ (x,y) for x,y in zip(px,py)]
vdict={ v:i for i,v in enumerate( vlist) }
h,w,c =im.shape
rect=(0,0,w,h)

subdiv=cv2.Subdiv2D((0,0,w,h))
for i,(x,y) in enumerate(zip(px,py)):
if i==68:
continue
subdiv.insert((x,y))

triangleList = subdiv.getTriangleList()
tvert=[]
for t in triangleList :
if 0 in t or w in t or h in t:
continue
t=np.array(t)
if (np.any(t[::2]<px.min()) or np.any( t[1::2]<py.min()) or
np.any( t[::2]>px.max()) or np.any( t[1::2]>py.max())):
continue
p0=(t[0],t[1])
p1=(t[2],t[3])
p2=(t[4],t[5])
tvert.append((p0,p1,p2))
vindex=[ [vdict[v] for v in t] for t in tvert]
aindex=np.array( vindex)

im[:,:,:]=255
col=(0,0,0)
index=[]
for idx in aindex:
if np.all ( (idx>=60) & (idx<68)):
continue
i1=idx[0]
i2=idx[1]
i3=idx[2]
index.append( (i1,i2,i3) )
p0=vlist[i1]
p1=vlist[i2]
p2=vlist[i3]
cv2.line( im, p0,p1,col )
cv2.line( im, p1,p2,col)
cv2.line( im, p2,p0,col )
aindex=np.array(index)
cv2.imshow("subdiv",im)
np.savetxt("facepoly.txt",aindex, "%d")
cv2.waitKey(1)


f:id:boxheadroom:20181020081408p:plain