功能描述

  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下载,也可以留言交流,这个项目我也会继续更新,如果喜欢,请给个星星。