Python3.5+openCv在Windows下利用LBP算法进行人脸识别并匹配

  以前的人脸识别匹配须要大量图片进行建模,而后经过几率匹配,结果不是很准确,同时也不符合通常需求。通常需求是人员经过摄像头拍摄一张照片,而后将照片保存进行命名,以后若是再次经过摄像头进行验证时候,经过算法特征匹配这我的跟保存的图片中的类似度,类似度最低的就是这我的,固然若是有足够的理论跟实验支持,能够肯定最低的这个若是大于某个值,也认为不是这我的。git

LBP算法github

参考博客地址: http://blog.csdn.net/zouxy09/article/details/7929531算法

     http://blog.csdn.net/u010006643/article/details/46417091多线程

第二篇的最后结果是监测照片中是不是人脸,和人脸的各类表情匹配。可是咱们的需求是要让摄像头里的人匹配上后台保存的那张单独的图片,全部改进一下让LBP算法只比较两张图片差别,差别最小的就是这我的,虽然最后偏差仍然存在,可是算法是慢慢改进的,至少测试的过程个人识别结果都是我本身。app

下面说思路:ide

一 。摄像头截图,截图成灰色处理的,而且尺寸为98*116的,(后面LBP算法是按照98*116的,方便分割),而后手动挑取一张最好的看成对比库放到指定路径下。****注意文件名不要中文测试

  说明:这个截取若是断定是人脸了,就进行截取图片,有时候不会识别出人脸,人稍微移动一下就能够,这个跟手机识别软件差很少,多数状况你要动态的才能更好识别。ui

  操做:运行shibieJietu.pyspa

import numpy as np 
import cv2
import sys
import time
import os
def CatVideo():
    cv2.namedWindow("shibie")
    #1调用摄像头
    cap=cv2.VideoCapture(0)
    #2人脸识别器分类器
    classfier=cv2.CascadeClassifier("Train.xml")
    color=(0,255,0)
    while cap.isOpened():
        ok,frame=cap.read()
        if not ok:
            break
        #2灰度转换
        grey=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
        #人脸检测,1.2和2分别为图片缩放比例和须要检测的有效点数
        faceRects = classfier.detectMultiScale(grey, scaleFactor = 1.2, minNeighbors = 3, minSize = (32, 32))
        if len(faceRects) > 0:            #大于0则检测到人脸                                
            for  (x, y, w, h) in faceRects :
                listStr = [str(int(time.time())), str(0)]  #以时间戳和读取的排序做为文件名称
                fileName = ''.join(listStr)

                f = cv2.resize(grey[y:(y + h), x:(x + w)], (98, 116))
                cv2.imwrite('D:\opencv\pictures\picTest'+os.sep+'%s.jpg' % fileName, f)   
                cv2.rectangle(frame, (x - 10, y - 10), (x + w + 10, y + h + 10), color, 3)
        cv2.imshow("shibie",frame)
        print("ceshi2")
        if cv2.waitKey(10)&0xFF==ord('q'):
            break

    cap.release()
    cv2.destroyAllWindows()



CatVideo()

二 。photoKu文件夹的六个文件夹,分别放上不一样人,照片都是灰化处理的,尺寸98*116。灰化图片详情参考上一篇博客的pick_face.py。若是周围人多的话也可让他经过摄像头进行步骤一取到图片,但  是我这实在没什么人帮忙,就用网上图片凑活了。.net

      运行compare.py首先执行runLBP算法,将六个文件夹里的图片经过算法算出LBP算子和统计直方图。

三 。开启摄像头,识别人脸后将人脸进行judgeFace 方法与刚才的结果进行逐一匹配,找到方差最小的那个就是要匹配的那我的了。

from numpy import *
from numpy import linalg as la
import cv2
import os
import math
from read_data import read_name_list


os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

# 为了让LBP具备旋转不变性,将二进制串进行旋转。
# 假设一开始获得的LBP特征为10010000,那么将这个二进制特征,
# 按照顺时针方向旋转,能够转化为00001001的形式,这样获得的LBP值是最小的。
# 不管图像怎么旋转,对点提取的二进制特征的最小值是不变的,
# 用最小值做为提取的LBP特征,这样LBP就是旋转不变的了。
def minBinary(pixel):
    length = len(pixel)
    zero = ''
    for i in range(length)[::-1]:
        if pixel[i] == '0':
            pixel = pixel[:i]
            zero += '0'
        else:
            return zero + pixel
    if len(pixel) == 0:
        return '0'

