305 lines
10 KiB
C#
305 lines
10 KiB
C#
|
//------------------------------------------------------------------------------
|
|||
|
// <copyright file="MainWindow.xaml.cs" company="Microsoft">
|
|||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|||
|
// </copyright>
|
|||
|
//------------------------------------------------------------------------------
|
|||
|
|
|||
|
namespace Microsoft.Samples.AzureKinectBasics
|
|||
|
{
|
|||
|
using System;
|
|||
|
using System.ComponentModel;
|
|||
|
using System.Diagnostics;
|
|||
|
using System.Globalization;
|
|||
|
using System.IO;
|
|||
|
using System.Threading.Tasks;
|
|||
|
using System.Windows;
|
|||
|
using System.Windows.Media;
|
|||
|
using System.Windows.Media.Imaging;
|
|||
|
using Microsoft.Azure.Kinect.Sensor;
|
|||
|
|
|||
|
using Microsoft.Azure.CognitiveServices.Vision.ComputerVision;
|
|||
|
using Microsoft.Azure.CognitiveServices.Vision.ComputerVision.Models;
|
|||
|
|
|||
|
using System.Collections.Generic;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Interaction logic for MainWindow
|
|||
|
/// </summary>
|
|||
|
public partial class MainWindow : Window, INotifyPropertyChanged
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// Azure Kinect sensor
|
|||
|
/// </summary>
|
|||
|
private readonly Device kinect = null;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Azure Kinect transformation engine
|
|||
|
/// </summary>
|
|||
|
private readonly Transformation transform = null;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Bitmap to display
|
|||
|
/// </summary>
|
|||
|
private readonly WriteableBitmap bitmap = null;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Current status text to display
|
|||
|
/// </summary>
|
|||
|
private string statusText = null;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// The width in pixels of the color image from the Azure Kinect DK
|
|||
|
/// </summary>
|
|||
|
private readonly int colorWidth = 0;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// The height in pixels of the color image from the Azure Kinect DK
|
|||
|
/// </summary>
|
|||
|
private readonly int colorHeight = 0;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Status of the application
|
|||
|
/// </summary>
|
|||
|
private bool running = true;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Subscription key for Cognitive Services
|
|||
|
/// </summary>
|
|||
|
private const string subscriptionKey = "YOUR SUBSCRIPTION KEY HERE";
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Connection to Azure Computer Vision Cognitive Service
|
|||
|
/// </summary>
|
|||
|
private ComputerVisionClient computerVision;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Bounding box of the person
|
|||
|
/// </summary>
|
|||
|
BoundingRect boundingBox;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// List of features to find in images
|
|||
|
/// </summary>
|
|||
|
private static readonly List<VisualFeatureTypes> features =
|
|||
|
new List<VisualFeatureTypes>()
|
|||
|
{
|
|||
|
VisualFeatureTypes.Categories, VisualFeatureTypes.Description,
|
|||
|
VisualFeatureTypes.Faces, VisualFeatureTypes.ImageType,
|
|||
|
VisualFeatureTypes.Tags, VisualFeatureTypes.Objects
|
|||
|
};
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Initializes a new instance of the MainWindow class.
|
|||
|
/// </summary>
|
|||
|
public MainWindow()
|
|||
|
{
|
|||
|
// Open the default device
|
|||
|
this.kinect = Device.Open();
|
|||
|
|
|||
|
// Configure camera modes
|
|||
|
this.kinect.StartCameras(new DeviceConfiguration
|
|||
|
{
|
|||
|
ColorFormat = ImageFormat.ColorBGRA32,
|
|||
|
ColorResolution = ColorResolution.R1080p,
|
|||
|
DepthMode = DepthMode.NFOV_2x2Binned,
|
|||
|
SynchronizedImagesOnly = true
|
|||
|
});
|
|||
|
|
|||
|
// Initialize the transformation engine
|
|||
|
this.transform = this.kinect.GetCalibration().CreateTransformation();
|
|||
|
|
|||
|
this.colorWidth = this.kinect.GetCalibration().ColorCameraCalibration.ResolutionWidth;
|
|||
|
this.colorHeight = this.kinect.GetCalibration().ColorCameraCalibration.ResolutionHeight;
|
|||
|
|
|||
|
// Create the computer vision client
|
|||
|
computerVision = new ComputerVisionClient(
|
|||
|
new ApiKeyServiceClientCredentials(subscriptionKey),
|
|||
|
new System.Net.Http.DelegatingHandler[] { })
|
|||
|
{
|
|||
|
// You must use the same region as you used to get
|
|||
|
// your subscription keys.
|
|||
|
Endpoint = "https://westus.api.cognitive.microsoft.com/"
|
|||
|
};
|
|||
|
|
|||
|
this.bitmap = new WriteableBitmap(colorWidth, colorHeight, 96.0, 96.0, PixelFormats.Bgra32, null);
|
|||
|
|
|||
|
this.DataContext = this;
|
|||
|
|
|||
|
this.InitializeComponent();
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// INotifyPropertyChangedPropertyChanged event to allow window controls to bind to changeable data
|
|||
|
/// </summary>
|
|||
|
public event PropertyChangedEventHandler PropertyChanged;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets the bitmap to display
|
|||
|
/// </summary>
|
|||
|
public ImageSource ImageSource
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return this.bitmap;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets or sets the current status text to display
|
|||
|
/// </summary>
|
|||
|
public string StatusText
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return this.statusText;
|
|||
|
}
|
|||
|
|
|||
|
set
|
|||
|
{
|
|||
|
if (this.statusText != value)
|
|||
|
{
|
|||
|
this.statusText = value;
|
|||
|
|
|||
|
if (this.PropertyChanged != null)
|
|||
|
{
|
|||
|
this.PropertyChanged(this, new PropertyChangedEventArgs("StatusText"));
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Execute shutdown tasks
|
|||
|
/// </summary>
|
|||
|
/// <param name="sender">object sending the event</param>
|
|||
|
/// <param name="e">event arguments</param>
|
|||
|
private void MainWindow_Closing(object sender, CancelEventArgs e)
|
|||
|
{
|
|||
|
running = false;
|
|||
|
|
|||
|
if (this.kinect != null)
|
|||
|
{
|
|||
|
this.kinect.Dispose();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Handles the user clicking on the screenshot button
|
|||
|
/// </summary>
|
|||
|
/// <param name="sender">object sending the event</param>
|
|||
|
/// <param name="e">event arguments</param>
|
|||
|
private void ScreenshotButton_Click(object sender, RoutedEventArgs e)
|
|||
|
{
|
|||
|
// Create a render target to which we'll render our composite image
|
|||
|
RenderTargetBitmap renderBitmap = new RenderTargetBitmap((int)CompositeImage.ActualWidth, (int)CompositeImage.ActualHeight, 96.0, 96.0, PixelFormats.Pbgra32);
|
|||
|
|
|||
|
DrawingVisual dv = new DrawingVisual();
|
|||
|
using (DrawingContext dc = dv.RenderOpen())
|
|||
|
{
|
|||
|
VisualBrush brush = new VisualBrush(CompositeImage);
|
|||
|
dc.DrawRectangle(brush, null, new System.Windows.Rect(new Point(), new Size(CompositeImage.ActualWidth, CompositeImage.ActualHeight)));
|
|||
|
}
|
|||
|
|
|||
|
renderBitmap.Render(dv);
|
|||
|
|
|||
|
BitmapEncoder encoder = new PngBitmapEncoder();
|
|||
|
encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
|
|||
|
|
|||
|
string time = System.DateTime.Now.ToString("hh'-'mm'-'ss", CultureInfo.CurrentUICulture.DateTimeFormat);
|
|||
|
|
|||
|
string myPhotos = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
|
|||
|
|
|||
|
string path = Path.Combine(myPhotos, "KinectScreenshot-" + time + ".png");
|
|||
|
|
|||
|
// Write the new file to disk
|
|||
|
try
|
|||
|
{
|
|||
|
using (FileStream fs = new FileStream(path, FileMode.Create))
|
|||
|
{
|
|||
|
encoder.Save(fs);
|
|||
|
}
|
|||
|
|
|||
|
this.StatusText = string.Format(Properties.Resources.SavedScreenshotStatusTextFormat, path);
|
|||
|
}
|
|||
|
catch (IOException)
|
|||
|
{
|
|||
|
this.StatusText = string.Format(Properties.Resources.FailedScreenshotStatusTextFormat, path);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private Stream StreamFromBitmapSource(BitmapSource bitmap)
|
|||
|
{
|
|||
|
Stream jpeg = new MemoryStream();
|
|||
|
|
|||
|
BitmapEncoder enc = new JpegBitmapEncoder();
|
|||
|
enc.Frames.Add(BitmapFrame.Create(bitmap));
|
|||
|
enc.Save(jpeg);
|
|||
|
jpeg.Position = 0;
|
|||
|
|
|||
|
return jpeg;
|
|||
|
}
|
|||
|
|
|||
|
private async void Window_Loaded(object sender, RoutedEventArgs e)
|
|||
|
{
|
|||
|
int count = 0;
|
|||
|
|
|||
|
while (running)
|
|||
|
{
|
|||
|
using (Image transformedDepth = new Image(ImageFormat.Depth16, colorWidth, colorHeight, colorWidth * sizeof(UInt16)))
|
|||
|
using (Capture capture = await Task.Run(() => { return this.kinect.GetCapture(); }))
|
|||
|
{
|
|||
|
count++;
|
|||
|
|
|||
|
this.transform.DepthImageToColorCamera(capture, transformedDepth);
|
|||
|
|
|||
|
this.bitmap.Lock();
|
|||
|
|
|||
|
var color = capture.Color;
|
|||
|
var region = new Int32Rect(0, 0, color.WidthPixels, color.HeightPixels);
|
|||
|
|
|||
|
unsafe
|
|||
|
{
|
|||
|
using (var pin = color.Memory.Pin())
|
|||
|
{
|
|||
|
this.bitmap.WritePixels(region, (IntPtr)pin.Pointer, (int)color.Size, color.StrideBytes);
|
|||
|
}
|
|||
|
|
|||
|
if (boundingBox != null)
|
|||
|
{
|
|||
|
int y = (boundingBox.Y + boundingBox.H / 2);
|
|||
|
int x = (boundingBox.X + boundingBox.W / 2);
|
|||
|
|
|||
|
this.StatusText = "The person is:" + transformedDepth.GetPixel<ushort>(y, x) + "mm away";
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
this.bitmap.AddDirtyRect(region);
|
|||
|
this.bitmap.Unlock();
|
|||
|
|
|||
|
if (count % 30 == 0)
|
|||
|
{
|
|||
|
var stream = StreamFromBitmapSource(this.bitmap);
|
|||
|
_ = computerVision.AnalyzeImageInStreamAsync(stream, MainWindow.features).ContinueWith((Task<ImageAnalysis> analysis) =>
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
foreach (var item in analysis.Result.Objects)
|
|||
|
{
|
|||
|
if (item.ObjectProperty == "person")
|
|||
|
{
|
|||
|
this.boundingBox = item.Rectangle;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
catch (System.Exception ex)
|
|||
|
{
|
|||
|
this.StatusText = ex.ToString();
|
|||
|
}
|
|||
|
}, TaskScheduler.FromCurrentSynchronizationContext());
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|