• C#使用Emgu CV来进行图片人脸检测


    感谢大哥  https://www.cnblogs.com/wdw984/p/11758163.html

    C#使用Emgu CV来进行图片人脸检测

     

    项目需求:某市级组织考试,在考试前需审核考生采集表中的考生照片是否合格,由于要审核的考生信息采集表有很多,原先进行的是手动人工审核,比较费时费力,审核的要求也很简单,并不判断考生是否是图片本人(身份验证有另外一套程序来进行),只是看考生采集表中考生头像是否是人脸(是否存在辨识不清楚,不是人脸)。因此提出需求,看是否能用程序来检测考生信息采集表中的照片,只需找出来疑似不是人脸的考生所在文档位置(pdf文档)即可,存疑的考生再由人工进行审核。

    PDF文档中有很多页,每一页都是如图中的结构。

     

    经过百度摸索,采用了C#+WPF+Spire.PDF+Emgu CV+MvvmLight来进行人脸判断的技术选型。

    Emgu CV(https://sourceforge.net/projects/emgucv/files/emgucv/)是.NET平台下对OpenCV图像处理库的封装,也就是.NET版的
    OpenCV的全称是:Open Source Computer Vision Library。OpenCV是一个基于(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows和Mac OS操作系统上。Emgu CV官方带的有训练过的人脸识别模板,可以直接使用。

    Spire.PDF可以来读取PDF文档,同时可以读取到PDF文档中的图片。

    MvvmLight是WPF可以使用的一种MVVM模式的实现框架。

    项目技术选型确定以后,下面就是代码的编写。

    项目引用Emgu CV、Spire.PDF、MvvmLight

    从官网下载Emgu CV后,我们把它项目中的haarcascade_eye.xml、haarcascade_frontalface_alt.xml两个训练过的人脸识别模板放到bin/debug下,供Emgu CV使用时调用。

    引用MvvmLight后,会自动在项目中创建ViewModel目录,我们在此目录中新建一个Pdf2FaceInfoModel.cs类,用来做为检测结果的通知类。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    using System.ComponentModel;
      
    namespace Pdf2Face.ViewModel
    {
        public class Pdf2FaceInfoModel : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
      
            private string pdfName { getset; }
            /// <summary>
            /// Pdf文件名
            /// </summary>
            public string PdfName
            {
                get => pdfName;
                set
                {
                    pdfName = value;
                    PropertyChanged?.Invoke(this,new PropertyChangedEventArgs("PdfName"));
                }
            }
      
            private int pdfImgCount { getset; } = 0;
            /// <summary>
            /// Pdf中图片数量
            /// </summary>
            public int PdfImgCount
            {
                get => pdfImgCount;
                set
                {
                    pdfImgCount = value;
                    PropertyChanged?.Invoke(thisnew PropertyChangedEventArgs("PdfImgCount"));
                }
            }
      
            private int pdfFaceCount { getset; } = 0;
            /// <summary>
            /// Pdf中人脸数量
            /// </summary>
            public int PdfFaceCount
            {
                get => pdfFaceCount;
                set
                {
                    pdfFaceCount = value;
                    PropertyChanged?.Invoke(thisnew PropertyChangedEventArgs("PdfFaceCount"));
                }
            }
      
            private string pdfFaceSuccess { getset; } ="否";
            /// <summary>
            /// 数量相对是否存疑 0 正常 1存疑
            /// </summary>
            public string PdfFaceSuccess
            {
                get => pdfFaceSuccess;
                set
                {
                    pdfFaceSuccess = value;
                    PropertyChanged?.Invoke(thisnew PropertyChangedEventArgs("PdfFaceSuccess"));
                }
            }
        }
    }

    主程序只有一个界面,界面两个按钮,一个用来选择要检测pdf所在文件夹,一个用来开始检测。

    主程序代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.IO;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows;
    using Emgu.CV;
    using Emgu.CV.Structure;
    using Microsoft.WindowsAPICodePack.Dialogs;
    using Pdf2Face.ViewModel;
    using Spire.Pdf;
      
    namespace Pdf2Face
    {
        /// <summary>
        /// 人脸检测功能的交互逻辑
        /// </summary>
        public partial class MainWindow : Window
        {
            private string _pdfDirPath;
            private readonly string _pdfFaceSaveDir;
            private readonly ObservableCollection<Pdf2FaceInfoModel> facelist = new ObservableCollection<Pdf2FaceInfoModel>();
      
            public MainWindow()
            {
                InitializeComponent();
                Thread.Sleep(10000);
                dataGrid.ItemsSource = facelist;
                _pdfFaceSaveDir = $"{AppDomain.CurrentDomain.BaseDirectory}face";
                if (!Directory.Exists(_pdfFaceSaveDir))
                {
                    Directory.CreateDirectory(_pdfFaceSaveDir);
                }
            }
            /// <summary>
            /// 选择Pdf所在目录
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void BtnChooseDir_OnClick(object sender, RoutedEventArgs e)
            {
                using (var folderBrowser = new CommonOpenFileDialog())
                {
                    folderBrowser.IsFolderPicker = true;
                    folderBrowser.Multiselect = false;
                    folderBrowser.Title = "选择考生照片所在文件夹";
                    if (folderBrowser.ShowDialog(GetWindow(this)) != CommonFileDialogResult.Ok) return;
                    _pdfDirPath = folderBrowser.FileName;
                    txtBlockPath.Text = _pdfDirPath;
                }
            }
            /// <summary>
            /// 人脸识别检测
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void BtnCheck_OnClick(object sender, RoutedEventArgs e)
            {
                if (string.IsNullOrEmpty(_pdfDirPath) || !Directory.Exists(_pdfDirPath))
                {
                    MessageBox.Show("目录无法访问。""错误", MessageBoxButton.OK, MessageBoxImage.Error);
                    return;
                }
      
                var pdfs = FileSearch(_pdfDirPath, "*.pdf", SearchOption.AllDirectories,
                    x => x.Length > 6);
                if (pdfs.Length == 0)
                {
                    MessageBox.Show("指定的目录中没有发现PDF文件。""错误", MessageBoxButton.OK, MessageBoxImage.Information);
                    return;
                }
      
                txtBlockInfo.Text = $"Pdf文件数量{pdfs.Length}";
                var doc = new PdfDocument();
      
                Dispatcher?.InvokeAsync(async () =>
                {
                    await Task.Run(() =>
                    {
                        foreach (var pdf in pdfs)
                        {
                            doc.LoadFromFile(pdf);
                            var pagenum = 1;
      
                            foreach (PdfPageBase page in doc.Pages)
                            {
                                var newPdfFaceSaveDir = $"{_pdfFaceSaveDir}\{pdf.Substring(pdf.LastIndexOf('\') + 1)}";
                                if (page.ExtractImages() != null)
                                {
                                    if (!Directory.Exists(newPdfFaceSaveDir))
                                    {
                                        Directory.CreateDirectory(newPdfFaceSaveDir);
                                    }
                                    var images = new List<Image>();
                                    var model = new Pdf2FaceInfoModel
                                    {
                                        PdfName = $"{pdf.Substring(pdf.LastIndexOf('\') + 1)}_第{pagenum}页"
                                    };
                                    Dispatcher?.Invoke(() =>
                                    {
                                        facelist.Add(model);
      
                                    });
                                    var c = 0;
                                    foreach (var image in page.ExtractImages())
                                    {
                                        images.Add(image);
                                        var filename = $"{newPdfFaceSaveDir}\{pagenum}_{c}.png";
                                        image.Save(filename, ImageFormat.Png);
      
                                        #region 人脸判断
                                        //检测是否是人脸
                                        //如果支持用显卡,则用显卡运算
                                        CvInvoke.UseOpenCL = CvInvoke.HaveOpenCLCompatibleGpuDevice;
                                        //构建级联分类器,利用已经训练好的数据,识别人脸
                                        var face = new CascadeClassifier("haarcascade_frontalface_alt.xml");
                                        var eyes = new CascadeClassifier("haarcascade_eye.xml");
                                        //加载要识别的图片
                                        var img = new Image<Bgr, byte>(filename);
                                        var img2 = new Image<Gray, byte>(img.ToBitmap());
      
                                        //把图片从彩色转灰度
                                        CvInvoke.CvtColor(img, img2, Emgu.CV.CvEnum.ColorConversion.Bgr2Gray);
                                        //亮度增强
                                        CvInvoke.EqualizeHist(img2, img2);
                                        //返回的是人脸所在的位置和大小
                                        var facesDetected = face.DetectMultiScale(img2, 1.1, 10, new System.Drawing.Size(50, 50));                                   
      
                                        if (facesDetected.Length > 0)
                                        {
                                            model.PdfFaceCount += facesDetected.Length;
                                            model.PdfFaceSuccess = facesDetected.Length > 1 ? "是" "否";
                                            //删除图片,留下的都是无法正确识别的
                                            try
                                            {
                                                File.Delete(filename);
                                            }
                                            catch (Exception exception)
                                            {
                                                //
                                            }
                                        }
      
                                        img.Dispose();
                                        img2.Dispose();
                                        face.Dispose();
                                        #endregion
      
                                        c += 1;
                                    }
                                    model.PdfImgCount = images.Count;
                                }
                                pagenum += 1;
                            }
                            doc.Close();
                        }
      
                    });
                });
            }
      
            private string[] FileSearch(string directoryPath, string searchFilter, SearchOption option, Func<stringbool> func)
            {
                if (!Directory.Exists(directoryPath)) return null;
                var s = Directory.GetFiles(directoryPath, searchFilter, option).Where(func).ToArray();
                return s;
            }
      
            private void MainWindow_OnClosing(object sender, CancelEventArgs e)
            {
                Application.Current.Shutdown(0);
            }
        }
    }

    程序运行效果:

  • 相关阅读:
    《图解HTTP》读书笔记
    Python3 官方文档翻译
    Python3 官方文档翻译
    支付宝Payto接口的C#.net实现方法
    updatepanel用法之triggers(局部刷新,全部刷新)使用示例
    SQL Server中解决死锁
    js字符串与16进制互相转换
    文字超出隐藏并显示省略号,表格固定表头,两表格左右对齐,
    SQL Server中行列转换 Pivot UnPivot
    查看SQL Server日志 Part 1
  • 原文地址:https://www.cnblogs.com/ning-xiaowo/p/13153631.html
Copyright © 2020-2023  润新知