效率有點低,你們看看哪裏開能夠節省時間?
源代碼:https://github.com/catzhou2002/ArcFaceDemo
整個項目使用虹軟技術完成開發java
說實話,爲了提升識別效率,我也是竭盡所能,幹了很多自認爲的優化,若有興趣聽我說說。git
第一部分 單線程時候的各類折騰github
1、折騰LPASVLOFFSCREEN
話說這個LPASVLOFFSCREEN的結果文檔裏面沒有說明,或者是我沒找到。
我也不知道從哪裏複製來的,主要折騰的是ppu8Plane[0]地址,通常操做是數組
一、鎖定圖片內存
二、ppu8Plane[0]分配製定長度的內存
三、把圖片內存中的字節複製到一個臨時數組
四、而後用Marshal.Copy複製到指定的地址
五、解鎖圖片內存
我改爲:
一、鎖定圖片內存
二、ppu8Plane[0]指向圖片地址
三、等不須要LPASVLOFFSCREEN時(人臉檢測、獲取特徵值、性別判斷、年齡估算等結束後)解鎖圖片內存微信
就晚一點解鎖,省了好多事情,耗時由4毫秒沒成2微妙。當時就發了個帖:C# Bitmap轉ASVLOFFSCREEN的最佳方式?多線程
後來以爲這名字實在記不住,也不C#,改爲了ImageData,整個轉換過程以下:編輯器
ar bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); var imageData = new ImageData { PixelArrayFormat = 513,//Rgb24, Width = bitmap.Width, Height = bitmap.Height, Pitch = new int[4] { bmpData.Stride, 0, 0, 0 }, ppu8Plane = new IntPtr[4] { bmpData.Scan0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero } }; bitmap.UnlockBits(bmpData);
其實若是是視頻圖片的話,圖片的寬度和高度都是固定的,想了想,沒折騰。ide
2、單線程時將獲取到的FaceModel直接作人臉比對的參數測試
ExtractFeature(_FaceMatchEngine, ref imageData, ref faceFeatureInput, out var <font color="#ff8c00">faceModel</font>); FacePairMatch(_FaceMatchEngine, ref fm, ref <font color="#ff8c00">faceModel</font>, out float score);
通常操做是faceModel裏面的字節複製到臨時字節數組,而後建立新的FaceModel,分配內存,在將臨時字節數組複製到FaceModel。優化
3、人臉庫直接用FaceModel
/// <summary> /// 人臉庫 /// </summary> public class FaceLib { public List<Item> Items { get; set; } = new List<Item>(); public class Item { /// <summary> /// 用於排序 /// </summary> public long OrderId { get; set; } /// <summary> /// 文件名做爲ID /// </summary> public string ID { get; set; } /// <summary> /// 人臉模型 /// </summary> <font color="#ff8c00"> public FaceModel FaceModel { get; set; }</font> } }
4、比對結果>0.5就算成功
5、人臉庫增長OrderId
識別成功後再次比對就很快,應該是首發命中。
6、將人臉比對和結果顯示分開
一開始沒想太多,將人臉比對和結果顯示放在新視頻幀事件裏面,流程是:
新視頻幀(30幀/秒)
獲取檢測和識別的結果(人臉框和ID)
顯示檢測和識別的結果
結果視頻卡頓,獲取人臉特徵的200毫秒成爲瓶頸,改爲:
人臉比對
Task.Factory.StartNew(() => { Task.Delay(1000).Wait(); while (!_CancellationTokenSource.IsCancellationRequested) { #region 200毫秒左右 MatchFrame(); #endregion } }, _CancellationTokenSource.Token);
結果顯示
private void VideoPlayer_Paint(object sender, PaintEventArgs e) { e.Graphics.DrawRectangle(Pens.White, _FaceResult.Rectangle); e.Graphics.DrawString(_FaceResult.ID , this.Font, Brushes.White, _FaceResult.Rectangle.Left, _FaceResult.Rectangle.Top - 20); }
測試了一下,效果還能夠,就在博客園發表了
C# 虹軟SDK視頻人臉識別和註冊
,還順手弄了個打賞二維碼。
發表完以爲這麼辛苦寫出來的文章,必須到首頁去亮個相,9天后終於學會發表到博客園首頁了,因而刪除了打賞二維碼,去首頁亮了個相。
話說首頁和非首頁效果着實不同,截圖爲證:
![在這裏插入圖片描述](http://ai.arcsoft.com.cn/bbs/data/attachment/forum/201805/11/002853k57rrlhsbh5bwhc1.png)
第二部分 多線程的折騰
1、肯定4線程爲最佳
各類測試後得出的結論,也不知道對不對,也不知道爲何,哎。
因網友的要求,同步到了github
2、刪除了單線程
有了更快的,就不要慢的了。
3、n張臉如何分配給4個線程獲取特徵值?
動了很多腦筋,Interlocked.Increment是關鍵。
最終有改了下面的內容
若是隻有一張臉(竊覺得一張臉的機率比較高),也用Task,影響效率,增長了 if (detectResult.FaceCount ==
1)
Intptr之間複製字節用CopyMemory比較快
兩三張臉的時候開4個線程很差,改爲 new Task[TaskNum < detectResult.FaceCount ?
TaskNum : detectResult.FaceCount]
4、識別結果(集)的折騰
弄了個結果集,按最大人臉數設了個List( Items = new List();)
增長了FaceFeatureInput FFI,省的每次都去建立
並將人臉方向設成1(Orient = 1)(由於是視頻圖片,其餘方向的人臉,呵呵),人臉檢測後都不要去獲取人臉方向的值
增長並初始化了FaceModel(FaceModel FaceModel = new FaceModel() { Size =
22020, PFeature = Marshal.AllocCoTaskMem(22020) };),獲取到的特徵字節直接複製過來即可
5、保存特徵值到人臉庫的時候同時保存頭像
由於虹軟說了,sdk升級的時候,特徵值也有可能變化。那咱先把頭像保存起來,到時候從新生成一下。
主要的操做是把矩形放大一點(Inflate((int)(r.Width * 0.5), (int)(r.Height * 0.5))),咱保存的頭像怎麼着得是我的頭吧。
(想來條分割線,竟然只有華麗的分割線,算了。順便吐槽一下,這個論壇的編輯器實在是讓人無語_)
各類折騰後,黔驢技窮了,10,000人臉的庫得出10張不認識的臉的結論,須要10秒鐘。固然,換好一點的電腦能夠提升效率,如個人臺式機(i5-7500),輸入圖片只有1張臉的時候,遍歷
1萬張人臉僅需390毫秒
5萬張人臉也就1525毫秒
10萬張人臉說我內存不夠,多是個人程序是32位的緣故,換成64位的sdk估計3秒鐘也能搞定(太麻煩,不折騰了)
結論是:虹軟中型sdk用於考勤、小區門禁、寫字樓門禁等場所徹底沒問題。
下一步我打算(其實已經差很少完成,我公司的項目——酒店自助機)改爲單臉多線程識別,增長如下功能:
40次檢測人臉數爲0,則確認爲沒人,識別頻率下降是否換人了?同一我的三、4次識別不出ID後,確認爲陌生人,不在遍歷刷身份證獲取照片人臉比對後存入人臉庫另外想跟企業微信結合開發開發門禁、CRM什麼的,有興趣的朋友一塊兒交流交流?