2017-02-10 7 views
1

저는 Microsoft Cognitive Face API를 탐색 중이며 매우 익숙합니다. 나는 쉬운 얼굴을 가진 얼굴 속성을 얻을 수 있지만, 제 질문은 WPF C#의 Kinect에서 실시간 비디오 피드로 사람의 얼굴 속성을 얻는 방법입니다. 누군가가 나를 도울 수 있으면 좋을 것입니다. 미리 감사드립니다.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의 각 프레임을 직접 스트림으로 변환하고 싶지만 검색 한 방법은 모르지만 나에게 도움이되는 것은 없습니다. 만약 누군가가 나를 도울 수 있다면 그것은 위대 할 것이다. 감사!

+0

Welcome to Stack Overflow! 그것이 그렇듯, 당신의 질문은 다소 광범위합니다. 지금까지 시도한 것을 보여주는 몇 가지 코드를 추가하는 것이 좋습니다. 이것을 당신의 질문에 편집 할 수 있습니다. 행운을 빕니다! –

+0

안녕하세요 S.L.Barth 나는 몇 가지 파일 위치에 매 2 초마다 kinect 컬러 피드에서 프레임을 캡처하고 그 파일 경로를 스트림으로 변환 한 다음 Face-API 함수에 전달하여 작동했습니다. 다음은 내가 시도한 코드입니다. –

+0

"편집"기능을 사용하여 질문을 편집하십시오. 이 링크는 [edit] 또는 질문 바로 아래에있는 "edit"링크를 사용할 수 있습니다. 코드를 표시 할 때 편집기의 "{}"버튼을 사용하여 코드로 형식을 지정할 수 있습니다. –

답변

1

대신 SaveImage에있는 파일에 프레임을 지속, 당신은 MemoryStream로 유지할 수 있습니다 (Position = 0를 호출하여)을 되감기 및 DetectAsync() 해당 스트림을 보낼 수 있습니다.

UploadAndDetectFaces에서 imageFilePath이 아닌 imageFileStreamDetectAsync()으로 보내야합니다. 작업 (및 할당량/속도 제한 히트)이 두 배가되기 때문에 어쨌든 UploadAndDetectFacesUploadAndDetectFaceAttributes을 모두 호출하고 싶지 않을 것입니다.

+0

안녕하세요, 어떤 오류도주지는 않지만'MemoryStream'을 사용해 보았지만 작동하지 않았습니다. 나는 다음과 같은 문제들을 발견했다 :'capacity : 'printStream.Capacity'는 'System.ObjectDisposedException'타입의 예외를 던졌다.'Length : 'printStream.Length'는 'System.ObjectDisposedException'타입의 예외를 던졌다.'Position : 'printStream.Position '예외'System.ObjectDisposedException' 던졌습니다 –

+0

'개인 스트림 StreamFromBitmapSource (BitmapSource writeBmp) {스트림 bmp; using (bmp = new MemoryStream()) {BitmapEncoder enc = 새 BmpBitmapEncoder(); enc.Frames.Add (BitmapFrame.Create (writeBmp)); enc.Save (bmp); bmp.Position = 0; } 반환 bmp; }'제가 시도한 코드입니다. –

+0

스트림은'using' 문장의 끝 부분에 처리됩니다. 서비스 요청이 완료 될 때까지 계속 유지해야합니다. 가장 쉬운 방법은 using을 삭제하고 나중에'stream.Dispose'를 호출하는 것입니다. – cthrash