从此以往加上帽子体育365网址,那里写图片描述

前日就想把这一个弄出来,结果白天太懒,上午出去玩,后天眼睁睁地望着有人发了类似小说。但是,嘛,都弄了大体上了,就弄完吧,完结格局也有个别差异。

此间写图片描述

引言

从今日起,朋友圈陆陆续续早先出现“给本人一顶圣诞帽@微信官方”的消息,自个儿也被涮了一把。

引言

乘势圣诞的过来,大家纷纭@官方微信给自个儿的头像加上一顶圣诞帽。当然这种工功效恒河沙数P图软件都得以形成。然而作为2个上学图像处理的技歌手,照旧认为我们有供给写3个顺序来做那件业务。而且那全然可以作为2个练手的小项目,工作量相当小,而且很有趣。

乘胜圣诞的赶到,我们纷纭@官方微信给协调的头像加上一顶圣诞帽。当然那种事情用比比皆是P图软件都可以落成。不过作为三个读书图像处理的技能人,依然认为大家有供给写2个主次来做那件工作。而且那一点一滴能够当做叁个练手的小项目,工作量非常小,而且很有意思。

即刻想了半天,微信官方肯定是先把用户的头像提取出来,之后用电脑视觉技术拓展面部识别,找出人脸的坐标,并且判断角度,之后加上帽子。是的,正是那样
!不由惊叹,今后腾讯真牛啊,这么快就把那几个都用上了。

用到的工具

  • OpenCV(毕竟大家最首要的始末就是OpenCV…)
  • dlib(前一篇作品刚说过,dlib的人脸检查和测试比OpenCV更好用,而且dlib有OpenCV没有的关键点检查和测试。)

用到的言语为Python。然则完全能够改成C++版本,时间有限,就不写了。有趣味的伴儿能够拿来练手。

用到的工具

结果,发现整个都特么是假的…

流程

OpenCV(究竟大家第壹的剧情正是OpenCV…)

唯独既然有想法了,那不妨本人弄一弄呗,作为调包小能人,只要用现成的库就好了。

① 、素材准备

第①我们必要安不忘虞一个圣诞帽的资料,格式最好为PNG,因为PNG的话我们能够直接用Alpha通道作为掩膜使用。大家用到的圣诞帽如下图:

那里写图片描述

作者们透过通道分别能够收获圣诞帽图像的阿尔法通道。代码如下:

r,g,b,a = cv2.split(hat_img) 
rgb_hat = cv2.merge((r,g,b))

cv2.imwrite("hat_alpha.jpg",a)

为了可以与rgb通道的头像图片实行演算,大家把rgb三通道合成一张rgb的五颜六色帽子图。Alpha通道的图像如下图所示。

那边写图片描述

dlib(前一篇小说刚说过,dlib的人脸检查和测试比OpenCV更好用,而且dlib有OpenCV没有的关键点检查和测试。)

贯彻想法

第3先说说想法,先把全体经过分成几步,那样子每一种部分写好区别的函数就好了。

  1. 最开端我们要做的自然是找到脸,并且取得脸部的坐标。

  2. 接下来依照脸部的坐标,调整帽子的大大小小和职务,参与图片。

  3. 插足不相同档次的罪名,竣工!

贰 、人脸检查和测试与人脸关键点检查和测试

笔者们用上边那张图作为大家的测试图片。

此间写图片描述

下边大家用dlib的正脸检查和测试器进行人脸检测,用dlib提供的模子提取人脸的多个关键点。代码如下:

    # dlib人脸关键点检测器
    predictor_path = "shape_predictor_5_face_landmarks.dat"
    predictor = dlib.shape_predictor(predictor_path)  

    # dlib正脸检测器
    detector = dlib.get_frontal_face_detector()

    # 正脸检测
    dets = detector(img, 1)

    # 如果检测到人脸
    if len(dets)>0:  
        for d in dets:
            x,y,w,h = d.left(),d.top(), d.right()-d.left(), d.bottom()-d.top()
            # x,y,w,h = faceRect  
            cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2,8,0)

            # 关键点检测,5个关键点
            shape = predictor(img, d)
            for point in shape.parts():
                cv2.circle(img,(point.x,point.y),3,color=(0,255,0))

            cv2.imshow("image",img)
            cv2.waitKey()  

