저는 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의 각 프레임을 직접 스트림으로 변환하고 싶지만 검색 한 방법은 모르지만 나에게 도움이되는 것은 없습니다. 만약 누군가가 나를 도울 수 있다면 그것은 위대 할 것이다. 감사!
Welcome to Stack Overflow! 그것이 그렇듯, 당신의 질문은 다소 광범위합니다. 지금까지 시도한 것을 보여주는 몇 가지 코드를 추가하는 것이 좋습니다. 이것을 당신의 질문에 편집 할 수 있습니다. 행운을 빕니다! –
안녕하세요 S.L.Barth 나는 몇 가지 파일 위치에 매 2 초마다 kinect 컬러 피드에서 프레임을 캡처하고 그 파일 경로를 스트림으로 변환 한 다음 Face-API 함수에 전달하여 작동했습니다. 다음은 내가 시도한 코드입니다. –
"편집"기능을 사용하여 질문을 편집하십시오. 이 링크는 [edit] 또는 질문 바로 아래에있는 "edit"링크를 사용할 수 있습니다. 코드를 표시 할 때 편집기의 "{}"버튼을 사용하여 코드로 형식을 지정할 수 있습니다. –