OpenCv識別小羅伯特唐尼

一、OpenCV簡單介紹

在實現人臉識別之前,我們先簡單瞭解一下OpenCv的一些基本操作。在此之前,我們需要先安裝OpenCv,我們使用pip安裝:

pip install opencv-python

另外我們還需要另外一個模塊:

pip install opencv-contrib-python

接下來我們就可以學習OpenCv了。

1.1、OpenCv操作圖像

我們來簡單讀取一個圖像,並將該圖像顯示:

# 導入模塊
import cv2
# 讀取圖片
im = cv2.imread('1.jpg')
# 顯示圖片,該方法只會顯示一瞬間。(第一個參數爲窗口名稱,第二個參數爲ndarray對象)
cv2.imshow('im', im)
# 等待鍵盤輸入,傳入毫秒值,當傳入0時表示無限等待。(imshow配合該方法可以讓界面一直顯示)
cv2.waitKey(0)
# 因爲OpenCv是用C/C++寫的,所以需要釋放內存
cv2.destroyAllWindows()

上述代碼就實現了最簡單的讀取並顯示圖像的操作了。

1.2、灰度轉換

灰度就是使用黑色調錶示物體,即用黑色爲基準色,不同的飽和度的黑色來顯示圖像。 灰度轉換就是將圖片轉換成黑白圖像。因爲我們在人臉識別時,灰度圖像便於識別,所以我們先來了解一下。用OpenCv實現灰度轉換很簡單:

import cv2
# 讀取圖像
im = cv2.imread('1.jpg')
# 灰度轉換(第一個參數爲ndarray對象,第二個參數爲cv2中的常量),返回一個ndarray對象
grey = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# 將grey保存
cv2.imwrite('grey.jpg', grey)
# 顯示灰度轉換後的圖像
cv2.imshow('grey', grey)
# 等待鍵盤輸入
cv2.waitKey(0)
# 銷燬窗口
cv2.destroyAllWindows()

效果如下:

在這裏插入圖片描述

1.3、繪製圖形

我們後續在檢測人臉的時候,我們會繪製圖形,將人臉框起來。圖形的繪製也非常簡單,我們看如下代碼:

import cv2
# 讀取圖像
im = cv2.imread('1.jpg')
# 在圖像im上繪製矩形
"""
第一個參數爲ndarray對象
第二個參數爲左上角的座標(x1, y1)
第三個參數爲右下角的座標(x2, y2)
第四個參數爲顏色值,其順序不同於我們之前的,使用的是BGR
第五個參數爲線條寬度
"""
cv2.rectangle(im, (0, 0), (200, 200), (255, 255, 0), 2)
# 顯示圖像
cv2.imshow('im', im)
# 等待輸入
cv2.waitKey(0)
# 銷燬窗口
cv2.destroyAllWindows()

對比圖如下:

在這裏插入圖片描述

瞭解上面知識後,我們就可以進入下一步的學習了。

二、人臉檢測

2.1、獲取特徵數據

開始人類檢測之前,我們要先獲取一個特徵數據。我們先去官網,看到如下界面:

在這裏插入圖片描述

點擊相應的下載後,雙擊安裝就可以了。我們進入D:\CodeField\OpenCv\opencv\sources\data\haarcascades,前面爲你opencv的安裝目錄。進入該文件夾後,裏面全是特徵文件,我們一般選用haarcascade_frontalface_default.xml

2.1、檢測人臉

我們可以把特徵文件複製到我們項目下,也可以直接用絕對路徑引用。我們檢測人臉需要一個cv2.CascadeClassifier對象,該對象可以用來檢測人臉。代碼如下:

face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')

其中,傳入參數爲特徵文件的路徑。我們可以選擇相對路徑,也可以選擇絕對路徑。完整人類檢測代碼如下:

import cv2
# 加載特徵數據
face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
# 讀取圖片
im = cv2.imread('1.jpg')
# 檢測人臉,返回人臉的位置信息
faces = face_detector.detectMultiScale(im)
# 遍歷人臉
for x, y, w, h in faces:
    # 在人臉區域繪製矩形
    cv2.rectangle(im, (x, y), (x+w, y+h), (255, 255, 0), 2)
# 顯示圖像
cv2.imshow('im', im)
cv2.waitKey(0)
cv2.destroyAllWindows()

其中detectMultiScale方法返回一個ndarray對象,這個對象保存了n張人臉的左上角座標、臉的寬、臉的高。檢測效果如下:

在這裏插入圖片描述

不過有時會有一些誤差,大多數清晰人臉可以正常檢測到。

三、人臉識別

