機器學習 | 人臉關鍵點檢測

2021-03-02 沈浩老師

你有沒有想過Snapchat(色拉布,是由史丹福大學兩位學生開發的一款「閱後即焚」照片分享應用)是如何根據你的臉來使用神奇的濾鏡的?它已經被編程來檢測你臉上的一些標記,並根據這些標記投射濾鏡。在機器學習中,這些標記被稱為人臉關鍵點。在本文中,我將指導您如何使用機器學習來檢測這些「面部坐標」。

首先,我將簡單地從導入這個任務所需的所有庫開始。在本文中,我將使用PyTorch使用深度學習進行地標檢測。讓我們導入所有庫:

import timeimport cv2import osimport randomimport numpy as npimport matplotlib.pyplot as pltfrom PIL import Imageimport imutilsimport matplotlib.image as mpimgfrom collections import OrderedDictfrom skimage import io, transformfrom math import *import xml.etree.ElementTree as ET 
import torchimport torchvisionimport torch.nn as nnimport torch.optim as optimimport torch.nn.functional as Fimport torchvision.transforms.functional as TFfrom torchvision import datasets, models, transformsfrom torch.utils.data import Datasetfrom torch.utils.data import DataLoader


下載DLIB數據集

我將在這裡選擇的數據集來檢測官方dlib數據集中的臉地標,該數據集包含超過6666幅不同維度的圖像。下面的代碼將下載數據集並解壓縮以進行進一步的探索:

%%captureif not os.path.exists('/content/ibug_300W_large_face_landmark_dataset'):    !wget http:    !tar -xvzf 'ibug_300W_large_face_landmark_dataset.tar.gz'        !rm -r 'ibug_300W_large_face_landmark_dataset.tar.gz'

可視化數據集

現在,讓我們來看看我們正在進行的工作,看看我們需要經歷的所有數據清理和預處理機會。下面是我們為此任務拍攝的數據集中的圖像示例。

file = open('ibug_300W_large_face_landmark_dataset/helen/trainset/100032540_1.pts')points = file.readlines()[3:-1]
landmarks = []
for point in points: x,y = point.split(' ') landmarks.append([floor(float(x)), floor(float(y[:-1]))])
landmarks = np.array(landmarks)
plt.figure(figsize=(10,10))plt.imshow(mpimg.imread('ibug_300W_large_face_landmark_dataset/helen/trainset/100032540_1.jpg'))plt.scatter(landmarks[:,0], landmarks[:,1], s = 5, c = 'g')plt.show()

你可以看到臉部在圖像中所佔的空間非常小。如果我們在神經網絡中使用這張圖像,它也會作為背景。因此,就像我們準備文本數據一樣,我們也將準備這個圖像數據集以進行進一步的探索。

創建數據集類

現在,讓我們深入研究數據集中的類和標籤。labels_ibug_300W_tra.xml由輸入圖像和地標以及裁剪臉部的邊框組成。我將將所有這些值存儲在列表中,以便我們可以在培訓過程中輕鬆地訪問它們。

