AI時代的網站與手機App建置與開發Part26 - ML.NET與人臉辨識
· 摘要
人臉辨識的應用很廣泛, 例如應用在海關的出入境管制, 企業的門禁系統, 判斷人臉是否配戴眼鏡, 口罩等配件, 或是手機登入管制, 都是人臉識別常見的應用場合.
圖: 人臉識別示意圖
在本篇文章中, 我們將使用Microsoft ML.NET搭配Facenet.onnx人臉辨識模型執行人臉辨識..
· 準備訓練資料
首先請準備兩張欲判斷是否為同一個人的人臉照片, 加入到Visual Studio專案中名稱為Faces的資料夾中, 並到[屬性]視窗將兩張人臉照片的[複製到輸出目錄]屬性的內容值設定為:有更新時才複製.
圖1所示即為欲判斷是否為同一個人的兩張人臉照片, 讀者可以使用自行提供的人臉照片:
圖1: 欲判斷是否為同一個人的兩張人臉照片
· 準備人臉辨識模型
首先請啟動瀏覽器, 瀏覽至faceNet.onnx, 下載名稱為faceNet.onnx的人臉辨識模型(下載網址: https://github.com/NicolasSM-001/faceNet.onnx-). 請將人臉辨識模型加入到Visual Studio專案中名稱為Models資料夾中, 並到[屬性]視窗將faceNet.onnx檔案的[複製到輸出目錄]屬性的內容值設定為:有更新時才複製.
· 定義抽取人臉特徵向量的類別
public class OnnxModelExtractor : IDisposable
{
private InferenceSession _session;// 存放抽取人臉特徵向量的模型的變數
private string _inputName; // 存放人臉特徵Metadata的變數
public OnnxModelExtractor(string modelPath)
//建構函式
{
//利用人臉辨識模型建立InferenceSession類別的物件,並存放在_session變數
_session = new InferenceSession(modelPath);
// 將人臉特徵的Metadata存放在_inputName變數
_inputName = _session.InputMetadata.Keys.FirstOrDefault();
}
// 支援取得人臉特徵向量的函式
public float[] GetEmbedding(string imagePath)
{
using var image =
SixLabors.ImageSharp.Image.Load<Rgb24>(
imagePath); // 載入代表人臉的圖片檔案
var input = PreprocessImage(
image); // 將圖片資料整理成人臉辨識模型需要的規格
// 將圖片資料與metadata準備成人臉辨識模型能夠處理的List集合
var
inputs = new List<NamedOnnxValue>
{
NamedOnnxValue.CreateFromTensor(_inputName, input)
};
using
IDisposableReadOnlyCollection<DisposableNamedOnnxValue>
results = _session.Run(inputs);
// 取出128個特徵向量
var embedding =
results.First().AsEnumerable<float>()
.ToArray();
// 將取出的特徵向量轉型成陣列
return embedding;
// 傳回陣列的內容
}
// 支援將圖片資料整理成人臉辨識模型需要的規格的函式
private Tensor<float> PreprocessImage(Image<Rgb24>
image)
{
image.Mutate(x => x.Resize
(160, 160)); // 將讀取到的圖片轉換成人臉辨識模型需要的大小
// 建位代表[batch size,height,width,channels]四個維度的DenseTensor
var
input = new DenseTensor<float>(new[] { 1, 160, 160, 3 });
//調整RGB色彩內容值至0~1之間的範圍並填入DenseTensor
for (int y = 0; y < 160; y++)
{
for (int x = 0; x < 160; x++)
{
var pixel = image[x, y];
input[0, 0, y, x] = pixel.R / 255f;
input[0, 1, y, x] = pixel.G / 255f;
input[0, 2, y, x] = pixel.B / 255f;
}
}
return input;
// 傳回調整後的內容
}
// 支援自動資源管理的函式
public void Dispose()
{
_session?.Dispose();
}
}
· 使用ML.NET判定兩張代表人臉的圖片的相似程度
首先請定義計算兩組特徵向量餘弦相似度的函式
· 定義計算兩組特徵向量餘弦相似度的函式
// 支援判斷兩個陣列對應的內容值的餘弦相似度Cosine Similarity的函式
float CosineSimilarity(float[] vector1, float[] vector2)
{
float dotProduct = vector1.Zip(vector2, (a,
b) => a * b).Sum();
float magnitude1 = (float)Math.Sqrt(vector1.Sum(a => a * a));
float magnitude2 = (float)Math.Sqrt(vector2.Sum(b => b * b));
return dotProduct / (magnitude1 * magnitude2);
}
· 判定兩張代表人臉的圖片的相似程度
private void btnVerify_Click(object sender, EventArgs e)
{
var embeddingExtractor = new OnnxModelExtractor(
@"Models/facenet.onnx"); // 載入facenet.onnx人臉辨識模型
float[] embedding1 =
embeddingExtractor.GetEmbedding(
@"Faces/測試圖片1.jpg"); // 取出第一張圖片的特徵向量
float[] embedding2 =
embeddingExtractor.GetEmbedding(
@"Faces/測試圖片2.jpg"); // 取出第二張圖片的特徵向量
var similarityScore = CosineSimilarity(embedding1,
embedding2); // 計算代表兩張圖片的特徵向量的餘弦相似度
// 如果餘弦相似度大於0,7(可視需要調整), 則判定兩張圖片代表同一個人
bool isMatch = similarityScore > 0.7;
// 顯示判定結果
Trace.WriteLine(
$@"測試圖片1和測試圖片2的相似程度為{similarityScore:P2}, 是否為同一人:{isMatch}");
}
執行上述的程式碼會顯示判定兩張代表人臉的照片是否為同一個人的照片的預測結果, 如圖2所示:
圖2: 判定兩張代表人臉的照片是否為同一個人的照片的預測結果
範例下載:


留言
張貼留言