關鍵點提取:face_recognition、疲勞檢測、人臉校準、人臉數據庫

日萌社

人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度學習實戰(不定時更新)


人臉識別功能實現的原理介紹與算法介紹

人臉識別:人臉數據集

Adaboost 人臉檢測:Haar特徵及積分圖、分類器的級聯

關鍵點提取:face_recognition、疲勞檢測、人臉校準、人臉數據庫

 


face_recognition是世界上最簡單的人臉識別庫了,你可以通過Python引用或者命令行的形式使用
它,來管理和識別人臉。
該軟件包使用dlib中最先進的人臉識別深度學習算法,使得識別準確率在Labled Faces in the world
數據集下達到了99.38%準確率。
它同時提供了一個叫face_recognition的命令行工具,以便你可以用命令行對一個文件夾中的圖片進
行識別操作。
安裝:pip install face_recognition

 

創建兩個存儲圖片的目錄,known_people目錄存儲的圖片,
 
輸入命令:
face_recognition /known_people/ /unknown_pictures/
輸出結果:
/unknown_pictures/unknown1.jpg,Obama
輸出中,識別到的每張臉都單獨佔一行,輸出格式爲<圖片名稱>,<人名>
如果想指定想並行處理圖像,則可以指定cpu核數,例如指定4個cpu則可認爲是並行處理4倍的圖像:
face_recognition --cpus 4 /known_people/ /unknown_pictures/

 

圖像載入函數——load_image_file
load_image_file(file, mode='RGB')
加載一個圖像文件到一個numpy array類型的對象上。
參數:
file:待加載的圖像文件名字
mode:轉換圖像的格式
只支持“RGB”(8位RGB, 3通道)和“L”(黑白)
返回值: 一個包含圖像數據的numpy array類型的對象

 

首先我們加載一張人臉圖片,調用face_landmarks函數 從該圖片中,得到一個由臉部特徵關鍵點位置組成的字
典記錄列表:
(臉部特徵包括:鼻樑nose_bridge、鼻尖nose_tip、 下巴chin、左眼left_eye、右眼right_eye、左眉 left_eyebrow、右眉right_eyebrow、上脣top_lip、下 脣bottom_lip)
 

 

Dlib庫實現了2014年一篇非常經典的人 臉特徵點檢測的論文: Face Alignment at 3000 FPS via
Regression Local Binary Features,其 人臉特徵點檢測又快又準。 深圳大學於仕祺老師公佈的免費的
libfacedetect,人臉特徵點檢測也非常 快,效果也不錯,和Dlib一樣爲68特徵 點檢測,但魯棒性不如Dlib。Seetaface、
Dlib和libfacedetect都提供了人臉特徵 點檢測的接口。

 

人臉特徵提取函數——face_landmarks
face_landmarks(face_image,face_locations=None,model="large")
給定一個圖像,提取圖像中每個人臉的臉部特徵位置
參數:
face_image:輸入的人臉圖片
face_locations=None
可選參數,默認值爲None,代表默認解碼圖片中的每一個人臉。 若輸入face_locations()[i]可指定人臉進行解碼
model="large":輸出的特徵模型,默認爲“large”,可選“small”。 當選擇爲"small"時,只提取左眼、右眼、鼻尖這三種臉部特徵。

 

人臉特徵提取函數——face_landmarks
face_landmarks(face_image,face_locations=None,model="large")
給定一個圖像,提取圖像中每個人臉的臉部特徵位置
參數:
face_image:輸入的人臉圖片
face_locations=None
可選參數,默認值爲None,代表默認解碼圖片中的每一個人臉。
若輸入face_locations()[i]可指定人臉進行解碼 model="large"
輸出的特徵模型,默認爲“large”,可選“small”。 當選擇爲"small"時,只提取左眼、右眼、鼻尖這三種臉部特徵。

 

 

人臉編碼函數——face_encodings

 

 