class Transforms():    def __init__(self):        pass        def rotate(self, image, landmarks, angle):        angle = random.uniform(-angle, +angle)
transformation_matrix = torch.tensor([ [+cos(radians(angle)), -sin(radians(angle))], [+sin(radians(angle)), +cos(radians(angle))] ])
image = imutils.rotate(np.array(image), angle)
landmarks = landmarks - 0.5 new_landmarks = np.matmul(landmarks, transformation_matrix) new_landmarks = new_landmarks + 0.5 return Image.fromarray(image), new_landmarks
def resize(self, image, landmarks, img_size): image = TF.resize(image, img_size) return image, landmarks
def color_jitter(self, image, landmarks): color_jitter = transforms.ColorJitter(brightness=0.3, contrast=0.3, saturation=0.3, hue=0.1) image = color_jitter(image) return image, landmarks
def crop_face(self, image, landmarks, crops): left = int(crops['left']) top = int(crops['top']) width = int(crops['width']) height = int(crops['height'])
image = TF.crop(image, top, left, height, width)
img_shape = np.array(image).shape landmarks = torch.tensor(landmarks) - torch.tensor([[left, top]]) landmarks = landmarks / torch.tensor([img_shape[1], img_shape[0]]) return image, landmarks
def __call__(self, image, landmarks, crops): image = Image.fromarray(image) image, landmarks = self.crop_face(image, landmarks, crops) image, landmarks = self.resize(image, landmarks, (224, 224)) image, landmarks = self.color_jitter(image, landmarks) image, landmarks = self.rotate(image, landmarks, angle=10) image = TF.to_tensor(image) image = TF.normalize(image, [0.5], [0.5]) return image, landmarksclass FaceLandmarksDataset(Dataset):
def __init__(self, transform=None):
tree = ET.parse('ibug_300W_large_face_landmark_dataset/labels_ibug_300W_train.xml') root = tree.getroot()
self.image_filenames = [] self.landmarks = [] self.crops = [] self.transform = transform self.root_dir = 'ibug_300W_large_face_landmark_dataset' for filename in root[2]: self.image_filenames.append(os.path.join(self.root_dir, filename.attrib['file']))
self.crops.append(filename[0].attrib)
landmark = [] for num in range(68): x_coordinate = int(filename[0][num].attrib['x']) y_coordinate = int(filename[0][num].attrib['y']) landmark.append([x_coordinate, y_coordinate]) self.landmarks.append(landmark)
self.landmarks = np.array(self.landmarks).astype('float32')
assert len(self.image_filenames) == len(self.landmarks)
def __len__(self): return len(self.image_filenames)
def __getitem__(self, index): image = cv2.imread(self.image_filenames[index], 0) landmarks = self.landmarks[index] if self.transform: image, landmarks = self.transform(image, landmarks, self.crops[index])
landmarks = landmarks - 0.5
return image, landmarks
dataset = FaceLandmarksDataset(Transforms())

可視化隊列轉化

現在讓我們快速地看看到現在為止我們已經做了些什麼。我將通過執行上述類將提供給數據集的轉換來可視化數據集:

image, landmarks = dataset[0]landmarks = (landmarks + 0.5) * 224plt.figure(figsize=(10, 10))plt.imshow(image.numpy().squeeze(), cmap='gray');plt.scatter(landmarks[:,0], landmarks[:,1], s=8);

人臉關鍵點檢測訓練與預測數據集的分割:

現在,為了更進一步,我將將數據集拆分為一個序列和一個有效的數據集:

len_valid_set = int(0.1*len(dataset))len_train_set = len(dataset) - len_valid_set
print("The length of Train set is {}".format(len_train_set))print("The length of Valid set is {}".format(len_valid_set))
train_dataset , valid_dataset, = torch.utils.data.random_split(dataset , [len_train_set, len_valid_set])
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True, num_workers=4)valid_loader = torch.utils.data.DataLoader(valid_dataset, batch_size=8, shuffle=True, num_workers=4)

輸出:

The length of Train set is 6000 
The length of Valid set is 666

測試輸入數據的形狀:

images, landmarks = next(iter(train_loader))
print(images.shape)print(landmarks.shape)

輸出:

torch.Size([64, 1, 224, 224]) 
torch.Size([64, 68, 2])

人臉關鍵點檢測模型的定義

現在,我將使用ResNet 18作為我們的基本框架。我將修改第一層和最後一層,以便這些層能夠很容易地適應我們的目的:

class Network(nn.Module):    def __init__(self,num_classes=136):        super().__init__()        self.model_name='resnet18'        self.model=models.resnet18()        self.model.conv1=nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3, bias=False)        self.model.fc=nn.Linear(self.model.fc.in_features, num_classes)        def forward(self, x):        x=self.model(x)        return ximport sysdef print_overwrite(step, total_step, loss, operation):    sys.stdout.write('\r')    if operation == 'train':        sys.stdout.write("Train Steps: %d/%d  Loss: %.4f " % (step, total_step, loss))       else:        sys.stdout.write("Valid Steps: %d/%d  Loss: %.4f " % (step, total_step, loss))     sys.stdout.flush()

人臉關鍵點檢測的神經網絡訓練

現在我將使用真實和預測的人臉標記之間的均方誤差:

