神龙,神龙,请给我一顶圣诞帽,我和微信官方已经没有爱了。

昨天就想把这个弄出来,结果白天太懒,晚上出去玩,今天眼睁睁地看着有人发了类似文章。但是,嘛,都弄了一半了,就弄完吧,实现方法也有些差别。

从前天起,朋友圈陆陆续续开始出现“给我一顶圣诞帽@微信官方”的信息,自己也被涮了一把。

当时想了半天,微信官方肯定是先把用户的头像提取出来,之后用计算机视觉技术进行脸部识别,找出脸部的坐标,并且判断角度,之后加上帽子。是的,就是这样 !不由感叹,现在腾讯真牛啊,这么快就把这些都用上了。

结果,发现一切都特么是假的...

不过既然有想法了,那不妨自己弄一弄呗,作为调包小能手,只要用现成的库就好了。

实现想法

首先先说说想法,先把整个过程分成几步,这样子每个部分写好不同的函数就好了。

  1. 最开始我们要做的当然是找到脸,并且得到脸部的坐标。
  1. 然后根据脸部的坐标,调整帽子的大小和位置,加入图片。
  2. 加入不同种类的帽子,完工!

什么都别说,先把人给我找出来!

最初想到脸部检测,当然是各种深度学习CNN什么的,但是结果发现太麻烦了。自己训练的话需要比较久,用已有模型也比较大,跑起来麻烦。

之后突然看到OpenCV直接有脸部检测模块,就拿来直接用吧。懒人第一原则,能不动手就不动手,信奉拿来主义。

OpenCV 有两种常用的脸部检测器,一个是Haar 分类器,一个是LBP 分类器,两个都不是深度学习脸部检测器。

Haar的话,主要是利用人脸的长相特征,然后用一定形状的滤镜来检测这种特征。比如比较有特点的眼睛部分。

而LBP的话,将图片分为很多小的区域,然后用一定方法进行编码,最后产生一个特征向量。过程比较复杂,有兴趣自己仔细看看。

这两个都需要事先在许多图片上进行训练,幸运的是OpenCV已经提供了一些训练好的模型。那么这两个哪个更好呢,一般来说Haar的准确率更高,而LBP的速度更快

来敲代码吧,首先召唤各种小帮手们。

import cv2 # 计算机视觉库
import matplotlib.pyplot as plt # 画图
import numpy as np
import random
from os import listdir
from PIL import Image, ImageDraw # 图像处理
%matplotlib inline

脸部识别函数代码如下。

def face_detection(path, method='haar'):
    """
    Face detection funciton.
    Input: Photo path, and detection methods (Haar or LBP)
    Output: The coordinates of faces
    """
    # Load Photos
    photo = cv2.imread(path)
    # Face detector can only use gray scale img
    gray_photo = cv2.cvtColor(photo, cv2.COLOR_BGR2GRAY)

首先读入图片,并且转换成灰度图片。因为模型是在灰度图片上训练的。

# Load Classifier, we detect both frontal faces and profile faces
if method.lower() == 'haar':
    front_detector = cv2.CascadeClassifier('models/haarcascade_frontalface_alt.xml')
    side_detector = cv2.CascadeClassifier('models/haarcascade_profileface.xml')
elif method.lower() == 'lbp':
    front_detector = cv2.CascadeClassifier('models/lbpcascade_frontalface_improved.xml')
    side_detector = cv2.CascadeClassifier('models/lbpcascade_profileface.xml')
else:
    print('No such method! Only provide haar and lbp now.')

然后加载训练好的正脸和侧脸识别器(看不到脸,就没有帽子XD)。

# Detect Faces
faces = front_detector.detectMultiScale(gray_photo, scaleFactor=1.1, minNeighbors=5)
side_faces = side_detector.detectMultiScale(gray_photo, scaleFactor=1.1, minNeighbors=5)
if len(faces) < 1:
    faces = side_faces
elif len(side_faces) >= 1:
    np.append(faces, side_faces, axis=0)
return faces

最后,分别用两个分类器检测脸,再把两个结果合起来。

这样子就完成第一步,有了脸的坐标了。

送你一顶圣诞帽

然后就是根据脸的坐标来把帽子贴上去了,首先第一个问题是,因为帽子的尺寸和图片尺寸可能并不吻合,所以如果直接戴的话,会出现大小不一致的问题,而且位置也比较奇怪。比如说这样子。