这一部分功力如下图:

那边写图片描述

用到的语言为Python。然而完全能够改成C++版本,时间少于,就不写了。有趣味的同伙能够拿来练手。

怎么样都别说,先把人给笔者找出来!

初期想到脸部检查和测试,当然是种种深度学习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

末尾,分别用四个分类器检查和测试脸,再把多个结果合起来。

那规范就成功第三步,有了脸的坐标了。

③ 、调整帽子大小

大家选用四个眼角的点,求中央作为放置帽子的x方向的参考坐标,y方向的坐标用人脸框上线的y坐标表示。然后大家依照人脸检查和测试获得的人脸的大小调整帽子的大小,使得帽子大小适当。

            # 选取左右眼眼角的点
            point1 = shape.part(0)
            point2 = shape.part(2)

            # 求两点中心
            eyes_center = ((point1.x+point2.x)//2,(point1.y+point2.y)//2)

            # cv2.circle(img,eyes_center,3,color=(0,255,0))  
            # cv2.imshow("image",img)
            # cv2.waitKey()

            #  根据人脸大小调整帽子大小
            factor = 1.5
            resized_hat_h = int(round(rgb_hat.shape[0]*w/rgb_hat.shape[1]*factor))
            resized_hat_w = int(round(rgb_hat.shape[1]*w/rgb_hat.shape[1]*factor))

            if resized_hat_h > y:
                resized_hat_h = y-1

            # 根据人脸大小调整帽子大小
            resized_hat = cv2.resize(rgb_hat,(resized_hat_w,resized_hat_h))

流程一、**材料准备**

送您一顶圣诞帽

接下来就是依据脸的坐标来把帽子贴上去了,首先第1个难点是,因为帽子的尺寸和图片尺寸或然并不相符,所以只要一直戴的话,会冒出大小不平等的标题,而且地点也相比奇怪。比如说那样子。

故此就要求调整帽子尺寸和职位。代码如下,分成多少个函数。

# 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循环一张张读脸,然后加帽子,于是就完事了主旨的功能了,超级简单是或不是。嘿。

不过唯有一款帽子,不心旷神怡,圣诞节怎么能没有暗绿的罪名呢。

肆 、提取帽子和急需加上帽子的区域

根据事先所述,去Alpha通道作为mask。并求反。那五个mask三个用来把帽子图中的帽子区域取出来,三个用于把人物图中供给填帽子的区域空出来。前面你将会看到。

            # 用alpha通道作为mask
            mask = cv2.resize(a,(resized_hat_w,resized_hat_h))
            mask_inv =  cv2.bitwise_not(mask)

从原图中取出供给丰盛帽子的区域,那里大家用的是位运算操作。

            # 帽子相对与人脸框上线的偏移量
            dh = 0
            dw = 0
            # 原图ROI
            # bg_roi = img[y+dh-resized_hat_h:y+dh, x+dw:x+dw+resized_hat_w]
            bg_roi = img[y+dh-resized_hat_h:y+dh,(eyes_center[0]-resized_hat_w//3):(eyes_center[0]+resized_hat_w//3*2)]

            # 原图ROI中提取放帽子的区域
            bg_roi = bg_roi.astype(float)
            mask_inv = cv2.merge((mask_inv,mask_inv,mask_inv))
            alpha = mask_inv.astype(float)/255

            # 相乘之前保证两者大小一致(可能会由于四舍五入原因不一致)
            alpha = cv2.resize(alpha,(bg_roi.shape[1],bg_roi.shape[0]))
            # print("alpha size: ",alpha.shape)
            # print("bg_roi size: ",bg_roi.shape)
            bg = cv2.multiply(alpha, bg_roi)
            bg = bg.astype('uint8')

那是的背景区域(bg)如下图所示。能够看出,刚好是亟需填写帽子的区域缺失了。

此处写图片描述

下一场咱们领到帽子区域。

            # 提取帽子区域
            hat = cv2.bitwise_and(resized_hat,resized_hat,mask = mask)

领到获得的罪名区域如下图。罪名区域正好与上贰个背景区域互补。

此间写图片描述

首先我们须求未焚徙薪3个圣诞帽的资料,格式最好为PNG,因为PNG的话大家能够直接用Alpha通道作为掩膜使用。大家用到的圣诞帽如下图:

充实帽子款式,随机采取

那个就非常不难了,首先把帽子的路线都检查和测试出来,之后再在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,然后就到位啦!

伍 、添加圣诞帽

终极我们把八个区域相加。再放回到原图中去,就能够赢得大家想要的圣诞帽图了。那里须求留意的正是,相加在此以前resize一下担保两者大小一样,因为也许会出于四舍五入原因不一致。

            # 相加之前保证两者大小一致(可能会由于四舍五入原因不一致)
            hat = cv2.resize(hat,(bg_roi.shape[1],bg_roi.shape[0]))
            # 两个ROI区域相加
            add_hat = cv2.add(bg,hat)
            # cv2.imshow("add_hat",add_hat) 

            # 把添加好帽子的区域放回原图
            img[y+dh-resized_hat_h:y+dh,(eyes_center[0]-resized_hat_w//3):(eyes_center[0]+resized_hat_w//3*2)] = add_hat

末尾大家获取的职能图如下所示。

output.jpg

关切群众号:CVPy,回复“圣诞”恐怕”圣诞帽“大概参预下方知识星球皆可收获完整代码的Github地址。


知识星球

除外平日发小说之外,也会发一些日常学习进度中其它的参考资料和代码,欢迎到场。

此处写图片描述

体育365网址 1

宜人的测试时间

后来就到了可喜的测试时间啦,让我们来探视效果怎样呢。

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

啊,不错不错,都是别出来了。再来看看笔者欢娱的四重奏。

功能喜人,原来不光有带帽子功用,还是能够够准确地识别出有没有被NT福睿斯,厉害厉害。

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

嗯….
怎么才如此点,难道说除非姿容大于8的人才能带上圣诞帽。不对,笔者的分类器怎么会这么肤浅呢!

那么调调face_detection里面detectMultiScale的参数看看,因为scaleFactor参数影响了图片中国远洋运输总公司近人脸的检查和测试,把它调大学一年级些。

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

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

效用不一般,还很亲密地给前边毛主席像加了顶圣诞帽。发给老爹,阿爸代表很中意给了个红包。

啊,还是能怎么玩呢。

体育365网址,对了!未来微信不都快成了动物园了呢,拿喵星人来测试一下。当当!

噫,啥也不曾,又测试了多只猫居然还丰富,看来未来的模型只可以检查和测试人脸。那会不会有猫脸检测模型呢,跑去OpenCV的代码库找了找,居然很亲切的还真有。修改了一下face_detection函数,具体参考文后github的链接。

再一测试,当当!

大概无微不至!

咱俩因而通道分别能够取得圣诞帽图像的alpha通道。代码如下:

尾声

早上拿着电脑去给心上人彰显活动戴圣诞帽系统,先传输图片,然后输入模型,保存图片,传到手提式有线电话机,整个进度竟然只用了10分钟。作者只问您,你可知过这么高级的系统啊!!!

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

r,g,b,a = cv2.split(hat_img) 
rgb_hat = cv2.merge((r,g,b))

cv2.imwrite("hat_alpha.jpg",a)

…………………………………………………………………………………..

劳方和资方才不罕见这么low逼的P图技术吗!!!

github代码:
https://github.com/andy-yangz/gimme\_a\_Santa\_hat

为了能够与rgb通道的头像图片进行演算,大家把rgb三通道合成一张rgb的彩色帽子图。Alpha通道的图像如下图所示。

体育365网址 2

贰 、人脸检查和测试与人脸关键点检查和测试

咱俩用下边那张图作为我们的测试图片。

体育365网址 3

上面咱们用dlib的正脸检查和测试器进行人脸检查和测试,用dlib提供的模型提取人脸的两个关键点。代码如下:

  # dlib人脸关键点检测器
  predictor_path = "shape_predictor_5_face_landmarks.dat"
  predictor = dlib.shape_predictor(predictor_path) 

  # dlib正脸检测器
  detector = dlib.get_frontal_face_detector()

  # 正脸检测
  dets = detector(img, 1)

  # 如果检测到人脸
  if len(dets)>0: 
    for d in dets:
      x,y,w,h = d.left(),d.top(), d.right()-d.left(), d.bottom()-d.top()
      # x,y,w,h = faceRect 
      cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2,8,0)

      # 关键点检测,5个关键点
      shape = predictor(img, d)
      for point in shape.parts():
        cv2.circle(img,(point.x,point.y),3,color=(0,255,0))

      cv2.imshow("image",img)
      cv2.waitKey() 

这一部分成效如下图:

体育365网址 4

三 、调整帽子大小

作者们选取多个眼角的点,求大旨作为放置帽子的x方向的参阅坐标,y方向的坐标用人脸框上线的y坐标表示。然后大家遵照人脸检查和测试获得的人脸的深浅调整帽子的轻重,使得帽子大小适当。

# 选取左右眼眼角的点
  point1 = shape.part(0)
  point2 = shape.part(2)

  # 求两点中心
  eyes_center = ((point1.x+point2.x)//2,(point1.y+point2.y)//2)

  # cv2.circle(img,eyes_center,3,color=(0,255,0)) 
  # cv2.imshow("image",img)
  # cv2.waitKey()

  # 根据人脸大小调整帽子大小
  factor = 1.5
  resized_hat_h = int(round(rgb_hat.shape[0]*w/rgb_hat.shape[1]*factor))
  resized_hat_w = int(round(rgb_hat.shape[1]*w/rgb_hat.shape[1]*factor))

  if resized_hat_h > y:
    resized_hat_h = y-1

  # 根据人脸大小调整帽子大小
resized_hat = cv2.resize(rgb_hat,(resized_hat_w,resized_hat_h))

肆 、提取帽子和须要加上帽子的区域

安份守己事先所述,去Alpha通道作为mask。并求反。那八个mask1个用于把帽子图中的帽子区域取出来,三个用来把人物图中要求填帽子的区域空出来。前面你将相会到。         

# 用alpha通道作为mask
mask = cv2.resize(a,(resized_hat_w,resized_hat_h))
mask_inv = cv2.bitwise_not(mask)

从原图中取出需求加上帽子的区域,那里大家用的是位运算操作。

 # 帽子相对与人脸框上线的偏移量
 dh = 0
 dw = 0
  # 原图ROI
  # bg_roi = img[y+dh-resized_hat_h:y+dh, x+dw:x+dw+resized_hat_w]
  bg_roi = img[y+dh-resized_hat_h:y+dh,(eyes_center[0]-resized_hat_w//3):(eyes_center[0]+resized_hat_w//3*2)]

 # 原图ROI中提取放帽子的区域
  bg_roi = bg_roi.astype(float)
 mask_inv = cv2.merge((mask_inv,mask_inv,mask_inv))
 alpha = mask_inv.astype(float)/255

  # 相乘之前保证两者大小一致(可能会由于四舍五入原因不一致)
  alpha = cv2.resize(alpha,(bg_roi.shape[1],bg_roi.shape[0]))
  # print("alpha size: ",alpha.shape)
  # print("bg_roi size: ",bg_roi.shape)
  bg = cv2.multiply(alpha, bg_roi)
  bg = bg.astype('uint8')

那是的背景区域(bg)如下图所示。能够看到,刚好是急需填写帽子的区域缺点和失误了。

体育365网址 5

下一场大家领到帽子区域。

# 提取帽子区域
hat = cv2.bitwise_and(resized_hat,resized_hat,mask = mask)

领取获得的罪名区域如下图。帽子区域正好与上一个背景区域互补。

体育365网址 6

五 、添加圣诞帽

最后大家把多个区域相加。再放回到原图中去,就能够收获大家想要的圣诞帽图了。那里要求专注的正是,相加以前resize一下担保两者大小一样,因为恐怕会出于四舍五入原因不雷同。

# 相加之前保证两者大小一致(可能会由于四舍五入原因不一致)
   hat = cv2.resize(hat,(bg_roi.shape[1],bg_roi.shape[0]))
   # 两个ROI区域相加
   add_hat = cv2.add(bg,hat)
   # cv2.imshow("add_hat",add_hat) 

   # 把添加好帽子的区域放回原图
 img[y+dh-resized_hat_h:y+dh,(eyes_center[0]-resized_hat_w//3):(eyes_center[0]+resized_hat_w//3*2)] = add_hat

最终大家获得的意义图如下所示。

体育365网址 7

下载:完整代码

如上正是本文的全体内容,希望对大家的求学抱有扶助,也愿意我们多多帮助脚本之家。

你或然感兴趣的文章:

相关文章