torch.autograd.set_detect_anomaly(True)network = Network()network.cuda()    criterion = nn.MSELoss()optimizer = optim.Adam(network.parameters(), lr=0.0001)loss_min = np.infnum_epochs = 10start_time = time.time()for epoch in range(1,num_epochs+1):        loss_train = 0    loss_valid = 0    running_loss = 0        network.train()    for step in range(1,len(train_loader)+1):            images, landmarks = next(iter(train_loader))        images = images.cuda()        landmarks = landmarks.view(landmarks.size(0),-1).cuda()                 predictions = network(images)        optimizer.zero_grad()        loss_train_step = criterion(predictions, landmarks)        loss_train_step.backward()        optimizer.step()        loss_train += loss_train_step.item()        running_loss = loss_train/step        print_overwrite(step, len(train_loader), running_loss, 'train')    network.eval()     with torch.no_grad():                for step in range(1,len(valid_loader)+1):                        images, landmarks = next(iter(valid_loader))                    images = images.cuda()            landmarks = landmarks.view(landmarks.size(0),-1).cuda()                    predictions = network(images)
loss_valid_step = criterion(predictions, landmarks)
loss_valid += loss_valid_step.item() running_loss = loss_valid/step
print_overwrite(step, len(valid_loader), running_loss, 'valid') loss_train /= len(train_loader) loss_valid /= len(valid_loader) print('\n') print('Epoch: {} Train Loss: {:.4f} Valid Loss: {:.4f}'.format(epoch, loss_train, loss_valid)) print('') if loss_valid < loss_min: loss_min = loss_valid torch.save(network.state_dict(), '/content/face_landmarks.pth') print("\nMinimum Validation Loss of {:.4f} at epoch {}/{}".format(loss_min, epoch, num_epochs)) print('Model Saved\n')print('Training Complete')print("Total Elapsed Time : {} s".format(time.time()-start_time))

人臉關鍵點預測

讓我們使用上面我們在DataSet中未見過的圖像上訓練的模型:

start_time = time.time()with torch.no_grad():    best_network = Network()    best_network.cuda()    best_network.load_state_dict(torch.load('/content/face_landmarks.pth'))     best_network.eval()    images, landmarks = next(iter(valid_loader))    images = images.cuda()    landmarks = (landmarks + 0.5) * 224
predictions = (best_network(images).cpu() + 0.5) * 224 predictions = predictions.view(-1,68,2) plt.figure(figsize=(10,40)) for img_num in range(8): plt.subplot(8,1,img_num+1) plt.imshow(images[img_num].cpu().numpy().transpose(1,2,0).squeeze(), cmap='gray') plt.scatter(predictions[img_num,:,0], predictions[img_num,:,1], c = 'r', s = 5) plt.scatter(landmarks[img_num,:,0], landmarks[img_num,:,1], c = 'g', s = 5)
print('Total number of test images: {}'.format(len(valid_dataset)))
end_time = time.time()print("Elapsed Time : {}".format(end_time - start_time))

以下是人臉關鍵點檢測的一些照片,可以看出,現在已經可以精確的檢測出人臉各個關鍵點。


指導老師

長按二維碼關注我們

歡迎關注公眾號:沈浩老師