所以就需要调整帽子尺寸和位置。代码如下,分成两个函数。

# Adjust the size of hats
def resize_hat(face, hat, scale=1.5):
    w = int(face[2] * scale)
    h = int(face[3] * scale)
    new_hat = new_hat.resize((w, h))
    return newhat, w, h

首先调尺寸,我就随便看着头的大小调了调,帽子大小可以根据scale参数来调整,默认1.5倍脸部的长宽大小。

# Add one hat to a face
def add_one_hat(image, hat_img, face, x_offset_rate=2.8, y_offset_rate=0.95):
    # x_offset_rate bigger then the hat will move right
    # y_offset_rate bigger then the hat will move above
    hat, w, h = resize_hat(face, hat_img)
    y = int(face[1] - face[3]*0.95)
    x = int(face[0] + face[2]/2 - w/2.8)
    image.paste(hat, (x, y), hat)

给一张脸戴帽子,根据多次运行结果,选定了x和y的位置偏移值,不满意默认值也可以自己调偏移参数。

有了上面两个函数之后,只要给我一张脸我就能给它戴帽子了,之后只要把检测到的脸一一输进去就可以了。

# Loop faces add hat to each detected face
def add_hats(img_path, hat_path, faces):
    image = Image.open(img_path)
    hat_img = Image.open(hat_path)
    for face in faces:
        add_one_hat(image, hat_img, face)
    return image

通过for循环一张张读脸,然后加帽子,于是就完成了基本的功能了,超级简单是不是。嘿。

但是只有一款帽子,不开心,圣诞节怎么能没有绿色的帽子呢。

增加帽子款式,随机选择

这个就非常简单了,首先把帽子的路径都检测出来,之后再在add_hats函数里面加入随机选择帽子的代码。

# Get paths of all hat
hat_dir = 'photos/hats/'
hat_paths = [hat_dir+f for f in listdir(hat_dir) if f.endswith('png')]

获得所有帽子的路径。

def add_hats(img_path, hats_path, faces):
    image = Image.open(img_path)
    # Random select one hat from hats path
    for face in faces:
        hat_path = random.choice(hats_path)
        hat_img = Image.open(hat_path)
        add_one_hat(image, hat_img, face)
    return image

修改add_hats,然后就完成啦!

喜闻乐见的测试时间

之后就到了喜闻乐见的测试时间啦,让我们来看看效果怎么样吧。

先拿张多人照片测试一下。

嗯,不错不错,都是别出来了。再来看看我喜欢的四重奏。

效果喜人,原来不光有带帽子功能,还能够精确地识别出有没有被NTR,厉害厉害。

好,那再来测试一下人数上限。嘿,接招。

嗯.... 怎么才这么点,难道说只有颜值大于8的人才能带上圣诞帽。不对,我的分类器怎么会这么肤浅呢!

那么调调face_detection里面detectMultiScale的参数看看,因为scaleFactor参数影响了图片中远近人脸的检测,把它调大一点。

Bingo ! 一下就多了好多绿帽子。

恩,看来只要不是太极端的情况,还是很好用的。那么现在来测试一下微信头像吧,就拿老爹的头像来测试一下先。当当!

效果不一般,还很贴心地给后面毛爷爷像加了顶圣诞帽。发给老爹,老爹表示很满意给了个红包。

嗯,还能怎么玩呢。

对了!现在微信不都快成了动物园了吗,拿喵星人来测试一下。当当!

噫,啥也没有,又测试了几只猫居然还不行,看来现在的模型只能检测人脸。那会不会有猫脸检测模型呢,跑去OpenCV的代码库找了找,居然很贴心的还真有。修改了一下face_detection函数,具体参考文后github的链接。

再一测试,当当!

简直完美!

尾声

下午拿着电脑去给朋友展示自动戴圣诞帽系统,先传输图片,然后输入模型,保存图片,传到手机,整个过程居然只用了10分钟。我只问你,你可见过这么高级的系统吗!!!

朋友默默拿过手机,下载了一款图片编辑app,搜索圣诞帽,贴图,保存。整个过程花了2分钟。

...............................................................................................

劳资才不稀罕这么low逼的P图技术呢!!!

github代码: https://github.com/andy-yangz/gimme_a_Santa_hat

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容