<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      基于C#的機(jī)器學(xué)習(xí)--面部和動(dòng)態(tài)檢測(cè)-圖像過濾器

      在本章中,我們將展示兩個(gè)獨(dú)立的例子,一個(gè)用于人臉檢測(cè),另一個(gè)用于動(dòng)態(tài)檢測(cè),以及如何快速地將這些功能添加到應(yīng)用程序中。

             在這一章中,我們將討論:

      1. 面部檢測(cè)
      2. 動(dòng)態(tài)檢測(cè)
      3. 將檢測(cè)添加到應(yīng)用程序中

      面部檢測(cè)

             人臉檢測(cè),是人臉識(shí)別的第一部分。如果你不能從屏幕上的所有東西中識(shí)別出一個(gè)或多個(gè)人臉,那么你將永遠(yuǎn)無(wú)法識(shí)別那是誰(shuí)的臉。

             首先讓我們看一張我們的應(yīng)用程序截圖:

       

       

             上圖中,通過攝像頭我們已經(jīng)捕獲到一張圖像,接下來(lái)啟用面部跟蹤,看看會(huì)發(fā)生什么:

       

       

             物體面部特征正在被追蹤。我們?cè)谖矬w周圍看到的是面部追蹤器(白色線框),它告訴我們我們這里有一張臉;以及我們的角度探測(cè)器(紅線),它提供了一些關(guān)于我們臉?biāo)幩椒较虻膮⒖肌?/p>

             當(dāng)我們移動(dòng)物體時(shí),面部追蹤器和角度探測(cè)器會(huì)追蹤他。這一切都很好,但是如果我們?cè)谡鎸?shí)的人臉上啟用面部跟蹤會(huì)發(fā)生什么呢?

      如下圖,面部追蹤器和角度探測(cè)器正在追蹤人的面部。

       

       

             當(dāng)我們把頭從一邊移到另一邊時(shí),面部追蹤器會(huì)跟蹤這個(gè)動(dòng)作,可以看到角度探測(cè)器會(huì)根據(jù)它所識(shí)別的面部水平角度進(jìn)行調(diào)整。

      可以看到,在這里我們的顏色是黑白的,而不是彩色的。因?yàn)檫@是一個(gè)直方圖的反向投影,而且它是一個(gè)可以更改的選項(xiàng)。

       

       

      即使我們遠(yuǎn)離攝像機(jī),讓其他物體也進(jìn)入視野中,面部追蹤器也能在諸多噪音中跟蹤我們的臉,如下圖所示。這正是我們?cè)陔娪爸锌吹降拿娌孔R(shí)別系統(tǒng)的工作原理,盡管它更為先進(jìn)。

       

       

      現(xiàn)在讓我們深入程序內(nèi)部,看看它到底是如何工作的。

      首先,我們需要問自己一個(gè)問題,我們想要解決的問題到底是什么。到底是人臉識(shí)別還是人臉檢測(cè)。這里不得不提到Viola-Jones算法,因?yàn)椋紫人泻芨叩臋z出率和很低的誤報(bào)率,然后它非常擅長(zhǎng)對(duì)數(shù)據(jù)的實(shí)時(shí)處理,最終要的一點(diǎn)是,它非常善于從非人臉中分別出人臉。

      要永遠(yuǎn)記住,人臉檢測(cè)只是人臉識(shí)別的第一步!

      這個(gè)算法要求輸入一個(gè)完整的正面,垂直的臉。臉部需要直接指向采集設(shè)備,頭部盡量不要歪,不要昂頭或低頭。

      這里有必要在強(qiáng)調(diào)一次,我們要做的只是在圖像中檢測(cè)出人臉即可。

      我們的算法需要經(jīng)過四個(gè)步驟來(lái)完成這件事:

      1. Haar 特征選擇
      2. 創(chuàng)建一個(gè)完整的圖像
      3. AdaBoost算法(通過迭代弱分類器而產(chǎn)生最終的強(qiáng)分類器的算法) 訓(xùn)練分類器
      4. 級(jí)聯(lián)分類器

      在正式開始之前,讓我們先捋一捋面部檢測(cè)到底是如果工作的。所有的臉,無(wú)論是人的,動(dòng)物的還是其他的,都有一些相似的特征。例如,都有一個(gè)鼻子,兩個(gè)鼻孔,一張嘴巴,兩個(gè)眼睛,兩個(gè)耳朵等等。我們的算法通過Haar特征來(lái)匹配這些內(nèi)容,我們可以通過其中任一項(xiàng)找到其他的特征。

             但是,我們這里會(huì)遇到一個(gè)問題。在一個(gè)24x24像素的窗口中,一共有162336個(gè)可能的特征。如果這個(gè)計(jì)算結(jié)果是正確的,那么計(jì)算他們的時(shí)間和成本將非常之高。因此,我們將會(huì)使用一種被稱為adaptive boosting(自適應(yīng)提升法)的算法,或者更為常見的AdaBoost算法。如果你研究過機(jī)器學(xué)習(xí),我相信你聽說(shuō)過一種叫做boosting(提升)的技術(shù)。我們的學(xué)習(xí)算法將使用AdaBoost來(lái)選擇最好的特征并訓(xùn)練分類器來(lái)使用它們。

             AdaBoost可以與許多類型的學(xué)習(xí)算法一起使用,并且被業(yè)界認(rèn)為是許多需要增強(qiáng)的任務(wù)的最佳開箱即用算法。通常在切換到另一種算法并對(duì)其進(jìn)行基準(zhǔn)測(cè)試之前,您不會(huì)注意到它有多好和多快。實(shí)際上這種區(qū)別是非常明顯的。

             在繼續(xù)之前,我們先來(lái)了解一下什么是boosting(提升)技術(shù)。

      Boosting從其他弱學(xué)習(xí)算法中獲取輸出,并將其與weighted sum(加權(quán)和)結(jié)合,加權(quán)和是boost分類器的最終輸出。AdaBoost的自適應(yīng)部分來(lái)自于這樣一個(gè)事實(shí),即后續(xù)的學(xué)習(xí)者被調(diào)整,以支持那些被以前的分類器錯(cuò)誤分類的實(shí)例。

             與其他算法相比,該算法更傾向于對(duì)數(shù)據(jù)進(jìn)行過擬合,所以AdaBoost對(duì)噪聲數(shù)據(jù)和異常值很敏感。因此我們?cè)跍?zhǔn)備數(shù)據(jù)的時(shí)候,需要格外注意這一點(diǎn)。

             現(xiàn)在,讓我們來(lái)看看示例中的程序到底是如何工作的。對(duì)于這個(gè)示例,我們將再次使用Accord框架。

             首先創(chuàng)建一個(gè)FaceHaarCascade對(duì)象。該對(duì)象包含一系列 Haarlike 的特征的弱分類階段的集合。每個(gè)階段都包含一組分類器樹, 這些分類器樹將在決策過程中使用。FaceHaarCascade自動(dòng)為我們創(chuàng)建了所有這些階段和樹,而不需要我們?nèi)リP(guān)心具體實(shí)現(xiàn)的細(xì)節(jié)。

             首先,需要在底層構(gòu)建一個(gè)決策樹,它將為每個(gè)階段提供節(jié)點(diǎn),并為每個(gè)特性提供數(shù)值。以下是Accord的部分源碼。

      List<HaarCascadeStage> stages = new List<HaarCascadeStage>();
      List<HaarFeatureNode[]> nodes;
      HaarCascadeStage stage;
      stage = new HaarCascadeStage(0.822689414024353);
      nodes = new List<HaarFeatureNode[]>();
      nodes.Add(
          new[] {
              new HaarFeatureNode(
                  0.004014195874333382,0.0337941907346249, 
                  0.8378106951713562,
                  new int[] { 3, 7, 14, 4, -1 },
                  new int[] { 3, 9, 14, 2, 2 }
              ) 
          }
      );
      nodes.Add(
          new[] { 
              new HaarFeatureNode(
                  0.0151513395830989,
                  0.1514132022857666,
                  0.7488812208175659,
                  new int[] { 1, 2, 18, 4, -1 },
                  new int[] { 7, 2, 6, 4, 3 }
              ) 
          }
      );
      nodes.Add(
          new[] { 
              new HaarFeatureNode(
                  0.004210993181914091,
                  0.0900492817163467, 
                  0.6374819874763489,
                  new int[] { 1, 7, 15, 9, -1 },
                  new int[] { 1, 10, 15, 3, 3 }
              )
          }
      );

      一旦構(gòu)建完成,我們就可以使用cascade對(duì)象來(lái)創(chuàng)建HaarObjectDetector,這就是我們將用于檢測(cè)的對(duì)象。

      接下來(lái)我們需要提供:

      1. 我們的面部級(jí)聯(lián)對(duì)象
      2. 搜索對(duì)象時(shí)使用的最小窗口大小
      3. 我們的搜索模式,假設(shè)我們只搜索一個(gè)對(duì)象
      4. 在搜索期間重新縮放搜索窗口時(shí)要使用的重新縮放因子
      HaarCascade cascade = new FaceHaarCascade();
      detector = new HaarObjectDetector(
        cascade,
        25,   ObjectDetectorSearchMode.Single,
        1.2f,   ObjectDetectorScalingMode.GreaterToSmaller
      );

      現(xiàn)在,我們需要準(zhǔn)備數(shù)據(jù),在本示例中,我們將使用筆記本電腦上的攝像頭捕獲所有圖像。然而,Accord.NET framework 使得使用其他源進(jìn)行數(shù)據(jù)采集變得很容易。例如 avi文件,jpg文件等等。

      接下來(lái),連接攝像頭,選擇分辨率:

      // 創(chuàng)建視頻源
      VideoCaptureDevice videoSource = new VideoCaptureDevice(form.VideoDevice);
      // 設(shè)置幀的大小
      videoSource.VideoResolution = selectResolution(videoSource);
      
      /// <summary>
      /// 獲取幀的大小
      /// </summary>
      /// <param name="videoSource">視頻源</param>
      /// <returns>幀的大小</returns>
      private VideoCapabilities selectResolution(VideoCaptureDevice videoSource)
      {
              foreach (var cap in videoSource?.VideoCapabilities)
              {
                  if (cap.FrameSize.Height == 240)
                          return cap;
                  if (cap.FrameSize.Width == 320)
                          return cap;
              }
               return videoSource?.VideoCapabilities.Last();
      } 

       

      在這個(gè)演示中,你會(huì)注意到檢測(cè)物體正對(duì)著攝像機(jī),在背景中,還有一些其他的東西,那就是所謂的隨機(jī)噪聲。這樣做是為了展示人臉檢測(cè)算法是如何區(qū)分出臉的。如果我們的探測(cè)器不能處理這些,它就會(huì)在噪聲中消失,從而無(wú)法檢測(cè)到臉。

      隨著視頻源的加入,我們需要在接收到新的視頻幀時(shí)得到通知,以便處理它、應(yīng)用標(biāo)記,等等。我們通過頻源播放器的NewFrameReceived事件來(lái)實(shí)現(xiàn)這一點(diǎn)。\

      在我們已經(jīng)有了一個(gè)視頻源和一個(gè)視頻,讓我們看看每當(dāng)我們被通知有一個(gè)新的視頻幀可用時(shí)發(fā)生了什么。

      我們需要做的第一件事是對(duì)圖像進(jìn)行采樣,以使它更容易工作:

      ResizeNearestNeighbor resize = new ResizeNearestNeighbor(160, 120);
      
      UnmanagedImage downsample = resize.Apply(im);

      如果我們沒有找到一張臉,我們將保持跟蹤模式,等待一個(gè)具有可檢測(cè)面部的幀。一旦我們找到了面部區(qū)域,我們需要重置跟蹤器,定位臉部,減小它的大小,以盡可能的剔除背景噪聲,然后初始化跟蹤器,并將在圖像上進(jìn)行標(biāo)記。代碼如下:

      Rectangle[] regions = detector?.ProcessFrame(downsample);
      if (regions != null && regions.Length > 0)
      {
           tracker?.Reset();
          // 跟蹤第一張臉
          Rectangle face = regions[0];
          // 減小人臉檢測(cè)的大小,避免跟蹤背景上的其他內(nèi)容
          Rectangle window = new Rectangle(
            (int)((regions[0].X + regions[0].Width / 2f) * xscale),
            (int)((regions[0].Y + regions[0].Height / 2f) * yscale),
            1,
            1
        ); window.Inflate((int)(0.2f * regions[0].Width * xscale), (int)(0.4f * regions[0].Height * yscale)); if (tracker != null) { tracker.SearchWindow = window; tracker.ProcessFrame(im); } marker = new RectanglesMarker(window); marker.ApplyInPlace(im); eventArgs.Frame = im.ToManagedImage(); tracking = true; } else { detecting = true; }

      一旦檢測(cè)到臉,我們的圖像幀是這樣的:

       

       

      如果把頭偏向一邊,我們現(xiàn)在的形象應(yīng)該是這樣的:

       

       

      動(dòng)態(tài)檢測(cè)

      可以看到,在上一個(gè)例子中,我們不僅實(shí)現(xiàn)了面部檢測(cè),還實(shí)現(xiàn)了動(dòng)態(tài)檢測(cè)。現(xiàn)在,讓我們把目光轉(zhuǎn)向更大的范圍,檢測(cè)任何物體的運(yùn)動(dòng),而不僅僅是面部。我們將繼續(xù)使用Accord.NET來(lái)實(shí)現(xiàn)。

      在動(dòng)態(tài)檢測(cè)中,我們會(huì)用紅色高亮顯示屏幕上的任何運(yùn)動(dòng)。移動(dòng)的數(shù)量由任何一個(gè)區(qū)域的紅色濃度表示。所以,如下圖所示,我們可以看到手指在移動(dòng)但是其他的都是靜止的。

       

       

      如下圖所示,可以看到整個(gè)手的移動(dòng)范圍在增加。

       

       

      如下圖所示,一旦整只手開始移動(dòng),你不僅可以看到更多的紅色,而且紅色的總量是在增加的:

       

       

      如果不希望對(duì)整個(gè)屏幕區(qū)域進(jìn)行運(yùn)動(dòng)處理,可以自定義運(yùn)動(dòng)區(qū)域;運(yùn)動(dòng)檢測(cè)只會(huì)發(fā)生在這些區(qū)域。如下圖,可以看到我們已經(jīng)定義了一個(gè)運(yùn)動(dòng)區(qū)域,這是唯一的一個(gè)區(qū)域。

       

       

      現(xiàn)在,如果我們?cè)跀z像頭前面做一些運(yùn)動(dòng),可以看到程序只檢測(cè)到了來(lái)自我們定義區(qū)域發(fā)生的運(yùn)動(dòng)。

       

       

      現(xiàn)在,我們來(lái)做這樣一個(gè)測(cè)試,在我們自定義的檢測(cè)區(qū)域范圍內(nèi),放置一個(gè)物體,然后我們把手放在這個(gè)物體后面進(jìn)行運(yùn)動(dòng),當(dāng)然手也是在這個(gè)自定義的檢測(cè)區(qū)域范圍內(nèi)進(jìn)行運(yùn)動(dòng)的。如下圖,可以看到,手的運(yùn)動(dòng)被檢測(cè)出來(lái)了。

       

       

      現(xiàn)在我們使用另一個(gè)選項(xiàng),網(wǎng)格運(yùn)動(dòng)突出顯示。它會(huì)使得檢測(cè)到的運(yùn)動(dòng)區(qū)域基于定義的網(wǎng)格在紅色方塊中突出顯示,如下圖所示。

       

       

      將檢測(cè)添加到應(yīng)用程序中

      以下是處理接收到新的幀的代碼:       

       private void videoSourcePlayer_NewFrame(object sender, NewFrameEventArgs args)
       {
        lock (this)   {     if (motionDetector != null)     {       float motionLevel = motionDetector.ProcessFrame(args.Frame);       if (motionLevel > motionAlarmLevel)       {         //快門速度2秒         flash = (int)(2 * (1000 / timer.Interval));       }       //檢查對(duì)象的數(shù)       if (motionDetector.MotionProcessingAlgorithm is BlobCountingObjectsProcessing)       {         BlobCountingObjectsProcessing countingDetector = (BlobCountingObjectsProcessing)motionDetector.MotionProcessingAlgorithm;         detectedObjectsCount = countingDetector.ObjectsCount;       }       else       {         detectedObjectsCount = -1;       }       // 積累的歷史       motionHistory.Add(motionLevel);       if (motionHistory.Count > 300)       {         motionHistory.RemoveAt(0);       }       if (顯示運(yùn)動(dòng)歷史ToolStripMenuItem.Checked)       DrawMotionHistory(args.Frame);
          }
        }
      }

      這里的關(guān)鍵是檢測(cè)視頻幀中發(fā)生的動(dòng)量,這是通過以下代碼完成的。對(duì)于本例,我們使用的是兩級(jí)的運(yùn)動(dòng)報(bào)警級(jí)別,但是你也可以使用任何你喜歡的級(jí)別定義。一旦超過這個(gè)閾值,就可以實(shí)現(xiàn)所需的邏輯,例如發(fā)送電子郵件、開始視頻捕獲等等。

      float motionLevel = motionDetector.ProcessFrame(args.Frame);
      if (motionLevel > motionAlarmLevel)
      {
        //快門速度2秒
        flash = (int)(2 * (1000 / timer.Interval));
      } 

      總結(jié)

             在這一章中,我們學(xué)習(xí)了面部和動(dòng)態(tài)檢測(cè),還展示了一些簡(jiǎn)單易用的代碼。我們可以輕松的將這些功能添加到自己的程序中。

      posted @ 2019-02-16 10:22  王振耀  閱讀(4558)  評(píng)論(5)    收藏  舉報(bào)
      主站蜘蛛池模板: 一区二区三区国产亚洲网站| 一亚洲一区二区中文字幕| 久久久久久久久久久久中文字幕| 91精品国产免费人成网站| 熟妇人妻av无码一区二区三区| 国产精品日韩av一区二区| 中文字幕日韩有码av| 久青草国产在视频在线观看 | 亚洲中文字幕无码中字| 国产色a在线观看| 亚洲AV成人一区国产精品| 亚洲天堂一区二区三区四区 | 国产一区二区三区综合视频| 久久综合激情网| 国产精品SM捆绑调教视频| 男女猛烈无遮挡免费视频APP| 77777亚洲午夜久久多人| 欧美亚洲国产成人一区二区三区| 国产精品日韩中文字幕| 天天做天天爱夜夜爽| 国产亚洲另类无码专区| 亚洲欧美日韩在线码| 亚洲日韩精品无码av海量| 亚洲精品免费一二三区| 少妇人妻av毛片在线看| 午夜精品久久久久久久久| 欧美亚洲另类制服卡通动漫| 51妺嘿嘿午夜福利| 91亚洲精品一区二区三区| 中文字幕在线精品国产| 成人无码视频在线观看免费播放| 美女一区二区三区在线观看视频| 日韩精品亚洲专在线电影| 人妻人人澡人人添人人爽| 色综合天天综合网国产人| 国产玩具酱一区二区三区| 人妻系列无码专区69影院| 高清免费毛片| 国产在线视频精品视频| 天堂va欧美ⅴa亚洲va在线| 免费无码一区无码东京热|