相關焦點

  • 人臉專集3 | 人臉關鍵點檢測(下)—文末源碼
    今天繼續上期的《人臉關鍵點檢測》,精彩的現在才真正的開始,後文會陸續講解現在流行的技術,有興趣的我們一起來學習!
  • 使用Python+OpenCV+Dlib實現人臉檢測與人臉特徵關鍵點識別
    今天,我們將學習如何檢測圖像中的人臉並提取面部特徵,如眼睛、鼻子、嘴巴等。當我們使用DLib算法檢測這些特徵時,我們實際上得到了每個特徵點的映射。該映射由67個點(稱為地標點)組成,可識別以下特徵:安裝要求與往常一樣,本文將用代碼演示示例,並將逐步指導你實現一個完整的人臉特徵識別示例。
  • 獲ICME人臉106關鍵點檢測比賽冠軍 百度大腦彰顯AI實力
    在今年4月初結束的ICME人臉106關鍵點檢測比賽(Grand Challenge of 106-p Facial Landmark Localization)中,百度大腦視覺技術團隊與來自全球的20多個優秀代表隊同臺競技,其中包括阿里、華為、美團、中科大等國內視覺技術實力強勁的團隊,最終一舉摘得桂冠。
  • 從人臉識別到機器翻譯:58個超有用的機器學習和預測API
    2 Betaface官網:https://www.betaface.com/wpa/人臉識別和檢測的 Web 服務。其特點包括多個人臉檢測、人臉裁剪、123 個人臉特徵點檢測(22 個基本點、101 個高級點)、大型資料庫中的人臉驗證、識別、相似搜索等。
  • 機器學習和深度學習的 5 個關鍵區別
    有人認為深度學習是機器學習的下一個前沿,是最前沿的前沿。如果你看過Netflix,一些流媒體音樂服務會根據你過去聽過的歌曲,或你點讚過的歌曲,為你推薦觀看的內容。這些能力都建立在深入學習的基礎上。谷歌的語音識別和圖像識別算法也使用深度學習。
  • 人臉關鍵點越多越好?曠視Face++為你詳解1000點和106點的差別
    日前,Face++人工智慧開放平臺推出稠密人臉關鍵點SDK產品,而在近日,Face++雲端稠密人臉關鍵點API也正式上線。所謂稠密人臉關鍵點,即其可檢測人臉1000個關鍵點信息,那不僅有人問:人臉關鍵點是越多越好麼?1000點和106點、81點有什麼區別呢?對此,Face++也給出了一些解讀。
  • 用 cv2 實現人臉檢測
    西瓜書手推筆記後臺回復CV入坑必備獲得CV入坑學習資料【導語】:人臉檢測除了深度網絡等等高端技術下載地址:https://github.com/opencv/opencv/tree/master/data/haarcascades代碼實現實現人臉識別的基本步驟:1.加載文件和圖片 2.進行灰度處理 3.得到haar特徵 4.檢測人臉 5.進行標記
  • VH留學|清華大學博士:面向人臉對齊的機器學習算法研究
    面向人臉對齊的機器學習算法研究人臉對齊是幾乎所有的人臉應用場景中必不可少的基礎環節,如人臉識別,3D人臉重建,人臉動畫風格轉換等。本項目主要是以人臉對齊為切入點,從而熟悉人臉任務實現的流程,即如何從人臉檢測到對齊,再到最後的識別,重建等;並對其中涉及到的機器學習算法進行學習,優化甚至創新。
  • 人臉檢測發展:從VJ到深度學習(下)
    目標檢測任務作為一個分類問題,其不僅受益於計算機視覺領域相關技術的不斷發展,在機器學習領域的研究進展同樣也對目標檢測任務具有推波助瀾的作用。事實上,從2006年開始逐步蔓延開的深度學習大爆發給目標檢測的研究帶來了強勁的助推力,使得通用的目標檢測以及各種特定類型目標的檢測任務得到了跨越式地發展。
  • 基於Adaboost算法的人臉檢測分類器!
    ,早期人們的主要研究方向是人臉識別,即根據人臉來識別人物的身份,後來在複雜背景下的人臉檢測需求越來越大,人臉檢測也逐漸作為一個單獨的研究方向發展起來。目前人臉檢測的方法主要有兩大類:基於知識和基於統計。基於知識的方法:主要利用先驗知識將人臉看作器官特徵的組合,根據眼睛、眉毛、嘴巴、鼻子等器官的特徵以及相互之間的幾何位置關係來檢測人臉。主要包括模板匹配、人臉特徵、形狀與邊緣、紋理特性、顏色特徵等方法。
  • 人臉檢測發展:從VJ到深度學習(上)
    本文分上下兩篇,上篇主要介紹人臉檢測的基本流程,以及傳統的VJ人臉檢測器及其改進,下篇介紹基於深度網絡的檢測器,以及對目前人臉檢測技術發展的思考與討論。為了讓本文更適合非計算機視覺和機器學習背景的讀者,文中對所涉及到的專業術語儘量以通俗的語言和用舉例的方式來進行解釋,同時力求嚴謹,以體現實事求是和一絲不苟的科學研究精神。   這是一個看臉的世界!
  • 雪梨科技大學CVPR 2018論文:無監督學習下的增強人臉關鍵點檢測器
    Supervision-by-Registration 的整體框架Supervision-by-Registration(SBR) 是一個訓練人臉關鍵點檢測器的算法框架,能夠利用無監督的方式增強任何基於圖像的人臉關鍵點檢測器。SBR 利用了物體在視頻中的運動比較平滑的特性來提升一個現有的人臉關鍵點檢測器。
  • 萌顏SDK中的人臉貼紙功能如何檢測
    人臉貼紙如何實現萌顏中的人臉貼紙功能主要是基於人臉識別技術實現的,人臉檢測將人像數據進行提取,可以實時高效的檢測出視頻中的多張人臉,精準定位到畫面中的人臉位置並獲取相關信息。並且對圖像和視頻中給定的人臉進行特徵點定位,同時還要準確地識別人臉五官和輪廓的坐標點,實時高效地進行人臉追蹤,從而實現人臉貼紙功能。
  • 深扒人臉識別60年技術發展史(附國內人臉識別科技企業名單)
    如表1所示,我們給出了人臉識別發展過程中一些經典的方法及其在LFW上的精度,一個基本的趨勢是:訓練數據規模越來越大,識別精度越來越高。人臉識別十大關鍵技術1、人臉檢測(Face Detection)「人臉檢測(Face Detection)」的作用就是要檢測出圖像中人臉所在位置。
  • 中星微AI刷新WIDER FACE人臉檢測世界記錄
    摘要:近日,中星微AI自研的人臉檢測算法VIM_FD,在世界數據規模最大的權威人臉檢測平臺 WIDER FACE的人臉檢測競賽一舉奪得世界第一,彰顯中星微AI在人臉識別領域的創新能力和先進性。近日,中星微AI自研的人臉檢測算法VIM_FD,在世界數據規模最大的權威人臉檢測平臺 WIDER FACE的人臉檢測競賽一舉奪得世界第一,彰顯中星微AI在人臉識別領域的創新能力和先進性。這是中星微AI首次斬獲人臉檢測領域的世界第一的名次,也是中星微AI在檢測領域,階段性的重要研究成果。
  • 彌補傳統惡意代碼檢測短板,機器學習技術還能這樣做?
    這篇文章將介紹基於機器學習的惡意代碼檢測技術,主要參考鄭師兄的視頻總結,包括機器學習概述與算法舉例、基於機器學習方法的惡意代碼檢測、機器學習算法在工業界的應用
  • 美圖影像實驗室(MTlab)10000 點人臉關鍵點技術全解讀
    點 3D 人臉關鍵點技術」——利用深度學習技術實現 10000 點的人臉五官精細定位,該項技術可以在 VR 遊戲中構建玩家人臉的 3D 遊戲角色並且驅動,也可以應用於虛擬試妝試戴和醫療美容領域等。正文如下:簡介在計算機視覺領域,人臉關鍵點定位在視覺和圖形中具有廣泛的應用,包括面部跟蹤、情感識別以及與多媒體相關的交互式圖像視頻編輯任務。
  • OpenCV手部關鍵點檢測(手勢識別)代碼示例
    昨日Satya Mallick又發表了使用OpenCV調用OpenPose工程中的手部關鍵點檢測(hand pose estimation)模型的文章,對於想要使用手部關鍵點檢測做手勢識別、手語識別、抽菸檢測等工程開發的朋友來說這是一個非常簡單的上手教程。先來看看作者發布的視頻效果:在大部分情況下還是不錯的,但也出現了少數幀關鍵點跳變的情況。
  • 從人臉識別到文本分析,50+超實用的 API 推薦清單
    Betafacehttps://www.betaface.com/wpa/面部識別和檢測 Web 服務。其特點包括多人臉檢測、人臉裁剪、123 個人臉特徵點檢測、人臉驗證與識別、以及在大規模資料庫中進行相似性搜索。3.
  • 乾貨 | MTCNN實時人臉檢測網絡詳解與代碼演示
    微信公眾號:OpenCV學堂關注獲取更多計算機視覺與深度學習知識覺得文章對你有用,請戳底部廣告支持MTCNN模型概述多任務卷積神經網絡(MTCNN)實現人臉檢測與對齊是在一個網絡裡實現了人臉檢測與五點標定的模型