using DirectShowLib; using Emgu.CV; using Emgu.CV.CvEnum; using Emgu.CV.Face; using Emgu.CV.Ocl; using Emgu.CV.Structure; using Emgu.CV.Util; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.SqlClient; using System.Diagnostics; using System.Drawing; using System.IO; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using Timer = System.Windows.Forms.Timer; using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel; namespace ImpulseVision { public partial class FormGuard : Form { public FormGuard() { InitializeComponent(); CaptureTimer = new Timer() { Interval = Config.TimerResponseValue }; CaptureTimer.Tick += CaptureTimer_Tick; } private void CaptureTimer_Tick(object sender, EventArgs e) { TslDate.Text = $"Сейчас: {DateTime.Now.ToString("HH:mm")} {DateTime.Now.ToString("dd.MM.yyyy")}"; ProcessFrame(); } #region <Переменные> public event PropertyChangedEventHandler PropertyChanged; private VideoCapture Capture; private CascadeClassifier HaarCascade; private Image BgrFrame = null; private Image DetectedFace = null; private List FaceList = new List(); private VectorOfMat ImageList = new VectorOfMat(); private List NameList = new List(); private VectorOfInt LabelList = new VectorOfInt(); private EigenFaceRecognizer recognizer; private Timer CaptureTimer; public string UserName { get; set; } = "Лицо не обнаружено"; /// /// ID пользователя, который обнаружен /// private string CurrentUserID = string.Empty; public struct VisitInput { public string FIO, TimeEntrance, TimeExit, Identification; } List LstVisitInput = new List(); #region FaceName private string faceName; public string FaceName { get { return faceName; } set { faceName = value; if (faceName == "Лицо не обнаружено") { IsRecognized = false; } else { IsRecognized = true; } //this.Text = IsRecognized.ToString(); UserName = faceName; NotifyPropertyChanged(); } } #endregion #region CameraCaptureImage private Bitmap cameraCapture; //Image bgrFrame, Rectangle face Rectangle CurrentFace; public Bitmap CameraCapture { get { return cameraCapture; } set { cameraCapture = value; DrawName(cameraCapture, CurrentFace); PbxEther.Image = cameraCapture; NotifyPropertyChanged(); } } /// /// отрисовка имени над прямоугольком /// private void DrawName(Bitmap cameraCapture, Rectangle face) { Pen PenForFace = new Pen(Brushes.Red, 5); Brush BrushForFace = Brushes.White; Font MyFont = new Font("Segoe UI Variable Small Semibol; 12pt; style=Bold", 12, FontStyle.Regular); Brush BrushInfo = Brushes.White; Pen PenInfo = new Pen(Brushes.White, 4); Graphics Graph = Graphics.FromImage(cameraCapture); //Graph.DrawRectangle(PenForFace, face.X, face.Y, face.Width, face.Height); //позиция отрисовки имени человека Point PointName = new Point(face.X, face.Y - 25); Graph.DrawString($"{UserName}", MyFont, BrushForFace, PointName); } #endregion #region CameraCaptureFaceImage private Bitmap cameraCaptureFace; public Bitmap CameraCaptureFace { get { return cameraCaptureFace; } set { cameraCaptureFace = value; //imgDetectFace.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { imgDetectFace.Source = BitmapToImageSource(cameraCaptureFace); })); //PbxFaces.Image = BitmapToImageSource(cameraCapture); PbxEther.Image = cameraCapture; NotifyPropertyChanged(); } } #endregion //уведомление о том, что пользователь распознан bool IsRecognized = false; //включена ли на данный момент камера bool IsWorking = false; //выбранная камера int SelectedCameraID = 0; //доступные видеокамеры private DsDevice[] WebCams = null; int CountCams = -1; //множество для хранения списка камер HashSet HtBefore = new HashSet(); //пути доступа к изображениям пользователей List LstUserPictures = new List(); SqlConnection SCon = new SqlConnection(Properties.Settings.Default.ImpulseVisionAppConnectionString); #endregion struct Pictures { public string UserID, PicturePath; } /// /// получение данных об изображениях /// public void GetFacesList() { //haar cascade classifier if (!File.Exists(Config.HaarCascadePath)) { string text = "Не удаётся найти файл данных - каскад Хаара:\n\n"; text += Config.HaarCascadePath; DialogResult result = MessageBox.Show(text, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); } HaarCascade = new CascadeClassifier(Config.HaarCascadePath); FaceList.Clear(); FaceData FaceItem = null; // Create empty directory / file for face data if it doesn't exist if (!Directory.Exists(Config.FacePhotosPath)) { Directory.CreateDirectory(Config.FacePhotosPath); } //получить из БД инфо о пользователе (id, имя, фамилия, путь до фото) SCon.Open(); string QueryGetInfoAboutUser = $@"select Users.ID ,Users.Lastname, Users.Firstname, Users.Patronymic, FaceImages.Picture from Users join FaceImages on Users.ID = FaceImages.UserID"; SqlCommand Cmd = new SqlCommand(QueryGetInfoAboutUser, SCon); SqlDataReader Res = Cmd.ExecuteReader(); if(Res.HasRows) { while (Res.Read()) { FaceItem = new FaceData(); FaceItem.FaceImage = new Image(Application.StartupPath +"\\"+ Res["Picture"].ToString()); FaceItem.PersonName = Res["Firstname"].ToString(); FaceItem.LastName = Res["Lastname"].ToString(); FaceItem.Patronymic = Res["Patronymic"].ToString(); FaceItem.UserID = Res["ID"].ToString(); FaceList.Add(FaceItem); } } else { SCon.Close(); MessageBox.Show("Данные о пользователях отсутствуют!", "ImpulseVision", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } SCon.Close(); int i = 0; foreach (var face in FaceList) { ImageList.Push(face.FaceImage.Mat); NameList.Add(face.PersonName + " " + face.LastName); LabelList.Push(new[] { i++ }); } // Тренировка распознавания if (ImageList.Size > 0) { recognizer = new EigenFaceRecognizer(ImageList.Size); recognizer.Train(ImageList, LabelList); } } private Image CurrentFrame = null; /// /// получение данных с камеры и обработка изображени /// private void ProcessFrame() { BgrFrame = Capture.QueryFrame().ToImage().Flip(FlipType.Horizontal); if (BgrFrame != null) { try {//for emgu cv bug Image grayframe = BgrFrame.Convert(); Rectangle[] faces = HaarCascade.DetectMultiScale(grayframe, 1.2, 10, new System.Drawing.Size(50, 50), new System.Drawing.Size(200, 200)); //detect face FaceName = "Лицо не обнаружено"; foreach (var face in faces) { CurrentFace = face; BgrFrame.Draw(face, new Bgr(53, 23, 247), 2); DetectedFace = BgrFrame.Copy(face).Convert(); FaceRecognition(); break; } CameraCapture = BgrFrame.ToBitmap(); } catch (Exception ex) { MessageBox.Show(ex.Message); } } } /// /// распознавание лица /// private void FaceRecognition() { if (ImageList.Size != 0) { FaceRecognizer.PredictionResult result = recognizer.Predict(DetectedFace.Resize(100, 100, Inter.Cubic)); FaceName = NameList[result.Label]; CurrentUserID = FaceList[result.Label].UserID; CameraCaptureFace = DetectedFace.ToBitmap(); PbxSourceImage.Image = FaceList[result.Label].FaceImage.ToBitmap(); } else { FaceName = "Пожалуйста добавьте лицо"; } } protected virtual void NotifyPropertyChanged([CallerMemberName] String propertyName = "") { var handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); } /// /// получение id и путей доступа к изображениям пользователей /// private bool GetPicturesPath() { SCon.Open(); string Query1 = $@"select UserID,Picture from FaceImages"; SqlCommand Cmd = new SqlCommand(Query1, SCon); SqlDataReader Res = Cmd.ExecuteReader(); if(Res.HasRows) { LstUserPictures.Clear(); while(Res.Read()) { Pictures Pic = new Pictures(); Pic.UserID = Res["UserID"].ToString(); Pic.PicturePath = Res["Picture"].ToString(); LstUserPictures.Add(Pic); } } else { MessageBox.Show("Не удалось получить информацию об изображениях!", "ImpulseVision", MessageBoxButtons.OK, MessageBoxIcon.Error); SCon.Close(); return false; } SCon.Close(); return true; } private void FormGuard_Load(object sender, EventArgs e) { // TODO: This line of code loads data into the 'impulseVisionAppDataSet1.Staffs' table. You can move, or remove it, as needed. this.staffsTableAdapter.Fill(this.impulseVisionAppDataSet1.Staffs); LblID.Hide(); GetCams(); Task.Factory.StartNew(() => { PbxEther.Image = Properties.Resources.loading_7; PbxSourceImage.Image = Properties.Resources.loading_7; }); IsWorking = true;//камера включена GetFacesList(); Capture = new VideoCapture(SelectedCameraID); //настройка кадров Capture.SetCaptureProperty(CapProp.Fps, 30); Capture.SetCaptureProperty(CapProp.FrameHeight, 450); Capture.SetCaptureProperty(CapProp.FrameWidth, 370); CaptureTimer.Start(); GetVisits(); } /// /// получение списка доступных камер /// private void GetCams() { WebCams = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice); CountCams = WebCams.Length; CmbCams.Items.Clear(); for (int i = 0; i < CountCams; i++) { CmbCams.Items.Add(WebCams[i].Name); HtBefore.Add(WebCams[i].Name); } if (CountCams > 0) { CmbCams.SelectedIndex = 0; SelectedCameraID = 0; } } private void CmbCams_SelectedIndexChanged(object sender, EventArgs e) { try { if (BgrFrame != null) { BgrFrame = null; Capture.Dispose(); CaptureTimer.Tick -= CaptureTimer_Tick; } } catch (Exception ex) { MessageBox.Show(ex.Message, "Внимание!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } SelectedCameraID = CmbCams.SelectedIndex; Capture = new VideoCapture(SelectedCameraID); //настройка кадров Capture.SetCaptureProperty(CapProp.Fps, 30); Capture.SetCaptureProperty(CapProp.FrameHeight, 450); Capture.SetCaptureProperty(CapProp.FrameWidth, 370); CaptureTimer.Tick += CaptureTimer_Tick; CaptureTimer.Start(); } private void TimerCam_Tick(object sender, EventArgs e) { DsDevice[] Cams = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice); int Count = Cams.Length; //если количество подключённых камер изменилось if (Count != CountCams) { //if (Count > CountCams) //{ // StatusAddNewDevice(Cams); //} //else if (Count < CountCams) //{ // StatusOffDevice(Cams); //} GetCams(); } } private void CameraOff() { if (BgrFrame != null) { BgrFrame = null; Capture.Dispose(); CaptureTimer.Tick -= CaptureTimer_Tick; } PbxEther.Image = Properties.Resources._9110852_video_no_icon; CaptureTimer.Tick -= CaptureTimer_Tick; } private void DgbOutput_CellContentClick(object sender, DataGridViewCellEventArgs e) { } private void FormGuard_FormClosing(object sender, FormClosingEventArgs e) { CameraOff(); } /// /// добавление в БД информации о входе /// private void BtnSkip_Click(object sender, EventArgs e) { RegisterVisit(1); GetVisits(); } /// /// регистрация посещения /// /// успешность идентификации (1-успешно, 0- нет) private void RegisterVisit(int IsIdentification) { if (!IsRecognized) { MessageBox.Show("Убедитесь, что лицо находится в кадре и обведено красным прямоугольником!", "Ошибка распознавания!"); return; } if (RbtIn.Checked) { if (IsIdentification == 1) { #region Предупреждение при попытке повторной идентификации пользователя за один день SCon.Open(); string QueryCheckExistsVisit = $@"select Count(ID) as Cnt from UserTraffic where UserID = '{CurrentUserID}' and [Date] = CAST(GETDATE() as date)"; SqlCommand CmdCheckVisit = new SqlCommand(QueryCheckExistsVisit, SCon); SqlDataReader Res = CmdCheckVisit.ExecuteReader(); Res.Read(); int n = int.Parse(Res["Cnt"].ToString()); if (n >= 1) { MessageBox.Show("Сегодня данный пользователь уже прошёл идентификацию при входе!", "ImpulseVision", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); SCon.Close(); return; } SCon.Close(); #endregion } SCon.Open(); string QueryAddVisit = $@"set dateformat dmy insert into UserTraffic (UserID,TimeEntrance,Identification,[Date]) values ('{CurrentUserID}','{DateTime.Now.ToString("HH:mm:ss")}','{IsIdentification}','{DateTime.Now.ToString("dd.MM.yyyy")}')"; SqlCommand Cmd = new SqlCommand(QueryAddVisit, SCon); Cmd.ExecuteNonQuery(); SCon.Close(); } else { SCon.Open(); string QueryCheckRecord = $@"set dateformat dmy select * from UserTraffic where UserID = '{CurrentUserID}' and [Date] = cast(GETDATE() as date) and TimeExit is null "; SqlCommand CmdCheck = new SqlCommand(QueryCheckRecord, SCon); SqlDataReader Res = CmdCheck.ExecuteReader(); if (!Res.HasRows) { MessageBox.Show("Данный пользователь уже вышел!", "ImpulseVision", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); SCon.Close(); return; } SCon.Close(); //!!! Выход пользователя, который не прошёл идентификацию не регистрируется SCon.Open(); string QueryTimeExit = $@"update UserTraffic set TimeExit = '{DateTime.Now.ToString("HH:mm:ss")}' where UserID = '{CurrentUserID}' and [Date] = cast(GETDATE() as date) and Identification != 0 "; SqlCommand Cmd = new SqlCommand(QueryTimeExit, SCon); Cmd.ExecuteNonQuery(); SCon.Close(); } } /// /// получение списка посещений за текущую дату /// private void GetVisits() { SCon.Open(); string QueryGetVisits = $@"select Users.Lastname+' '+Users.Firstname + ' ' + Users.Patronymic as FIO, TimeEntrance,TimeExit, Identification from UserTraffic ut join Users on ut.UserID = Users.ID where ut.[Date] = cast(GETDATE() as date)"; SqlCommand Cmd = new SqlCommand(QueryGetVisits, SCon); SqlDataReader Res = Cmd.ExecuteReader(); if (Res.HasRows) { LstVisitInput.Clear(); while (Res.Read()) { VisitInput visit = new VisitInput(); visit.FIO = Res["FIO"].ToString(); visit.TimeEntrance = Res["TimeEntrance"].ToString(); visit.TimeExit = Res["TimeExit"].ToString(); visit.Identification = Res["Identification"].ToString(); LstVisitInput.Add(visit); } } SCon.Close(); DgbInput.Rows.Clear(); foreach (VisitInput item in LstVisitInput) { DgbInput.Rows.Add(item.FIO + $" {item.TimeEntrance}"); if (item.Identification.ToLower() == "false") { DgbInput.Rows[DgbInput.RowCount - 1].DefaultCellStyle.BackColor = ColorTranslator.FromHtml("#E84855"); DgbInput.Rows[DgbInput.RowCount - 1].DefaultCellStyle.ForeColor = Color.White; } } DgbOutput.Rows.Clear(); string STime = string.Empty; foreach (VisitInput item in LstVisitInput) { STime = item.TimeExit; if (STime != string.Empty) { DgbOutput.Rows.Add(item.FIO + $" {STime}"); if (item.Identification.ToLower() == "false") { DgbInput.Rows[DgbInput.RowCount - 1].DefaultCellStyle.BackColor = ColorTranslator.FromHtml("#E84855"); DgbInput.Rows[DgbInput.RowCount - 1].DefaultCellStyle.ForeColor = Color.White; } } } } private void BtnReject_Click(object sender, EventArgs e) { RegisterVisit(0); if (!IsRecognized) return; try { Image Img = BgrFrame.Copy(); string PathLog = Application.StartupPath + $"\\Source\\log\\{"User_" + CurrentUserID + "_" + DateTime.Now.ToString("HHmmss") + "_" + DateTime.Now.ToString("dd.MM.yyyy") + "_" + Guid.NewGuid().ToString().Substring(0, 4)}.bmp"; Img.Save(PathLog); } catch(Exception ex) { MessageBox.Show(ex.Message, "ImpulseVision", MessageBoxButtons.OK, MessageBoxIcon.Error); } GetVisits(); } private void FormGuard_KeyDown(object sender, KeyEventArgs e) { if(e.KeyCode == Keys.S) { BtnSkip_Click(sender, e); } if(e.KeyCode == Keys.D) { BtnReject_Click(sender, e); } } } }