【问题标题】:Microsoft Cognitive Face API- how can i get Face Attributes in video feed from Kinect?Microsoft Cognitive Face API - 如何从 Kinect 获取视频源中的人脸属性?
【发布时间】:2023-03-24 02:52:01
【问题描述】:

我正在探索 Microsoft Cognitive Face API,我对它非常陌生。我可以使用一个简单的图像来实现人脸属性,但是,我的问题是如何在 WPF c# 中的 Kinect 的实时视频源中获取一个人的人脸属性。如果有人可以帮助我,那就太好了。提前致谢!

我尝试每隔 2 秒从 Kinect 颜色源捕获帧到某个文件位置,并使用该文件路径并将其转换为流,然后将其传递给 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,虽然我搜索过但我不知道该怎么做,但对我没有任何效果。如果有人可以帮助我,那就太好了。谢谢!

【问题讨论】:

  • 欢迎来到 Stack Overflow!事实上,你的问题相当广泛。我建议添加一些代码来显示您到目前为止所尝试的内容。你可以edit这个进入你的问题。祝你好运!
  • 嗨 S.L.Barth 我尝试每隔 2 秒从 kinect 颜色馈送捕获帧到某个文件位置,并使用该文件路径将其转换为流,然后将其传递给 Face- API Functions 并且有效。以下是我尝试过的代码。
  • 请使用“编辑”功能将其编辑到您的问题中。您可以使用此链接:edit,或直接在您的问题下方的“编辑”链接。显示代码时,您可以使用编辑器中的“{}”按钮将其格式化为代码。
  • 哦,顺便说一句-也许我误读了您的评论。如果你真的知道如何解决它,那么请把它作为答案发布。
  • 我编辑了我的问题。感谢您的帮助:)

标签: c# wpf microsoft-cognitive kinect-v2 face-api


【解决方案1】:

您可以将帧保存到MemoryStream,倒回(通过调用Position = 0),然后将该流发送到DetectAsync(),而不是将帧保存到SaveImage 中的文件。

另请注意,在UploadAndDetectFaces 中,您应该将imageFileStream 而非imageFilePath 发送至DetectAsync()。无论如何,您可能不想同时调用UploadAndDetectFacesUploadAndDetectFaceAttributes,因为您只是将工作加倍(并且达到了配额/速率限制。)

【讨论】:

  • 嗨,我尝试使用MemoryStream 虽然它没有给出任何错误,但它也没有工作。我发现了这些问题:Capacity: 'printStream.Capacity' threw an exception of type 'System.ObjectDisposedException'Length: 'printStream.Length' threw an exception of type 'System.ObjectDisposedException'Position: 'printStream.Position' threw an exception of type 'System.ObjectDisposedException'
  • 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; } 这是我试过的那段代码。
  • 流将在您的 using 语句的末尾被释放。您需要保留它,直到服务请求完成。最简单的做法是放弃使用并稍后致电stream.Dispose
  • 我将代码更改为private Stream StreamFromBitmapSource(BitmapSource writeBmp) { Stream bmp = new MemoryStream(); BitmapEncoder enc = new BmpBitmapEncoder(); enc.Frames.Add(BitmapFrame.Create(writeBmp)); enc.Save(bmp); return bmp; }
  • 上面的代码现在给出了另外两个例外:ReadTimeout = 'imgStream.ReadTimeout' threw an exception of type 'System.InvalidOperationException' WriteTimeout = 'imgStream.WriteTimeout' threw an exception of type 'System.InvalidOperationException'我该如何解决。
猜你喜欢
  • 1970-01-01
  • 2017-08-22
  • 2018-12-13
  • 2018-08-01
  • 2017-05-20
  • 2017-12-21
  • 2017-05-10
  • 2019-07-28
  • 2018-02-28
相关资源
最近更新 更多