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) { 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; } = "FACE NOT EXISTS"; #region FaceName private string faceName; public string FaceName { get { return faceName; } set { faceName = value.ToUpper(); this.Text = faceName; UserName = faceName; //PbxFaces.Invoke(DispatcherPriority.Normal, new Action(() => { lblFaceName.Content = faceName; })); NotifyPropertyChanged(); } } #endregion #region CameraCaptureImage private Bitmap cameraCapture; public Bitmap CameraCapture { get { return cameraCapture; } set { cameraCapture = value; //imgCamera.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { imgCamera.Source = BitmapToImageSource(cameraCapture); })); PbxEther.Image = cameraCapture; //PbxFaces.Image = BitmapToImageSource(cameraCapture); NotifyPropertyChanged(); } } #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 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); } // /* if (!File.Exists(Config.FaceListTextFile)) { string text = "Не удается найти файл с данными о лице:\n\n"; text += Config.FaceListTextFile + "\n\n"; text += "Если вы впервые запускаете приложение, для вас будет создан пустой файл."; DialogResult result = MessageBox.Show(text, "Предупреждение", MessageBoxButtons.OK, MessageBoxIcon.Warning); switch (result) { case DialogResult.OK: String dirName = Path.GetDirectoryName(Config.FaceListTextFile); Directory.CreateDirectory(dirName); File.Create(Config.FaceListTextFile).Close(); break; } } */ // //получить из БД инфо о пользователе (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) { FaceItem = new FaceData(); while (Res.Read()) { FaceItem.FaceImage = new Image(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; /* StreamReader reader = new StreamReader(Config.FaceListTextFile); while ((line = reader.ReadLine()) != null) { string[] lineParts = line.Split(':'); FaceItem = new FaceData(); FaceItem.FaceImage = new Image(Config.FacePhotosPath + lineParts[0] + Config.ImageFileExtension); FaceItem.PersonName = lineParts[1]; FaceList.Add(FaceItem); } reader.Close(); */ foreach (var face in FaceList) { ImageList.Push(face.FaceImage.Mat); NameList.Add(face.PersonName); LabelList.Push(new[] { i++ }); } // Тренировка распознавания if (ImageList.Size > 0) { recognizer = new EigenFaceRecognizer(ImageList.Size); recognizer.Train(ImageList, LabelList); } } /// /// получение данных с камеры и обработка изображени /// private void ProcessFrame() { BgrFrame = Capture.QueryFrame().ToImage().Flip(FlipType.Horizontal); 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); 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 = "No face detected"; foreach (var face in faces) { BgrFrame.Draw(face, new Bgr(53, 23, 247), 2); DetectedFace = BgrFrame.Copy(face).Convert(); Point PointInfo = new Point(face.Width - face.Width, 0); Graphics GraphInfo = Graphics.FromImage(BgrFrame.ToBitmap()); Graphics Graph = Graphics.FromImage(BgrFrame.ToBitmap()); 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); FaceRecognition(); break; } CameraCapture = BgrFrame.ToBitmap(); } catch (Exception ex) { //todo log } } } /// /// распознавание лица /// private void FaceRecognition() { if (ImageList.Size != 0) { //Eigen Face Algorithm FaceRecognizer.PredictionResult result = recognizer.Predict(DetectedFace.Resize(100, 100, Inter.Cubic)); FaceName = NameList[result.Label]; CameraCaptureFace = DetectedFace.ToBitmap(); } else { FaceName = "Please Add Face"; } } 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 BtnCheck_Click(object sender, EventArgs e) { if(!GetPicturesPath()) { return; } string CurrentID = LstUserPictures[0].UserID; for (int i = 0; i < LstUserPictures.Count; i++) { if (!LstUserID.Contains(LstUserPictures[i].UserID)) { LstUserID.Add(LstUserPictures[i].UserID); } } if(LstUserID.Count > 0) { //TrainImageFromDir(LstUserID[iterator]); } /* for (int i = 0; i < LstUserID.Count; i++) { //Thread.Sleep(5000); IsTrained = false; NextFace = false; //тренировать изображения текущего пользователя TrainImageFromDir(LstUserID[i]); ////подождать некоторое время //Task.Delay(5000); } //TrainImageFromDir(LstUserID[0]); */ //IsTrained = 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(); //if (VideoCapture != null) //{ // IsWorking = false; // VideoCapture.Stop(); // VideoCapture.Dispose(); // //VideoCapture = null; //} IsWorking = true;//камера включена ////при нескольких веб- камерах в параметрах передаётся её индекс //VideoCapture = new Capture(SelectedCameraID); //Application.Idle += VideoProcess; GetFacesList(); if(CmbCams.Items.Count > 0) { SelectedCameraID = Config.ActiveCameraIndex; } //задание активной камеры Capture = new VideoCapture(SelectedCameraID); //настройка кадров Capture.SetCaptureProperty(CapProp.Fps, 30); Capture.SetCaptureProperty(CapProp.FrameHeight, 450); Capture.SetCaptureProperty(CapProp.FrameWidth, 370); CaptureTimer.Start(); } /// /// получение списка доступных камер /// 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(); } } } }