.net, Computer Vision, UWP, Visual Studio

How to use the camera on your device with C# in a UWP application: Part #1, previewing the output

I’ve recently started writing some UWP applications, and I am really enjoying learning the challenges of WPF and app programming (admittedly I’ve come to the party pretty late on this).

I’ve decided to write a short series of posts on how to use the camera on Windows devices – my plan is to write articles covering:

  1. Previewing the camera output to the device’s screen;
  2. Adding the ability to focus;
  3. Allowing the user to capture an image;
  4. And finally add error handling and resource clean-up.

This first part will just be about writing an app that will preview the device’s camera output to the device’s screen.

Since I’m adding error handling in the final part of the series, this first part will assume that the device running this code has a camera connected.

Note: This series is meant to use the absolute minimum number of lines of code necessary. For much more functional samples, check out the sample UWP code released by Microsoft to Github.

Step 1: Create the project and set capabilities

In VS2015, create a new Windows 10 UWP “Blank App” project.

screenshot.1460844693

Once the project has been created, you need to open the Package.appmanifest file (which was created as part of the Blank App), and click on the Capabilities tab. You need to tick boxes for:

  • Microphone
  • Webcam

It took me a little while to understand why the microphone would be required because you don’t need the microphone to take a picture. The reason is that the camera on the device is actually a video recorder (which records sound and images) – in order to use this device in code, you need access to both hardware features.

Step 2: Add the XAML control to preview the camera output

The CaptureElement control renders a stream from a capture device, such as a device camera or a webcam. We need to add one of these controls to the MainPage.xaml file.

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <CaptureElement Name="PreviewControl" Stretch="Uniform"/>
</Grid>

Step 3: Create a private asynchronous method to initialise the camera

This is where the main part of the application lives.

We need a member variable (a class property would be fine as well) – the MediaCapture control to allows us to see a preview of what the camera sees in the CaptureElement (and later, we’ll use this to capture the photograph).

// Provides functionality to preview and capture the photograph
private MediaCapture _mediaCapture;

We’ll need to initialise the camera asynchronously a few times, so we need a method to repeat this process:

  1. First this method needs to test if instantiation of the camera has already happened (specifically initialisation of the MediaCapture object) . If it hasn’t been initialised, then we need to go through the process.
  2. Next, we need to get a reference to the actual camera device. We’d prefer a back facing camera (usually the case for a phone) – but since this is a UWP and might run on a desktop as well, it’s possible that a back facing camera doesn’t exist. In that case, we’ll just take a reference to whatever the first camera device is.
  3. Once we have the camera, we’ll initialise the MediaCapture object, and initialise it by telling it the camera device identifier that we want it to use.
  4. Almost done – we’ll set the MediaCapture object to be the source of the CaptureElement object added to the Xaml earlier.
  5. Finally, tell the MediaCapture object to allow us to start previewing through the CaptureElement object.
private async Task InitializeCameraAsync()
{
    if (_mediaCapture == null)
    {                
        // Get the camera devices
        var cameraDevices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
                
        // try to get the back facing device for a phone
        var backFacingDevice = cameraDevices
            .FirstOrDefault(c => c.EnclosureLocation?.Panel == Windows.Devices.Enumeration.Panel.Back);
 
        // but if that doesn't exist, take the first camera device available
        var preferredDevice = backFacingDevice ?? cameraDevices.FirstOrDefault();
 
        // Create MediaCapture
        _mediaCapture = new MediaCapture();
                
        // Initialize MediaCapture and settings
        await _mediaCapture.InitializeAsync(
            new MediaCaptureInitializationSettings {
                VideoDeviceId = preferredDevice.Id
            });
                
        // Set the preview source for the CaptureElement
        PreviewControl.Source = _mediaCapture;
                
        // Start viewing through the CaptureElement 
        await _mediaCapture.StartPreviewAsync();
    }
}

This is pretty much the most complicated part.

Step 4. Register and override app events

We need to capture when the application is starting and suspending to carry out initialisation actions.

We can register one of these events in the MainPage constructor.

public MainPage()
{
    InitializeComponent();
 
    Application.Current.Resuming += Application_Resuming;
}

Additionally, we need to override the events when we navigate to the application – the code below shows the methods that handle each of the two events.

private async void Application_Resuming(object sender, object o)
{
    await InitializeCameraAsync();
}
 
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
    await InitializeCameraAsync();
}

Summary

So that’s it – just a few lines of code to display what the camera views on your device. In summary:

  1. Create an app and set the capabilities to microphone and webcam;
  2. Add a CaptureElement to the app’s Xaml;
  3. Add the code to initialise and start previewing the camera’s view through the CaptureElement.

Remember that this isn’t code that’s good enough to be used in a production app – there’s no error handling or resource clean-up yet, and it doesn’t really do anything (like focus or record a picture).

The code I used to complete this part of the series is shown below:

public sealed partial class MainPage : Page
{
    // Provides functionality to capture the output from the camera
    private MediaCapture _mediaCapture;
 
    public MainPage()
    {
        InitializeComponent();
 
        Application.Current.Resuming += Application_Resuming;
    }
 
    private async void Application_Resuming(object sender, object o)
    {
        await InitializeCameraAsync();
    }
 
    protected override async void OnNavigatedTo(NavigationEventArgs e)
    {
        await InitializeCameraAsync();
    }

    private async Task InitializeCameraAsync()
    {
        if (_mediaCapture == null)
        {
            // Get the camera devices
            var cameraDevices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
 
            // try to get the back facing device for a phone
            var backFacingDevice = cameraDevices
                .FirstOrDefault(c => c.EnclosureLocation?.Panel == Windows.Devices.Enumeration.Panel.Back);
 
            // but if that doesn't exist, take the first camera device available
            var preferredDevice = backFacingDevice ?? cameraDevices.FirstOrDefault();
 
            // Create MediaCapture
            _mediaCapture = new MediaCapture();
 
            // Initialize MediaCapture and settings
            await _mediaCapture.InitializeAsync(
                new MediaCaptureInitializationSettings {
                    VideoDeviceId = preferredDevice.Id
                });
 
            // Set the preview source for the CaptureElement
            PreviewControl.Source = _mediaCapture;
 
            // Start viewing through the CaptureElement 
            await _mediaCapture.StartPreviewAsync();
        }
    }
}

Next time in this series, I’ll look at how to test if the camera is capable of focussing, and if so, how to make it focus.