# 加载图像
def loadImageSet(add):  #add是路径
    print("步骤1")
    FaceMat = mat(zeros((1,98*116)))#根据图片尺寸更改   一共有几行
    j =0
    for i in os.listdir(add):
        #print(i)  #图片正常显示了
        #print(i.split('.')[1])  输出结果:jpg
        if i.split('.')[1] == 'jpg':
            try:
                img = cv2.imread(add+i,0)
                #print(add+i)   输出结果:D:\opencv\huge/15138183801.jpg
                # cv2.imwrite(str(i)+'.jpg',img)
            except:
                print ('load %s failed'%i)
            FaceMat[j,:] = mat(img).flatten()
            #print(FaceMat[j,:])   #取第j行
            #print(FaceMat[:,j])   #取第j列
            #http://blog.csdn.net/qq_18433441/article/details/54916991  flatten详解
            j += 1
    #print(FaceMat)
    return FaceMat

# 算法主过程
def LBP(FaceMat,R = 2,P = 8):
    print("步骤2")
    Region8_x=[-1,0,1,1,1,0,-1,-1]
    Region8_y=[-1,-1,-1,0,1,1,1,0]
    pi = math.pi
    LBPoperator = mat(zeros(shape(FaceMat)))
    for i in range(shape(FaceMat)[1]):
        # 对每个图像进行处理  转化成116*98的二维矩阵
        face = FaceMat[:,i].reshape(116,98)

        W,H = shape(face)
        tempface = mat(zeros((W,H)))
        for x in range(R,W-R):
            for y in range(R,H-R):
                repixel = ''
                pixel=int(face[x,y]) #取每个值
                # 圆形LBP算子
                for p in [2,1,0,7,6,5,4,3]:
                    p = float(p)
                    xp = x + R* cos(2*pi*(p/P))
                    yp = y - R* sin(2*pi*(p/P))
                    #print(xp)  输出结果 2.0
                    #print(pixel)  输出结果 1
                    #print(yp)   0.0
                    #print(face[2,0])  1.0
                    if int(face[int(xp),int(yp)])>pixel:
                        repixel += '1'
                    else:
                        repixel += '0'
                # minBinary保持LBP算子旋转不变
                tempface[x,y] = int(minBinary(repixel),base=2)
        LBPoperator[:,i] = tempface.flatten().T
        # cv2.imwrite(str(i)+'hh.jpg',array(tempface,uint8))
    return LBPoperator

    # judgeImg:未知判断图像
    # LBPoperator:实验图像的LBP算子
    # exHistograms:实验图像的直方图分布
def judgeFace(judgeImg,LBPoperator,exHistograms):
    judgeImg = judgeImg.T
    ImgLBPope = LBP(judgeImg)
    #  把图片分为7*4份 , calHistogram返回的直方图矩阵有28个小矩阵内的直方图
    judgeHistogram = calHistogram(ImgLBPope)
    minIndex = 0
    minVals = inf    #正无穷


    for  i in range(shape(LBPoperator)[1]):
        exHistogram = exHistograms[:,i]
        diff = (array(exHistogram-judgeHistogram)**2).sum()
        print(diff)
    return diff

# 统计直方图
def calHistogram(ImgLBPope):
    Img = ImgLBPope.reshape(116,98)
    W,H = shape(Img)
    # 把图片分为7*4份
    Histogram = mat(zeros((256,7*4)))
    maskx,masky = W/4,H/7  #29 14
    for i in range(4):
        for j in range(7):
            # 使用掩膜opencv来得到子矩阵直方图
            mask = zeros(shape(Img), uint8)
            mask[int(i*maskx): int((i+1)*maskx),int(j*masky) :int((j+1)*masky)] = 255
            hist = cv2.calcHist([array(Img,uint8)],[0],mask,[ 256],[0,256])
            Histogram[:,(i+1)*(j+1)-1] = mat(hist).flatten().T
    return Histogram.flatten().T

