zoukankan      html  css  js  c++  java
  • 关于人脸识别的视频图片处理

    这篇随笔记录一下最近做人脸识别遇到过的一些问题的解决办法,方便加强印象。以双目摄像头为例。

    首先是封装:

    视频处理在主窗体下操作比较简单,但是如果是将视频处理过程封装起来,就稍微有些麻烦了,会引起线程安全的问题。

    首先将视频控件的对象或者是句柄传到接口里,然后对该对象进行操作。

     1         private AForge.Controls.VideoSourcePlayer VideoPlayer { get; set; }
     2         private AForge.Controls.VideoSourcePlayer VideoPlayer2 { get; set; }
     3       public void SetAFVideo(bool isDefault, AForge.Controls.VideoSourcePlayer video)
     6         {
     7             if (isDefault)
     8             {
     9                 this.VideoPlayer = video;
    10                 this.VideoPlayer.Paint += VideoPlayer_Paint;
    11             }
    12             else
    13             {
    14                 this.VideoPlayer2 = video;
    15             }
    16         }

    有了视频控件的对象后,接着是打开摄像头

     1  /// <summary>
     2         /// 打开摄像头
     3         /// </summary>
     4         /// <param name="isDefault"></param>
     5         /// <param name="videoName">摄像头名称</param>
     6         /// <returns></returns>
     7         public bool AFOpenVideo(bool isDefault, string videoName)
     8         {
     9             FaceResult.Reset();          
    10             _isStopDetect = false;
    11             if (isDefault)
    12             {
    13                 if (this.VideoPlayer == null) return false;
    14                 this.VideoPlayer.Show();
    15                 if (_deviceVideoClr == null)
    16                 {
    17                     _deviceVideoClr = Video.GetVideoSource(videoName);
    18                 }
    19                 this.VideoPlayer.VideoSource = _deviceVideoClr;
    20                 this.VideoPlayer.Start();
    21                 return true;
    22             }
    23             else
    24             {
    25                 if (this.VideoPlayer2 == null) return false;
    26                 this.VideoPlayer2.Show();
    27                 if (_deviceVideoGry == null)
    28                 {
    29                     _deviceVideoGry = Video.GetVideoSource(videoName);
    30                 }
    31                 this.VideoPlayer2.VideoSource = _deviceVideoGry;
    32                 this.VideoPlayer2.Start();
    33                 return true;
    34             }
    35         }

    关闭摄像头。关闭摄像头,有两种方式,一种是在主线程中直接关闭,另外一种是在子线程里关闭

    /// <summary>
            /// 关闭摄像头
            /// </summary>
            public void CloseVideo()
            {
                _isStopDetect = true;
                Thread.Sleep(150);
            }
            /// <summary>
            /// 关闭摄像头
            /// </summary>
            public void CloseVideoDirect()
            {
                CancelFaceDetect();
                if (this.VideoPlayer != null)
                {
                    if (this.VideoPlayer.IsRunning)
                    {
                        VideoPlayer.SignalToStop();
                        VideoPlayer.Hide();
                    }
                }
                if (this.VideoPlayer2 != null)
                {
                    if (this.VideoPlayer2.IsRunning)
                    {
                        VideoPlayer2.SignalToStop();
                        VideoPlayer2.Hide();
                    }
                }
            }

    取消人脸比对

     private void CancelFaceDetect()
            {
                _mEvent.Set();
            }

    人脸识别算法初始化

     /// <summary>
            /// 人脸算法初始化
            /// </summary>
            /// <returns></returns>
            public void InitFaceEngine(Action<bool, string> action)
            {
                   //初始化过程
            }

    人脸比对过程,在子线程里处理,防止页面卡顿,同时每次只处理一帧。通过ManualResetEvent信号变量来终止人脸比对过程,视频比对过程在

    FaceDetect方法里。比对完成,必须释放img对象占用的内存
     
     1 public void StartFaceDetect()
     2         {
     3             if (!_isFaceCompare) return;
     4             _mEvent.Reset();
     5             Task.Factory.StartNew(() =>
     6             {
     7                 Task.Delay(2000).Wait();
     8                 while (true)
     9                 {
    10                     try
    11                     {
    12                         if (_mEvent.WaitOne(100))
    13                         {
    14                             FaceResult.Reset();
    15                             break;
    16                         }
    17                         var imgClr = this.VideoPlayer.GetCurrentVideoFrame();
    18                         var imgGry = this.VideoPlayer2.GetCurrentVideoFrame();
    19                         float offsetX = VideoPlayer.Width * 1f / imgClr.Width;
    20                         float offsetY = VideoPlayer.Height * 1f / imgClr.Height;
    21                         FaceResult.OffsetX = offsetX;
    22                         FaceResult.OffsetY = offsetY;
    23                         FaceDetect(imgClr, imgGry);
    24                         imgClr.Dispose();
    25                         imgGry.Dispose();
    26                     }
    27                     catch (System.Exception ex)
    28                     {
    29                         throw new Exception(ex.Message);
    30                     }
    31                 }
    32             });
    33         }

    给人脸框选。通过_isStopDetect变量来标识,在人脸识别通过后是否关闭摄像头

     1  private void VideoPlayer_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
     2         {
     3             for (int i = 0; i < FaceResult.FaceNumber; i++)
     4             {
     5                 //根据Rect进行画框
     6                 e.Graphics.DrawRectangle(_rectPen, FaceResult.X, FaceResult.Y, FaceResult.Width, FaceResult.Height);
     7                 if (_trackUnit.message != "" && FaceResult.X > 0 && FaceResult.Y > 0)
     8                 {
     9                     //将上一帧检测结果显示到页面上
    10                     e.Graphics.DrawString(_trackUnit.message, _trackFont, _trackBrush, FaceResult.X, FaceResult.Y + 5);
    11                 }
    12             }
    13             if (_isStopDetect)
    14             {
    15                 CloseVideoDirect();
    16             }
    17         }

    将比对结果实时告诉前端。比对的信息通过事件FaceDetectShowHandler 来通知到前端,人脸比对成功通过事件FaceDectctResultHandler通知前端,前端收到FaceDectctResultHandler后执CloseVideo(),以关闭摄像头

     1  public Action<string> FaceDetectShowHandler { get; set; }
     2  public Action FaceDectctResultHandler { get; set; }
     3  /// <summary>
     4  /// 人脸比对
     5  /// </summary>
     6  /// <param name="bitClr"></param>
     7  /// <param name="bitGry"></param>
     8   public void FaceDetect(Bitmap bitClr, Bitmap bitGry)
     9   {
    10 //...
    11       this.__errString = "没有检测到人脸,请正视相机!!";
    12      FaceDetectShowHandler?.Invoke(_errString);
    13     this.__errString = "相似度高";
    14        FaceDectctResultHandler?.Invoke();
    15 
    16  }
    通过前面的示例代码知道,视频比对是在一个task子线程进行,前端要收到比对信息的消息通知,也是在子线程进行,如果将消息显示在前端界面上进行刷新,就必须通过委托
    来刷新界面,否则引起线程安全的问题。同理,前端收到FaceDectctResultHandler事件通知后,要关闭摄像头,就不能直接调用close方法来关闭,而必须在主线程
    关闭,这里通过一个变量_isStopDetect在paint事件里关闭摄像头,因为Paint事件是主线程,所以主线程里关闭摄像头完全没问题。另外关于视频图像的处理,有两种
    方式,一种是用一个while循环,一种是通过线程池,每捕捉到一帧图像就丢到线程池里异步处理,但是用线程池可能会引发一个问题,就是引用类型变量在一个循环没有处
    理完时,变量就被修改了,此时容易引起程序崩溃。用while循环,需要开启一个子线程,防止页面卡顿,是一个同步处理的过程。
    在关闭摄像头时,有一个休眠150毫秒的动作,目的是让ManualResetEvent先收到终止的信号,终止while循环,然后执行关闭摄像头的动作,否则时间过短,导致while
    一直执行。

















  • 相关阅读:
    字符串拼接练习
    java数字字符的全半角转化
    mysql 的group by 满足的规则要求:
    从指定字符串获取n个随机数
    jQuery去除空格的$.trim()
    mysql里的位运算小结
    sql的case 用法
    泛型之元组示例
    jQuery里的replaceAll和replaceWith
    根据索引条件查询结果与原表关联的查询
  • 原文地址:https://www.cnblogs.com/Serialport/p/11231609.html
Copyright © 2011-2022 走看看