上面的內容我們已經說了人臉檢測的實現,那人臉識別和人臉檢測有什麼區別呢?它們的區別在於,人臉檢測是要確定一張圖像裏面有沒有人臉,而人臉識別則是要確定圖像中的人臉是誰。不過要確定是誰之前,我們需要先見過人臉的主人,這就需要我們訓練數據了。

3.1、訓練數據

訓練數據主要有兩個部分,人臉信息和標籤,其中標籤爲int列表。我在目錄gtx中準備了50來張鋼鐵俠圖片,爲了方便獲取標籤,我們先編寫如下代碼:

import os

path = "./gtx/"
# 獲取文件列表
paths = os.listdir(path)
i = 0	# 循環變量
for file in paths:
    i += 1
    # 將文件重命名
    os.rename(path+file, path + str(i) + str(1) + ".jpg")

這段代碼就是遍歷當前目錄下gtx文件夾下的圖片,將圖片名稱改爲數字+1+.jpg格式。

在這裏插入圖片描述

上面是我用爬蟲爬取的一些圖片,我們將這些使用上述代碼轉換成數字+1+.jpg格式,我們把1做爲小羅伯特唐尼的標籤,我們可以繼續多把其他人的人臉改爲數字+2+.jpg格式,這樣就可以做到區分。不過上述代碼有一個問題,即當我們遍歷到第四個圖片時,名稱需要改爲41.jpg,而在我的文件夾中已經存在41.jpg,所以會產生錯誤。我們將代碼改爲如下:

import os
path = "./gtx/"
paths = os.listdir(path)
i = 0
for file in paths:
    i += 1
    try:
        os.rename(path + file, path + str(i) + str(1) + ".jpg")
    except Exception as e:
        print(e)
        # 當發生異常時,直接跳過
        continue

準備好圖像後,我們就可以開始訓練數據了,訓練數據代碼如下:

import cv2
import os
import numpy

root_path = "./gtx/"

def getFacesAndLabels():
    """讀取圖片特徵和標籤"""
    global root_path
    faces = []
    lables = []

    # 獲取人臉檢測器
    face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')

    # 獲取圖片路徑
    files = os.listdir(root_path)
    for file in files:
        path = root_path + file

        # 讀取圖片
        im = cv2.imread(path)
        # 轉換灰度
        grey = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
        # 讀取人臉數據
        face = face_detector.detectMultiScale(grey)
        for x, y, w, h in face:
            # 設置標籤,分離文件名稱
            lables.append(int(file.split('.')[0]))
            # 設置人臉數據
            faces.append(grey[y:y+h, x:x+w])

    return faces, lables

# 調用方法獲取人臉信息及標籤
faces, labels = getFacesAndLabels()
# 獲取訓練對象
recognizer = cv2.face.LBPHFaceRecognizer_create()
# 訓練數據
recognizer.train(faces, numpy.array(labels))
# 保存訓練數據
recognizer.write('./trainer/trainer.yml')

在上面代碼中,我們上面的並沒有對文件名稱中的最後一個數字1進行區分,後續會使用到。關於訓練數據,大家可以多準備一些人物和圖片。

3.2、人臉識別

我們訓練完數據後,就可以進行人臉識別了。在識別之前我們先加載訓練數據,然後就是基本的人類檢測步驟。最後我們調用predict方法進行人臉識別,在訓練數據中匹配人物。

import cv2

# 加載訓練數據集
recognizer = cv2.face.LBPHFaceRecognizer_create()
recognizer.read('./trainer/trainer.yml')

# 準備識別的圖片
im = cv2.imread('1.jpg')
grey = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)

# 檢測人臉
face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
face = face_detector.detectMultiScale(grey)

for x, y, w, h in face:
    # 返回人臉標籤和可信度,可信度數值越低,可信度越高(用詞不當,不要在意)
    label, confidence = recognizer.predict(grey[y:y+h, x:x+w])
	# 這裏將60作爲界限,當檢測檢測值爲60時,我們就確定人物
    if confidence <= 60:
        if label % 10 == 1:
            print('小羅伯特唐尼')
        elif lable % 10 == 2:
            pass
    else:
        print("未匹配到數據")
    cv2.imshow('im', im)
    cv2.waitKey(0)
# 銷燬窗口
cv2.destroyAllWindows()

上述代碼中,我們用標籤label%10,可以獲得文件最後一個數字,這樣就可以達到區分人物的作用,我們用如下圖片進行測試。

在這裏插入圖片描述

輸出結果如下:

小羅伯特唐尼

算是成功了,多次測試後,發現準備率方面比較中規中矩。大家可以嘗試多準備寫圖片用來訓練,從而提高準確率。代碼已上傳GitHub:https://github.com/IronSpiderMan/GtxFaceDetector

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章