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类,用来做为检测结果的通知类。
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);
}
}
}
程序运行效果:
C#使用Emgu CV来进行图片人脸检测的更多相关文章
- 图片人脸检测——Dlib版(四)
上几篇给大家讲了OpenCV的图片人脸检测,而本文给大家带来的是比OpenCV更加精准的图片人脸检测Dlib库. 点击查看往期: <图片人脸检测——OpenCV版(二)> <视频人脸 ...
- 图片人脸检测——OpenCV版(二)
图片人脸检测 人脸检测使用到的技术是OpenCV,上一节已经介绍了OpenCV的环境安装,点击查看. 往期目录 视频人脸检测——Dlib版(六)OpenCV添加中文(五)图片人脸检测——Dlib版(四 ...
- 图片人脸检测(OpenCV版)
图片人脸检测 人脸检测使用到的技术是OpenCV,上一节已经介绍了OpenCV的环境安装,点击查看. 功能展示 识别一种图上的所有人的脸,并且标出人脸的位置,画出人眼以及嘴的位置,展示效果图如下: 多 ...
- 在opencv3中进行图片人脸检测
在opencv中,人脸检测用的是harr或LBP特征,分类算法用的是adaboost算法.这种算法需要提前训练大量的图片,非常耗时,因此opencv已经训练好了,把训练结果存放在一些xml文件里面.在 ...
- Emgu cv人脸检测识别
Emgu cv人脸检测识别 1.开发平台:WIN10 X64 VS2012 Emgucv版本:3.1 2.先给大家分享一个官网给的示例源代码: https://ncu.dl.sourcef ...
- Python使用OpenCV实现简单的人脸检测
文章目录: OpenCV安装 安装numpy 安装opencv OpenCV使用 OpenCV测试 效果图: 注意: 图片人脸检测 程序要求: 技术实现思路 注意 本文使用的环境是:Windows+P ...
- 使用python实现人脸检测
人脸检测 人脸检测使用到的技术是OpenCV,上一节已经介绍了OpenCV的环境安装,点击查看. 功能展示 识别一种图上的所有人的脸,并且标出人脸的位置,画出人眼以及嘴的位置,展示效果图如下: 多张脸 ...
- 视频人脸检测——OpenCV版(三)
视频人脸检测是图片人脸检测的高级版本,图片检测详情点击查看我的上一篇<图片人脸检测——OpenCV版(二)> 实现思路: 调用电脑的摄像头,把摄像的信息逐帧分解成图片,基于图片检测标识出人 ...
- 视频人脸检测——Dlib版(六)
往期目录 视频人脸检测--Dlib版(六) OpenCV添加中文(五) 图片人脸检测--Dlib版(四) 视频人脸检测--OpenCV版(三) 图片人脸检测--OpenCV版(二) OpenCV环境搭 ...
随机推荐
- JS Proxy(代理)
前言 Proxy 也就是代理,可以帮助我们完成很多事情,例如对数据的处理,对构造函数的处理,对数据的验证,说白了,就是在我们访问对象前添加了一层拦截,可以过滤很多操作,而这些过滤,由你来定义. 想了解 ...
- 一、I/O模型之BIO
I/O模型之BIO 基本介绍 Java BIO 就是传统的 Java IO 编程,其相关的类和接口再 java.io 包下 BIO(blocking I/O):同步阻塞,服务器实现模式为一个连接一个线 ...
- Java每日一面(Part1:计算机网络)[19/10/14]
作者:故事我忘了¢个人微信公众号:程序猿的月光宝盒 1.1 说一说TCP的四次挥手 "挥手",即终止TCP连接,断开一个TCP连接池. 需要客户端和服务端总共发出四个包,以 ...
- layui table 分页 序号始终从”1“开始解决方法
在用Layui table 分页显示数据,用 type:"numbers" 进行显示序号有以下的问题 1.表格自带的分页,page:true 这种分页,在切换页面的时候序号可以正常 ...
- 【转载】Android App应用启动分析与优化
前言: 昨晚新版本终于发布了,但是还是记得有测试反馈app启动好长时间也没进入app主页,所以今天准备加个班总结一下App启动那些事! app的启动方式: 1.)冷启动 当启动应用时,后台没有该应用 ...
- ckeditor5 使用第一天 下载并加载居中,居左,居右功能
官方网站地址https://ckeditor.com/,下载zip包或者从git上下载, 下载完成后解压文件,将文件复制到项目中 , 引用ckeditor.js,zh-cn.js路径到项目中, 初始化 ...
- 转战物联网·基础篇03-从JSON数据到短指令谈思维的转变
了解了物联网项目的大体结构之后,我们先从物联网的联网相关部分说起,这也是物联网项目中的关键环节.在联网环节中,不仅要考虑如何连接上,还要考虑连接后如何传输数据.换句话说数据是以什么格式进行传输,对 ...
- hadoop访问50070
http://ip:50070 注意id必须是namenode节点才能访问,datanode不能访问
- django之查询操作及开启事务
目录 聚合查询 aggregate 聚合函数 分组查询 annotate F与Q查询 F查询 Q查询 ORM操作事务 django中开启事务 聚合查询 aggregate 操作外键字段管理数据的时候, ...
- tornado的IOLoop.instance()方法和IOLoop.current()方法区别
在使用tornado时,经常有人疑惑IOLoop.instance()方法和IOLoop.current()方法的区别是什么. IOLoop.instance() 返回一个全局 IOLoop实例. 大 ...