snapchat图片使用特效 (snapchat如何弄多人脸)

看到美图秀秀,

Faceu 这样的软件,

居然能够把河马酱的圆脸

变大,变小,变漂亮。

实在是觉得好惊奇,

好意外。

snapchat换人脸特效叫什么,漫画脸特效snapchat教程

太神奇了吧?

怎么做到的?

这一定是魔法吧?

snapchat换人脸特效叫什么,漫画脸特效snapchat教程

然而,今天在网上发现一篇教程。

发现,嘿嘿。

原来用Python, OpenCV, 和Dlib

我们自己也能做一个。

snapchat换人脸特效叫什么,漫画脸特效snapchat教程

俗话说的好,

自己动手,随便得瑟。

所以我们自己来实现一次。

效果预览

snapchat换人脸特效叫什么,漫画脸特效snapchat教程

整体思路是这样

首先,我们用OpenCV加载网络摄像头

加载贴图

用 Dlib的脸部检测来定位脸部,

然后使用面部标识来查找眼睛的位置

计算每只眼睛的贴图的大小及位置。

最后,将贴图覆盖到每只眼睛上。

并调整到合适的尺寸

在开始之前,

我们首先,要先加载必要的libraries。

import cv2

import dlib

from scipy.spatial import distance as dist

from scipy.spatial import ConvexHull

除了OpenCV和Dlib,

我们还需要从scipy.spatial package中

加载两种方法,

这些方法能够帮助我们

进行距离和大小计算。

然后,我们还需要设置Dlib Face Detector

和Face Landmark Detector的参数。

接着需要初始化参数,

这些参数将帮助我们

从Dlib返回的68个landmark中

提取个人面部landmark。

PREDICTOR_PATH = "path/to/your/shape_predictor_68_face_landmarks.dat"

FULL_POINTS = list(range(0, 68))

FACE_POINTS = list(range(17, 68))

JAWLINE_POINTS = list(range(0, 17))

RIGHT_EYEBROW_POINTS = list(range(17, 22))

LEFT_EYEBROW_POINTS = list(range(22, 27))

NOSE_POINTS = list(range(27, 36))

RIGHT_EYE_POINTS = list(range(36, 42))

LEFT_EYE_POINTS = list(range(42, 48))

MOUTH_OUTLINE_POINTS = list(range(48, 61))

MOUTH_INNER_POINTS = list(range(61, 68))

detector = dlib.get_frontal_face_detector()

predictor = dlib.shape_predictor(PREDICTOR_PATH)

接着我们就能加载用于叠加的贴图文件了。

就是这对大眼睛。

切记图片一定需要找能支持透明背景的 PNG 文件。不然会AR出你方方的眼睛。

#---------------------------------------------------------

# 加载并预处理眼睛贴图

#---------------------------------------------------------

# 加载贴图

imgEye = cv2.imread('path/to/your/Eye.png',-1)

# 给贴图创建蒙版

orig_mask = imgEye[:,:,3]

# 创建反转的眼睛图像

orig_mask_inv = cv2.bitwise_not(orig_mask)

# 将贴图转换为BGR

# 并保存原图片的尺寸

imgEye = imgEye[:,:,0:3]

origEyeHeight, origEyeWidth = imgEye.shape[:2]

其中cv2.imread参数 '-1' 用于告诉OpenCV读取Alpha 通道(透明通道)和BGR通道。从alpha通道建立一个mask。同时创建一个相反的mask,用来定义属于眼睛外部的像素。最后,将贴图转回BGR格式,并删除alpha通道。

然后我们就能够开始用摄像头获取画面了。捕捉画面后,用算法检测人脸,并检测面部landmark。当获取了landmark我们就能够从中分别提取左右眼的相关landmark 数组。.

# Start capturing the WebCam

video_capture = cv2.VideoCapture(0)

while True:

ret, frame = video_capture.read()

if ret:

gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

rects = detector(gray, 0)

for rect in rects:

x = rect.left()

y = rect.top()

x1 = rect.right()

y1 = rect.bottom()

landmarks = np.matrix([[p.x, p.y] for p in predictor(frame, rect).parts()])

left_eye = landmarks[LEFT_EYE_POINTS]

right_eye = landmarks[RIGHT_EYE_POINTS]

获取了眼睛的landmark后,

下一步该怎么做呢?

我们还需要获取眼睛的大小

以及每个眼睛的中心位置,

不然无法很好得准确叠加。

def eye_size(eye):

eyeWidth = dist.euclidean(eye[0], eye[3])

hull = ConvexHull(eye)

eyeCenter = np.mean(eye[hull.vertices, :], axis=0)

eyeCenter = eyeCenter.astype(int)

return int(eyeWidth), eyeCenter

这里就需要用到欧几里德函数

来计算眼睛的宽度,

并使用ConvexHull函数

来计算中心位置。

将左右眼的值分别传入

leftEyeSize, leftEyeCenter = eye_size(left_eye)

rightEyeSize, rightEyeCenter = eye_size(right_eye)

然后定义一个place eye function。

好了,魔法开始了。

你的二次元眼睛就要长出来了。

def place_eye(frame, eyeCenter, eyeSize):

eyeSize = int(eyeSize * 1.5)

x1 = int(eyeCenter[0,0] - (eyeSize/2))

x2 = int(eyeCenter[0,0] + (eyeSize/2))

y1 = int(eyeCenter[0,1] - (eyeSize/2))

y2 = int(eyeCenter[0,1] + (eyeSize/2))

h, w = frame.shape[:2]

# 检查裁剪

if x1 < 0:

x1 = 0

if y1 < 0:

y1 = 0

if x2 > w:

x2 = w

if y2 > h:

y2 = h

# 重新计算大小以避免裁剪

eyeOverlayWidth = x2 - x1

eyeOverlayHeight = y2 - y1

# 计算贴图的mask

eyeOverlay = cv2.resize(imgEye, (eyeOverlayWidth,eyeOverlayHeight), interpolation = cv2.INTER_AREA)

mask = cv2.resize(orig_mask, (eyeOverlayWidth,eyeOverlayHeight), interpolation = cv2.INTER_AREA)

mask_inv = cv2.resize(orig_mask_inv, (eyeOverlayWidth,eyeOverlayHeight), interpolation = cv2.INTER_AREA)

# 从背景获取背景图像的ROI,等于叠加图像的大小

roi = frame[y1:y2, x1:x2]

# roi_bg仅包含贴图层不覆盖大小的区域中的原始图像。

roi_bg = cv2.bitwise_and(roi,roi,mask = mask_inv)

# roi_fg只包含贴图覆盖区域像素

roi_fg = cv2.bitwise_and(eyeOverlay,eyeOverlay,mask = mask)

# 合并roi_fg 和 roi_bg

dst = cv2.add(roi_bg,roi_fg)

# 将合并的图像放置在原始图像上,保存到dst

frame[y1:y2, x1:x2] = dst

这里我们根据眼睛的大小和位置,

来计算出贴图的大小和位置。

我们还需要检查剪辑。

否则,当您尝试计算

具有图像框之外的像素的mask时,

会收到以下错误消息。

OpenCV Error: Assertion failed ((mtype == CV_8U || mtype == CV_8S) && _mask.same

Size(*psrc1)) in cv::binary_op, file C:\bld\opencv_1492084805480\work\opencv-3.2

.0\modules\core\src\arithm.cpp, line 241

Traceback (most recent call last):

File "WebCam-Overlay.py", line 135, in

place_eye(frame, leftEyeCenter, leftEyeSize)

File "WebCam-Overlay.py", line 51, in place_eye

roi_bg = cv2.bitwise_and(roi,roi,mask = mask_inv)

cv2.error: C:\bld\opencv_1492084805480\work\opencv-3.2.0\modules\core\src\arithm

.cpp:241: error: (-215) (mtype == CV_8U || mtype == CV_8S) && _mask.sameSize(*ps

rc1) in function cv::binary_op

这几个步骤基本就是,计算贴图的大小,从脸部取出在贴图位置大小的区域的像素,并用贴图来取代(不包括透明像素)。最后将替换的像素框放回到面部图像中。当然啦,我们需要一只眼睛一只眼睛得做

place_eye(frame, leftEyeCenter, leftEyeSize)

place_eye(frame, rightEyeCenter, rightEyeSize)

塔哒。。。好了,快来看看你的大眼睛。有没有变水灵

cv2.imshow("Faces with Overlay", frame)

除了给自己加装个漫画版的大眼睛。你也能够加任何其他东西到自己脸上。虽然可能你很有创意,不过还是不要加些奇怪的东西为好。

完全代码

import numpy as np

import cv2

import dlib

from scipy.spatial import distance as dist

from scipy.spatial import ConvexHull

PREDICTOR_PATH = "path/to/your/shape_predictor_68_face_landmarks.dat"

FULL_POINTS = list(range(0, 68))

FACE_POINTS = list(range(17, 68))

JAWLINE_POINTS = list(range(0, 17))

RIGHT_EYEBROW_POINTS = list(range(17, 22))

LEFT_EYEBROW_POINTS = list(range(22, 27))

NOSE_POINTS = list(range(27, 36))

RIGHT_EYE_POINTS = list(range(36, 42))

LEFT_EYE_POINTS = list(range(42, 48))

MOUTH_OUTLINE_POINTS = list(range(48, 61))

MOUTH_INNER_POINTS = list(range(61, 68))

detector = dlib.get_frontal_face_detector()

predictor = dlib.shape_predictor(PREDICTOR_PATH)

def eye_size(eye):

eyeWidth = dist.euclidean(eye[0], eye[3])

hull = ConvexHull(eye)

eyeCenter = np.mean(eye[hull.vertices, :], axis=0)

eyeCenter = eyeCenter.astype(int)

return int(eyeWidth), eyeCenter

def place_eye(frame, eyeCenter, eyeSize):

eyeSize = int(eyeSize * 1.5)

x1 = int(eyeCenter[0,0] - (eyeSize/2))

x2 = int(eyeCenter[0,0] + (eyeSize/2))

y1 = int(eyeCenter[0,1] - (eyeSize/2))

y2 = int(eyeCenter[0,1] + (eyeSize/2))

h, w = frame.shape[:2]

# check for clipping

if x1 < 0:

x1 = 0

if y1 < 0:

y1 = 0

if x2 > w:

x2 = w

if y2 > h:

y2 = h

# re-calculate the size to avoid clipping

eyeOverlayWidth = x2 - x1

eyeOverlayHeight = y2 - y1

# calculate the masks for the overlay

eyeOverlay = cv2.resize(imgEye, (eyeOverlayWidth,eyeOverlayHeight), interpolation = cv2.INTER_AREA)

mask = cv2.resize(orig_mask, (eyeOverlayWidth,eyeOverlayHeight), interpolation = cv2.INTER_AREA)

mask_inv = cv2.resize(orig_mask_inv, (eyeOverlayWidth,eyeOverlayHeight), interpolation = cv2.INTER_AREA)

# take ROI for the verlay from background, equal to size of the overlay image

roi = frame[y1:y2, x1:x2]

# roi_bg contains the original image only where the overlay is not, in the region that is the size of the overlay.

roi_bg = cv2.bitwise_and(roi,roi,mask = mask_inv)

# roi_fg contains the image pixels of the overlay only where the overlay should be

roi_fg = cv2.bitwise_and(eyeOverlay,eyeOverlay,mask = mask)

# join the roi_bg and roi_fg

dst = cv2.add(roi_bg,roi_fg)

# place the joined image, saved to dst back over the original image

frame[y1:y2, x1:x2] = dst

#---------------------------------------------------------

# Load and pre-process the eye-overlay

#---------------------------------------------------------

# Load the image to be used as our overlay

imgEye = cv2.imread(&apos;path/to/your/Eye.png&apos;,-1)

# Create the mask from the overlay image

orig_mask = imgEye[:,:,3]

# Create the inverted mask for the overlay image

orig_mask_inv = cv2.bitwise_not(orig_mask)

# Convert the overlay image image to BGR

# and save the original image size

imgEye = imgEye[:,:,0:3]

origEyeHeight, origEyeWidth = imgEye.shape[:2]

# Start capturing the WebCam

video_capture = cv2.VideoCapture(0)

while True:

ret, frame = video_capture.read()

if ret:

gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

rects = detector(gray, 0)

for rect in rects:

x = rect.left()

y = rect.top()

x1 = rect.right()

y1 = rect.bottom()

landmarks = np.matrix([[p.x, p.y] for p in predictor(frame, rect).parts()])

left_eye = landmarks[LEFT_EYE_POINTS]

right_eye = landmarks[RIGHT_EYE_POINTS]

# cv2.rectangle(frame, (x, y), (x1, y1), (0, 255, 0), 2)

leftEyeSize, leftEyeCenter = eye_size(left_eye)

rightEyeSize, rightEyeCenter = eye_size(right_eye)

place_eye(frame, leftEyeCenter, leftEyeSize)

place_eye(frame, rightEyeCenter, rightEyeSize)

cv2.imshow("Faces with Overlay", frame)

ch = 0xFF & cv2.waitKey(1)

if ch == ord(&apos;q&apos;):

break

cv2.destroyAllWindows()

AR酱原创,转载务必注明

微信号AR酱(ARchan_TT)

AR酱官网:www.arjiang.com