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

时间:2022-09-01 17:45:15

前言

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

具体思路及流程

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

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

项目结构

基于虹软人脸识别,实现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#)

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

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

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

GitHub源码已上传

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

  1. 基于GPUImage的多滤镜rtmp直播推流

    之前做过开源videocore的推流改进:1)加入了美颜滤镜; 2) 加入了librtmp替换原来过于简单的rtmpclient: 后来听朋友说,在videocore上面进行opengl修改,加入新的 ...

  2. day122&colon;MoFang&colon;OSSRS流媒体直播服务器&amp&semi;基于APICloud的acLive直播推流模块实现RTMP直播推流

    目录 1.docker安装OSSRS流媒体直播服务器 2.基于APICloud的acLive直播推流模块实现RTMP直播推流 3.直播流管理 1.docker安装OSSRS流媒体直播服务器 1.OSS ...

  3. Android流媒体开发之路二&colon;NDK开发Android端RTMP直播推流程序

    NDK开发Android端RTMP直播推流程序 经过一番折腾,成功把RTMP直播推流代码,通过NDK交叉编译的方式,移植到了Android下,从而实现了Android端采集摄像头和麦克缝数据,然后进行 ...

  4. jQuery 人脸识别插件,支持图片和视频

    jQuery Face Detection 是一款人脸检测插件,能够检测到图片,视频和画布中的人脸坐标.它跟踪人脸并输出人脸模型的坐标位置为一个数组.我们相信,面部识别技术能够给我们的 Web 应用带 ...

  5. EasyRTMP&plus;EasyRTSPClient实现的多路&lpar;支持断线重连&rpar;RTSP转RTMP直播推流工具

    本文转自EasyDarwin开源团队成员Kim的博客:http://blog.csdn.net/jinlong0603/article/details/73441405 介绍 EasyRTMP是Eas ...

  6. 不用任何第三方&comma;写一个RTMP直播推流器

    2016年是移动直播爆发年,不到半年的时间内无数移动直播App掀起了全民直播的热潮.然而个人觉得直播的门槛相对较高,从推流端到服务端器到播放端,无不需要专业的技术来支撑,仅仅推流端就有不少需要学习的知 ...

  7. Python人脸识别最佳教材典范,40行代码搭建人脸识别系统!

    Face Id是一款高端的人脸解锁软件,官方称:"在一百万张脸中识别出你的脸."百度.谷歌.腾讯等各大企业都花费数亿来鞭策人工智能的崛起,而实际的人脸识别技术是否有那么神奇? 绿帽 ...

  8. 简单机器学习人脸识别工具face-recognition python小试,一行代码实现人脸识别

    摘要: 1行代码实现人脸识别,1. 首先你需要提供一个文件夹,里面是所有你希望系统认识的人的图片.其中每个人一张图片,图片以人的名字命名.2. 接下来,你需要准备另一个文件夹,里面是你要识别的图片.3 ...

  9. EasyRTMP结合海康HCNetSDK获取海康摄像机H&period;264实时流并转化成为RTMP直播推流(附源码)

    最近一家深耕于南方电网的科技公司同事找到我们,咨询关于调用海康HCNetSDK取流,并进行互联网转化的方案,经过反复的沟通以及自身在EasyDSS和EasyNVR方面的经验,我们推荐了海康HCNetS ...

随机推荐

  1. mybatis- spring 批量实现数据导入数据库

    终于实现了ibatis的批量插入,此方法插入3000条数据,比单条插入可以节省一半的时间XML代码: <insert id="insertBatch" parameterTy ...

  2. Foundation框架

    1.框架是由许多类.方法.函数.文档按照一定的逻辑组织起来的集合,以便使研发程序变的更容易 清除缓存,删除这个文件夹下的所有文件/Users/fanyafang/Library/Developer/X ...

  3. &period;NET并行编程 - 并行方式

    使用多线程可以利用多核CPU的计算能力,可以提供更好的程序响应能力,但是每个线程都有开销,需要注意控制线程的数量. 1. System.Threading.Thread 使用多线程最直接的是使用Sys ...

  4. python 序列化之JSON和pickle详解

    JSON模块 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.它基于ECMAScript的一个子集. JSON采用完全独立于语言的文本格式,但是也使用了类 ...

  5. 在Windows下开发Node&period;js的C&sol;C&plus;&plus;原生扩展

    准备工作 (1)本机系统说明:本人机器为win7 64位,32位也可以. (2)软件安装: VISUAL C++ 2010 EXPRESS(Visual Studio 2010也可以): window ...

  6. &period;NET MVC与三层架构

    虽然接触了两者有一段时间了,但是有时还是会混淆概念,在此处不打算说明二者的区别,因为二者都是架构模式,并且也有一定的共存度,在实际开发中,严格区分意义不大.基于最近涉及到这部分知识就在复习下,编程过程 ...

  7. 【CQOI2017】小Q的表格

    [CQOI2017]小Q的表格 稍加推导就会发现\(f(a,b)=a\cdot b\cdot h(gcd(a,b))\). 初始时\(h(n)=1\). 询问前\(k\)行\(k\)列时我们就反演: ...

  8. Golang字符串格式化

    Go对字符串格式化提供了良好的支持.下面我们看些常用的字符串格式化的例子. package main import ( "fmt" "os" ) type po ...

  9. canal 入门(基于docker)

    第一步:安装MySQL:(可以参考:https://my.oschina.net/amhuman/blog/1941540) 命令: sudo docker run -it -d --restart ...

  10. vue set

    Vue 可以通过数组变异的方法可以控制数组的增减,却不能更改数组及对象,vue可以通过set方法改变数组的长度,改变某项的值,在组件中可以使用$set方法改变数组长度和某项的值 调用方法:Vue.se ...