功能描述

  1. 上傳照片檔名及是系統要識別標籤或是照片的名稱(人物標識)
  2. 提取照片臉部特徵值(呼叫 facemesh模型)
  3. 儲存特徵值新增樣本(呼叫 knnClassifier)
  4. 測試上傳的圖片是否識別正確

專案依賴的庫

原始碼(neozhu/smartadmin.core.urf: Domain Driven Design (DDD) ultra-lightweight rapid development architecture(support .net 5.0) (github.com)

tensorflowjs,在該專案中我使用了ml5js這個封裝過的機器學習JavaScript類庫, 使用起來更簡單

Demo

http://106.52.105.140:6200/photos/index

demo/123456

程式碼實現

上傳照片功能

asp.net core 參考CleanArchitecture 結構實現後臺程式碼,

參考程式碼如下(具體請看原始碼):

namespace SmartAdmin.Application.Photos.Commands
{
public partial class AddPhotoCommand : IRequest<Result<int>>
{
public Stream Stream { get; set; }
public string FileName { get; set; }
public decimal Size { get; set; }
public string Path { get; set; } }
internal class AddPhotoCommandHandler : IRequestHandler<AddPhotoCommand, Result<int>>
{
private readonly IUnitOfWork unitOfWork;
private readonly IPhotoService photoService; public AddPhotoCommandHandler(IUnitOfWork unitOfWork,
IPhotoService photoService)
{
this.unitOfWork = unitOfWork;
this.photoService = photoService;
}
public async Task<Result<int>> Handle(AddPhotoCommand request, CancellationToken cancellationToken)
{
var info = new DirectoryInfo(request.Path);
if (!info.Exists)
{
info.Create();
}
using (FileStream outputFileStream = new FileStream(Path.Combine(request.Path,request.FileName), FileMode.Create))
{
request.Stream.CopyTo(outputFileStream);
outputFileStream.Close();
}
var photo = new Photo()
{
Name = Path.GetFileNameWithoutExtension(request.FileName),
Size = request.Size,
Path = $"/photos/{request.FileName}",
};
this.photoService.Insert(photo);
await this.unitOfWork.SaveChangesAsync();
return await Result<int>.SuccessAsync(0, "儲存成功");
} }
}

facemesh模型提取照片中臉部特特資訊

掃描圖片獲取圖片中臉部的特徵資訊以一個多維陣列的形式儲存到資料庫中,這些特徵值將用與下一步的KNN分類識別使用

完成每一張照片中臉部資訊的數字轉化

參考程式碼如下:

 function predict() {
const img = document.getElementById('photo-canvas');
facemesh.predict(img).then(faces => {
console.log(faces)
if (faces) {
const canvas = document.getElementById("photo-canvas");
const photoId=canvas.getAttribute("photo-id");
const photoName=canvas.getAttribute("photo-name");
console.log(canvas)
var draw = canvas.getContext("2d");
var mesh = faces[0].scaledMesh;
console.log(mesh);
/* highlight facial landmark points on canvas board */
draw.fillStyle = "#00FF00";
for (i = 0; i < mesh.length; i++) {
var [x, y, z] = mesh[i];
draw.fillRect(Math.round(x), Math.round(y), 2, 2);
}
updateLandmarks(photoId,JSON.stringify(mesh));
knnClassifier.addExample(mesh, photoName);
canvas.setAttribute("photo-mesh", JSON.stringify(mesh));
$('#testbutton').attr('disabled', false);
}
});
} function updateLandmarks(id,landmarks){
$.post('/Photos/Update',{Id:id,Landmarks:landmarks}).done(res=>{
console.log(res);
reload();
}).fail(res=>{
$.messager.alert('更新失敗', res, 'error');
})
} 

新增分類識別樣本資料

facemesh模型只負責把照片中面部特徵轉換成一個數組,如果需要對每一張照片的資料再進行分類就需要用到KNN模型,新增的樣本資料越多,識別的就越正確。

參考程式碼:

let knnClassifier =ml5.KNNClassifier();
function training(){
$.messager.progress({msg:'training....'});
$.get('/Photos/GetAll').done(res=>{
for(let i=0;i<50;i++){
res.map(item=>{
if(item.Landmarks){
knnClassifier.addExample(JSON.parse(item.Landmarks), item.Name);
}
});
}
$.messager.progress('close')
if(knnClassifier.getNumLabels()>0){
knnClassifier.classify(JSON.parse(res[2].Landmarks),(err,result)=>{
console.log(result);
})
$('#testbutton').attr('disabled', false);
}
})
}

測試照片識別結果

上傳一張照片匹配維護的照片庫中照片名稱是否正確

參考程式碼:

function testPredict(){
const img = document.getElementById('testphoto_img');
facemesh.predict(img).then(faces => {
console.log(faces)
if (faces) {
knnClassifier.classify(faces[0].scaledMesh,(err,result)=>{
console.log(result);
$.messager.alert('Result:',result.label);
$('#testresult').text(result.label);
})
}
});
}

到這裡就全部完成了,對tensorflow感興趣的朋友可以留言,下面有時間會繼續更新,實現利用攝像頭來識別人臉。

對asp.net core CleanArchitecture 感興趣的朋友可以從github下載,也可以留言交流,這個專案我也會繼續更新,如果喜歡,請給個星星。