2017-02-10 1 views
1

Я изучаю API Microsoft Cognitive Face, и я очень к этому знаком. Я могу получить Face Attributes с изображением, которое легко, но, на мой вопрос, как я могу получить Face Attributes человека в режиме видео в реальном времени от Kinect в WPF C#. Было бы здорово, если кто-нибудь сможет мне помочь. Заранее спасибо!Microsoft Cognitive Face API - как я могу получить атрибуты лица в видеопотоке от Kinect?

Я попытался захватить кадр из цветовой ленты Kinect каждые 2 секунды в какое-то местоположение файла и использовать этот путь к файлу и преобразовать его в поток, а затем передать его функциям Face-API и работать. Ниже приведен код, который я пробовал.

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]; 
      } 
     } 
} 

Над кодом работал хорошо. Но я хочу преобразовать каждый кадр Kinect Color Feed непосредственно в Stream, и я не знаю, как это сделать, хотя я искал, но ничего не работало для меня. Если кто-то может мне помочь, тогда это будет здорово. Благодаря!

+0

Добро пожаловать в Stack Overflow! Как бы то ни было, ваш вопрос довольно широк. Я предлагаю добавить код, показывающий, что вы пробовали до сих пор. Вы можете отредактировать это в своем вопросе. Удачи! –

+0

Hi S.L.Barth Я попытался захватить кадр из корня цвета kinect каждые 2 секунды в какое-то местоположение файла и использовать этот путь к файлу, чтобы преобразовать его в поток, а затем передать его функциям Face-API, и это сработало. Ниже приведен код, который я попробовал. –

+0

Используйте функцию редактирования, чтобы изменить ее в своем вопросе. Вы можете использовать эту ссылку: [править] или ссылку «изменить» непосредственно под своим вопросом. При показе кода вы можете использовать кнопку «{}» в редакторе, чтобы отформатировать ее как код. –

ответ

1

Вместо сохраняющегося кадр в файл в SaveImage, вы можете сохраняться его к MemoryStream, перемотать его (по телефону Position = 0), и направить этот поток в DetectAsync().

Также отметим, что в UploadAndDetectFaces, вы должны отправить imageFileStream, не imageFilePath, к DetectAsync(). Вы, вероятно, не хотите звонить и UploadAndDetectFaces, и UploadAndDetectFaceAttributes в любом случае, так как вы просто удваиваете свою работу (и квоты/лимит ставок).

+0

Привет, я попытался использовать 'MemoryStream', хотя он не дает никаких ошибок, но он тоже не работает. Я нашел эти проблемы: «Емкость:« printStream.Capacity »выбрасывает исключение типа« System.ObjectDisposedException »' 'Length: 'printStream.Length' выбрасывает исключение типа 'System.ObjectDisposedException''' Position:' printStream.Position 'выбрал исключение типа' System.ObjectDisposedException'' –

+0

'private Stream StreamFromBitmapSource (BitmapSource writeBmp) {Stream bmp; using (bmp = new MemoryStream()) {BitmapEncoder enc = new BmpBitmapEncoder(); enc.Frames.Add (BitmapFrame.Create (writeBmp)); enc.Save (BMP); bmp.Position = 0; } return bmp; } 'Это часть кода, которую я пробовал. –

+0

Поток будет удален в конце вашего 'использования'. Вам нужно сохранить его до тех пор, пока запрос на обслуживание не завершится. Самое простое - отказаться от использования и позже вызвать 'stream.Dispose'. – cthrash

Смежные вопросы