Skip to content

Commit

Permalink
Allow using pictures as decorations
Browse files Browse the repository at this point in the history
* face_decor.py: Only preserve decorating eyebrows
* rotate.py: Demonstration of rotating pictures
* pic_on_pic.py: Test of putting 4-channel pictures on RGB background
* thuglife_resized.png: Square version of Thug Life's sunglasses, in order
	to avoid stripping in rotation
* face_thuglife.py: Created. To put sunglasses in either pictures or in
	the view of webcam
  • Loading branch information
TravorLZH committed Jul 28, 2019
1 parent a521d1c commit 9931d99
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 3 deletions.
7 changes: 4 additions & 3 deletions face_decor.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ def do_decor(frame):
top_lip=np.array(face_landmarks["top_lip"],np.int32)
bottom_lip=np.array(face_landmarks["bottom_lip"],np.int32)
frame=cv2.fillPoly(frame,[k*eyebrow_l,k*eyebrow_r],(0xFF,0xFF,0xFF))
frame=cv2.fillPoly(frame,[k*nose],(0,0x80,0xFF))
frame=cv2.fillPoly(frame,[k*bottom_lip],(0,0,0xFF))
frame=cv2.fillPoly(frame,[k*top_lip],(0,0xFF,0))
#frame=cv2.fillPoly(frame,[k*nose],(0,0x80,0xFF))
mouth_color=(0x3E,0x51,0xFC)
#frame=cv2.fillPoly(frame,[k*bottom_lip],mouth_color)
#frame=cv2.fillPoly(frame,[k*top_lip],mouth_color)
return frame

while webcam.isOpened():
Expand Down
95 changes: 95 additions & 0 deletions face_thuglife.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/usr/bin/env python3
import numpy as np
import face_recognition as fr
from os.path import exists,splitext
import sys
import cv2

thuglife_file="./thuglife_resized.png"
assert(exists(thuglife_file))
# The second argument cv2.IMREAD_UNCHANGED is extremely important because it
# supports reading pictures using alpha channel
thuglife=cv2.imread("thuglife_resized.png",cv2.IMREAD_UNCHANGED)

assert(thuglife.shape[2]==4) # Must have alpha channel

# determines whether to print debug messages in the session or not
debug=False

k=1

def put_sunglasses(frame,pic,mid,angle):
h,w=pic.shape[0:2]
coeff=0.63
y=int(mid[1]-h/2)
x=int(mid[0]-coeff*w)
M=cv2.getRotationMatrix2D((w/2,h/2),angle,1)
pic=cv2.warpAffine(pic,M,(w,h))
a,b=y+h,x+w
roi=frame[y:a,x:b]
for i,row in enumerate(pic):
for j,pix in enumerate(row):
try:
alpha=pix[3]/0xFF
vec=np.array([alpha,1-alpha])
mat=np.array([pix[0:3],roi[i][j]],dtype=np.int8).T
mixed=mat.dot(vec)
assert(len(mixed.shape)==1 and mixed.shape[0]==3)
roi[i][j]=mixed
except IndexError:
continue
frame[y:a,x:b]=roi
return frame

def mark_eye(frame):
small=cv2.resize(frame,(0,0),fx=1/k,fy=1/k)
rgb_frame=small[:,:,::-1]
all_landmarks=fr.face_landmarks(rgb_frame)
slopes=[]
mids=[]
for i,landmarks in enumerate(all_landmarks):
pt1=np.array(landmarks["left_eye"][0],dtype=np.int32)
pt2=np.array(landmarks["right_eye"][3],dtype=np.int32)
mids.append(np.array(k*(pt1+pt2)/2,dtype=np.int32))
diff=pt2-pt1
width=int(k*np.sqrt(np.sum(np.square(diff))))
ratio=width/thuglife.shape[1]*3/2
slopes.append(diff[1]/diff[0])
#frame=cv2.line(frame,(pt1[0]*k,pt1[1]*k),(pt2[0]*k,pt2[1]*k),
# (0xFF,0,0),2,8)
#frame=cv2.rectangle(frame,(pt1[0]*k,pt1[1]*k),(pt2[0]*k,pt2[1]*k),
# (0,0xFF,0),2)
pic=cv2.resize(thuglife,(0,0),fx=ratio,fy=ratio)
frame=put_sunglasses(frame,pic,mids[i],-np.arctan(slopes[i])/np.pi*180)
if debug and len(slopes)>0:
print("Slopes: {}".format(slopes))
print("Angles: {}".format(-np.arctan(slopes)/np.pi*180))
print("Midpoints: {}".format([m.tolist() for m in mids]))
return frame

def decor_img(name):
img=cv2.imread(name)
img=mark_eye(img)
out="%s_thuglife.png" % splitext(name)[0]
print("Saved to %s" % out)
cv2.imwrite(out,img)

argc=len(sys.argv)
if argc>=2:
if not exists(sys.argv[1]):
print("%s: No such file or directory" % sys.argv[1])
exit(-1)
decor_img(sys.argv[1])
exit(0)

webcam=cv2.VideoCapture(0)

while webcam.isOpened():
ret,frame=webcam.read()
if ret==False:
break
frame=cv2.flip(frame,1)
frame=mark_eye(frame)
cv2.imshow("Thug Life",frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
33 changes: 33 additions & 0 deletions pic_on_pic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env python3
import cv2
import numpy as np
import face_recognition as fr

background=cv2.imread("known_people/Barack_Obama.jpg",cv2.IMREAD_COLOR)
foreground=cv2.imread("thuglife.png",cv2.IMREAD_UNCHANGED)

[face]=fr.face_locations(background[:,:,::-1])
top,right,left,bottom=face

assert(foreground.shape[2]==4) # Assume foreground image has alpha channel

height=foreground.shape[0]
width=foreground.shape[1]

a=top
b=left

c=a+height
d=b+width

roi=background[a:c,b:d]
for i,row in enumerate(foreground):
for j,pix in enumerate(row):
alpha=pix[3]/0xFF
mixed=pix[0:3]*alpha+roi[i][j]*(1-alpha).astype(np.int8)
roi[i][j]=mixed

background[a:c,b:d]=roi

cv2.imshow("Mixed",background)
cv2.waitKey(0)
26 changes: 26 additions & 0 deletions rotate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env python3
import sys
import cv2
import numpy as np

argc=len(sys.argv)
if argc<3:
print("usage: %s image_file counter_clockwise" % sys.argv[0])
exit(-1)

degree=float(sys.argv[2])
rad=degree*np.pi/180.0

image=cv2.imread(sys.argv[1],cv2.IMREAD_UNCHANGED)

height,width=image.shape[0:2] # Get the shape

print("w=%d,h=%d" % (width,height))

M=cv2.getRotationMatrix2D((width/2,height/2),degree,1)


image=cv2.warpAffine(image,M,(width,height))

cv2.imshow("Rotated",image)
cv2.waitKey(0)
Binary file added thuglife_resized.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 9931d99

Please sign in to comment.