python进阶之基于pynq开发板的人脸检测程序解析

__author__ = 'Jonny'
__doc__ ='http://pillow.readthedocs.io/en/3.1.x/reference/Image.html?highlight=fromarray'
# """
# 脸检测属于计算机视觉的范畴,早期人们的主要研究方向是人脸识别,即根据人脸来识别人物的身份,
# 后来在复杂背景下的人脸检测需求越来越大,人脸检测也逐渐作为一个单独的研究方向发展起来。
#
# 目前的人脸检测方法主要有两大类:基于知识和基于统计。
#
# “基于知识的方法主要利用先验知识将人脸看作器官特征的组合,根据眼睛、眉毛、嘴巴、鼻子等器官的特征以及相互之间的几何位置关系来检测人脸。
# 基于统计的方法则将人脸看作一个整体的模式——二维像素矩阵,从统计的观点通过大量人脸图像样本构造人脸模式空间,根据相似度量来判断人脸是否存在。
# 在这两种框架之下,发展了许多方法。目前随着各种方法的不断提出和应用条件的变化,将知识模型与统计模型相结合的综合系统将成为未来的研究趋势。”
#
# 基于知识的人脸检测方法
#
# Ø 模板匹配
# Ø 人脸特征
# Ø 形状与边缘
# Ø 纹理特性
# Ø 颜色特征
# 基于统计的人脸检测方法
# Ø 主成分分析与特征脸
# Ø 神经网络方法
# Ø 支持向量机
# Ø 隐马尔可夫模型
# Ø Adaboost算法
#
# PIL (Python Image Library) 是 Python 平台处理图片的事实标准,兼具强大的功能和简洁的 API.
#  实际上安装的却是 Pillow。PIL 的更新速度很慢,而且存在一些难以配置的问题,不推荐使用;
#  而 Pillow 库则是 PIL 的一个分支,维护和开发活跃,Pillow 兼容 PIL 的绝大多数语法,推荐使用
#
#
# OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows、Android和Mac OS操作系统上。
# 它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,
# 实现了图像处理和计算机视觉方面的很多通用算法。
#
# OpenCV提供了两个程序可以训练自己的级联分类器opencv_haartraining与opencv_traincascade。
# opencv_traincascade是一个新程序,使用OpenCV 2.x API 以C++编写。
# 这二者主要的区别是opencv_traincascade支持 Haar和 LBP (Local Binary Patterns)两种特征,
# 并易于增加其他的特征。与Haar特征相比,LBP特征是整数特征,因此训练和检测过程都会比Haar特征快几倍。
# LBP和Haar特征用于检测的准确率,是依赖训练过程中的训练数据的质量和训练参数。训练一个与基于Haar特征同样准确度的LBP的分类器是可能的。
# """
#打开 base>video 文件夹下的 opencv_face_detect_hdmi.ipynb。按照提示依次运行代码。
from pynq.overlays.base import BaseOverlay
from pynq.lib.video import *

base = BaseOverlay("base.bit")

#实例化一个视频图像输入接口对象
hdmi_in = base.video.hdmi_in
#实例化一个视频图像输出接口对象
hdmi_out = base.video.hdmi_out

#初始化
#配置多媒体接口以使用合适的像素模式,
#24指的是色彩位数,
# ‘1’==>黑白两色
# ‘2’==>4color,用于CGA
# ‘4’==>16中颜色,用于CGA,EGA,VGA
# '8'==>灰阶,都是在黑灰白之间
# '15/16' ==>高彩色
# ‘24’==>真彩色 也就是通常说的256*256*256
# ‘32’==>真彩色+alpha频道(储存重叠图层的图形资料)
# PIXEL_RGB = PixelFormat(24, COLOR_IN_RGB, COLOR_OUT_RGB)、
# PIXEL_RGBA = PixelFormat(32, COLOR_IN_RGB, COLOR_OUT_RGB)
# PIXEL_BGR = PixelFormat(24, COLOR_IN_BGR, COLOR_OUT_BGR)
# PIXEL_YCBCR = PixelFormat(24, COLOR_IN_YCBCR, COLOR_OUT_YCBCR)
# PIXEL_GRAY = PixelFormat(8, COLOR_IN_YCBCR, COLOR_OUT_GRAY)
hdmi_in.configure(PIXEL_RGB)
hdmi_out.configure(hdmi_in.mode, PIXEL_RGB)

#开启输入输出多媒体接口,实现图片的输入和输出
hdmi_in.start()
hdmi_out.start()

#输入待检测的图片(截屏)
import PIL.Image

#从通道读取一个帧并返回给用户
# 这个函数可能会阻塞,直到一个完整的框架被读取。》》必须是一次读取一个完整的视频图片的框架之后才能够进行处理,生成相应的图片和视频
# 一个单独的帧缓冲区被保存,因此在长时间的暂停阅读之后,第一个帧会返回一个陈旧的框架。
# 在开始处理循环之前,要确保一个最新的帧,在开始处理循环之前要读取一个额外的时间。
frame = hdmi_in.readframe()
img = PIL.Image.fromarray(frame)
#  从导出数组阵列接口的对象(使用缓冲协议)创建图像内存。
#  如果obj不是连续的,则调用tobytes方法并frombuffer()使用它。
# 参数:
#   obj - 具有数组接口的对象
#   模式 - 使用的模式(如果没有,将从类型确定)参见:模式。
# 返回:
#   一个图像对象。
img.save("/home/xilinx/jupyter_notebooks/base/video/data/face_detect.jpg")
# 将该图像保存在给定的文件名下。如果没有指定格式,如果可能的话,使用的格式是从文件扩展名确定的。
# 关键字选项可以用来为作者提供额外的指令。如果一个作者不能识别一个选项,它会被默默地忽略。每个作者的图像格式文档中描述了可用的选项 。
# 您可以使用文件对象而不是文件名。在这种情况下,您必须始终指定格式。文件对象必须实现seek,tell和write 方法,并在二进制模式打开。
# 参数:
#  fp - 文件名(字符串),pathlib.Path对象或文件对象。
#  格式 - 可选的格式覆盖。如果省略,则使用的格式由文件扩展名确定。如果使用文件对象而不是文件名,则应始终使用此参数。
#  选项 - 额外的参数给图像写入器。
#  返回:	没有
#
# 举例:
#    KeyError - 如果输出格式不能从文件名确定。使用格式选项来解决这个问题。
#    IOError - 如果文件无法写入。该文件可能已被创建,并可能包含部分数据。
#img
#使用 opencv 进行面部检测

import cv2
import numpy as np
#frame = hdmi_in.readframe()
#先加载xml文件(也就是实现训练好的数据)生成级联分类器face_cascade。
face_cascade = cv2.CascadeClassifier(
 '/home/xilinx/jupyter_notebooks/base/video/data/'
 'haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier(
 '/home/xilinx/jupyter_notebooks/base/video/data/'
 'haarcascade_eye.xml')
#将图片灰度化,如果img维度为3,说明不是灰度图,先转化为灰度图gray,如果不为3,也就是2,原图就是灰度图
# if img.ndim == 3:
#  gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# else:
#  gray = img
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

#获取人脸坐标
# scale_factor:被检测对象的尺度变化。尺度越大,越容易漏掉检测的对象,但检测速度加快;尺度越小,检测越细致准确,但检测速度变慢。
# min_neighbors:数值越大,检测到对象的条件越苛刻;反之检测到对象的条件越宽松;
# minSize:检测对象的大小
#返回值是一个以元组形式为元素的列表
# 先加载xml文件生成级联分类器face_cascade
# ,然后用这个级联分类器对灰度图进行检测face_cascade.detectMultiScale(gray, 1.2, 5),
# 返回值即图片中所有人脸的坐标(x,y,w,h),在上面的函数中,我们转化了一下,使得函数返回的是人脸矩形的左上、右下顶点坐标。
# (注:坐标零点即原始图像左上顶点,往下y增加,往右x增加)。
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
#利用训话读取每一张人脸的位置坐标
for (x,y,w,h) in faces:
 #用矩形将人脸框出来,
 cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)
 roi_gray = gray[y:y+h, x:x+w]
 roi_color = frame[y:y+h, x:x+w]
 eyes = eye_cascade.detectMultiScale(roi_gray)
 for (ex,ey,ew,eh) in eyes:
  cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)

#将 OpenCV 面部识别结果输出到显示器
hdmi_out.writeframe(frame)

#在 Jupyter 中显示 OpenCV 面部识别结果并保存为 JPEG 格式图片
img = PIL.Image.fromarray(frame)
img.save("/home/xilinx/jupyter_notebooks/base/video/data/face_detect.jpg")
#img

#关闭 HDMI
hdmi_out.stop()
hdmi_in.stop()
del hdmi_in, hdmi_out

你可能感兴趣的:(python)