Python + Opencv / Dlib做人脸检测(视频/图片)

之前文章的记录比较泛泛,而且也没系统整理过,后面想着自己整理一下这些年的学习过程。此贴为证。

python:脚本型语言,计算机是不能够识别高级语言的,所以当我们运行一个高级语言程序的时候,就需要一个“翻译机”来从事把高级语言转变成计算机能读懂的机器语言的过程。这个过程分成两类,第一种是编译,第二种是解释。python是一种解释型语言,建立在虚拟机之上,执行脚本时同样是先编译到pyc再进行解释执行。

opencv:图像处理的基础类库,内含多种图像处理的函数。低版本的oepncv不支持python3,目前采用的是opencv4.2.0+python3.7.2

使用python调用opencv,将上图编译好的pyd文件拷贝到site-packages目录下就可以。

使用时import cv2即可查看

opencv对人脸检测的支持是在:

这两个分类器是常见的较为简单的分类器,但是人脸检测效果不太好。

dlib:人脸识别类库。对人脸检测、人脸关键点检测、表情检测均有较好的效果。

链接要收藏:http://dlib.net/files/

安装dlib:--安装opencv  --安装cmake(支持C++11及以上)  --安装boost(这个不知道为何)  --安装dlib(python setup.py install)

安装时假如电脑安装了visual studio 2015一定要升级到新的2015 update3,否则会报错。

下载dlib的训练模型data:

网速比较慢,先下载了两个一个是卷积积分人脸检测、一个是5点人脸landmark关键点。

实际测试时发现,对于打开电脑摄像头都有较好的效果,但是对于侧脸、低头等效果都不好,而且dlib对80*80的人脸进行的训练,所以小人脸检测不好,现在在学习精确度提高和速度优化。

代码很简单,如下:

# 参考示例
#_*_ coding:utf-8 _*_

import numpy as np
import cv2
import dlib

cap = cv2.VideoCapture(0)

# hog_face_detector = dlib.cnn_face_detection_model_v1(r'D:\Python37\Lib\site-packages\dlib-19.14\data\mmod_human_face_detector.dat')
detector = dlib.get_frontal_face_detector()

while 1:
    ret, img = cap.read()
    # 取灰度
    img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    # 人脸数rects
    # face_rects = hog_face_detector(img, 0)
    face_rects = detector(img, 1)

    for index, face in enumerate(face_rects):
        print('face {}; left {}; top {}; right {}; bottom {}'.format(index, face.left(), face.top(), face.right(),
                                                                     face.bottom()))

        # 在图片中标注人脸,并显示
        left = face.left()
        top = face.top()
        right = face.right()
        bottom = face.bottom()
        cv2.rectangle(img, (left, top), (right, bottom), (0, 255, 0), 2)

    cv2.namedWindow("img", 2)
    cv2.imshow("img", img)
    if cv2.waitKey(1) & 0xFF == ord("q"):
        break

opencv只对视频内的图像做的一帧帧的处理,而没有处理音频的函数。

这时对音频处理可以使用ffmpeg,ffmpeg有很多的命令行,当前做的小工具:

1、主要是想将一个视频内自动跟踪人脸实现人脸打码。

2、将一些不清晰的图像/视频转换成清晰的视频。

目前来看,只有对正脸的检测效果好,在积极优化中。

果然兴趣是最好的老师,拍点小电影可以省去自己打码的时间,哈哈。

ffmpeg相关代码如下:

# encoding: utf-8


import os
import subprocess
import cv2

def mkdir(path):
    path = path.strip()
    path = path.rstrip("\\")
    isExists = os.path.exists(path)
    if not isExists:
        os.makedirs(path)
        print (path + " 创建成功 ")
    else:
        print (path + " 目录已存在 ")

def listfile(root):
    listfilename = []
    for dirpath, dirnames, filenames in os.walk(root):
        for file in filenames:
            if file.endswith('.mp4'):
                listfilename.append(os.path.join(dirpath, file))
    return listfilename

if __name__ == '__main__' :

    rootpth = r"E:\test\0"

    listmp4 = listfile(rootpth)

    mp3path  = rootpth + "\\" + "mp3"
    frszpath = rootpth + "\\" + "formatsize"
    oputpath = rootpth + "\\" + "output"

    os.mkdir(mp3path)
    os.mkdir(frszpath)
    os.mkdir(oputpath)

    # 分离视频的音频信号
    for i in range(0,len(listmp4)):
        mp3name = mp3path + "\\" + listmp4[i].split('\\')[-1].split('.')[0]
        command = "ffmpeg -i" + " " + listmp4[i] + " " + \
                  "-vn" + " " + mp3name + ".mp3"
        print('cmd',command)
        subprocess.call(command, shell=True)
    print ("mp3 split done!")

    # 将不符合9/16的视频通过添加黑边format到9/16
    for k in range(0, len(listmp4)):
        cap = cv2.VideoCapture(listmp4[k])
        w = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
        h = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
        if (w/h <= 0.56):
            frszname = frszpath + "\\" + listmp4[k].split('\\')[-1].split('.')[0]
            padstr  = str(w) + ":" + str(h) + ",pad=136:240:0:108:black"
            command = "ffmpeg -i" + " " + listmp4[k] + " " \
                      + "-vf scale=" + padstr + " " + frszname + ".mp4"
            print('cmd', command)
            subprocess.call(command, shell=True)
        cap.release()
    print("formatsize done!")

    # 视频插值到480P,画面清晰度提高
    for k in range(0, len(listmp4)):
        cap = cv2.VideoCapture(listmp4[k])
        w = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
        h = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
        fourcc = cv2.VideoWriter_fourcc(*'XVID')  # 指定编码器
        outname = oputpath + '\\' + listmp4[k].split('\\')[-1].split('.')[0] + '.mp4'
        out = cv2.VideoWriter(outname, fourcc, 30.0, (480, 640), True)  # 设置视频属性
        if (w/h > 0.56):
            while (cap.isOpened()):
                ret, frame = cap.read()
                if ret == True:
                    fes = cv2.resize(frame, (480, 640), interpolation=cv2.INTER_CUBIC)
                    out.write(fes)
                else:
                    break
            cap.release()
            out.release()
    print("convert done!")

其实可以看出上述只是利用opencv做了一下插值处理,实际实验效果并非那么好。看来还得去学下超分辨率啊。

上面这些内容用了一周的时间才搞好,果然上班忙里偷闲还是挺累的,不过加油吧。

/*******************************华丽的分割线************************************/

后续学习点:

人脸检测的侧脸、小人脸精度提高。

图像单帧超分辨率学习。

运行速度优化?多线程?笔记本已经很吃力了。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值