using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; //подключение библиотек using Emgu.CV; using Emgu.CV.Structure; using Emgu.CV.Face; using Emgu.CV.CvEnum; using System.IO; using System.Threading; using System.Xml; using System.Drawing.Imaging; using DirectShowLib; namespace ImpulseVision { /* * При выключении камеры, сделать так, чтобы картинка отсутствия изображения отображалась корректно * * */ public partial class FormMain : Form { #region <Переменные> //для захвата вилео с веб-камеры private Capture VideoCapture = null; //текущее изображение лица private Image CurrentFrame = null; Mat Frame = new Mat();//кадры изображения //на начало работы распознавание лиц включено bool FacesDetectionEnabled = true; //каскадный классификатор CascadeClassifier Classifier = new CascadeClassifier("haarcascade_frontalface_alt_tree.xml"); Image FaceResult = null; public static List> LstTrainedFaces = new List>(); public static List PersonLabes = new List(); bool EnableSaveImage = false; public static List LstPersonNames = new List(); private static bool IsTrained = false; //тренировщик изображения private static EigenFaceRecognizer Recognizer = null; private static Image TempImageForRazn = null; int SelectedCameraID = -1; //доступные видеокамеры private DsDevice[] WebCams = null; int CountCams = -1; //множество для хранения списка камер HashSet HtBefore = new HashSet(); //включена ли на данный момент камера bool IsWorking = false; #endregion public FormMain() { InitializeComponent(); } private void FormMain_Load(object sender, EventArgs e) { HideAdding(); //скрытие заголовков вкладок в TabControl TbPage.Appearance = TabAppearance.FlatButtons; TbPage.ItemSize = new Size(0, 1); TbPage.SizeMode = TabSizeMode.Fixed; this.Show(); GetCams(); ColorRegular(false); TrainImageFromDir(); } 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 BtnAdd_Click(object sender, EventArgs e) { ShowAdding(); } /// /// показ окна добавления /// private void ShowAdding() { TableLayoutWorks.ColumnStyles[0].Width = 250; TableLayoutWorks.BackColor = Color.White; } /// /// скрытие окна добавления /// private void HideAdding() { TableLayoutWorks.ColumnStyles[0].Width = 0; TableLayoutWorks.BackColor = Color.Black; } private void PbxEther_Click(object sender, EventArgs e) { HideAdding(); } private void BtnOn_Click(object sender, EventArgs e) { if (IsWorking) return; BtnAdd.Enabled = true; TableLayoutWorks.BackColor = Color.Black; IsWorking = true;//камера включена //при нескольких веб- камерах в параметрах передаётся её индекс VideoCapture = new Capture(SelectedCameraID); VideoCapture.ImageGrabbed += VideoCapture_ImageGrabbed; VideoCapture.Start(); FacesDetectionEnabled = true;//включить распознавание CvInvoke.UseOpenCL = true; ColorRegular(IsWorking); } /// /// вычисление разницы между изображениями /// void FaceDifferent() { if(File.Exists(Application.StartupPath+ @"\CurrentFace\imgFace.jpg")) { File.Delete(Application.StartupPath + @"\CurrentFace\imgFace.jpg"); } TempImageForRazn.Save(Application.StartupPath + $@"\CurrentFace\imgFace.jpg"); using (Image sourceImage = new Image(Application.StartupPath + @"\CurrentFace\Вячеслав__12-02-2023-07-35-36afe633.jpg")) { using (Image templateImage = new Image(Application.StartupPath + @"\CurrentFace\imgFace.jpg")) { Image resultImage = new Image(sourceImage.Width, templateImage.Height); CvInvoke.AbsDiff(sourceImage, templateImage, resultImage); //resultImage.Save(@"some path" + "imagename.jpeg"); int diff = CvInvoke.CountNonZero(resultImage); //if diff = 0 exact match, otherwise there are some difference. this.Text = $"Разница: {diff}"; } } } /// /// распознавание изображения, его отображение и сохранение /// private void VideoCapture_ImageGrabbed(object sender, EventArgs e) { 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); CvInvoke.EqualizeHist(GrayImage, GrayImage); CvInvoke.EqualizeHist(GrayImage, GrayImage); //PbxTemplateImage.Image = GrayImage; //записать распознанные изображения в массив Rectangle[] RectFaces = Classifier.DetectMultiScale(GrayImage, 1.1, 3, Size.Empty, Size.Empty); //если лица обнаружены if (RectFaces.Length > 0) { 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.WhiteSmoke; Pen PenInfo = new Pen(Brushes.White, 4); Point PointInfo = new Point(CurrentFrame.Width - CurrentFrame.Width, 0); foreach (Rectangle CurrentFace in RectFaces) { //нарисовать прямоугольники вокруг лиц //CvInvoke.Rectangle(CurrentFrame, CurrentFace, new Bgr(Color.White).MCvScalar, 5); Point PointForFace = new Point(CurrentFace.X, CurrentFace.Y); //результирующее изображение Image ResultImage = CurrentFrame.Convert(); Graphics Graph = Graphics.FromImage(CurrentFrame.Bitmap); Graphics GraphInfo = 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"; if (!Directory.Exists(Path)) { Directory.CreateDirectory(Path); } //сохранить 10 изображений Task.Factory.StartNew(() => { for (int i = 0; i < 30; i++) { ResultImage.Resize(400, 400, Inter.Cubic).Save(Path + @"\" + TbxName.Text.Trim() + "__" + DateTime.Now.ToString("dd-MM-yyyy-hh-mm-ss") + Guid.NewGuid().ToString().Substring(0, 6) + ".jpg"); Thread.Sleep(200); } 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(400, 400, Inter.Cubic); CvInvoke.EqualizeHist(GrayFaceResult, GrayFaceResult); var Result = Recognizer.Predict(GrayFaceResult); if (Result.Label > 0)//если лица найдены { BrushForFace = Brushes.LightGreen; Graph.DrawString($"{LstPersonNames[Result.Label]}", MyFont, BrushForFace, PersonName); GraphInfo.DrawString($"На изображении: {LstPersonNames[Result.Label]}", MyFont, BrushInfo, PointInfo); } else { BrushForFace = Brushes.LightPink; Graph.DrawString("Неизвестный", MyFont, BrushForFace, PersonName); GraphInfo.DrawString("Обнаруженные лица отсутствуют", MyFont, BrushInfo, PointInfo); } } } } } //NormalizeImage(CurrentFrame); try { //вывести изображение в PictureBox PbxEther.Image = CurrentFrame.Bitmap; } catch(Exception ex) { MessageBox.Show(ex.Message, "Внимание!", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void BtnOff_Click(object sender, EventArgs e) { HideAdding(); BtnAdd.Enabled = false; if (VideoCapture != null) { FacesDetectionEnabled = false; VideoCapture.ImageGrabbed -= VideoCapture_ImageGrabbed; VideoCapture.Stop(); VideoCapture.Dispose(); VideoCapture = null; //CurrentFrame = null; } PbxEther.Image = Properties.Resources._9110852_video_no_icon; TableLayoutWorks.BackColor = Color.Gray; IsWorking = false; ColorRegular(IsWorking); } /// /// переключение цветов кнопок включения/выключения /// /// статус работы камеры private void ColorRegular(bool IsWorking) { if(IsWorking) { BtnOn.BackColor = Color.LightGreen; BtnOff.BackColor = Color.White; } else { BtnOn.BackColor = Color.White; BtnOff.BackColor = Color.LightPink; } } private void BtnSave_Click(object sender, EventArgs e) { if(TbxName.Text.Trim() == string.Empty) { MessageBox.Show("Укажите имя и повторите попытку!", "Ошибка добавления!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } TslStatus.Text = "Сохранение данных о пользователе.."; ProgressTrain.Value = 0; EnableSaveImage = true; BtnSave.Text = "Сохранение..."; IsTrained = false; TrainImageFromDir(); BtnSave.Text = "Сохранить"; BtnSave.Enabled = false; TslStatus.Text = "Готов"; ProgressTrain.Value = 100; } /// /// тренировка изображения /// /// результат тренировки (true или false) private void TrainImageFromDir() { int CountImage = 0; //порог double Threshold = 10000; LstTrainedFaces.Clear(); PersonLabes.Clear(); LstPersonNames.Clear(); try { //ProgressTrain.Value += 15; string MyPath = Directory.GetCurrentDirectory() + @"\TrainedImages\"; string[] Files = Directory.GetFiles(MyPath, "*.jpg", SearchOption.AllDirectories); int n = Files.Length; double PlusDigit = 75 / n; foreach (string file in Files) { //ProgressTrain.Value += (int)PlusDigit; Image TrainedImage = new Image(file); //добавить обученное изображение LstTrainedFaces.Add(TrainedImage); PersonLabes.Add(CountImage); string CurrentFileName = Path.GetFileName(file); string Name = CurrentFileName.Remove(CurrentFileName.IndexOf("_"), CurrentFileName.Length - CurrentFileName.IndexOf("_")); //(0, CurrentFileName.Length - CurrentFileName.IndexOf("_") + 1); //добавить имя LstPersonNames.Add(Name); CountImage++; } if (CountImage == 0) { IsTrained = false; return; } //тренировка изображения Recognizer = new EigenFaceRecognizer(CountImage, Threshold); Recognizer.Train(LstTrainedFaces.ToArray(), PersonLabes.ToArray()); //ProgressTrain.Value += 100 - ProgressTrain.Value; //записать, что обучен IsTrained = true; MessageBox.Show("Тренировка изображений выполнена!"); } catch (Exception ex) { IsTrained = false; } } /// /// разница между изображениями /// private void ImageDifferens() { string[] ArrFiles = Directory.GetFiles(Application.StartupPath + @"\TrainedImages\", @"*.jpg", SearchOption.AllDirectories); List LstImages = new List(); Image Im = null; LstImages.Clear(); foreach (string file in ArrFiles) { Im = Image.FromFile(file); LstImages.Add(Im); } Image Pic1 = new Image(ArrFiles[0]); Image Pic2 = new Image(ArrFiles[1]); Image DifferensImage = Pic2 - Pic1; //PbxDifferens.Image = DifferensImage.Bitmap; //LblRazn.Text; } private void CmbCams_SelectedIndexChanged(object sender, EventArgs e) { try { //если захват видео уже идёт if(VideoCapture != null) { VideoCapture.Pause(); VideoCapture.Stop(); VideoCapture.Dispose(); VideoCapture = null; PbxEther.Image = null; SelectedCameraID = -1; } } catch(Exception ex) { MessageBox.Show(ex.Message, "Внимание!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } SelectedCameraID = CmbCams.SelectedIndex; if (IsWorking) { VideoCapture = new Capture(SelectedCameraID); VideoCapture.ImageGrabbed += VideoCapture_ImageGrabbed; VideoCapture.Start(); FacesDetectionEnabled = true;//включить распознавание CvInvoke.UseOpenCL = true; } } private void FormMain_FormClosing(object sender, FormClosingEventArgs e) { Application.ExitThread(); } private void TimerNewCam_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(); } } /// /// уведомление об отключении web-камеры /// /// массив с доступными камерами async void StatusOffDevice(DsDevice[] cams) { HashSet HtAfter = new HashSet(); foreach(DsDevice device in cams) { HtAfter.Add(device.Name); } HtBefore.Except(HtAfter); ProgressTrain.Value = 0; TslStatus.Text = $"Устройство: {string.Join(" ",HtBefore)} - отключено"; await Task.Delay(1000); ProgressTrain.Value = 100; TslStatus.Text = "Готов"; } /// /// уведомление о подключении нового устройствва /// /// массив с доступными web-камерами async void StatusAddNewDevice(DsDevice[] Cams) { TslStatus.Text = "Добавление нового устройства.."; ProgressTrain.Value = 0; while(ProgressTrain.Value < 100) { ProgressTrain.Value += 5; await Task.Delay(50); } TslStatus.Text = "Добавлено новое устройство"; await Task.Delay(1000); TslStatus.Text = $"{Cams[Cams.Length-1].Name}"; await Task.Delay(1000); ProgressTrain.Value = 100; TslStatus.Text = "Готов"; } private void BtnCheck_Click(object sender, EventArgs e) { TslStatus.Text = "Подождите.. выполняется анализ лица.."; ProgressTrain.Value = 45; //TrainImageFromDir(); FaceDifferent(); //Task.Factory.StartNew(new Action(() => TrainImageFromDir())); //ProgressTrain.Value = 55; //TslStatus.Text = "Готов"; } private void TimerCheckTrain_Tick(object sender, EventArgs e) { if(IsTrained) { TimerCheckTrain.Stop(); } } private void PbxEther_Click_1(object sender, EventArgs e) { HideAdding(); } private void STools_Click(object sender, EventArgs e) { TbPage.SelectTab(1); ToolsMenu.Enabled = false; ImList.Images.Clear(); LswView.Items.Clear(); } /// /// получить изображения пользователей системы /// private void SUsers_Click(object sender, EventArgs e) { TbPage.SelectTab(2); ToolsMenu.Enabled = false; ImList.Images.Clear(); LswView.Items.Clear(); string[] ArrFiles = Directory.GetFiles(Application.StartupPath + @"\TrainedImages\", "*.JPG", SearchOption.AllDirectories); for (int i = 0; i < ArrFiles.Length; i++) { try { string Path = ArrFiles[i].ToString(); Image Pic = Image.FromFile(Path); ImList.Images.Add(i.ToString(), Pic); LswView.Items.Add($"{i.ToString()}", ImList.Images.Count - 1); } catch { continue; } } } } }