2017-02-10 1 views
1

Ich erkunde Microsoft Cognitive Face API und ich bin sehr neu dazu. Ich kann Gesichtsattribute mit einem einfachen Bild erzielen, aber meine Frage ist, wie ich Gesichtsattribute einer Person in einem Echtzeit-Videofeed von Kinect in WPF C# erhalten kann. Es wäre toll, wenn mir jemand helfen könnte. Danke im Voraus!Microsoft Cognitive Face API - Wie kann ich Gesichtsattribute im Video-Feed von Kinect erhalten?

Ich habe versucht, den Rahmen aus dem Kinect-Farbfeed alle 2 Sekunden zu einem Dateispeicherort zu erfassen und diesen Dateipfad zu verwenden und ihn in einen Stream zu konvertieren und dann an die Face-API-Funktionen weiterzugeben, und das hat funktioniert. Folgendes ist der Code, den ich ausprobiert habe.

namespace CognitiveFaceAPISample 
{ 

    public partial class MainWindow : Window 
    { 
     private readonly IFaceServiceClient faceServiceClient = new FaceServiceClient("c2446f84b1eb486ca11e2f5d6e670878"); 
     KinectSensor ks; 
     ColorFrameReader cfr; 
     byte[] colorData; 
     ColorImageFormat format; 
     WriteableBitmap wbmp; 
     BitmapSource bmpSource; 
     int imageSerial; 
     DispatcherTimer timer,timer2; 
     string streamF = "Frames//frame.jpg"; 

     public MainWindow() 
     { 
      InitializeComponent(); 
      ks = KinectSensor.GetDefault(); 
      ks.Open(); 
      var fd = ks.ColorFrameSource.CreateFrameDescription(ColorImageFormat.Bgra); 
      uint frameSize = fd.BytesPerPixel * fd.LengthInPixels; 
      colorData = new byte[frameSize]; 
      format = ColorImageFormat.Bgra; 
      imageSerial = 0; 

      cfr = ks.ColorFrameSource.OpenReader(); 
      cfr.FrameArrived += cfr_FrameArrived; 
     } 

     void cfr_FrameArrived(object sender, ColorFrameArrivedEventArgs e) 
     { 
      if (e.FrameReference == null) return; 

      using (ColorFrame cf = e.FrameReference.AcquireFrame()) 
      { 
       if (cf == null) return; 
       cf.CopyConvertedFrameDataToArray(colorData, format); 
       var fd = cf.FrameDescription; 

       // Creating BitmapSource 
       var bytesPerPixel = (PixelFormats.Bgr32.BitsPerPixel)/8; 
       var stride = bytesPerPixel * cf.FrameDescription.Width; 

       bmpSource = BitmapSource.Create(fd.Width, fd.Height, 96.0, 96.0, PixelFormats.Bgr32, null, colorData, stride); 

       // WritableBitmap to show on UI 
       wbmp = new WriteableBitmap(bmpSource); 
       FacePhoto.Source = wbmp;   

      } 
     } 

     private void SaveImage(BitmapSource image) 
     { 
      try 
      { 
       FileStream stream = new System.IO.FileStream(@"Frames\frame.jpg", System.IO.FileMode.OpenOrCreate); 
       JpegBitmapEncoder encoder = new JpegBitmapEncoder(); 
       encoder.FlipHorizontal = true; 
       encoder.FlipVertical = false; 
       encoder.QualityLevel = 30; 
       encoder.Frames.Add(BitmapFrame.Create(image)); 
       encoder.Save(stream); 
       stream.Close(); 
      } 
      catch (Exception) 
      { 

      } 
     }  


     private void Window_Loaded(object sender, RoutedEventArgs e) 
     { 
      timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(2) }; 
      timer.Tick += Timer_Tick; 
      timer.Start(); 
      timer2 = new DispatcherTimer { Interval = TimeSpan.FromSeconds(5) }; 
      timer2.Tick += Timer2_Tick; 
      timer2.Start(); 
     } 
     private void Timer_Tick(object sender, EventArgs e) 
     { 
      SaveImage(bmpSource); 
     } 
     private async void Timer2_Tick(object sender, EventArgs e) 
     { 
      Title = "Detecting..."; 
      FaceRectangle[] faceRects = await UploadAndDetectFaces(streamF); 
      Face[] faceAttributes = await UploadAndDetectFaceAttributes(streamF); 
      Title = String.Format("Detection Finished. {0} face(s) detected", faceRects.Length); 

      if (faceRects.Length > 0) 
      { 
       DrawingVisual visual = new DrawingVisual(); 
       DrawingContext drawingContext = visual.RenderOpen(); 
       drawingContext.DrawImage(bmpSource, 
        new Rect(0, 0, bmpSource.Width, bmpSource.Height)); 
       double dpi = bmpSource.DpiX; 
       double resizeFactor = 96/dpi; 

       foreach (var faceRect in faceRects) 
       { 
        drawingContext.DrawRectangle(
         Brushes.Transparent, 
         new Pen(Brushes.Red, 2), 
         new Rect(
          faceRect.Left * resizeFactor, 
          faceRect.Top * resizeFactor, 
          faceRect.Width * resizeFactor, 
          faceRect.Height * resizeFactor 
          ) 
        ); 
       } 

       drawingContext.Close(); 
       RenderTargetBitmap faceWithRectBitmap = new RenderTargetBitmap(
        (int)(bmpSource.PixelWidth * resizeFactor), 
        (int)(bmpSource.PixelHeight * resizeFactor), 
        96, 
        96, 
        PixelFormats.Pbgra32); 
       faceWithRectBitmap.Render(visual); 
       FacePhoto.Source = faceWithRectBitmap; 
      } 

      if (faceAttributes.Length > 0) 
      { 
       foreach (var faceAttr in faceAttributes) 
       { 
        Label lb = new Label(); 
        //Canvas.SetLeft(lb, lb.Width); 
        lb.Content = faceAttr.FaceAttributes.Gender;// + " " + faceAttr.Gender + " " + faceAttr.FacialHair + " " + faceAttr.Glasses + " " + faceAttr.HeadPose + " " + faceAttr.Smile; 
        lb.FontSize = 50; 
        lb.Width = 200; 
        lb.Height = 100; 
        stack.Children.Add(lb); 
       } 
      } 
     } 

