用Python获取摄像头并实时控制人脸的实现示例


Posted in Python onJuly 11, 2019

实现流程

从摄像头获取视频流,并转换为一帧一帧的图像,然后将图像信息传递给opencv这个工具库处理,返回灰度图像(就像你使用本地静态图片一样)

程序启动后,根据监听器信息,使用一个while循环,不断的加载视频图像,然后返回给opencv工具呈现图像信息。

创建一个键盘事件监听,按下"d"键,则开始执行面部匹配,并进行面具加载(这个过程是动态的,你可以随时移动)。

面部匹配使用Dlib中的人脸检测算法来查看是否有人脸存在。如果有,它将为每个人脸创建一个结束位置,眼镜和烟卷会移动到那里结束。

然后我们需要缩放和旋转我们的眼镜以适合每个人的脸。我们将使用从Dlib的68点模型返回的点集来找到眼睛和嘴巴的中心,并为它们之间的空间旋转。

在我们实时获取眼镜和烟卷的最终位置后,眼镜和烟卷从屏幕顶部进入,开始匹配你的眼镜和嘴巴。

假如没有人脸,程序会直接返回你的视频信息,不会有面具移动的效果。

默认一个周期是4秒钟。然后你可以通过"d"键再次检测。

程序退出使用"q"键。

这里我将这个功能抽象成一个面具加载服务,请跟随我的代码一窥究竟吧。

1.导入对应的工具包

from time import sleep

import cv2
import numpy as np
from PIL import Image
from imutils import face_utils, resize

try:
  from dlib import get_frontal_face_detector, shape_predictor
except ImportError:
  raise

创建面具加载服务类DynamicStreamMaskService及其对应的初始化属性: 

class DynamicStreamMaskService(object):
  """
  动态黏贴面具服务
  """

  def __init__(self, saved=False):
    self.saved = saved # 是否保存图片
    self.listener = True # 启动参数
    self.video_capture = cv2.VideoCapture(0) # 调用本地摄像头
    self.doing = False # 是否进行面部面具
    self.speed = 0.1 # 面具移动速度
    self.detector = get_frontal_face_detector() # 面部识别器
    self.predictor = shape_predictor("shape_predictor_68_face_landmarks.dat") # 面部分析器
    self.fps = 4 # 面具存在时间基础时间
    self.animation_time = 0 # 动画周期初始值
    self.duration = self.fps * 4 # 动画周期最大值
    self.fixed_time = 4 # 画图之后,停留时间
    self.max_width = 500 # 图像大小
    self.deal, self.text, self.cigarette = None, None, None # 面具对象

按照上面介绍,我们先实现读取视频流转换图片的函数: 

def read_data(self):
  """
  从摄像头获取视频流,并转换为一帧一帧的图像
  :return: 返回一帧一帧的图像信息
  """
  _, data = self.video_capture.read()
  return data

接下来我们实现人脸定位函数,及眼镜和烟卷的定位: 

def get_glasses_info(self, face_shape, face_width):
  """
  获取当前面部的眼镜信息
  :param face_shape:
  :param face_width:
  :return:
  """
  left_eye = face_shape[36:42]
  right_eye = face_shape[42:48]

  left_eye_center = left_eye.mean(axis=0).astype("int")
  right_eye_center = right_eye.mean(axis=0).astype("int")

  y = left_eye_center[1] - right_eye_center[1]
  x = left_eye_center[0] - right_eye_center[0]
  eye_angle = np.rad2deg(np.arctan2(y, x))

  deal = self.deal.resize(
    (face_width, int(face_width * self.deal.size[1] / self.deal.size[0])),
    resample=Image.LANCZOS)

  deal = deal.rotate(eye_angle, expand=True)
  deal = deal.transpose(Image.FLIP_TOP_BOTTOM)

  left_eye_x = left_eye[0, 0] - face_width // 4
  left_eye_y = left_eye[0, 1] - face_width // 6

  return {"image": deal, "pos": (left_eye_x, left_eye_y)}

