基于虹软人脸识别,实现RTMP直播推流追踪视频中所有人脸信息(C#)

大家应该都知道几个很常见的例子,比如在张学友的演唱会,在安检通道检票时,通过人像识别系统成功识别捉了好多在逃人员,被称为逃犯克星;人行横道不遵守交通规则闯红灯的路人被人脸识别系统抓拍放在大屏上以示警告;参加某次活动通过人脸进行签到来统计实时人流量等等, 我现在也来做一个通过电视直播,追踪画面中所有人脸信息,并捕获我需要的目标人物。

具体思路及流程

基于虹软人脸识别,对直播画面中的每一帧图片进行检测,得到图片中所有人脸信息。可以添加目标人物的照片,用目标人物的人脸特征值与直播画面帧图片中人脸信息列表中的每一个特征值进行比对。如果有匹配到目标人物,把直播画面抓拍。具体流程如下:

项目结构

播放地址我们可以在网上搜索一下电视直播RTMP地址,在程序中可进行播放

private void PlayVideo()
{videoCapture = new VideoCapture(rtmp);if (videoCapture.IsOpened()){videoInfo.Filename = rtmp;videoInfo.Width = (int)videoCapture.FrameWidth;videoInfo.Height = (int)videoCapture.FrameHeight;videoInfo.Fps = (int)videoCapture.Fps;myTimer.Interval = videoInfo.Fps == 0 ? 300 : 1000 / videoInfo.Fps;IsStartPlay = true;myTimer.Start();}else{MessageBox.Show("视频源异常");}
}private void MyTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{try{if (IsStartPlay){lock (LockHelper){var frame = videoCapture.RetrieveMat();if (frame != null){if (frame.Width == videoInfo.Width && frame.Height == videoInfo.Height)this.SetVideoCapture(frame);elseLogHelper.Log($"bad frame");}}}}catch(Exception ex){LogHelper.Log(ex.Message);}
}
Bitmap btm = null;
private void SetVideoCapture(Mat frame)//视频捕获
{try{btm = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(frame);pic_Video.Image = btm;}catch(Exception ex){LogHelper.Log(ex.Message);}
}

以上这些就是在OpenCv中通过VideoCaptrue类对视频进行读取操作,然后把图像渲染到PictureBox控件上。在PictureBox的Paint事件中进行人脸识别与比对操作。

/// <summary>
/// 比对函数,将每一帧抓拍的照片和目标人物照片进行比对
/// </summary>
/// <param name="bitmap"></param>
/// <param name="e"></param>
/// <returns></returns>
private void CompareImgWithIDImg(Bitmap bitmap, PaintEventArgs e)
{if (bitmap != null){//保证只检测一帧,防止页面卡顿以及出现其他内存被占用情况if (isLock == false){isLock = true;Graphics g = e.Graphics;float offsetX = (pic_Video.Width * 1f / bitmap.Width);float offsetY = (pic_Video.Height * 1f / bitmap.Height);//根据Bitmap 获取人脸信息列表List<FaceInfoModel> list = FaceUtil.GetFaceInfos(pImageEngine, bitmap);foreach (FaceInfoModel sface in list){//异步处理提取特征值和比对,不然页面会比较卡ThreadPool.QueueUserWorkItem(new WaitCallback(delegate{try{//提取人脸特征float similarity = CompareTwoFeatures(sface.feature, imageTemp);if (similarity > threshold){this.pic_cutImg.Image = bitmap;this.Invoke((Action)(() =>{this.lbl_simiValue.Text = similarity.ToString();}));}}catch (Exception ex){Console.WriteLine(ex.Message);}}));MRECT rect = sface.faceRect;float x = rect.left * offsetX;float width = rect.right * offsetX - x;float y = rect.top * offsetY;float height = rect.bottom * offsetY - y;//根据Rect进行画框g.DrawRectangle(pen, x, y, width, height);trackUnit.message = "年龄:" + sface.age.ToString() + "\r\n" + "性别:" + (sface.gender == 0 ? "男" : "女");g.DrawString(trackUnit.message, font, brush, x, y + 5);}isLock = false;}}
}

 单张图片可能包含多张人脸,我们用FaceInfoModel 人脸信息实体类,把人脸信息放在此类中。

public class FaceInfoModel
{/// <summary>/// 年龄/// </summary>public int age { get; set; }/// <summary>/// 性别/// </summary>public int gender { get; set; }public ASF_Face3DAngle face3dAngle { get; set; }/// <summary>/// 人脸框/// </summary>public MRECT faceRect { get; set; }/// <summary>/// 人脸角度/// </summary>public int faceOrient { get; set; }/// <summary>/// 单人脸特征/// </summary>public IntPtr feature { get; set; }
}

多人脸实体类存放单人脸信息列表

public class MultiFaceModel : IDisposable
{/// <summary>/// 多人脸信息/// </summary>public ASF_MultiFaceInfo MultiFaceInfo { get; private set; }/// <summary>/// 单人脸信息List/// </summary>public List<ASF_SingleFaceInfo> FaceInfoList { get; private set; }/// <summary>/// 人脸信息列表/// </summary>/// <param name="multiFaceInfo"></param>public MultiFaceModel(ASF_MultiFaceInfo multiFaceInfo) {this.MultiFaceInfo = multiFaceInfo;this.FaceInfoList = new List<ASF_SingleFaceInfo>();FaceInfoList = PtrToMultiFaceArray(multiFaceInfo.faceRects, multiFaceInfo.faceOrients, multiFaceInfo.faceNum);}/// <summary>/// 指针转多人脸列表/// </summary>/// <param name="faceRect"></param>/// <param name="faceOrient"></param>/// <param name="length"></param>/// <returns></returns>private List<ASF_SingleFaceInfo> PtrToMultiFaceArray(IntPtr faceRect, IntPtr faceOrient, int length){List<ASF_SingleFaceInfo> FaceInfoList = new List<ASF_SingleFaceInfo>();var size = Marshal.SizeOf(typeof(int));var sizer = Marshal.SizeOf(typeof(MRECT));for (var i = 0; i < length; i++){ASF_SingleFaceInfo faceInfo = new ASF_SingleFaceInfo();MRECT rect = new MRECT();var iPtr = new IntPtr(faceRect.ToInt32() + i * sizer);rect = (MRECT)Marshal.PtrToStructure(iPtr, typeof(MRECT));faceInfo.faceRect = rect;int orient = 0;iPtr = new IntPtr(faceOrient.ToInt32() + i * size);orient = (int)Marshal.PtrToStructure(iPtr, typeof(int));faceInfo.faceOrient = orient;FaceInfoList.Add(faceInfo);}return FaceInfoList;}public void Dispose(){Marshal.FreeCoTaskMem(MultiFaceInfo.faceRects);Marshal.FreeCoTaskMem(MultiFaceInfo.faceOrients);}
}

然后获取所有人脸信息,放在列表中备用

/// <summary>
/// 获取人脸信息列表
/// </summary>
/// <param name="pEngine"></param>
/// <param name="bitmap"></param>
/// <returns></returns>
public static List<FaceInfoModel>GetFaceInfos(IntPtr pEngine,Image bitmap)
{List<FaceInfoModel> listRet = new List<FaceInfoModel>();try{List<int> AgeList = new List<int>();List<int> GenderList = new List<int>();//检测人脸,得到Rect框ASF_MultiFaceInfo multiFaceInfo = FaceUtil.DetectFace(pEngine, bitmap);MultiFaceModel multiFaceModel = new MultiFaceModel(multiFaceInfo);//人脸信息处理ImageInfo imageInfo = ImageUtil.ReadBMP(bitmap);int retCode = ASFFunctions.ASFProcess(pEngine, imageInfo.width, imageInfo.height, imageInfo.format, imageInfo.imgData, ref multiFaceInfo, FaceEngineMask.ASF_AGE| FaceEngineMask.ASF_GENDER);//获取年龄信息ASF_AgeInfo ageInfo = new ASF_AgeInfo();retCode = ASFFunctions.ASFGetAge(pEngine, ref ageInfo);AgeList = ageInfo.PtrToAgeArray(ageInfo.ageArray, ageInfo.num);//获取性别信息ASF_GenderInfo genderInfo = new ASF_GenderInfo();retCode = ASFFunctions.ASFGetGender(pEngine, ref genderInfo);GenderList = genderInfo.PtrToGenderArray(genderInfo.genderArray, genderInfo.num);for (int i = 0; i < multiFaceInfo.faceNum; i++){FaceInfoModel faceInfo = new FaceInfoModel();faceInfo.age = AgeList[i];faceInfo.gender = GenderList[i];faceInfo.faceRect = multiFaceModel.FaceInfoList[i].faceRect;faceInfo.feature = ExtractFeature(pEngine, bitmap, multiFaceModel.FaceInfoList[i]);//提取单人脸特征faceInfo.faceOrient = multiFaceModel.FaceInfoList[i].faceOrient;listRet.Add(faceInfo);}return listRet;//返回多人脸信息}catch {return listRet;}
}

从列表中获取到的多张人脸,在人脸上画框作出标识,也可以把提取的人脸信息,年龄、性别作出展示。接下来就是选择一张目标人物的照片,通过SDK提取目标人物的人脸特征值作为比较对象,逐一与视频中的人脸特征进行比较。如果有判断到相似度匹配的人脸,则把视频帧图像呈现出来。

/// <summary>
/// 比较两个特征值的相似度,返回相似度
/// </summary>
/// <param name="feature1"></param>
/// <param name="feature2"></param>
/// <returns></returns>
private float CompareTwoFeatures(IntPtr feature1, IntPtr feature2)
{float similarity = 0.0f;//调用人脸匹配方法,进行匹配ASFFunctions.ASFFaceFeatureCompare(pImageEngine, feature1, feature2, ref similarity);return similarity;
}

之前只实现了从多张人脸中获取一张最大尺寸的人脸作为比较对象,这样视频中也就只能对一张人脸进行画框标记了,现在是把所有提取到的人脸均进行标记,并把各自特征值存在列表中,以便与目标人脸特征值进行匹配。

这样也就粗略的实现了人脸识别追踪,并对目标人物进行抓拍的功能了。

GitHub源码已上传:https://github.com/yumaster/FaceTracking

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/302300.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

这些数据获取方式,一般人不知道

全世界只有3.14 % 的人关注了数据与算法之美在这个用数据说话的时代&#xff0c;能够打动人的往往是用数据说话的理性分析&#xff0c;无论是对于混迹职场的小年轻&#xff0c;还是需要数据进行分析和研究的同学&#xff0c;能够找到合适的数据源都是非常重要的。特别是想要对一…

ftp 笔记

Ubuntu自带wget。如果没有密码的ftp&#xff0c;直接wget ftp://111.222.33.4/path/filename&#xff0c;就可以下载ftp://111.222.33.4的文件夹path里的文件filename。如果是有密码的ftp&#xff0c;则wget ftp://username:passwordftp.111.222.33.4/path/filename。如果用的…

java定义构造方法_JAVA基础学习之路(三)类定义及构造方法

类的定义及使用一&#xff0c;类的定义classBook {//定义一个类intprice;//定义一个属性intnum;public static int getMonney(int price, intnum) {//定义一个方法return price*num;}}public classtest2 {public static voidmain(String args[]) {Book monney newBook();//声明…

通过Dapr实现一个简单的基于.net的微服务电商系统(十一)——一步一步教你如何撸Dapr之自动扩/缩容...

上一篇我们讲到了dapr提供的bindings&#xff0c;通过绑定可以让我们的程序轻装上阵&#xff0c;在极端情况下几乎不需要集成任何sdk&#xff0c;仅需要通过httpclienttext.json即可完成对外部组件的调用&#xff0c;这样只需要对外暴露一个轻量级的http服务器提供restapi即可作…

了解IT行业前沿应用,关注数据与算法之美

点击上方蓝色字体&#xff0c;关注我们!

windows php的Memcache安装和使用方法

下载 &#xff1a;memcached.exe解压到 下载&#xff1a;php_memcache.dll 把它放入php文件夹的ext目录中。在php.ini加入一行引用扩展&#xff0c;代码如下&#xff1a;extensionphp_memcache.dll重启Apache服务器然后查看一下phpinfo可以找到memcache信息 说明安装成功测试启…

云原生ASP.NET Core程序的可监测性和可观察性

点击蓝字关注我们分布式应用程序很复杂&#xff0c;给开发人员调试和修复生产问题带来了一系列挑战。尽管微服务架构可帮助维持一支规模较小&#xff0c;可以自主工作并专注于独立业务团队&#xff0c;但由于其分布式性质&#xff0c;它带来了新的挑战。例如&#xff0c;在业务…

OxyPlot.Wpf 图表控件使用备忘

OxyPlot.Wpf 图表控件使用备忘目录OxyPlot.Wpf 图表控件使用备忘一、OxyPlot.Wpf 控件信息二、基本概念(一) PlotView 和 Plot(二) PlotModel(三) Axes(四) Series(五) Tracker三、样式设置(一) 效果对比(二) 图表边框和数据线条样式(三) 坐标轴样式(四) 自定义 Tracker四、装配…

造作吧,Python快速入门!

双十一的刀口还没愈合&#xff0c;双十二的折扣又戳到了胸口。买买买&#xff0c;还是小天最懂你看看小天都准备了什么&#xff01;课程限时优惠&#xff0c;网易云课堂平台优惠券&#xff0c;优惠叠加&#xff0c;课程包更享折上折&#xff01;双十二年终钜惠&#xff0c;还犹…

C# Hashtable和Dictionary区别

Hashtable和Dictionary都是.Net下的表示键值对的集合&#xff0c;那么我们在使用中该选择Hashtable还是Dictionary&#xff1f;下边我们看看他们之间的区别&#xff1a;1、Dictionary<K,V>在使用中是顺序存储的&#xff0c;而Hashtable由于使用的是哈希算法进行数据存储&…

java中如何运行小程序_一起学java(一)——运行第一个小程序

接下来的一段时间内会更新一起学java系列&#xff0c;喜欢的关注一下我吧。微信公众号&#xff1a;什么都不懂的大佬&#xff1b;初学&#xff0c;有错误的地方请大家多多指教。---------------分割线--------------一. 什么是java&#xff1f;java是一门面向对象的计算机编程语…

一分钟教你用Excel从统计局抓数据!

全世界只有3.14 % 的人关注了数据与算法之美现在呢&#xff0c;从网上爬虫数据来做分析越来越火&#xff0c;如果不会这个skillset做数据处理简直没办法装逼。作为一个兴趣广泛的高能物理phd&#xff0c;自然不能被时代落下。首先声明&#xff0c;我并没有学过HTML的语言&#…

记一次 .NET 某HIS系统后端服务 内存泄漏分析

一&#xff1a;背景 1. 讲故事前天那位 his 老哥又来找我了&#xff0c;上次因为CPU爆高的问题我给解决了&#xff0c;看样子对我挺信任的&#xff0c;这次另一个程序又遇到内存泄漏&#xff0c;希望我帮忙诊断下。其实这位老哥技术还是很不错的&#xff0c;他既然能给我dump&a…

freemarker 内置函数

2019独角兽企业重金招聘Python工程师标准>>> 在我们应用Freemarker过程中&#xff0c;经常会操作例如字符串&#xff0c;数字&#xff0c;集合等&#xff0c;却不清楚Freemrker有没有类似于Java一样有相关的类及方法。在本文当中&#xff0c;我将向大家详细的介绍Fr…

专业学习频道,欢迎关注数锐学堂

数锐学堂简介&#xff1a;致力于深耕数学领域的科普学习、竞赛、机器学习等算法技能应用优质课程&#xff0c;精心打造一站式的数学垂直领域教育服务。长按二维码可以关注如果识别二维码有问题请搜索微信号&#xff1a;supermodeling

在非容器(集群)环境下运行dapr

作者&#xff1a;李俱顺原文&#xff1a;https://www.4async.com/2021/03/2021-03-11-running-dapr-without-container/前一段时间一直关注的dapr正式发布了v1.0版本(实际上本文发布时还更新了v1.0.1)&#xff0c;代表dapr在某些程度上进入稳定状态&#xff0c;可以尝试在实际中…

【Silverlight5矢量打印】如何用C#代码检测打印机和驱动是否支持PostScript

Silverlight5支持PostScript矢量打印&#xff0c;矢量打印相比于位图打印速度更快&#xff0c;生成的打印文件更小。SL5默认会采用PS矢量打印&#xff0c;如果打印机不支持&#xff0c;自动切换到位图打印。 虽然微软SL打印组认为PS已经相当普遍&#xff0c;但我想大多数打印机…

用魔法打开科学,孩子惊叫连连,想不爱科学都难!

随着当今科技快速发展&#xff0c;和大家对于人工智能快速崛起的担忧&#xff0c;父母们对于孩子科学能力的培养&#xff0c;已经紧锣密鼓的提上了早教日程。看看近两年早教市场里火爆的课程&#xff0c;“少儿编程”、“儿童机器人教育”、“儿童STEAM课程”等等便是印证了这一…

java反射 获取局部变量_Java反射:如何获取变量的名称?

呼唤远方如果您使用以下的调试信息进行编译&#xff1a;javac -g)&#xff0c;局部变量的名称保存在.class文件中。例如&#xff0c;以这个简单的类为例&#xff1a;class TestLocalVarNames {public String aMethod(int arg) {String local1 "a string";StringBuil…

svn服务端及客户端搭建和使用(三)

接下来,试试用TortoiseSVN修改文件,添加文件,删除文件,以及如何解决冲突等.添加文件在检出的工作副本中添加一个Readme.txt文本文件,这时候这个文本文件会显示为没有版本控制的状态,如图:这时候,你需要告知TortoiseSVN你的操作,如图:加入以后,你的文件会变成这个状态,如图:这时…