基于虹软人脸识别,实现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);
else
LogHelper.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;
}


之前只实现了从多张人脸中获取一张最大尺寸的人脸作为比较对象,这样视频中也就只能对一张人脸进行画框标记了,现在是把所有提取到的人脸均进行标记,并把各自特征值存在列表中,以便与目标人脸特征值进行匹配。
这样也就粗略的实现了人脸识别追踪,并对目标人物进行抓拍的功能了。
基于虹软人脸识别,实现RTMP直播推流追踪视频中所有人脸信息(C#)的更多相关文章
- 基于GPUImage的多滤镜rtmp直播推流
之前做过开源videocore的推流改进:1)加入了美颜滤镜; 2) 加入了librtmp替换原来过于简单的rtmpclient: 后来听朋友说,在videocore上面进行opengl修改,加入新的 ...
- day122:MoFang:OSSRS流媒体直播服务器&基于APICloud的acLive直播推流模块实现RTMP直播推流
目录 1.docker安装OSSRS流媒体直播服务器 2.基于APICloud的acLive直播推流模块实现RTMP直播推流 3.直播流管理 1.docker安装OSSRS流媒体直播服务器 1.OSS ...
- Android流媒体开发之路二:NDK开发Android端RTMP直播推流程序
NDK开发Android端RTMP直播推流程序 经过一番折腾,成功把RTMP直播推流代码,通过NDK交叉编译的方式,移植到了Android下,从而实现了Android端采集摄像头和麦克缝数据,然后进行 ...
- jQuery 人脸识别插件,支持图片和视频
jQuery Face Detection 是一款人脸检测插件,能够检测到图片,视频和画布中的人脸坐标.它跟踪人脸并输出人脸模型的坐标位置为一个数组.我们相信,面部识别技术能够给我们的 Web 应用带 ...
- EasyRTMP+EasyRTSPClient实现的多路(支持断线重连)RTSP转RTMP直播推流工具
本文转自EasyDarwin开源团队成员Kim的博客:http://blog.csdn.net/jinlong0603/article/details/73441405 介绍 EasyRTMP是Eas ...
- 不用任何第三方,写一个RTMP直播推流器
2016年是移动直播爆发年,不到半年的时间内无数移动直播App掀起了全民直播的热潮.然而个人觉得直播的门槛相对较高,从推流端到服务端器到播放端,无不需要专业的技术来支撑,仅仅推流端就有不少需要学习的知 ...
- Python人脸识别最佳教材典范,40行代码搭建人脸识别系统!
Face Id是一款高端的人脸解锁软件,官方称:"在一百万张脸中识别出你的脸."百度.谷歌.腾讯等各大企业都花费数亿来鞭策人工智能的崛起,而实际的人脸识别技术是否有那么神奇? 绿帽 ...
- 简单机器学习人脸识别工具face-recognition python小试,一行代码实现人脸识别
摘要: 1行代码实现人脸识别,1. 首先你需要提供一个文件夹,里面是所有你希望系统认识的人的图片.其中每个人一张图片,图片以人的名字命名.2. 接下来,你需要准备另一个文件夹,里面是你要识别的图片.3 ...
- EasyRTMP结合海康HCNetSDK获取海康摄像机H.264实时流并转化成为RTMP直播推流(附源码)
最近一家深耕于南方电网的科技公司同事找到我们,咨询关于调用海康HCNetSDK取流,并进行互联网转化的方案,经过反复的沟通以及自身在EasyDSS和EasyNVR方面的经验,我们推荐了海康HCNetS ...
随机推荐
- P1781_宇宙总统(JAVA语言)
//水题 题目背景 宇宙总统竞选 题目描述 地球历公元6036年,全宇宙准备竞选一个最贤能的人当总统,共有n个非凡拔尖的人竞选总统,现在票数已经统计完毕,请你算出谁能够当上总统. 输入输出格式 输入格 ...
- Ubuntu20.04linux内核(5.4.0版本)编译准备与实现过程-编译前准备(1)
最近项目也和linux kernel技术有关,调试内核和内核模块.修改内核源码,是学习内核的重要技术手段之一.应用这些技术时,都有一本基本的要求,那就是编译内核.因此,在分析内核调试技术之前,本随笔给 ...
- 开源框架TLog核心原理架构解析
前言 最近在做TLog 1.2.5版本的迭代,许多小伙伴之前也表示说很想参与开源项目的贡献.为了让项目更好更快速的迭代新特性以及本着发扬开源精神互相学习交流,很有幸招募到了很多小伙伴与我一起前行. 为 ...
- 滴水逆向初级-C语言(二)
2.1.C语言的汇编表示 c语言代码 int plus(int x,int y) { return 0; } void main() { __asm { mov eax,eax } //调用函数 pl ...
- [Fundamental of Power Electronics]-PART I-3.稳态等效电路建模,损耗和效率-3.4 如何获得模型的输入端口
3.4 如何获得模型的输入端口 Fig 3.16 Buck converter example 让我们尝试使用3.3.3节的步骤来推导图3.16所示的Buck变换器的模型.电感绕组电阻同样由串联电阻\ ...
- java面试-垃圾回收器谈谈你的理解
一.垃圾回收算法: 引用计数 复制算法 标记-清除 标记-整理 二.垃圾回收的方式: 串行(Serial).并行(Parallel).并发(CMS).G1 1.串行垃圾回收器(Serial) 它为单线 ...
- 1.PreparedStatement VS Statement
两者都是Sun公司定义的接口,PreparedStatement属于Statement的子接口.二者类似信使,向数据库中执行sql语句: Statement存在拼串的操作,比较繁琐:存在SQL注入问题 ...
- (十)VMware Harbor 日志管理
VMware Harbor 日志管理 1. 项目日志 每个项目下都有一个"日志"页签. 单击"日志"可以列出所有日志.可以按用户名或"高级搜索&quo ...
- TLS Poison - When TLS Hack you
0x00 前言 本次学习的是2020 Blackhat 的一篇文章When TLS Hacks you,简单来说,作者提出了一种新的SSRF攻击思路:利用DNS重绑定和TLS协议的会话恢复进行攻击.具 ...
- spring boot最新版使用几个坑解决
<groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent ...