基于虹软人脸识别,实现RTMP直播推流追踪视频中所有人脸信息(C#)
大家應(yīng)該都知道幾個(gè)很常見的例子,比如在張學(xué)友的演唱會(huì),在安檢通道檢票時(shí),通過人像識(shí)別系統(tǒng)成功識(shí)別捉了好多在逃人員,被稱為逃犯克星;人行橫道不遵守交通規(guī)則闖紅燈的路人被人臉識(shí)別系統(tǒng)抓拍放在大屏上以示警告;參加某次活動(dòng)通過人臉進(jìn)行簽到來統(tǒng)計(jì)實(shí)時(shí)人流量等等, 我現(xiàn)在也來做一個(gè)通過電視直播,追蹤畫面中所有人臉信息,并捕獲我需要的目標(biāo)人物。
具體思路及流程
基于虹軟人臉識(shí)別,對(duì)直播畫面中的每一幀圖片進(jìn)行檢測(cè),得到圖片中所有人臉信息。可以添加目標(biāo)人物的照片,用目標(biāo)人物的人臉特征值與直播畫面幀圖片中人臉信息列表中的每一個(gè)特征值進(jìn)行比對(duì)。如果有匹配到目標(biāo)人物,把直播畫面抓拍。具體流程如下:
項(xiàng)目結(jié)構(gòu)
播放地址我們可以在網(wǎng)上搜索一下電視直播RTMP地址,在程序中可進(jìn)行播放
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類對(duì)視頻進(jìn)行讀取操作,然后把圖像渲染到PictureBox控件上。在PictureBox的Paint事件中進(jìn)行人臉識(shí)別與比對(duì)操作。
/// <summary> /// 比對(duì)函數(shù),將每一幀抓拍的照片和目標(biāo)人物照片進(jìn)行比對(duì) /// </summary> /// <param name="bitmap"></param> /// <param name="e"></param> /// <returns></returns> private void CompareImgWithIDImg(Bitmap bitmap, PaintEventArgs e) {if (bitmap != null){//保證只檢測(cè)一幀,防止頁面卡頓以及出現(xiàn)其他內(nèi)存被占用情況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);//根據(jù)Bitmap 獲取人臉信息列表List<FaceInfoModel> list = FaceUtil.GetFaceInfos(pImageEngine, bitmap);foreach (FaceInfoModel sface in list){//異步處理提取特征值和比對(duì),不然頁面會(huì)比較卡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;//根據(jù)Rect進(jìn)行畫框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 人臉信息實(shí)體類,把人臉信息放在此類中。
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; } }多人臉實(shí)體類存放單人臉信息列表
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>/// 指針轉(zhuǎn)多人臉列表/// </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>();//檢測(cè)人臉,得到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;} }從列表中獲取到的多張人臉,在人臉上畫框作出標(biāo)識(shí),也可以把提取的人臉信息,年齡、性別作出展示。接下來就是選擇一張目標(biāo)人物的照片,通過SDK提取目標(biāo)人物的人臉特征值作為比較對(duì)象,逐一與視頻中的人臉特征進(jìn)行比較。如果有判斷到相似度匹配的人臉,則把視頻幀圖像呈現(xiàn)出來。
/// <summary> /// 比較兩個(gè)特征值的相似度,返回相似度 /// </summary> /// <param name="feature1"></param> /// <param name="feature2"></param> /// <returns></returns> private float CompareTwoFeatures(IntPtr feature1, IntPtr feature2) {float similarity = 0.0f;//調(diào)用人臉匹配方法,進(jìn)行匹配ASFFunctions.ASFFaceFeatureCompare(pImageEngine, feature1, feature2, ref similarity);return similarity; }之前只實(shí)現(xiàn)了從多張人臉中獲取一張最大尺寸的人臉作為比較對(duì)象,這樣視頻中也就只能對(duì)一張人臉進(jìn)行畫框標(biāo)記了,現(xiàn)在是把所有提取到的人臉均進(jìn)行標(biāo)記,并把各自特征值存在列表中,以便與目標(biāo)人臉特征值進(jìn)行匹配。
這樣也就粗略的實(shí)現(xiàn)了人臉識(shí)別追蹤,并對(duì)目標(biāo)人物進(jìn)行抓拍的功能了。
GitHub源碼已上傳:https://github.com/yumaster/FaceTracking
總結(jié)
以上是生活随笔為你收集整理的基于虹软人脸识别,实现RTMP直播推流追踪视频中所有人脸信息(C#)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 技术分享|集成开放平台使用Consul
- 下一篇: 通过Dapr实现一个简单的基于.net的