def runLBP(tuPianPath):
    # 加载图像
    FaceMat = loadImageSet(tuPianPath).T  #反转矩阵
    LBPoperator = LBP(FaceMat) # 得到实验图像LBP算子
    
    # 得到实验图像的直方图分布,这里计算是为了能够屡次使用
    exHistograms = mat(zeros((256*4*7,shape(LBPoperator)[1])))
    for i in range(shape(LBPoperator)[1]):
        exHistogram = calHistogram(LBPoperator[:,i])
        exHistograms[:,i] = exHistogram
    allLBPoperator.append(LBPoperator)
    allexHistograms.append(exHistograms)
    #build_camera(LBPoperator,exHistograms)
    #loadname = 'D:\opencv/'+'8.jpg'
    #judgeImg = cv2.imread(loadname,0)
    #jresult=judgeFace(mat(judgeImg).flatten(),LBPoperator,exHistograms)
    #if judgeFace(mat(judgeImg).flatten(),LBPoperator,exHistograms)+1 == int(nameList[i]):
    
def build_camera():
    print(1111)
    #opencv文件中人脸级联文件的位置,用于帮助识别图像或者视频流中的人脸
    face_cascade = cv2.CascadeClassifier('Train.xml')

    #打开摄像头并开始读取画面
    cameraCapture = cv2.VideoCapture(0)
    success, frame = cameraCapture.read()

    while success and cv2.waitKey(1) == -1:
        success, frame = cameraCapture.read()
        grey = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) #图像灰化
        faces = face_cascade.detectMultiScale(grey, 1.3, 5) #识别人脸
        for (x, y, w, h) in faces:
            f = cv2.resize(grey[y:(y + h), x:(x + w)], (98, 116))
            result=inf
            show_name=''
            for i in range(len(allTuPianPath)):
                jresult=judgeFace(mat(f).flatten(),allLBPoperator[i],allexHistograms[i])
                if jresult==0:
                    show_name=allmen[i]
                    break
                elif jresult<result:
                    result=jresult
                    show_name=allmen[i]
            #print(f)
            # if prob >0.5:    #若是模型认为几率高于70%则显示为模型中已有的label
            #     show_name = name_list[label]
            # else:
            #     show_name = 'Stranger'
            cv2.putText(frame, show_name, (x, y - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, 255, 2)  #显示名字
            frame = cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2)  #在人脸区域画一个正方形出来
        cv2.imshow("Camera", frame)
    return show_name


    cameraCapture.release()
    cv2.destroyAllWindows()



if __name__ == '__main__':
    allLBPoperator=[]#六个LBP算子
    allexHistograms=[]#六个统计直方图
    #六个文件夹路径 allTuPianPath
=['D:\opencv\photoKu\huge/','D:\opencv\photoKu\luyi/','D:\opencv\photoKu\me/','D:\opencv\photoKu\shayi/','D:\opencv\photoKu\wuyanzu/','D:\opencv\photoKu\zhoujielun/'] #六我的名
   allmen
=['hege','luyi','me','shayi','wuyanzu','zhoujielun']

  #分别获取每张图片的LBP算子,和统计直方图
for tuPianPath in allTuPianPath: runLBP(tuPianPath)
   #开启摄像头 name
=build_camera()
   #最后摄像头若是关闭会打印出这我的名
print(name)

 

这张图片是输出的结果,开始分别算出六个LBP算子和统计立方图片,步骤一步骤二打印六次,而后1111进入摄像头,开始比较识别到的人脸,与六张图的平方差分别是

245164,175674,50472,248620,162249,222144。 (第三张是我本人,平方差是5万多,明显比其余的低的多)

****这里须要注意的是,摄像头以前截取的头像,应该跟对比时候的头像差异不会太大,由于都只有一个头,环境都差不太多,至于化妆,戴帽子什么的应该会有差别,可是谁家早上视频识别时候很差好的,非得戴帽子,带镜子啥的,因此,只要尽可能作到一致性,识别差距就不会太大。

 

因为是while循环摄像头,因此识别到的下一张头像继续运算下去,这里其实能够将摄像头关掉了,而后打印出人名便可,有须要的能够本身改动。我懒。

最后不得不认可,运算过程太卡顿,并且摄像头循环也没作退出处理,须要慢慢等着,而后六个平方差都算完后头像上显示人名,之后争取改进成多线程的,估计会快一些。如今是截取了一张图片而后就开始比对,这张图片此时不能再动了,致使摄像头发生卡顿,多线程应该可以解决这个问题。

代码地址:https://github.com/chaoyuebeijita/face

 

facecompare+LBP.zip

相关文章
相关标签/搜索