def get_cigarette_info(self, face_shape, face_width):
  """
  获取当前面部的烟卷信息
  :param face_shape:
  :param face_width:
  :return:
  """
  mouth = face_shape[49:68]
  mouth_center = mouth.mean(axis=0).astype("int")
  cigarette = self.cigarette.resize(
    (face_width, int(face_width * self.cigarette.size[1] / self.cigarette.size[0])),
    resample=Image.LANCZOS)
  x = mouth[0, 0] - face_width + int(16 * face_width / self.cigarette.size[0])
  y = mouth_center[1]
  return {"image": cigarette, "pos": (x, y)}

def orientation(self, rects, img_gray):
  """
  人脸定位
  :return:
  """
  faces = []
  for rect in rects:
    face = {}
    face_shades_width = rect.right() - rect.left()
    predictor_shape = self.predictor(img_gray, rect)
    face_shape = face_utils.shape_to_np(predictor_shape)
    face['cigarette'] = self.get_cigarette_info(face_shape, face_shades_width)
    face['glasses'] = self.get_glasses_info(face_shape, face_shades_width)

    faces.append(face)

  return faces

刚才我们提到了键盘监听事件,这里我们实现一下这个函数: 

def listener_keys(self):
  """
  设置键盘监听事件
  :return:
  """
  key = cv2.waitKey(1) & 0xFF
  if key == ord("q"):
    self.listener = False
    self.console("程序退出")
    sleep(1)
    self.exit()

  if key == ord("d"):
    self.doing = not self.doing

接下来我们来实现加载面具信息的函数: 

def init_mask(self):
  """
  加载面具
  :return:
  """
  self.console("加载面具...")
  self.deal, self.text, self.cigarette = (
    Image.open(x) for x in ["images/deals.png", "images/text.png", "images/cigarette.png"]
  )

上面基本的功能都实现了,我们该实现画图函数了,这个函数原理和之前我写的那篇用AI人脸识别技术实现抖音特效实现是一样的,这里我就不赘述了,可以去github或Python中文社区微信公众号查看。

