人臉檢測分為兩種:一種是基於知識的,一種是基於深度學習的。深度不會學習
人臉識別屬於目標檢測,主要涉及兩個方面:
①先對檢測的物體進行概率統計,從而知道待檢測對象的一些特征,建立其目標的檢測模型
②用得到的模型來匹配輸入的圖像,如果有匹配則則輸出匹配的區域,否則什么也不做。
我們看到的圖片和計算機不一樣,計算機看到的是一串串數字矩陣,圖片由多個像素組成,拿我們熟悉的RGB圖像來說,每個像素又有紅綠藍三個通道,假如每個像素的單個通道由uint8類型字符組成,那么三通道的像素便會有24位,這是我們常說的24位真彩。如果我們把RGB圖像轉化為gray圖像來處理,那一定會減少很多計算量。
所以第一步應該給圖像做預處理,比如先把圖像轉化為灰度圖像。
1 gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
把RGB轉gray的方法有很多,有直接求RGB平均值的還有分別賦權重的,opencv用什么方法我暫時沒查到。
這樣的轉化可能會造成圖片的灰度值分布不均勻,通常認為,對所有可用像素強度值都均衡使用,才是一副高質量的圖像。所以我們需要讓圖像的灰度直方圖盡可能的平穩,opencv提供了一個簡單好用的函數
1 cv.equalizeHist(gray, gray)
直方圖均衡化是通過拉伸像素強度分布范圍來增強圖像對比度的一種方法,在一個完全均衡化的直方圖中,所有的bins所包含的像素數量是相等的,這也就是說,像素大於128的有一半,像素值小於128的也是一半,像素值小於64的是小於128的一半,以此類推。
當然圖像預處理也可以用增強對比度的方法。
下面介紹提高對比度和增加亮度的函數
1 new_img = cv.addWeighted(img, c, new_img, 1-c, b) #c是對比度倍數 b是亮度增加數
圖像對比度指的是一幅圖像中明暗區域最亮的白和最暗的黑之間不同亮度層級的測量,即指一幅圖像灰度反差的大小。差異范圍越大代表對比越大,差異范圍越小代表對比越小。
圖象亮度是指畫面的明亮程度,通常用像素值來表示。
利用OpenCV自帶的xml文件,可以實時檢測攝像頭中人臉Haar特征、LBP特征都是常用的特征,描述不同的局部信息Haar描述的是圖像在局部范圍內像素值明暗變換信息LBP描述的是圖像在局部范圍內對應的紋理信息,HAAR與LBP區別:
① HAAR特征是浮點數計算,LBP特征是整數計算;
② LBP訓練需要的樣本數量比HAAR大;
③ LBP的速度一般比HAAR快;
④ 同樣的樣本HAAR訓練出來的檢測結果要比LBP准確;
⑤ 擴大LBP的樣本數據可達到HAAR的訓練效果
haar特征分類器是一個xml文件,文件描述了檢測物體的Haar特征值,Haar分類器需要通過大量的數據來訓練。Haar特征包括三類特征:邊緣特征、、線性特征、中心特征和對角線特征,組合成特征模板。特征模板內有白色和黑色兩種矩形,並定義該模板的特征值為白色矩形像素和減去黑色矩形像素和。Haar特征值反映了圖像的灰度變化情況。例如:臉部的一些特征能由矩形特征簡單的描述,如:眼睛要比臉頰顏色要深,鼻梁兩側比鼻梁顏色要深,嘴巴比周圍顏色要深等。但矩形特征只對一些簡單的圖形結構,如邊緣、線段較敏感,所以只能描述特定走向(水平、垂直、對角)的結構。
下面是特征模板
然后人臉特征矩形對應圖片,符合人臉特征的區域會被認定位人臉。
接下來開始人臉檢測,加載haar分類器
1 faceadd = "***/Lib/site-packages/cv2/data/haarcascade_frontalface_default.xml" 2 eyeadd = "***/Lib/site-packages/cv2/data/haarcascade_eye.xml" 3 smileadd = "***/Lib/site-packages/cv2/data/haarcascade_smile.xml" 4 5 face_detector = cv.CascadeClassifier(faceadd) 6 eye_detector = cv.CascadeClassifier(eyeadd) 7 smile_detector = cv.CascadeClassifier(smileadd)
檢測faces,eyes,smile
1 faces = face_detector.detectMultiScale(gray, 1.15, 5) 2 for x, y, w, h in faces: 3 cv.rectangle(image, (x, y), (x+w, y+h), (0, 0, 255), 2) 4 #把臉單獨拿出來檢測臉 5 face_img = gray[y:y+h, x:w+x] 6 cv.imshow("face_img", face_img) 7 eyes = eye_detector.detectMultiScale(face_img, 1.3, 5, 0, (40, 40)) 8 for ex, ey, ew, eh in eyes: 9 cv.rectangle(image, (x+ex, y+ey), (x+ex+ew, y+ey+eh), (255, 0, 0), 2) 10 smile = smile_detector.detectMultiScale(face_img, 1.16, 35, 0, (25,25)) 11 if(len(smile) >= 0): 12 print("檢測到微笑") 13 cv.putText(image, 'Smile', (x, y-20), 3, 1.3, (0, 255, 0), 2)
循環讀取人臉的矩形對象列表,獲得人臉矩形的坐標和寬高, 然后在原圖片中畫出該矩形框,調用的是OpenCV的rectangle 方法,其中矩形框的顏色等是可調整的,putText函數是加文字的(圖片,文字,位置,字體,大小,顏色,粗細)。

然后嘗試着用最原始的方法,對圖像依次更改各個像素值,發現降低藍綠色的占比時,圖像的變化類似於“懷舊”,提高藍綠色占比或者降低紅色占比,圖像風格類似於“清新”。暴力循環改像素值,就不展示代碼了。
關於馬賽克。
馬賽克效果原理就是用一個像素點去代替需要被替代的像素點 下面以給人臉打碼說明:
1 找到需要被馬賽克的區域: 2 face_img = image[y:y+h, x:w+x] 3 馬賽克: 4 for i in range(x, w+x, 10): 5 for j in range(y, y+h, 10): 6 a = random.randint(50,120) 7 image[i:10+i, j:j+10] = a 8 把圖片拼接回原圖: 9 image[y: y + h, x: w + x] = face_img
還有一種暴力摳圖法,對除了臉部分的區域進行虛化,效果類似於手機的人像模式。
就是把圖片分割為人臉區域和非人臉區域
|
Part1 |
part2 |
part4 |
|
Face |
||
|
part3 |
1 face_img = gray[y:y+h, x:w+x] 2 part1 = image[0:image.shape[0], 0:x] 3 part2 = image[0:y, x:x+w] 4 part3 = image[y+h:image.shape[0], x:w+x] 5 part4 = image[0:image.shape[0], x+w:image.shape[1]]
基於上圖給出我的暴力摳圖方法。然后對part1~4進行虛化,這里使用高斯濾波,同時把圖片拼接到原圖
1 image[0:image.shape[0], 0:x] = cv.GaussianBlur(part1, (5, 5), 0) 2 image[0:y, x:x+w] = cv.GaussianBlur(part2, (5, 5), 0) 3 image[y+h:image.shape[0], x:w+x] = cv.GaussianBlur(part3, (5, 5), 0) 4 image[0:image.shape[0], x+w:image.shape[1]] = cv.GaussianBlur(part4, (5, 5), 0)
現在的照相技術太發達了,沒找到什么很好說明例子的圖片,看頭發虛化了一點吧。

關於暴力摳圖虛化的bug,好像只能關注一張臉,如果同時存在多張臉會把其他臉也虛化了,背景被強行疊加虛化。
關於圖像濾波發現一篇不錯的文章:https://xiongyiming.blog.csdn.net/article/details/89788020
