<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          C# 人臉識別ViewFaceCore使用的經(jīng)驗分享

          共 50423字,需瀏覽 101分鐘

           ·

          2024-04-10 22:30

          前言

          POS軟件是什么?你好意思嗎,還在用老掉牙的Winform。

          22a87384627c2501f5c9802819b10322.webp 門店被淘汰的POS機

          銷售終端——POS(point of sale)是一種多功能終端,把它安裝在信用卡的特約商戶和受理網(wǎng)點中與計算機聯(lián)成網(wǎng)絡(luò),就能實現(xiàn)電子資金自動轉(zhuǎn)賬,它具有支持消費、預(yù)授權(quán)、余額查詢和轉(zhuǎn)賬等功能,使用起來安全、快捷、可靠。

          8071496d4d9ed85b0052a639e10261a4.webp

          萬事俱備只欠東風(fēng)------一個USB攝像頭和一個經(jīng)過改造的人臉識別程序。

          bfc05e5ef58ab3eb5f5fd3b1b48b8de7.webp

          地址

          ViewFaceCore/ViewFaceCore: C# 超簡單的離線人臉識別庫。

          https://github.com/ViewFaceCore/ViewFaceCore

          正文

          開始干活,動手改造。

          1、程序要支持無人值守,程序啟動時自動打開攝像頭。超過設(shè)定的時間無移動鼠標(biāo)和敲擊鍵盤,程序自動關(guān)閉攝像頭,進入“休眠”

          2、識別人臉成功后記錄當(dāng)前時間作為考勤記錄

          3、人臉信息放在服務(wù)器端,桌面程序和服務(wù)器端同步人臉信息

          4、關(guān)于不排班實現(xiàn)考勤的思考

          5、取消消息彈窗來和用戶交互。使用能自動關(guān)閉的消息彈窗

          1、檢測超過設(shè)定的時間無移動鼠標(biāo)和敲擊鍵盤,判斷是否無人使用。

                #region 獲取鍵盤和鼠標(biāo)沒有操作的時間 
          [StructLayout(LayoutKind.Sequential)]
          struct LASTINPUTINFO
          {
              [MarshalAs(UnmanagedType.U4)]
              public int cbSize;
              [MarshalAs(UnmanagedType.U4)]
              public uint dwTime;
          }
          [DllImport("user32.dll")]
          private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
          /// <summary>
          /// 獲取鍵盤和鼠標(biāo)沒有操作的時間
          /// </summary>
          /// <returns></returns>
          private static long GetLastInputTime()
          {
              LASTINPUTINFO vLastInputInfo = new LASTINPUTINFO();
              vLastInputInfo.cbSize = Marshal.SizeOf(vLastInputInfo);
              if (!GetLastInputInfo(ref vLastInputInfo))
                  return 0;
              else
                  return Environment.TickCount - (long)vLastInputInfo.dwTime;//單位ms  
          }
          #endregion

          2、把人臉識別這個用途改成考勤

                /// <summary>
          /// 窗體加載時
          /// </summary>
          /// <param name="sender"></param>
          /// <param name="e"></param>
          private void Form_Load(object sender, EventArgs e)
          {
              #region 窗體初始化
              WindowState = FormWindowState.Maximized;
              // 隱藏攝像頭畫面控件
              VideoPlayer.Visible = false;
              //初始化VideoDevices
              檢測攝像頭ToolStripMenuItem_Click(nullnull);
              //默認(rèn)禁用拍照按鈕
              FormHelper.SetControlStatus(this.ButtonSave, false);
              Text = "WPOS人臉識別&考勤";
              #endregion
              #region TTS
              try
              {
                  VoiceUtilHelper = new SpVoiceUtil();
                  StartVoiceTaskJob();
              }
              catch (Exception ex)
              {
                  byte[] zipfile = (byte[])Properties.Resources.ResourceManager.GetObject("TTSrepair");
                  System.IO.File.WriteAllBytes("TTSrepair.zip", zipfile);
                  Program.UnZip("TTSrepair.zip"""""true);
                  #region 語音引擎修復(fù)安裝
                  try
                  {
                      MessageBox.Show("初始化語音引擎出錯,錯誤描述:" + ex.Message + Environment.NewLine +
                                  "正在運行語音引擎安裝程序,請點下一步執(zhí)行安裝!", Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                      string physicalRoot = AppDomain.CurrentDomain.BaseDirectory;
                      string info1 = Program.Execute("TTSrepair.exe"3);
                  }
                  finally
                  {
                      System.IO.File.Delete("TTSrepair.zip");
                      Application.Restart();
                  }
                  #endregion
              }
              #endregion
              #region 自動打開攝像頭
              Thread thread = new Thread(() =>
              {
                  Thread.Sleep(5000);
                  sc.Post(SystemInit, this);
              });
              thread.Start();
              #endregion
              #region Sync face data
              Thread SyncThread = new Thread(() =>
              {
                  while (IsWorkEnd == false)
                  {
                      var theEmployeeList = SyncServerEmployeeInfomation().Where(r => r.EmpFacialFeature != null).ToList();
                      if (theEmployeeList != null && theEmployeeList.Count > 0)
                      {
                          foreach (var emp in theEmployeeList)
                          {
                              poolExt.Post(emp);
                          }
                      }
                      Thread.Sleep(5000);
                  }
              });
              SyncThread.Start();
              #endregion
              #region 自動關(guān)閉攝像頭線程
              Thread CameraCheckThread = new Thread(() =>
              {
                  while (IsWorkEnd == false)
                  {
                      if (IsNeedAutoCheck)
                      {
                          long Auto_close_camera_interval = long.Parse(string.IsNullOrEmpty(config.AppSettings.Settings["Auto_close_camera_interval"].Value) ? "60000" : config.AppSettings.Settings["Auto_close_camera_interval"].Value);
                          long ts = GetLastInputTime();
                          if (ts > Auto_close_camera_interval)
                          {
                              IsNeedAutoCheck = false;
                              sc.Post(CheckCameraStatus, this);
                          }
                      }
                      Thread.Sleep(1000);
                  }
              });
              CameraCheckThread.Start();
              btnSleep.Enabled = true;
              btnStopSleep.Enabled = true;
              #endregion
          }

          修改識別人臉后做的事情:

                /// <summary>
          /// 持續(xù)檢測一次人臉,直到停止。
          /// </summary>
          /// <param name="token">取消標(biāo)記</param>
          private async void StartDetector(CancellationToken token)
          {
              List<double> fpsList = new List<double>();
              double fps = 0;
              Stopwatch stopwatchFPS = new Stopwatch();
              Stopwatch stopwatch = new Stopwatch();
              isDetecting = true;
              try
              {
                  if (VideoPlayer == null)
                  {
                      return;
                  }
                  while (VideoPlayer.IsRunning && !token.IsCancellationRequested)
                  {
                      try
                      {
                          if (CheckBoxFPS.Checked)
                          {
                              stopwatch.Restart();
                              if (!stopwatchFPS.IsRunning)
                              { stopwatchFPS.Start(); }
                          }
                          Bitmap bitmap = VideoPlayer.GetCurrentVideoFrame(); // 獲取攝像頭畫面 
                          if (bitmap == null)
                          {
                              await Task.Delay(10, token);
                              FormHelper.SetPictureBoxImage(FacePictureBox, bitmap);
                              continue;
                          }
                          if (!CheckBoxDetect.Checked)
                          {
                              await Task.Delay(1000 / 60, token);
                              FormHelper.SetPictureBoxImage(FacePictureBox, bitmap);
                              continue;
                          }
                          List<Models.FaceInfo> faceInfos = new List<Models.FaceInfo>();
                          using (FaceImage faceImage = bitmap.ToFaceImage())
                          {
                              var infos = await faceFactory.Get<FaceTracker>().TrackAsync(faceImage);
                              for (int i = 0; i < infos.Length; i++)
                              {
                                  Models.FaceInfo faceInfo = new Models.FaceInfo
                                  {
                                      Pid = infos[i].Pid,
                                      Location = infos[i].Location
                                  };
                                  if (CheckBoxFaceMask.Checked || CheckBoxFaceProperty.Checked)
                                  {
                                      Model.FaceInfo info = infos[i].ToFaceInfo();
                                      if (CheckBoxFaceMask.Checked)
                                      {
                                          var maskStatus = await faceFactory.Get<MaskDetector>().PlotMaskAsync(faceImage, info);
                                          faceInfo.HasMask = maskStatus.Masked;
                                      }
                                      if (CheckBoxFaceProperty.Checked)
                                      {
                                          FaceRecognizer faceRecognizer = null;
                                          if (faceInfo.HasMask)
                                          {
                                              faceRecognizer = faceFactory.GetFaceRecognizerWithMask();
                                          }
                                          else
                                          {
                                              faceRecognizer = faceFactory.Get<FaceRecognizer>();
                                          }
                                          var points = await faceFactory.Get<FaceLandmarker>().MarkAsync(faceImage, info);
                                          float[] extractData = await faceRecognizer.ExtractAsync(faceImage, points);
                                          UserInfo userInfo = CacheManager.Instance.Get(faceRecognizer, extractData);
                                          if (userInfo != null)
                                          {
                                              faceInfo.Name = userInfo.Name;
                                              faceInfo.Age = userInfo.Age;
                                              switch (userInfo.Gender)
                                              {
                                                  case GenderEnum.Male:
                                                      faceInfo.Gender = Gender.Male;
                                                      break;
                                                  case GenderEnum.Female:
                                                      faceInfo.Gender = Gender.Female;
                                                      break;
                                                  case GenderEnum.Unknown:
                                                      faceInfo.Gender = Gender.Unknown;
                                                      break;
                                              }
                                              pool.Post(userInfo);
                                          }
                                          else
                                          {
                                              faceInfo.Age = await faceFactory.Get<AgePredictor>().PredictAgeAsync(faceImage, points);
                                              faceInfo.Gender = await faceFactory.Get<GenderPredictor>().PredictGenderAsync(faceImage, points);
                                          }
                                      }
                                  }
                                  faceInfos.Add(faceInfo);
                              }
                          }
                          using (Graphics g = Graphics.FromImage(bitmap))
                          {
                              #region 繪制當(dāng)前時間
                              StringFormat format = new StringFormat();
                              format.Alignment = StringAlignment.Center;
                              format.LineAlignment = StringAlignment.Center;
                              g.DrawString($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}"new Font("微軟雅黑"32), Brushes.Green, new Rectangle(00, Width - 32188), format);
                              #endregion
                              // 如果有人臉,在 bitmap 上繪制出人臉的位置信息
                              if (faceInfos.Any())
                              {
                                  g.DrawRectangles(new Pen(Color.Red, 4), faceInfos.Select(p => p.Rectangle).ToArray());
                                  if (CheckBoxDetect.Checked)
                                  {
                                      for (int i = 0; i < faceInfos.Count; i++)
                                      {
                                          StringBuilder builder = new StringBuilder();
                                          if (CheckBoxFaceProperty.Checked)
                                          {
                                              if (!string.IsNullOrEmpty(faceInfos[i].Name))
                                              {
                                                  builder.Append(faceInfos[i].Name);
                                              }
                                          }
                                          if (builder.Length > 0)
                                              g.DrawString(builder.ToString(), new Font("微軟雅黑"32), Brushes.Green, new PointF(faceInfos[i].Location.X + faceInfos[i].Location.Width + 24, faceInfos[i].Location.Y));
                                      }
                                  }
                              }
                              if (CheckBoxFPS.Checked)
                              {
                                  stopwatch.Stop();
                                  if (numericUpDownFPSTime.Value > 0)
                                  {
                                      fpsList.Add(1000f / stopwatch.ElapsedMilliseconds);
                                      if (stopwatchFPS.ElapsedMilliseconds >= numericUpDownFPSTime.Value)
                                      {
                                          fps = fpsList.Average();
                                          fpsList.Clear();
                                          stopwatchFPS.Reset();
                                      }
                                  }
                                  else
                                  {
                                      fps = 1000f / stopwatch.ElapsedMilliseconds;
                                  }
                                  g.DrawString($"{fps:#.#} FPS"new Font("微軟雅黑"24), Brushes.Green, new Point(1010));
                              }
                          }
                          FormHelper.SetPictureBoxImage(FacePictureBox, bitmap);
                      }
                      catch (TaskCanceledException)
                      {
                          break;
                      }
                      catch { }
                  }
              }
              finally
              {
                  isDetecting = false;
              }
          }
          #endregion

          3、把人臉信息放在服務(wù)器端,桌面程序和服務(wù)器端同步人臉信息

                /// <summary>
          /// 同步人員信息
          /// </summary>
          private List<PlatEmployeeDto> SyncServerEmployeeInfomation()
          {
              List<PlatEmployeeDto> list = new List<PlatEmployeeDto>();
              string url = $"{config.AppSettings.Settings["Platform"].Value}/business/employeemgr/POSSyncEmployeeInfomation";
              try
              {
                  string rs = Program.HttpGetRequest(url);
                  if (!string.IsNullOrEmpty(rs) && JObject.Parse(rs).Value<int>("code").Equals(200))
                  {
                      JObject jo = JObject.Parse(rs);
                      list = JsonConvert.DeserializeObject<List<PlatEmployeeDto>>(jo["data"].ToString());
                  }
              }
              catch (Exception ex)
              {
                  if (ex.Message.Contains("無法連接到遠(yuǎn)程服務(wù)器"))
                  {
                      Thread.Sleep(100);
                      ViewFaceCore.Controls.MessageTip.ShowError("無法連接到遠(yuǎn)程服務(wù)器" + Environment.NewLine + "Unable to connect to remote server"300);
                  }
              }
              return list;
          }
                private void btnSave_Click(object sender, EventArgs e)
          {
              try
              {
                  SetUIStatus(false);
                  UserInfo userInfo = BuildUserInfo();
                  if (userInfo == null)
                  {
                      throw new Exception("獲取用戶基本信息失敗!");
                  }
                  using (DefaultDbContext db = new DefaultDbContext())
                  {
                      db.UserInfo.Add(userInfo);
                      if (db.SaveChanges() > 0)
                      {
                          CacheManager.Instance.Refesh();
                          this.Close();
                          _ = Task.Run(() =>
                          {
                              //確保關(guān)閉后彈窗
                              Thread.Sleep(100);
                              try
                              {
                                  #region Post Data
                                  string url = $"{config.AppSettings.Settings["Platform"].Value}/business/employeemgr/PosNewEmployeeRegister";
                                  PlatEmployeeDto dto = new PlatEmployeeDto();
                                  dto.KeyId = Guid.NewGuid().ToString();
                                  dto.EmpNo = userInfo.EmpNo;
                                  dto.EmpName = userInfo.Name;
                                  dto.EmpSex = (int)userInfo.Gender.ToInt64();
                                  dto.Mobile = userInfo.Phone;
                                  dto.PositionValue = userInfo.JobPosition.ToString();
                                  dto.EmpFacialFeature = _globalUserInfo.Extract;
                                  dto.EmpMainPhoto = _globalUserInfo.Image;
                                  dto.CreateBy = "Client";
                                  dto.CreateTime = DateTime.Now;
                                  dto.IsAdmin = "N";
                                  dto.Status = 0;
                                  dto.FirstPositionLabel = cbxposition.Text;
                                  string jsondata = JsonConvert.SerializeObject(dto);
                                  string st = Program.PostJsonData(url, jsondata);
                                  #endregion 
                                  if (!string.IsNullOrEmpty(st) && st.Contains("200"))
                                  {
                                      //MessageBox.Show("保存用戶信息成功!同步到服務(wù)器成功,可到其他門店考勤。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                                      DialogResult = DialogResult.OK;
                                  }
                              }
                              catch (Exception ex)
                              {
                                  MessageBox.Show("本地保存用戶信息成功!但同步到服務(wù)器出錯,不能立即到其他門店考勤。" + ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                              }
                          });
                      }
                  }
              }
              catch (Exception ex)
              {
                  MessageBox.Show(ex.Message, "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
              }
              finally
              {
                  SetUIStatus(false);
              }
          }

          4、關(guān)于不排班實現(xiàn)考勤的思考

                /// <summary>
          /// 客戶端添加attendance考勤明細(xì)
          /// </summary>
          /// <returns></returns>
          [HttpPost("AddAttendanceDetails")]
          //[ActionPermissionFilter(Permission = "business:erpattendancedetails:add")]
          [Log(Title = "attendance考勤明細(xì)", BusinessType = BusinessType.INSERT)]
          [AllowAnonymous]
          public IActionResult AddAttendanceDetails([FromBody] AttendanceDetailsDto parm)
          {
              var modal = parm.Adapt<AttendanceDetails>().ToCreate(HttpContext);
              if (!string.IsNullOrEmpty(parm.FkStore))
              {
                  int storeId = -1;
                  int.TryParse(parm.FkStore, out storeId);
                  var store = _MerchantStoreService.GetFirst(s => s.Id == storeId);
                  if (store == null)
                      return BadRequest();
                  modal.FkStore = store.KeyId;
              }
              else
                  return BadRequest();
              if (!_AttendanceDetailsService.Any(r => r.AuditDate == parm.AuditDate && r.EmpNo == parm.EmpNo))
              {
                  modal.Remark = "上班&clock in";
                  var response = _AttendanceDetailsService.AddAttendanceDetails(modal);
                  return SUCCESS(response);
              }
              else
              {
                  var list = _AttendanceDetailsService.GetList(r => r.AuditDate == parm.AuditDate && r.EmpNo == parm.EmpNo);
                  var time1 = list.Max(r => r.AttendanceDatetime);
                  if (time1 != null)
                  {
                      var ts = DateTime.Now - DateTime.Parse(time1);
                      if (ts.TotalMinutes < 61)
                      {
                          return Ok();
                      }
                      else
                      {
                          modal.Remark = "下班&clock out";
                          var response = _AttendanceDetailsService.AddAttendanceDetails(modal);
                          return SUCCESS(response);
                      }
                  } 
                  else 
                  { 
                      return BadRequest(); 
                  }                
              }
          }

          5、取消消息彈窗來和用戶交互。使用能自動關(guān)閉的消息彈窗

          4a14a5ba18429438e2dac6d1ea2bf966.webp

          這個需要感謝以前在園子里的\一位\博主的分享他寫的控件名字叫"LayeredWindow",對外暴露的類叫“MessageTip”,不好意思已忘記作者。

          如果你仔細(xì)閱讀代碼還會發(fā)現(xiàn)集成了TTS。反正做得有點像無人值守的一些商業(yè)機器。

          204599922bec9afa8913692df68c02a2.webp

          轉(zhuǎn)自:數(shù)據(jù)酷軟件

          鏈接:cnblogs.com/datacool/p/18004303/ViewFaceCore2024

          73b40afbee12000eb737f97f2236fdac.webp

              

          關(guān)注公眾號DotNet開發(fā)跳槽?    

          瀏覽 40
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  精品欧美一区二区三区四区 | 靠逼免费观看 | 自拍肏屄视频 | 五月丁香花综合网 | 无码一区二区三区四 |