当前位置: 移动技术网 > IT编程>开发语言>.net > C#使用Emgu CV来进行图片人脸检测

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

2019年10月29日  | 移动技术网IT编程  | 我要评论

顶真联,油价上调最新消息,金龙传说

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

using system.componentmodel;
 
namespace pdf2face.viewmodel
{
    public class pdf2faceinfomodel : inotifypropertychanged
    {
        public event propertychangedeventhandler propertychanged;
 
        private string pdfname { get; set; }
        /// <summary>
        /// pdf文件名
        /// </summary>
        public string pdfname
        {
            get => pdfname;
            set
            {
                pdfname = value;
                propertychanged?.invoke(this,new propertychangedeventargs("pdfname"));
            }
        }
 
        private int pdfimgcount { get; set; } = 0;
        /// <summary>
        /// pdf中图片数量
        /// </summary>
        public int pdfimgcount
        {
            get => pdfimgcount;
            set
            {
                pdfimgcount = value;
                propertychanged?.invoke(this, new propertychangedeventargs("pdfimgcount"));
            }
        }
 
        private int pdffacecount { get; set; } = 0;
        /// <summary>
        /// pdf中人脸数量
        /// </summary>
        public int pdffacecount
        {
            get => pdffacecount;
            set
            {
                pdffacecount = value;
                propertychanged?.invoke(this, new propertychangedeventargs("pdffacecount"));
            }
        }
 
        private string pdffacesuccess { get; set; } ="否";
        /// <summary>
        /// 数量相对是否存疑 0 正常 1存疑
        /// </summary>
        public string pdffacesuccess
        {
            get => pdffacesuccess;
            set
            {
                pdffacesuccess = value;
                propertychanged?.invoke(this, new propertychangedeventargs("pdffacesuccess"));
            }
        }
    }
}

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

主程序代码:

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<string, bool> 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);
        }
    }
}

程序运行效果:

 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网