返回值:
返回值類型爲:List[Dict[str,List[Tuple[Any,Any]]]],是由各個臉部特徵關鍵點位置組成的字典記錄
列表,一個Dict對象對應圖片中的一個人臉,其key爲某個臉部特徵:
如輸出中的nose_bridge、left_eye等,value是由該臉部特徵各個關鍵點位置組成的List,關鍵點位置是
一個Tuple(如上輸出中,nose_bridge對應的關鍵點位置組成的列表爲[(881L, 128L), (880L, 141L),
(880L, 154L), (879L, 167L)]

人臉編碼函數——face_encodings
face_encodings(face_image, known_face_locations=None, num_jitters=1)
給定一個圖像,返回圖像中每個人臉的128臉部編碼(特徵向量)。
參數:
face_image輸入的人臉圖像
known_face_locations可選參數,如果你知道每個人臉所在的邊界框
num_jitters=1在計算編碼時要重新採樣的次數。越高越準確,但速度越慢(100就會慢100倍)
返回值: 一個128維的臉部編碼列表

 

載入圖片,構建一個ImageDraw對象: polygon()方法用於繪製多邊形:第一個參數是多邊
形的幾個頂點位置組成的list,第二個參數fill是填充該 多邊形的顏色。
line()方法是用來畫多個點之間構成的線段,第一個參 數是點位置組成的list,第二個參數fill是線段的顏色,
第三個參數width是線段的寬度。

 

face_distance(face_encodings, face_to_compare)
給定一組面部編碼,將它們與已知的面部編碼進行比較,得到歐氏距離。對於每一個比較的臉,歐氏距離代表了這些
臉有多相似。
參數:
faces:要比較的人臉編碼列表
face_to_compare:待進行對比的單張人臉編碼數據
tolerance:兩張臉之間有多少距離纔算匹配。該值越小對比越嚴格,0.6是典型的最佳值
返回值: 一個numpy ndarray,數組中的歐式距離與faces數組的順序一一對應

 

face_recognition
找到每個人眼睛、鼻子、嘴巴和下巴的位置和輪廓。
import face_recognition
image = face_recognition.load_image_file("your_file.jpg")
face_locations = face_recognition.face_locations(image)

 

 

batch_face_locations(images, number_of_times_to_upsample=1, batch_size=128)
使用cnn人臉檢測器返回一個包含人臉特徵的二維數組,如果使用了GPU,這個函數能夠更快速的返回結果;如果不使
用GPU的話,該函數就沒必要使用。
參數:
images : 一個包含圖像數據的list,每個成員都是一個 numpy array類型
number_of_times_to_upsample: 從images的樣本中查找多少次人臉,該參數的值越高的話越能發現更小的人臉
batch_size: 每個GPU一次批處理多少個image
返回值:
一個元組列表,列表中的每個元組包含人臉的位置(top, right, bottom, left)

 

compare_faces(known_face_encodings, face_encoding_to_check, tolerance=0.6)
比較臉部編碼列表和候選編碼,看看它們是否匹配。
參數:
known_face_encodings:已知的人臉編碼列表
face_encoding_to_check:待進行對比的單張人臉編碼數據
tolerance:兩張臉之間有多少距離纔算匹配。該值越小對比越嚴格,0.6是典型的最佳值。
返回值:
一個 True或者False值的列表,該表指示了known_face_encodings列表的每個成員的匹配結果

 

face_locations(img, number_of_times_to_upsample=1, model='hog')
給定一個圖像,返回圖像中每個人臉的面部特徵位置(眼睛、鼻子等)
參數:
img:一個image(numpy array類型)
number_of_times_to_upsample:從images的樣本中查找多少次人臉,該參數值越高的話越能發現更小的人臉。
model:使用哪種人臉檢測模型。“hog” 準確率不高,但是在CPUs上運行更快,“cnn” 更準確更深度(且
GPU/CUDA加速,如果有GPU支持的話),默認是“hog”
返回值:
一個元組列表,列表中的每個元組包含人臉的位置(top, right, bottom, left)

 

face_recognition API總結:
load_image_file(file, mode='RGB')
face_landmarks(face_image,face_locations=None,model="large")
face_encodings(face_image, known_face_locations=None, num_jitters=1)
batch_face_locations(images, number_of_times_to_upsample=1, batch_size=128)
compare_faces(known_face_encodings, face_encoding_to_check, tolerance=0.6)
face_distance(face_encodings, face_to_compare)

 

實踐 1:人臉特徵點定位及上妝

 

ImageDraw模塊提供了圖像對 象的簡單2D繪製。用戶可以 使用這個模塊創建新的圖像, 註釋或潤飾已存在圖像,爲 web應用實時產生各種圖形
 
Python圖像處理庫PILImageDraw模塊
https://pillow.readthedocs.io/en/3.1.x/reference/ImageDraw.html
 

 

載入圖片,構建一個ImageDraw對象:
polygon()方法用於繪製多邊形:第一個參數是多邊形的幾 個頂點位置組成的list,第二個參數fill是填充該多邊形的顏
色。
line()方法是用來畫多個點之間構成的線段,第一個參數是 點位置組成的list,第二個參數fill是線段的顏色,第三個參 數width是線段的寬度。
d.line(face_landmarks['right_eyebrow'], fill=(68, 54, 39, 150), width=5)

 

實踐 2:人臉相似度比較
 
 
 
 
 
 
dlib庫的“shape_predictor_68_face_landmarks.dat”提取的只是人臉的68個特徵點(例如眼、嘴等
位置),“dlib_face_recognition_resnet_model_v1.dat”是人臉特徵提取的分類網絡,提取的128
維信息即是人臉的特徵信息,即人臉特徵向量。
不同人臉特徵向量之間,餘弦距離或歐式距離越大,則兩個特徵值相似度越低,屬於同一個人
的可能性越小,此時判斷兩人爲不同的人。
 
 
 
 
 
 
人臉特徵向量距離函數——face_distance()
face_distance(face_encodings,face_to_compare)
給定一組面部編碼,將它們與已知的面部編碼進行比較,得到歐氏距離。對於每一個比較的 臉,歐氏距離代表了這些臉有多相似。
參數:
face_encodings:輸入的人臉圖片
face_to_compare:待進行對比的單張人臉編碼數據
tolerance: 比對閾值,即兩張臉之間有多少距離纔算匹配。該值越小對比越嚴格,0.6是典型的最佳值
返回值: 一個numpy ndarray,數組中的歐式距離與faces數組的順序一一對應
 
 
dlib庫的“shape_predictor_68_face_landmarks.dat”提取的只是人臉的68個特徵點(例如眼、嘴等
位置),“dlib_face_recognition_resnet_model_v1.dat”是人臉特徵提取的分類網絡,提取的128
維信息即是人臉的特徵信息,即人臉特徵向量。
不同人臉特徵向量之間,餘弦距離或歐式距離越大,則兩個特徵值相似度越低,屬於同一個人
的可能性越小,此時判斷兩人爲不同的人。
 
 
 
 

餘弦相似度/餘弦相似性

1.餘弦相似度
	通過計算兩個向量的夾角餘弦值來評估他們之間的相似度。
	夾角餘弦值的取值範圍在[-1,1],任何角度的餘弦值都在-1到1之間。
	兩個向量之間的夾角角度的餘弦值(餘弦相似度的值)確定兩個向量是否大致指向相同的方向,與向量的的長度無關,僅僅與向量的指向方向相關。
	兩個向量之間夾角爲0°的話,餘弦值(餘弦相似度的值)爲1,代表兩個向量的指向方向相同。
	兩個向量之間夾角爲90°的話,餘弦值(餘弦相似度的值)爲0,代表兩個向量的指向方向垂直。
	兩個向量之間夾角爲180°的話,餘弦值(餘弦相似度的值)爲-1,代表兩個向量的指向方向相反。
	餘弦相似度通常用於正空間,因此給出的值爲0到1之間,通常用於文本挖掘中的文件比較。
	一個向量空間中兩個向量夾角間的餘弦值作爲衡量兩個個體之間差異的大小,餘弦值接近1,夾角趨於0,表明兩個向量越相似;
	餘弦值接近於0,夾角趨於90度,表明兩個向量越不相似。

2.餘弦相似度,又稱爲餘弦相似性,是通過計算兩個向量的夾角餘弦值來評估他們的相似度。
  餘弦相似度將向量根據座標值,繪製到向量空間中,如最常見的二維空間。
  餘弦相似度用於評估兩個向量的夾角的相似度。
  餘弦值的範圍在[-1,1]之間,值越趨近於1,代表兩個向量的方向越接近;越趨近於-1,他們的方向越相反;接近於0,表示兩個向量近乎於正交。
  最常見的應用就是計算文本相似度。將兩個文本根據他們詞,建立兩個向量,計算這兩個向量的餘弦值,就可以知道兩個文本在統計學方法中他們的相似度情況。
  實踐證明,這是一個非常有效的方法。

3.餘弦相似性通過測量兩個向量的夾角的餘弦值來度量它們之間的相似性。0度角的餘弦值是1,而其他任何角度的餘弦值都不大於1;並且其最小值是-1。
  從而兩個向量之間的角度的餘弦值確定兩個向量是否大致指向相同的方向。兩個向量有相同的指向時,餘弦相似度的值爲1;
  兩個向量夾角爲90°時,餘弦相似度的值爲0;兩個向量指向完全相反的方向時,餘弦相似度的值爲-1。
  這結果是與向量的長度無關的,僅僅與向量的指向方向相關。餘弦相似度通常用於正空間,因此給出的值爲-1到1之間。
  注意這上下界對任何維度的向量空間中都適用,而且餘弦相似性最常用於高維正空間。
  例如在信息檢索中,每個詞項被賦予不同的維度,而一個維度由一個向量表示,其各個維度上的值對應於該詞項在文檔中出現的頻率。
  餘弦相似度因此可以給出兩篇文檔在其主題方面的相似度。
  另外,它通常用於文本挖掘中的文件比較。此外,在數據挖掘領域中,會用到它來度量集羣內部的凝聚力。
  
4.兩個向量間的餘弦值可以通過使用歐幾里得點積公式求出:

	給定兩個屬性向量,A和B,其餘弦相似性θ由點積和向量長度給出,如下所示:

	給出的相似性範圍從-1到1:-1意味着兩個向量指向的方向正好截然相反,1表示它們的指向是完全相同的,0通常表示它們之間是獨立的,
	而在這之間的值則表示中間的相似性或相異性。
	對於文本匹配,屬性向量A和B通常是文檔中的詞頻向量。餘弦相似性,可以被看作是在比較過程中把文件長度正規化的方法。
	在信息檢索的情況下,由於一個詞的頻率(TF-IDF權)不能爲負數,所以這兩個文檔的餘弦相似性範圍從0到1。並且,兩個詞的頻率向量之間的角度不能大於90°。

5.角相似性
	“餘弦相似性”一詞有時也被用來表示另一個係數,儘管最常見的是像上述定義那樣的。透過使用相同計算方式得到的相似性,
	向量之間的規範化角度可以作爲一個範圍在[0,1]上的有界相似性函數,從上述定義的相似性計算如下:

	這式子適用於向量係數可以爲正或負的情況。或者,用以下式子計算

	這式子適用於向量係數總爲正的情況。
	雖然“餘弦相似性”一詞有時會用來表示這個角距離,但實際上很少這樣說,因爲角度的餘弦值只是作爲一種計算角度的簡便方法而被用到,
	本身並不是意思的一部分。角相似係數的優點是,當作爲一個差異係數(從1減去它)時,產生的函數是一個嚴格距離度量,
	而對於第一種意義的“餘弦相似性”則不然。然而,對於大多數的用途,這不是一個重要的性質。若對於某些情況下,
	只有一組向量之間的相似性或距離的相對順序是重要的,那麼不管是使用哪個函數,所得出的順序都是一樣的。

6.與“Tanimoto”係數的混淆
	有時,餘弦相似性會跟一種特殊形式的、有着類似代數形式的相似係數相混淆:

	事實上,這個代數形式是首先被Tanimoto定義,作爲在所比較集合由位元向量表示時計算其Jaccard係數的方法。
	雖然這公式也可以擴展到向量,它具有和餘弦相似性頗爲不同的性質,並且除了形式相似外便沒有什麼關係。

7.Ochiai係數
	這個係數在生物學中也叫Ochiai係數,或Ochiai-Barkman係數:

	這裏A和B是集合,n(A)是A的元素個數。如果集合由位元向量所代表,那麼可看到Ochiai係數跟餘弦相似性是等同的。

8.計算餘弦值推導
	1.餘弦函數在三角形中的計算公式爲

		a和b代表兩個向量(向量是在空間中具有大小和方向的量,在數據計量中表示帶箭頭的線段)

	2.二維空間的餘弦函數的公式:將a、b兩個向量二維化,通過餘弦定理與二維空間結合,即可推導出來二維空間下計算兩個向量的餘弦相似性公式。

		上圖中向量a用座標(x1,y1)表示,向量b用座標(x2,y2)表示。向量a和向量b在直角座標中的長度分別爲

		向量a和向量b之間的距離我們用向量c表示,那麼向量c在直角座標系中的長度爲

		將a,b,c帶入三角函數的公式中便得到了直角座標系中向量表示的三角形的餘弦函數。
		二維向量圖和餘弦定理的結合:

	3.多維空間的餘弦函數的公式

9.計算餘弦相似度例子一
	1.餘弦相似度量:計算個體間的相似度。
		相似度越小,距離越大。相似度越大,距離越小。
	2.假設有3個物品,item1,item2和item3,用向量表示分別爲:item1[1,1,0,0,1],item2[0,0,1,2,1],item3[0,0,1,2,0]。
	3.用歐式距離公式計算item1、itme2之間的距離,以及item2和item3之間的距離,分別是:

	4.用餘弦函數計算item1和item2夾角間的餘弦值爲:

	5.用餘弦函數計算item2和item3夾角間的餘弦值爲:

	6.由此可得出item1和item2相似度小,兩個之間的距離大(距離爲7),item2和itme3相似度大,兩者之間的距離小(距離爲1)。
	7.餘弦相似度算法:
		一個向量空間中兩個向量夾角間的餘弦值作爲衡量兩個個體之間差異的大小,餘弦值接近1,夾角趨於0,表明兩個向量越相似;
	  	餘弦值接近於0,夾角趨於90度,表明兩個向量越不相似。
 
10.計算餘弦相似度例子二
	1.使用餘弦相似度計算兩段文本的相似度。
		思路:1、對原文進行jieba中文分詞;
		      2、set中去重後存儲所有詞,並使用dict字段存儲set中元素值(key)和索引值(value);
		      3、中文分詞進行編碼:每個中文分詞轉換爲出現在set中的索引值;
		      4、詞頻向量化:即計算每個分詞出現的次數,通過oneHot編碼對分詞進行編碼來計算詞頻,從而得到兩個句子分別的詞頻向量;
		      5、根據餘弦相似度的公式分別計算出兩個句子的的相似度,即計算兩個句子分別的詞頻向量之間夾角的餘弦值,值越大相似度越高。
	2.原文句子A:這隻皮靴號碼大了。那隻號碼合適。
	  原文句子B:這隻皮靴號碼不小,那隻更合適。
	3.分詞
		使用jieba分詞對上面兩個原文句子分詞後,分別得到兩個列表:
		listA=['這', '只', '皮靴', '號碼', '大', '了', '那', '只', '號碼', '合適']
		listB=['這', '只', '皮靴', '號碼', '不小', '那', '只','更合', '合適']
	3.列出所有詞,將listA和listB放在一個set中,set中去重後得到:
		set={'不小', '了', '合適', '那', '只', '皮靴', '更合', '號碼', '這', '大'}
	  將上述set轉換爲dict,key爲set中的詞,value爲set中詞出現的索引位置。
		dict1={'不小': 0, '了': 1, '合適': 2, '那': 3, '只': 4, '皮靴': 5, '更合': 6, '號碼': 7, '這': 8, '大': 9},
	  可以看出“不小”這個詞在set中排第1,下標爲0。
	4.將listA和listB中的中文分詞進行編碼,將每個中文分詞轉換爲出現在set中的索引值,轉換後爲:
		listAcode=[8, 4, 5, 7, 9, 1, 3, 4, 7, 2]
		listBcode=[8, 4, 5, 7, 0, 3, 4, 6, 2]
	  我們來分析listAcode,結合dict1,得知元素值8對應的字是“這”,元素值4對應的字是“只”,元素值9對應的字是“大”,就是句子A和句子B轉換爲用set中的索引值來表示。
	5.對listAcode和listBcode進行oneHot編碼,就是計算每個分詞出現的次數。
	  詞頻向量化:即計算每個分詞出現的次數,通過oneHot編碼對分詞進行編碼來計算詞頻,從而得到兩個句子分別的詞頻向量。
	  oneHot編號後得到的結果如下:
		listAcodeOneHot = [0, 1, 1, 1, 2, 1, 0, 2, 1, 1]
		listBcodeOneHot = [1, 0, 1, 1, 2, 1, 1, 1, 1, 0]
 	6.根據餘弦相似度的公式分別計算出兩個句子的的相似度,即計算兩個句子分別的詞頻向量之間夾角的餘弦值,值越大相似度越高。

	7.流程圖

11.實現餘弦相似度的代碼
                import jieba
                import math
                
                s1 = '這隻皮靴號碼大了。那隻號碼合適'
                s1_cut = [i for i in jieba.cut(s1, cut_all=True) if i != '']
                s2 = '這隻皮靴號碼不小,那隻更合適'
                s2_cut = [i for i in jieba.cut(s2, cut_all=True) if i != '']
                print(s1_cut) #['這', '只', '皮靴', '號碼', '大', '了', '那', '只', '號碼', '合適']
                print(s2_cut)#['這', '只', '皮靴', '號碼', '不小', '那', '只', '更合', '合適']
                
                #兩個set分別對中文切割後的數組元素進行去重,然後兩個set聯合union放到一起組成一個新的set
                word_set = set(s1_cut).union(set(s2_cut))
                print(word_set)#{'只', '合適', '不小', '更合', '號碼', '皮靴', '這', '了', '大', '那'}
                
                word_dict = dict()
                i = 0
                #構建dict字典中的key爲set中的每個中文單詞,value爲set中的該中文單詞的索引值
                for word in word_set:
                    word_dict[word] = i
                    i += 1
                print(word_dict) #{'只': 0, '合適': 1, '不小': 2, '更合': 3, '號碼': 4, '皮靴': 5, '這': 6, '了': 7, '大': 8, '那': 9}
                
                #把原文中每個中文單詞作爲key對應的從dict字典中取出對應的value,值爲set中的該中文單詞的索引值
                s1_cut_code = [word_dict[word] for word in s1_cut]
                print(s1_cut_code) #[6, 0, 5, 4, 8, 7, 9, 0, 4, 1]
                
                #把原文中每個中文單詞作爲key對應的從dict字典中取出對應的value,值爲set中的該中文單詞的索引值
                s2_cut_code = [word_dict[word] for word in s2_cut]
                print(s2_cut_code) #[6, 0, 5, 4, 2, 9, 0, 3, 1]
                
                #重新創建一個新的和dict字典鍵值對數量相同的初始化值爲0的數組
                s1_cut_code = [0]*len(word_dict)
                #oneHot編碼:計算原文中每個中文分詞出現的次數,即能得到原文句子的詞頻向量
                #根據原文中相同中文單詞出現的重複次數記錄到新數組中,出現次數要記錄到的索引位置爲該中文單詞在set中索引值,或者說dict字典中的該中文單詞作爲key對應的value
                for word in s1_cut:
                    s1_cut_code[word_dict[word]]+=1
                print(s1_cut_code)#[2, 1, 0, 0, 2, 1, 1, 1, 1, 1]
                
                #重新創建一個新的和dict字典鍵值對數量相同的初始化值爲0的數組
                s2_cut_code = [0]*len(word_dict)
                #oneHot編碼:計算原文中每個中文分詞出現的次數,即能得到原文句子的詞頻向量
                #根據原文中相同中文單詞出現的重複次數記錄到新數組中,出現次數要記錄到的索引位置爲該中文單詞在set中索引值,或者說dict字典中的該中文單詞作爲key對應的value
                for word in s2_cut:
                    s2_cut_code[word_dict[word]]+=1
                print(s2_cut_code)#[2, 1, 1, 1, 1, 1, 1, 0, 0, 1]
                
                
                # 計算餘弦相似度
                sum = 0
                sq1 = 0
                sq2 = 0
                #通過計算餘弦值的公式cos(θ)= (x1*x2 + y1*y2) / sqrt(pow(x1,2)+pow(y1,2)) * sqrt(pow(x2,2)+pow(y2,2))
                #pow(x,y)函數用於求 x 的 y 次方
                for i in range(len(s1_cut_code)):
                    #計算(x1*x2 + y1*y2):x1*x2或y1*y2均代表詞頻向量s1_cut_code中的元素值 乘以 詞頻向量s2_cut_code中的元素值
                    sum += s1_cut_code[i] * s2_cut_code[i]
                    #計算pow(x1,2)+pow(y1,2):代表求詞頻向量s1_cut_code中的每個元素值的2次方
                    sq1 += pow(s1_cut_code[i], 2)
                    #計算pow(x2,2)+pow(y2,2):代表求詞頻向量s2_cut_code中的每個元素值的2次方
                    sq2 += pow(s2_cut_code[i], 2)
                
                try:
                    #sqrt() 計算平方根,即開平方
                    #round(浮點數x,四捨五入要保留的小數位) 方法返回浮點數x的四捨五入值。
                    #計算出餘弦值的結果cos(θ)= (x1*x2 + y1*y2) / sqrt(pow(x1,2)+pow(y1,2)) * sqrt(pow(x2,2)+pow(y2,2))
                    result = round(float(sum) / (math.sqrt(sq1) * math.sqrt(sq2)), 2)
                except ZeroDivisionError:
                    result = 0.0
                print(result) #0.81

 
 

疲勞檢測

 

疲勞駕駛在造成交通事故的危險因素中高居第三位,在死亡交通事故原因中佔首位。
研究開發疲勞預警系統可以有效地減少疲勞駕駛所造成的交通事故,其中基於視頻的疲勞駕駛
監測系統因其實時性、非接觸性得到國內外的廣泛關注。
使用基於Haar特徵的Adaboost算法訓練分類器, 實現嘴的正常狀態和張嘴狀態的區分,再針
對區分結果實現二次處理,計算嘴的張開程度,判定是否處於疲勞狀態。
處理方法:
選取打哈欠及各種張嘴時的嘴部圖像爲正樣本,選取臉部其他部分圖像爲負樣本,正樣本和負
樣本圖像均從網上搜索得到,正樣本圖像250張,大小統一縮放爲24×24,負樣本圖像550張
 
由於嘴位於人臉的下半部分,所以搜索區域可縮小至人臉下半部分,節省搜索時間。
檢測完成得到打哈欠(或張嘴)的圖片,則再用局部搜索確定二值化分割閾值,把嘴的輪廓分割出來。
爲判斷嘴的張開程度,我們同樣在輪廓上取最具代表性的4個點: 上下邊緣點和左右邊緣點, 通過計
算輪廓的外接矩形的寬高比來判定是否爲打哈欠狀態,一般認爲當寬高比大於1.5的時候處於疲勞狀態。
 
 
 
數量:正樣本250張,負樣本550張。
正樣本:
 
 
 
負樣本:
 
 
駕駛員疲勞駕駛監測系統軟件設計過程中主要包含以下幾個方 面的內容:
(1)雙眼位置的精確定位:
在得到包含駕駛員人臉的圖像數據之後,應設計算法定位圖像 中的人眼。這個過程中需要解決的問題有:
①如何使駕駛員的雙眼特徵強於圖像中其他內容;
②如何區別圖像中可能存在的類似人眼的物體與真實人眼;
③如何減小計算量,保證算法效率
一般情況下,是在定位人眼之前先檢測並定位出人臉,然後在 人臉區域範圍內進行人眼的檢測和定位,這樣可以有效減少算
法在圖像內搜素的面積,且可排除圖像內的類人眼物體。
 
 
 
(2)雙眼位置的跟蹤
在完成初始的人眼定位後,如果仍按照常規途徑實現每一幀圖 像的人眼位置精確定位,那麼整個過程的計算量和計算複雜度
都較高,這樣無法滿足系統實時性要求;而且雖然大多數情況 下采集設備能夠得到包含人眼的圖像,但是,也不排除因爲故
障、駕駛員頭部姿態等因素導致無法按初始時的人眼定位算法 實現雙眼的檢測和定位
因此,爲了保證算法的效率和準確性,應當在完成雙眼位置的 定位之後隨即採用跟蹤算法來完成對人眼的後續定位和跟蹤,
這樣既能節省時間,還可以保證較複雜環境下人眼位置的準確 定位。
 
(3)雙眼狀態信息的分析
一旦實現駕駛員雙眼的準確跟蹤,就能夠獲得每一時刻駕 駛員雙眼的位置、張開幅度等信息,通過這些信息的統計
及分析,結合多個具有代表性的疲勞狀態評價指標建立疲 勞狀態評價模型,就能實現任意時刻對駕駛員精神狀態的
判斷。
 
 
 
眼睛縱橫比(eye aspect ratio (EAR)):
通過計算這個EAR的數值,我們可以判斷眼 睛是張開還是閉合,從而檢測眨眼動作,進 一步使用若干幀中檢測到的EAR組成一個特 徵向量,送到一個SVM中來進行分類。
 
 
分子中計算的是眼睛的特徵點在垂直方向上 的距離,分母計算的是眼睛的特徵點在水平 方向上的距離。由於水平點只有一組,而垂 直點有兩組,所以分母乘上了2,以保證兩組 特徵點的權重相同。
 
 
定義參數
EYE_AR_THRESH = 0.3# EAR閾值
# 當EAR小於閾值時,接連多少幀一定發生眨眼動作
EYE_AR_CONSEC_FRAMES = 3
# 對應特徵點的序號
RIGHT_EYE_START = 37 - 1
RIGHT_EYE_END = 42 - 1
LEFT_EYE_START = 43 - 1
LEFT_EYE_END = 48 - 1
 
 
 
 
EYE_AR_THRESH是判斷閾值,默認爲0.3。如果EAR大於它,則認爲眼睛是睜開的;如果EAR小於它,則認
爲眼睛是閉上的。
EYE_AR_CONSEC_FRAMES表示的是,當EAR小於閾值時,連續的幀數。只有小於閾值的幀數超過了這個值
時,才認爲當前眼睛是閉合的,即發生了疲勞閉眼的操作;否則則認爲是誤操作。
RIGHT_EYE_START、RIGHT_EYE_END、LEFT_EYE_START、LEFT_EYE_END:這幾個都對應了人臉特徵點
中對應眼睛的那幾個特徵點的序號。由於list中默認從0開始,爲保持一致,所以減1。
 
 
 
下面的眨眼和張嘴,搖頭和點頭,都是通 過連續的圖片,計算變化距離與不變距離 的比,進行上一幀圖像與下一幀圖像的比, 來判斷是否爲活體。 這裏用的是dlib,速度很快,可以做到實 施檢測,每秒20幀是可以做到的。
 
 
 
介紹張嘴檢測,見下圖。 模仿眨眼,取點的時候需要注意, 內圈的點變化更加明顯。變化距離 建議取內圈,固定距離選用外圈。
 
 
 
搖頭和點頭的方法和上面的想法幾乎一樣。
首先說搖頭,當搖頭的時候,你的臉頰會變窄,而你的鼻子長度幾乎是不變的。
 
 
 
點頭的時候,鼻子的距離會變短,而臉頰的會幾乎不會變窄。
 
 
 
 
 
 
在駕駛過程中,由於實際情況相對複雜,單一的攝像頭 必然存在一些問題:
(1)對人臉轉向比較敏感,當人臉發生偏轉時由於拍 攝角度的原因,使得採集到的人臉或人眼發生變形,易 導致檢測和定位失敗。
(2)在倒車時,駕駛員可能會轉頭觀察車後的情況, 此時易超出單一攝像頭的採集範圍。
 
 
 

人臉校準

LFW 人臉數據庫(LFW face database)是在各類人臉檢測和識別算法的研究中經常用到的數據集。而且在各類與
人臉有關的各類賽事上也經常用到。圖像的來源主要是網絡,涉及人物不分種族,性別和年齡。是一種完全真實
自然的狀態下的人臉圖像。該數據集被用於非限制性環境下的算法實驗。
數據集共有 13000 多張人臉照片,其中有的人只有一張,而有的人擁有兩張以及兩張以上圖像。此類共有1680
人。每張圖像已經被標好了唯一的標籤。LFW 數據集中的圖像裏的光照,姿態和遮擋情況各不相同,因此是一
個具有挑戰性的人臉數據集。
 
 
 
Yale 人臉數據庫是用作限制性環境下測試人臉識別 算法的經典數據集。 該數據集由 15 位志願者組成,每位志願者的具有表
情,姿態和光照因素的人臉圖像共11 張。整個數據 集有 1653 張圖片。每張圖片大小爲 100*100。整 個數據集非常小,圖片信息也較爲簡單。Yale 人臉 數據的擴展數據集 The extended Yale Face DatabaseB 共有 16178 張圖像。由 28 位志願者組
成,每位志願者共有 9 中姿態,另外有 64種不同光 照。該數據集包括人臉檢測對齊好的數據集和未對齊 的數據集。
 
 
Yale 人臉數據庫是用作限制性環境下測試人臉識別 算法的經典數據集。 數據集中人臉數據已經標定,因此這並不是傳統意義
上的人臉識別任務,而是一個簡單的圖像多分類問題。 另外,每個人包含了在不同表情、光照下的人臉圖像, 這就要求我們提取的圖像特徵要具有光照不敏感性, 能夠很好得體現人臉的輪廓信息。
 
 
 
FERET 數據庫同樣是用來檢測限制性環境 下人臉相關算法的數據集。 由 200多位志願者提供的不同姿態和表情
的圖像組成。該數據集最開始由 Counterdrug Technology Transfer Program (CTTP)發起了一個人臉識別技
術(Face Recognition Technology 簡稱 FERET)工程創建的,現在已經成爲人臉 識別領域應用最多的人臉數據集。部分數
據如圖所示。
 
 
 
在做人臉識別的時候,前期的數據處理過程中可能會遇到一個問題,即將人臉從不同尺寸的圖像中截取
出來,再進行“對齊”操作。這樣可以使每一個截取的人臉中的眼睛等位置處於同一位置,會對後面的
識別算法起到一定的優化作用。
比如,下面 3 張圖片所示,人臉的位置,圖像的大小各不一樣。我們所需要做的就是,將人臉從各個圖
片中截取出來,再旋轉進行校正,使得眼睛在同一位置上,最後將圖片的大小也統一調整爲 224 x 224。
 
 
校正的效果如下圖所示:
 
 
 
1. 計算直線距離及傾斜角度
計算兩眼之間的距離很簡單,只要找出兩個向量的座標就可以計算出來。計算兩眼之間的距離 直線的傾斜角度,就是將兩個向量相減,得到一組橫縱座標,然後利用 arctan 的公式求解角 度,公式如下所示:
 
 
 
 
 
 
 
 
 
 
整個過程遵循以下幾個步驟:
1,提取出每張圖片裏眼睛的座標,進行讀取數據
2,找兩眼間的直線距離並計算該直線與水平線之間的夾角,即傾斜角度
3,根據找到的傾斜角度旋轉圖片
4,在旋轉後的圖片中找到眼睛的位置
5,根據眼睛座標找到包含面部的框的寬度和高度,調整圖片的尺寸
 
 
在不受限環境中,人臉識別仍不能萬無一失,尤其是在人臉幾何變形的情況下。人臉在角度和對齊方面(由
人臉檢測邊界框定位引入)的變形將從根本上影響人臉的表徵和識別的性能。
有鑑於此,曠視科技創新性地提出 GridFace,通過學習局部單應變換減少人臉變形,提升識別性能。一句
話,先校正,再識別,過硬的校正技術使得人臉識別性能得到顯著提高。
 
 
不規則形狀分割人臉:
先用dlib等打點工具把人臉最外層的landmark點打出來,然後 利用opencv的convexhull得到凸包然後就可以摳出人臉區域了,
這裏使用兩種方式來得到人臉區域:
1,將mask作爲通道,來控制圖片區域的透明度,最後得到圖 片是4通道的;
2,掩模與原始圖像進行與運算,返回圖像是三通道。 最後完成人臉檢測-->人臉關鍵點檢測-->人臉分割-->人臉對齊
 
 
 
ASM主動外觀模型
 
人臉識別大體分爲三部分:
從複雜背景中檢測人臉的位置;對人臉信息進行提取;最後進行匹配和識別。
人臉識別的關鍵步驟就是抽取人臉特徵,而基於的人臉特徵提取算法通過對人臉特徵點的標定能夠準確定
位人臉主要信息,如眼睛、眉毛、鼻子、嘴巴等,因此AAM特徵定位與匹配在人臉識別領域有其一席之 地.
AAM(Active Shape Model)的理論基礎是形變模型,只考慮局部形狀信息的弊端影響了算法的精度,從
而ASM將紋理信息通過統計模型的方式引入人臉特徵點定位,因此使模型攜帶了更多的人臉信息,並且
面部特徵點的定位變得更加準確。
 
 
ASM主動形狀模型方法,是一種物體形狀描述技術,用於解決圖像中的目標搜尋的形狀統計模型,具有一
般性,可以爲任何物體形狀建立模型。被廣泛應用於醫學圖像處理、數字圖像理解和計算機視覺等領域。
主動形狀模型是一個基於統計學的模型,以目標物體的輪廓作爲訓練樣本構造的方法,通過模型的形變最
終與目標形狀相符合,最初由曼徹斯特大學提出。
 
1,使用人機交互方式提取目標輪廓的邊界 點集合,統計樣本的模型
2,根據訓練樣本建立局部灰度模型
3,進行主成分分析,獲得模型變化的模式
4,檢測圖像的形狀模型以達到最佳匹配。
 
 
 
算法主要分爲兩個階段:
模型訓練階段圖像搜索階段 人臉圖像之所以可能有不同的變化,是由於個性特徵、 面部表情、光線條件以及三維姿態等原因造成的。爲 了使能夠定位人臉特徵,我們必須首先建立能夠描述人 臉形狀及典型變化的模型。
 
 
從一組訓練樣本集建立一個模型
1,選取需要的特徵點
我們需要已經標定好的相關數據作爲訓練樣本,取N幅人臉圖片作爲訓練樣本集,手工標定每幅訓練圖片上的
n個特徵點,並且標記的順序要保持一致,各個特徵部位的特徵點的個數也必須相同,然後將每幅圖像對應的n
個特徵點的座標按序放在一個形狀向量裏。
這樣,所獲得的所有的形狀向量就組成了的觀察數據,第i個訓練樣本可表示爲一個大的列向量:
 
 
 
在二維空間裏的標記點最好是選擇物體邊界的 拐角點,在邊界的“T”型交叉點或容易定位的 生物的標記點(紅色的點是邊界的拐角點,藍色 的點是“T”型交叉點,黑色的是一些分佈較均 勻的描述形狀信息的點)如眼睛的中央及嘴巴 的拐角點。
然而這些點通常不夠用於人臉的精確描述。因 此,我們一般還需使用定義好的標記點間的中間 點。
 
 
 
 
具體的對特徵點的選取,我們可以按照如下原則進行:
1,關鍵特徵點,即可以用肉眼直接分辨出的特徵點,如面 部上的眼睛、鼻子的邊界點、嘴脣的形狀以及中心等
2,在關鍵特徵點之間儘量均勻分佈的一些特徵點
3,特徵點分佈的密度要適當。密度過大將增加標定的 工作量以及算法的效率問題,而密度過小將不能達到理想 的效果。
 
 
要想建立表現比較完備的平均人臉模型,標定的訓練集應該包括不同變化類型的圖像。 對於人的面部圖像來講,應該包括不同性別、不同表情、不同姿態姿態角度變化不要大於15度。
 
2,計算權重W
在選取的特徵點中,每個點的變化情況是不一樣的。有一些點相對其它的點來說變化劇烈,而有一些
點的變化就相對穩定。例如人臉樣本中的眼眉和鼻子的位置相對來說比較穩定,但是嘴巴和眼睛的
點就相對不穩定,虹膜兩側比較穩定但是上下因爲有遮擋點所以變化相對比較劇烈。
 
這裏拿一個訓練樣本Xi的特徵點來說:
1,計算這個樣本的每個特徵點和其它點的距離,例如,第k個點和第l個點的距離Rkl,比方說68個特徵點就 應該有68*68個距離組合(包括每個點到它自身的距離組合)。
2,接下來計算每個距離的方差(標準偏差的平方)標準偏差函數如式一所示:
 
 
 
3,對樣本中的每一個點如第個點求的和再取倒數,即爲該點的權重,其中n是每個樣本中所選取的 特徵點的數目
 
 
 
3,配準
對於標記好的圖像,由於其在圖像中所處的絕對位置有 差異,圖像尺寸、方向上也存在不同,因此直接對這些 標記好的點進行統計建模是不合理的,也不能夠反應它 們形變的規律。 因此爲了克服上述因素的影響,爲了能夠比較來自不同 形狀相對應的點,從而建立起能夠真正反映出形狀變化 規律的統計形狀模型,我們需要將訓練樣本集中的形狀 進行配準或稱爲對齊。所謂的配準,就是以某個形狀爲 基礎,對它形狀進行尺度變化、旋轉和平移使得它們與 基形狀儘可能接近,這些變換必須在不改變訓練樣本的 整個剛體形狀的前提下進行。
 
 
 
3,配準
之後,對計算得到的配準後的平均形狀向量作歸一化處 理,並以歸一化的平均形狀向量作爲樣本,再將其它經上 一步對齊的形狀向量與此平均形狀向量對齊。重複這 一過程,知道相鄰兩次的平均形狀向量差別小於某一個 特定值。這種樣本對齊的理論和方法非常關鍵,它影響 了算法的精確程度,貫穿了整個算法。
 
 
 
 
樣本配準的方法:
1,旋轉、尺度變化和平移,使得每個樣本的特徵點到一個選定樣本例如,選定的樣本爲戈的特徵
點,重複下面的步驟直到收斂
2,計算總的樣本特徵點的平均形狀
3,把平均形狀和選定的形狀對齊(相當於歸一化)
4,旋轉、尺度變化和平移每個樣本的特徵點到平均形狀
5,收斂檢驗
 
4,主成分分析
把訓練集中的形狀向量進行配準處理之後,就可以利用主成分分析的方法來找出形狀變化的統計信息及規律,同時實
現在變換域中的表示。
主成分分析PCA是一種簡化數據集的技術,它是一個線性變換,在特徵處理、模式識別、數據分析等領域已經得到了
廣泛的應用。
這個變換把數據變換到一個新的座標系統中,使得任何數據投影的第一大方差在第一個座標稱爲第一主成分上,第二
大方差在第二個座標第二主成分上,依次類推,減少數據集的維數,減少數據冗餘,使得數據在一個低維的特徵空間被處
理,同時保持數據集的對方差貢獻最大的特徵,也就保持了原始數據的絕大部分的信息,從而解決數據空間維數過高的
瓶頸問題。
對同一個體進行多項觀察時,必定涉及多個隨機變量,它們都是具有相關性的。這時就需要藉助主成分分析來概括諸
多信息的主要方面。我們希望有一個或幾個較好的綜合指標來概括信息,而且希望綜合指標能夠互相獨立地各自代
表某一方面的性質。
 
任何一個度量指標的好壞除了可靠、真實之外,還 必須能充分反映個體間的變異。如果有一項指標, 不同個體的取值都大同小異,那麼該指標不能用來 區分不同的個體。由這一點來看,一項指標在個體 間的變異越大越好。因此我們把“變異大”作爲 “好”標準來尋求綜合指標。 對於一個訓練集,每一幅人臉圖像都有鄉濰的特徵, 這樣的龐大的計算量勢必會影響到利用算法進行 搜索的速度。爲了提高算法的效率,我們就需要在 訓練階段進行主成分分析。
 
 
 
一個二維分佈的向量可以看成形狀,通過變換,我們可以找到其分佈軸,並求得其均值。如果我們現在 只取一個特徵向量作爲主軸,就可以用這個主軸來近似原來的向量。 經過主成分分析,取前t個特徵值對應的特徵向量,其選取依據爲使前個t個特徵值滿足:
 
 
 
5,取相應的特徵向量
把選定λ相對應的特徵向量p組成一個矩陣P。 這樣任一人臉形狀X的變化子空間中可表示爲
 
其中b是一個t*I的向量,通過改變就可以生成新的形狀,b中每個值對應了在相應向量方向上的 變化程度。
下圖即不同的b對應不同的人臉形狀。
 
 
而b向量中的每一個分量都具有相對的獨立性,即其中一個分量的變化不受其它分量變化的影 響。這樣一來,任何一個變量都有可能在一個相當大的範圍內變化,這樣就不能保證配準後得 到的新形狀是我們想要的人臉形狀,因此,需要對這些參數bi的變化範圍進行約束。
 
接下來,我們要通過訓練樣本建立起所標記的個點的局部灰度模型。 點的局部灰度模型就是在一個點附近的一定範圍內的灰度分佈情況,我們在 對訓練樣本的圖像進行手工標定後,就可以建立這樣的模型。 之所以要建立局部灰度模型,是因爲初始形狀不一定能夠和真實的形狀相一 致,需要不斷調整其形狀,使得它與真實的形狀相吻合。爲了調整形狀,就需要 對訓練圖像特徵點附近的灰度信息進行分析。因此,我們還需要提取特徵點 周圍的局部灰度信息,並計算其經驗灰度分佈。
 
 
 
採用三種常用的搜索策略:
基於像素鄰域最大梯度值的搜索策略計算圖像梯度場,在當前形狀模型 的每個標記點的一個夕的鄰域內,取梯度值最大的點作爲當前標記點的替 代點。 採用這種搜索策略,算法速度快,效率也比較高,大體上可以定位出輪廓的, 但是標記點的變化沒有方向性,容易受到其它邊緣的干擾,比如衣領、耳朵 等。
 
 
基於輪廓曲線法方向的搜索策略沿當前形狀曲線的法線所在直線上,以 標記點爲中心在順着法線方向和逆着法線方向各取無個像素,選擇的梯 度值最大的點爲當前標記點的替代點。針對不同的器官,選擇一些關鍵 的標記點,只調整這些關鍵標記點,而其它標記點則根據模型的形狀配準 算法來求出。
 
在傳統的算法中建立並使用了兩種模型全局形狀模型和特徵點的局部灰度模型。用特徵點集合去描 述人臉面部的各個顯著特徵區域形狀,採用全局特徵子空間去約束迭代過程中每個特徵點的定位結 果。每個特徵點周圍用局部灰度模型進行描述,在目標圖像搜索過程中來尋找每個特徵點移動的目 標點。 在擁有合理和足夠的訓練樣本所組成的訓練集的條件下,可以較好地學習樣本集類物體的形狀及變 化模式,對目標物體進行定位搜索 和解釋。但是容易陷入局部極值而且對於紋理匹配的誤差較大。
 
1,雖然傳統ASM在很多情況下能得到較好的 收斂效果,但對平均形狀模型的初始化依賴性 較強,當初始形狀在接近目標形狀的大致位置 時,算法效果較好,但當初始輪廓距離真實人 臉輪廓距離較遠時,易出現局部最優,無法搜 索到正確位置。
 
 
2,特徵點周圍的紋理特徵僅用灰度梯度信息描述容易受到光照和噪聲的影響,若測試集與訓練集光照條件
相差較大,會導致建立的灰度模型不能正確的指導特徵點運動,使算法不收斂,特徵點定位不理想甚至失敗
3,進行平均形狀建模時,對於但姿態人臉建模很有效,如左圖所示,但是,若存在各種姿態,比如圖像中
人臉出現左側,右側,擡頭,低頭等情況,建立模型可能出現右圖的情況;
4,在特徵點搜索過程中,只在法線方向進行了搜索,如果最佳位置不在法線方向上,就會導致模型不能很好地逼
近目標形狀。
5,由於主動形狀模型的方法是基於幾何形狀信息的方法,本身對圖片的質量有着比較高的要求,對噪聲和局部
變形比較敏感。
 

AAM與ASM
 
ASM 和主動外觀模型AAM(Active Appearance Model) 都能在人臉特徵 定位中取得良好的結果 :
ASM 利 用 特 徵 點 附 近 的 局 部 灰 度 信 息 ; AAM 則 利 用 臉 部patch 區域的紋理信息 。 由於人臉圖像中的原始數據就包含形狀向量信息,所以人臉的形狀特徵可以 直接通過標記面部的關鍵特徵點來獲取,但是圖像的紋理特徵並沒有顯性的 表示在人臉的圖像中,這裏我們需要通過德勞內(Delaunay)三角變換和仿 射(Affine)變換來獲取。
 
 
通過德勞內(Delaunay)三角變換和仿射(Affine)變換後建立的人臉的紋 理模型可以有效的消除樣本尺寸、方向角度以及絕對位置的差異,達到了歸 一化的效果。
 
 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章