opencv,tensorflow,cnn實(shí)現(xiàn)人臉識(shí)別

opencv實(shí)現(xiàn)人臉檢測(cè),tensorflow利用cnn實(shí)現(xiàn)人臉識(shí)別,python完成
github地址: https://github.com/wangdxh/tensorflow-learn

基礎(chǔ)知識(shí)

獲得人臉數(shù)據(jù)

tensorflow_face_camera.py
def getfacefromcamera(outdir):
    createdir(outdir)
    camera = cv2.VideoCapture(0)
    haar = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
    n = 1
    while 1:
        if (n <= 200):
            print('It`s processing %s image.' % n)
            # 讀幀
            success, img = camera.read()

            gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            faces = haar.detectMultiScale(gray_img, 1.3, 5)
            for f_x, f_y, f_w, f_h in faces:
                face = img[f_y:f_y+f_h, f_x:f_x+f_w]
                face = cv2.resize(face, (IMGSIZE, IMGSIZE))
                #could deal with face to train
                face = relight(face, random.uniform(0.5, 1.5), random.randint(-50, 50))
                cv2.imwrite(os.path.join(outdir, str(n)+'.jpg'), face)

                cv2.putText(img, 'haha', (f_x, f_y - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, 255, 2)  #顯示名字
                img = cv2.rectangle(img, (f_x, f_y), (f_x + f_w, f_y + f_h), (255, 0, 0), 2)
                n+=1
            cv2.imshow('img', img)
            key = cv2.waitKey(30) & 0xff
            if key == 27:
                break
        else:
            break
    camera.release()
    cv2.destroyAllWindows()
    
 name = input('please input yourename: ')
 getfacefromcamera(os.path.join('./image/trainfaces', name))
  • 根據(jù)輸入的名字在./image/trainfaces目錄下面創(chuàng)建子目錄,將本次采集的頭像保存在該目錄之下
  • 使用opencv打開攝像頭,獲取頭像
  • 檢測(cè)出人臉的區(qū)域,調(diào)整一下亮暗度,將圖片保存
  • 保存200張之后,采集結(jié)束

創(chuàng)建cnn網(wǎng)絡(luò)

具體在tensorflow_face_conv.py

def cnnLayer(classnum):
    ''' create cnn layer'''
    # 第一層
    W1 = weightVariable([3, 3, 3, 32]) # 卷積核大小(3,3), 輸入通道(3), 輸出通道(32)
    b1 = biasVariable([32])
    conv1 = tf.nn.relu(conv2d(x_data, W1) + b1)
    pool1 = maxPool(conv1)
    # 減少過擬合,隨機(jī)讓某些權(quán)重不更新
    drop1 = dropout(pool1, keep_prob_5) # 32 * 32 * 32 多個(gè)輸入channel 被filter內(nèi)積掉了

    # 第二層
    W2 = weightVariable([3, 3, 32, 64])
    b2 = biasVariable([64])
    conv2 = tf.nn.relu(conv2d(drop1, W2) + b2)
    pool2 = maxPool(conv2)
    drop2 = dropout(pool2, keep_prob_5) # 64 * 16 * 16

    # 第三層
    W3 = weightVariable([3, 3, 64, 64])
    b3 = biasVariable([64])
    conv3 = tf.nn.relu(conv2d(drop2, W3) + b3)
    pool3 = maxPool(conv3)
    drop3 = dropout(pool3, keep_prob_5) # 64 * 8 * 8

    # 全連接層
    Wf = weightVariable([8*16*32, 512])
    bf = biasVariable([512])
    drop3_flat = tf.reshape(drop3, [-1, 8*16*32])
    dense = tf.nn.relu(tf.matmul(drop3_flat, Wf) + bf)
    dropf = dropout(dense, keep_prob_75)

    # 輸出層
    Wout = weightVariable([512, classnum])
    bout = weightVariable([classnum])
    #out = tf.matmul(dropf, Wout) + bout
    out = tf.add(tf.matmul(dropf, Wout), bout)
    return out

使用tf創(chuàng)建3層cnn,3 * 3的filter,輸入為rgb所以:

  • 第一層的channel是3,圖像寬高為64,輸出32個(gè)filter,maxpooling是縮放一倍
  • 第二層的輸入為32個(gè)channel,寬高是32,輸出為64個(gè)filter,maxpooling是縮放一倍
  • 第三層的輸入為64個(gè)channel,寬高是16,輸出為64個(gè)filter,maxpooling是縮放一倍

所以最后輸入的圖像是8 * 8 * 64,卷積層和全連接層都設(shè)置了dropout參數(shù)

將輸入的8 * 8 * 64的多維度,進(jìn)行flatten,映射到512個(gè)數(shù)據(jù)上,然后進(jìn)行softmax,輸出到onehot類別上,類別的輸入根據(jù)采集的人員的個(gè)數(shù)來確定。

圖片發(fā)自簡(jiǎn)書App

識(shí)別人臉分類

tensorflow_face.py

訓(xùn)練神經(jīng)網(wǎng)絡(luò)
def getfileandlabel(filedir):
    ''' get path and host paire and class index to name'''
    dictdir = dict([[name, os.path.join(filedir, name)] \
                    for name in os.listdir(filedir) if os.path.isdir(os.path.join(filedir, name))])
                    #for (path, dirnames, _) in os.walk(filedir) for dirname in dirnames])

    dirnamelist, dirpathlist = dictdir.keys(), dictdir.values()
    indexlist = list(range(len(dirnamelist)))

    return list(zip(dirpathlist, onehot(indexlist))), dict(zip(indexlist, dirnamelist))
    
pathlabelpair, indextoname = getfileandlabel('./image/trainfaces')
train_x, train_y = readimage(pathlabelpair)
train_x = train_x.astype(np.float32) / 255.0
myconv.train(train_x, train_y, savepath)    
  1. 將人臉從子目錄內(nèi)讀出來,根據(jù)不同的人名,分配不同的onehot值,這里是按照遍歷的順序分配序號(hào),然后訓(xùn)練,完成之后會(huì)保存checkpoint
  2. 圖像識(shí)別之前將像素值轉(zhuǎn)換為0到1的范圍
  3. 需要多次訓(xùn)練的話,把checkpoint下面的上次訓(xùn)練結(jié)果刪除,代碼有個(gè)判斷,有上一次的訓(xùn)練結(jié)果,就不會(huì)再訓(xùn)練了
識(shí)別圖像
def testfromcamera(chkpoint):
    camera = cv2.VideoCapture(0)
    haar = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
    pathlabelpair, indextoname = getfileandlabel('./image/trainfaces')
    output = myconv.cnnLayer(len(pathlabelpair))
    #predict = tf.equal(tf.argmax(output, 1), tf.argmax(y_data, 1))
    predict = output

    saver = tf.train.Saver()
    with tf.Session() as sess:
        #sess.run(tf.global_variables_initializer())
        saver.restore(sess, chkpoint)
        
        n = 1
        while 1:
            if (n <= 20000):
                print('It`s processing %s image.' % n)
                # 讀幀
                success, img = camera.read()

                gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
                faces = haar.detectMultiScale(gray_img, 1.3, 5)
                for f_x, f_y, f_w, f_h in faces:
                    face = img[f_y:f_y+f_h, f_x:f_x+f_w]
                    face = cv2.resize(face, (IMGSIZE, IMGSIZE))
                    #could deal with face to train
                    test_x = np.array([face])
                    test_x = test_x.astype(np.float32) / 255.0
                    
                    res = sess.run([predict, tf.argmax(output, 1)],\
                                   feed_dict={myconv.x_data: test_x,\
                                   myconv.keep_prob_5:1.0, myconv.keep_prob_75: 1.0})
                    print(res)

                    cv2.putText(img, indextoname[res[1][0]], (f_x, f_y - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, 255, 2)  #顯示名字
                    img = cv2.rectangle(img, (f_x, f_y), (f_x + f_w, f_y + f_h), (255, 0, 0), 2)
                    n+=1
                cv2.imshow('img', img)
                key = cv2.waitKey(30) & 0xff
                if key == 27:
                    break
            else:
                break
    camera.release()
    cv2.destroyAllWindows()
  1. 從訓(xùn)練的結(jié)果中恢復(fù)訓(xùn)練識(shí)別的參數(shù),然后用于新的識(shí)別判斷
  2. 打開攝像頭,采集到圖片之后,進(jìn)行人臉檢測(cè),檢測(cè)出來之后,進(jìn)行人臉識(shí)別,根據(jù)結(jié)果對(duì)應(yīng)到人員名字,顯示在圖片中人臉的上面

遺留問題

  • weight 和 bias 的初始化好像有些問題,隨機(jī)初始化會(huì)造成在某些情況下cost很大,梯度下不去,導(dǎo)致train結(jié)果很差。重新跑一次命中率又搞了,隨機(jī)這里可以使用truncated_normal再測(cè)試測(cè)試。

  • 輸出的種類數(shù)目是根據(jù)采集的人數(shù)去動(dòng)態(tài)變化,但是沒有給陌生人預(yù)留class,所以結(jié)果肯定在某個(gè)采集的人中,區(qū)別不出陌生人來,可以在onehot的個(gè)數(shù)加1,增加一個(gè)陌生人類別,再進(jìn)行測(cè)試。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容