     private async Task<FaceRectangle[]> UploadAndDetectFaces(string imageFilePath) 
     { 
      try 
      { 
       using (Stream imageFileStream = File.OpenRead(imageFilePath)) 
       { 
        var faces = await faceServiceClient.DetectAsync(imageFilePath); 
        var faceRects = faces.Select(face => face.FaceRectangle); 
        var faceAttrib = faces.Select(face => face.FaceAttributes); 
        return faceRects.ToArray(); 

       } 
      } 
      catch (Exception) 
      { 
       return new FaceRectangle[0]; 
      } 
     } 

     private async Task<Face[]> UploadAndDetectFaceAttributes(string imageFilePath) 
     { 
      try 
      { 
       using (Stream imageFileStream = File.Open(imageFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
       { 
        var faces = await faceServiceClient.DetectAsync(imageFileStream, true, true, new FaceAttributeType[] { FaceAttributeType.Gender, FaceAttributeType.Age, FaceAttributeType.Smile, FaceAttributeType.Glasses, FaceAttributeType.HeadPose, FaceAttributeType.FacialHair }); 

        return faces.ToArray(); 

       } 
      } 
      catch (Exception) 
      { 
       return new Face[0]; 
      } 
     } 
} 

Der obige Code hat gut funktioniert. Aber ich möchte jeden Frame von Kinect Color Feed direkt in Stream umwandeln und ich habe keine Ahnung, wie es geht, obwohl ich gesucht habe, aber nichts hat für mich funktioniert. Wenn jemand mir helfen kann, dann wird es großartig. Vielen Dank!

+0

Willkommen bei Stack Overflow! Wie es ist, ist Ihre Frage ziemlich breit. Ich schlage vor, einen Code hinzuzufügen, der zeigt, was Sie bisher versucht haben. Sie können dies in Ihre Frage ändern. Viel Glück! –

+0

Hi S.L.Barth Ich habe versucht, den Frame aus der Kinect-Farbzufuhr alle zwei Sekunden an einen Speicherort einzufangen und diesen Dateipfad zu verwenden, um ihn in einen Stream umzuwandeln und ihn dann an die Face-API-Funktionen weiterzugeben. Folgendes ist der Code, den ich ausprobiert habe. –

+0

Bitte benutzen Sie die "Bearbeiten" -Funktion, um sie in Ihre Frage zu bearbeiten. Sie können diesen Link verwenden: [Bearbeiten], oder den Link "Bearbeiten" direkt unter Ihrer Frage. Wenn Sie Code anzeigen, können Sie ihn im Editor mit der Schaltfläche "{}" als Code formatieren. –

Antwort

1

Statt den Rahmen in eine Datei in SaveImage persistierender, können Sie es zu einem MemoryStream, zurückspulen bestehen bleiben (durch Position = 0 Aufruf) und diesen Strom zu DetectAsync() senden.

Beachten Sie auch, dass in UploadAndDetectFaces Sie imageFileStream senden sollte, nicht imageFilePath, zu DetectAsync(). Sie möchten wahrscheinlich nicht beide UploadAndDetectFaces und UploadAndDetectFaceAttributes auf jeden Fall anrufen, da Sie nur Ihre Arbeit verdoppeln (und Quote/Rate-Limit-Hit.)

+0

Hallo, ich habe versucht, 'MemoryStream' zu verwenden, obwohl es keinen Fehler gibt, aber es hat auch nicht funktioniert. Ich habe folgende Probleme gefunden: 'Capacity:' printStream.Capacity 'hat eine Ausnahme vom Typ' System.ObjectDisposedException' ausgelöst. 'Length: 'printStream.Length' hat eine Ausnahme vom Typ 'System.ObjectDisposedException'' Position: 'printStream.Position ausgelöst 'hat eine Ausnahme vom Typ' System.ObjectDisposedException 'ausgelöst' –

+0

'private Stream StreamFromBitmapSource (BitmapSource writeBmp) {Stream bmp; using (bmp = new MemoryStream()) {BitmapEncoder enc = neu BmpBitmapEncoder(); enc.Frames.Add (BitmapFrame.Create (writeBmp)); enc.Save (bmp); bmp.Position = 0; } zurück bmp; } 'Das ist der Code, den ich ausprobiert habe. –

+0

Der Stream wird am Ende Ihrer 'using'-Anweisung angeordnet. Sie müssen es beibehalten, bis die Serviceanfrage beendet ist. Am einfachsten ist es, die Verwendung zu beenden und 'stream.Dispose' später aufzurufen. – cthrash

Verwandte Themen