def drawing(self, draw_img, faces):
  """
  画图
  :param draw_img:
  :param faces:
  :return:
  """
  for face in faces:
    if self.animation_time < self.duration - self.fixed_time:
      current_x = int(face["glasses"]["pos"][0])
      current_y = int(face["glasses"]["pos"][1] * self.animation_time / (self.duration - self.fixed_time))
      draw_img.paste(face["glasses"]["image"], (current_x, current_y), face["glasses"]["image"])

      cigarette_x = int(face["cigarette"]["pos"][0])
      cigarette_y = int(face["cigarette"]["pos"][1] * self.animation_time / (self.duration - self.fixed_time))
      draw_img.paste(face["cigarette"]["image"], (cigarette_x, cigarette_y),
              face["cigarette"]["image"])
    else:
      draw_img.paste(face["glasses"]["image"], face["glasses"]["pos"], face["glasses"]["image"])
      draw_img.paste(face["cigarette"]["image"], face["cigarette"]["pos"], face["cigarette"]["image"])
      draw_img.paste(self.text, (75, draw_img.height // 2 + 128), self.text)

既然是一个服务类,那该有启动与退出函数吧,最后我们来写一下吧。

简单介绍一下这个start()函数, 启动后根据初始化监听信息,不断监听视频流,并将流信息通过opencv转换成图像展示出来。
并且调用按键监听函数,不断的监听你是否按下"d"键进行面具加载,如果监听成功,则进行图像人脸检测,并移动面具,
并持续一个周期的时间结束,面具此时会根据你的面部移动而移动。最终呈现文章顶部图片的效果.

def start(self):
  """
  启动程序
  :return:
  """
  self.console("程序启动成功.")
  self.init_mask()
  while self.listener:
    frame = self.read_data()
    frame = resize(frame, width=self.max_width)
    img_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    rects = self.detector(img_gray, 0)
    faces = self.orientation(rects, img_gray)
    draw_img = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
    if self.doing:
      self.drawing(draw_img, faces)
      self.animation_time += self.speed
      self.save_data(draw_img)
      if self.animation_time > self.duration:
        self.doing = False
        self.animation_time = 0
      else:
        frame = cv2.cvtColor(np.asarray(draw_img), cv2.COLOR_RGB2BGR)
    cv2.imshow("hello mask", frame)
    self.listener_keys()

def exit(self):
  """
  程序退出
  :return:
  """
  self.video_capture.release()
  cv2.destroyAllWindows()

最后,让我们试试:

if __name__ == '__main__':
  ms = DynamicStreamMaskService()
  ms.start()

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python实现绘制树枝简单示例
Jul 24 Python
python打开网页和暂停实例
Sep 30 Python
python使用装饰器和线程限制函数执行时间的方法
Apr 18 Python
Python的Django框架可适配的各种数据库介绍
Jul 15 Python
Python中动态创建类实例的方法
Mar 24 Python
python面向对象_详谈类的继承与方法的重载
Jun 07 Python
Kears+Opencv实现简单人脸识别
Aug 28 Python
wxpython+pymysql实现用户登陆功能
Nov 19 Python
基于TensorFlow常量、序列以及随机值生成实例
Jan 04 Python
Python namedtuple命名元组实现过程解析
Jan 08 Python
django日志默认打印request请求信息的方法示例
May 17 Python
python性能测试工具locust的使用
Dec 28 Python
python实现LBP方法提取图像纹理特征实现分类的步骤
Jul 11 #Python
Python用字典构建多级菜单功能
Jul 11 #Python
Python + OpenCV 实现LBP特征提取的示例代码
Jul 11 #Python
python切片的步进、添加、连接简单操作示例
Jul 11 #Python
python 日期排序的实例代码
Jul 11 #Python
Python qqbot 实现qq机器人的示例代码
Jul 11 #Python
python的一些加密方法及python 加密模块
Jul 11 #Python
You might like
十天学会php之第七天
2006/10/09 PHP
Windows下PHP的任意文件执行漏洞
2006/10/09 PHP
PHP程序员编程注意事项
2008/04/10 PHP
PHP读取文件,解决中文乱码UTF-8的方法分析
2020/01/22 PHP
准确获得页面、窗口高度及宽度的JS
2006/11/26 Javascript
关于jQuery参考实例2.0 用jQuery选择元素
2013/04/07 Javascript
javascript调试之DOM断点调试法使用技巧分享
2014/04/15 Javascript
用js代码和插件实现wordpress雪花飘落效果的四种方法
2014/12/15 Javascript
提高jQuery性能优化的技巧
2015/08/03 Javascript
解决JS无法调用Controller问题的方法
2015/12/31 Javascript
50 个 jQuery 插件可将你的网站带到另外一个高度
2016/04/26 Javascript
json与jsonp知识小结(推荐)
2016/08/16 Javascript
微信小程序 基础知识css样式media标签
2017/02/15 Javascript
bootstrap中模态框、模态框的属性实例详解
2017/02/17 Javascript
jQuery实现链接的title快速出现的方法
2017/02/20 Javascript
基于Vue.js 2.0实现百度搜索框效果
2020/12/28 Javascript
基于jQuery的$.getScript方法去加载javaScript文档解析
2017/11/08 jQuery
react-native封装插件swiper的使用方法
2018/03/20 Javascript
Node.js开发之套接字(socket)编程入门示例
2019/11/05 Javascript
使用 UniApp 实现小程序的微信登录功能
2020/06/09 Javascript
vue 项目@change多个参数传值多个事件的操作
2021/01/29 Vue.js
[08:04]TI4西雅图DOTA2前线报道 海涛探访各路人马
2014/07/09 DOTA
[01:42]DOTA2 – 虚无之灵
2019/08/25 DOTA
Python类的基础入门知识
2008/11/24 Python
Linux下将Python的Django项目部署到Apache服务器
2015/12/24 Python
Python实现自动发送邮件功能
2021/03/02 Python
python入门前的第一课 python怎样入门
2018/03/06 Python
详解python:time模块用法
2019/03/25 Python
Opencv-Python图像透视变换cv2.warpPerspective的示例
2019/04/11 Python
浅谈多卡服务器下隐藏部分 GPU 和 TensorFlow 的显存使用设置
2020/06/30 Python
数百万免费的图形资源:Freepik
2020/09/21 全球购物
请编写一个 C 函数,该函数在给定的内存区域搜索给定的字符,并返回该字符所在位置索引值
2014/09/15 面试题
护士岗位职责
2014/02/16 职场文书
计算机应用应届生求职信
2014/07/12 职场文书
投标人法定代表人授权委托书格式
2014/09/28 职场文书
卫生主题班会
2015/08/14 职场文书