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 System.Runtime.CompilerServices; 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; } 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); //идентификаторы пользователей, лица которых будут распознаваться List LstUserID = new List(); #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(); string line; 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 VideoProcess(object sender, EventArgs e) { int CountAllRectangle = 0; int CountRecognize = 0; if (VideoCapture == null && VideoCapture.Ptr == IntPtr.Zero) return; //1. Захват видео VideoCapture.Retrieve(Frame, 0);//восстановить нулевой кадр CurrentFrame = Frame.ToImage().Flip(FlipType.Horizontal); //2. Обнаружение лиц if (FacesDetectionEnabled) { //преобразовать изображение в серое Mat GrayImage = new Mat(); CvInvoke.CvtColor(CurrentFrame, GrayImage, ColorConversion.Bgr2Gray); //выравнивание гистограммы изображения CvInvoke.EqualizeHist(GrayImage, GrayImage); #region --Объекты для отрисовки надписей над изображением лица-- Pen PenForFace = new Pen(Brushes.Red, 5); Brush BrushForFace = Brushes.White; Font MyFont = new Font("Segoe UI Variable Small Semibol; 14pt; style=Bold", 14, FontStyle.Regular); Brush BrushInfo = Brushes.White; Pen PenInfo = new Pen(Brushes.White, 4); Point PointInfo = new Point(CurrentFrame.Width - CurrentFrame.Width, 0); Graphics GraphInfo = Graphics.FromImage(CurrentFrame.Bitmap); #endregion //записать распознанные изображения в массив Rectangle[] RectFaces = CasClassifier.DetectMultiScale(GrayImage, 1.1, 3, Size.Empty, Size.Empty); //имя распознанного пользователя, которое будет выводиться в сообщении string NameUserRecognize = string.Empty; //если лица обнаружены if (RectFaces.Length > 0) { foreach (var CurrentFace in RectFaces) { CountAllRectangle++; //нарисовать прямоугольники вокруг лиц Point PointForFace = new Point(CurrentFace.X, CurrentFace.Y); //результирующее изображение //Image ResultImage = CurrentFrame.Convert(); Graphics Graph = Graphics.FromImage(CurrentFrame.Bitmap); Graph.DrawRectangle(PenForFace, PointForFace.X, PointForFace.Y, CurrentFace.Width, CurrentFace.Height); //позиция отрисовки имени человека Point PersonName = new Point(CurrentFace.X, CurrentFace.Y - 25); //Graph.DrawString("Распознано", MyFont, MyBrush, PersonName); //3. Добавление человека (лица) ////результирующее изображение Image ResultImage = CurrentFrame.Convert(); ResultImage.ROI = CurrentFace; //отобразить на форме найденное изображение //PbxDetected.Image = ResultImage.ToBitmap(); //****************** TempImageForRazn = ResultImage; //если сохранение изображения включено //if (EnableSaveImage) //{ // //создать каталог, если он не существует // string Path = Directory.GetCurrentDirectory() + $@"\TrainedImages\{TbxFirstname.Text.Trim()}{TbxPasportSeria.Text.Trim()}{TbxPasportNum.Text.Trim()}"; // string PathPhoto = $@"\TrainedImages\{TbxFirstname.Text.Trim()}{TbxPasportSeria.Text.Trim()}{TbxPasportNum.Text.Trim()}"; // if (!Directory.Exists(Path)) // { // Directory.CreateDirectory(Path); // } // //сохранить 30 изображений // //Task.Factory.StartNew(() => // //{ // // Saving = false; // // LstPathImage.Clear(); // // for (int i = 0; i < 30; i++) // // { // // PathPhoto = $@"\TrainedImages\{TbxFirstname.Text.Trim()}{TbxPasportSeria.Text.Trim()}{TbxPasportNum.Text.Trim()}"; // // ResultImage.Resize(200, 200, Inter.Cubic).Save(Path + @"\" + TbxLastname.Text.Trim() + "+" + TbxFirstname.Text.Trim() + "__" + DateTime.Now.ToString("dd-MM-yyyy-hh-mm-ss") + Guid.NewGuid().ToString().Substring(0, 6) + ".jpg"); // // PathPhoto += @"\" + TbxLastname.Text.Trim() + "+" + TbxFirstname.Text.Trim() + "__" + DateTime.Now.ToString("dd-MM-yyyy-hh-mm-ss") + Guid.NewGuid().ToString().Substring(0, 6) + ".jpg"; // // LstPathImage.Add(PathPhoto); // // Thread.Sleep(200); // // } // // Saving = true; // // MessageBox.Show("Сохранение завершено!", "Результат операции.", MessageBoxButtons.OK, MessageBoxIcon.Information); // // //TrainImageFromDir(); // //}); //} //EnableSaveImage = false; //if (BtnSave.InvokeRequired) //{ // BtnSave.Invoke(new ThreadStart(delegate // { // BtnSave.Enabled = true; // })); //} //5. Узнавание изображения if (IsTrained) { Image grayFaceResult = ResultImage.Convert().Resize(200, 200, Inter.Cubic); CvInvoke.EqualizeHist(grayFaceResult, grayFaceResult); var Result = Recognizer.Predict(grayFaceResult); Debug.WriteLine(Result.Label + " | " + Result.Distance); // если лица найдены if (Result.Label != -1 && Result.Distance < 2000) { CountRecognize++; PenForFace = new Pen(Color.Green, 5); Graph.DrawRectangle(PenForFace, PointForFace.X, PointForFace.Y, CurrentFace.Width, CurrentFace.Height); BrushForFace = Brushes.LightGreen; Graph.DrawString($"{LstPersonNames[Result.Label]}", MyFont, BrushForFace, PersonName); NameUserRecognize = LstPersonNames[Result.Label]; GraphInfo.DrawString($"На изображении: {LstPersonNames[Result.Label]}", MyFont, BrushInfo, PointInfo); //CvInvoke.Rectangle(CurrentFrame, CurrentFace, new Bgr(Color.Green).MCvScalar, 2); } else { BrushForFace = Brushes.LightPink; Graph.DrawString("Неизвестный", MyFont, BrushForFace, PersonName); } } } //if (CountRecognize > CountRecognize / 2) //{ // MessageBox.Show($"Распознан: {NameUserRecognize}"); //} } } //NormalizeImage(CurrentFrame); try { //вывести изображение в PictureBox PbxEther.Image = CurrentFrame.Bitmap; } catch (Exception ex) { MessageBox.Show(ex.Message, "Внимание!", MessageBoxButtons.OK, MessageBoxIcon.Error); } } */ /// /// тренировка изображения /// /// результат тренировки (true или false) /* private void TrainImageFromDir(string UserID) { int CountImage = 0; //порог double Threshold = 2000; //LstTrainedFaces.Clear(); //PersonLabes.Clear(); //LstPersonNames.Clear(); //ProgressTrain.Value += 15; //string MyPath = Directory.GetCurrentDirectory() + @"\TrainedImages\"; //string[] Files = Directory.GetFiles(MyPath, "*.jpg", SearchOption.AllDirectories); int n = LstUserPictures.Count; foreach (Pictures picPath in LstUserPictures) { if (picPath.UserID == UserID) { Image TrainedImage = new Image(Application.StartupPath + picPath.PicturePath.Trim()).Resize(200, 200, Inter.Cubic); //выровнять гистограмму изображения CvInvoke.EqualizeHist(TrainedImage, TrainedImage); //добавить обученное изображение LstTrainedFaces.Add(TrainedImage); PersonLabes.Add(CountImage); string CurrentFileName = Path.GetFileName(Application.StartupPath + picPath.PicturePath); string Name = CurrentFileName.Remove(CurrentFileName.IndexOf("_"), CurrentFileName.Length - CurrentFileName.IndexOf("_")); //добавить имя LstPersonNames.Add(Name.Replace("+", " ")); CountImage++; } } if(LstTrainedFaces.Count() > 0) { //тренировка изображения Recognizer = new EigenFaceRecognizer(CountImage, Threshold); Recognizer.Train(LstTrainedFaces.ToArray(), PersonLabes.ToArray()); //записать, что обучен IsTrained = true; MessageBox.Show("Тренировка изображений выполнена!"); } else { IsTrained = false; MessageBox.Show("Ошибка при распознавании лица!", "ImpulseVision", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } */ 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); GetCams(); Task.Factory.StartNew(() => { PbxEther.Image = Properties.Resources.loading_7; PbxSourceImage.Image = Properties.Resources.loading_7; }); //if (VideoCapture != null) //{ // IsWorking = false; // VideoCapture.Stop(); // VideoCapture.Dispose(); // //VideoCapture = null; //} IsWorking = true;//камера включена ////при нескольких веб- камерах в параметрах передаётся её индекс //VideoCapture = new Capture(SelectedCameraID); //Application.Idle += VideoProcess; 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 (Capture != null) // { // //captureTimer.Stop(); // Capture.Dispose(); // Capture = null; // PbxEther.Image = null; // } //} //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.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.Stop(); //Capture.Dispose(); Capture.Dispose(); } //CaptureTimer.Stop(); CaptureTimer.Tick -= CaptureTimer_Tick; PbxEther.Image = Properties.Resources._9110852_video_no_icon; } 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) { if (!IsRecognized) { MessageBox.Show("Убедитесь, что лицо находится в кадре и обведено красным прямоугольником!", "Ошибка распознавания!"); return; } if (RbtIn.Checked) { SCon.Open(); string QueryAddVisit = $@"set dateformat dmy insert into UserTraffic (UserID,TimeEntrance,Identification,[Date]) values ('{CurrentUserID}','{DateTime.Now.ToString("HH:mm:ss")}','1','{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)"; SqlCommand Cmd = new SqlCommand(QueryTimeExit, SCon); Cmd.ExecuteNonQuery(); SCon.Close(); } GetVisits(); } /// /// получение списка посещений за текущую дату /// private void GetVisits() { SCon.Open(); string QueryGetVisits = $@"select Users.Lastname+' '+Users.Firstname + ' ' + Users.Patronymic as FIO, TimeEntrance,TimeExit 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(); LstVisitInput.Add(visit); } } SCon.Close(); DgbInput.Rows.Clear(); foreach (VisitInput item in LstVisitInput) { DgbInput.Rows.Add(item.FIO + $" {item.TimeEntrance}"); } 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}"); } } } } }