Click here to Skip to main content
15,867,594 members
Articles / Programming Languages / C# 4.0

Capture Image from Webcam using Silverlight

Rate me:
Please Sign up or sign in to vote.
4.19/5 (9 votes)
8 Nov 2012CPOL5 min read 56K   4.6K   17   21
Capture a frame from live webcam feed and save it as an image file to disk

Introduction 

Silverlight brings a whole new set of controls and libraries for developing rich internet applications that use media content like video and audio. In this article I explore Silverlight's capability for webcam access and the subsequent use of the webcam feed to freeze a frame and save it as a PNG file onto disk.

The code presented here can be wrapped into a nice user control and used in any Silverlight application to capture images, e.g., quick profile pictures, pictures for fun, etc., use your imagination Smile, although I don't discuss that part in this article.

Background 

This article explains the basics of Silverlight webcam access: Silverlight web cam access.

The Source Code 

I have uploaded the Silverlight project that can be added into Visual Studio straight away.

The Front End 

The XAML markup for the front end looks like this:

XML
<UserControl x:Class="SilverlightApplication1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="800" d:DesignWidth="900">

    <Grid x:Name="LayoutRoot" Background="White">
        <Button Content="Activate Camera" Height="23" HorizontalAlignment="Left" 
            Margin="156,20,0,0" Name="btnActivate" 
            VerticalAlignment="Top" Width="100" Click="btnActivate_Click" />
        <Rectangle Height="239" HorizontalAlignment="Left" 
            Margin="12,49,0,0" Name="rectangle1" Stroke="Black" 
            StrokeThickness="1" VerticalAlignment="Top" Width="376" />
        <Rectangle Height="239" HorizontalAlignment="Left" Margin="409,49,0,0" 
            Name="rectangle2" Stroke="Black" StrokeThickness="1" 
            VerticalAlignment="Top" Width="376" />
        <Button Content="Freeze Frame" Height="23" HorizontalAlignment="Left" 
            Margin="559,20,0,0" Name="btnFreeze" VerticalAlignment="Top" 
            Width="100" Click="btnFreeze_Click" />
        <Image Height="183" HorizontalAlignment="Left" Margin="409,305,0,0" 
            Name="image1" Stretch="Fill" VerticalAlignment="Top" Width="376" />
        <Button Name="btnSave" Content="Save Shot" Click="btnSave_Click" 
            Height="23" HorizontalAlignment="Left" Width="85" Margin="500,200,0,0"></Button>
    </Grid>
</UserControl>

This is what the GUI looks like, rather simple. On the left is the web cam feed live, on the right hand side is a frame captured. (My hand moved slightly after capturing the frame and taking the screen grab, so my hand appears lower on the left than on the right).

Clicking on "Activate Camera" starts the live video feed preview in the left box, clicking on "Freeze Frame" does just that, freezes a frame from the live video and shows in the right box. Clicking "Save Shot" saves the frozen frame as a PNG image on to disk. That's all.

Image 2

The C# code behind 

The C# code that does the capture and save is discussed in the following phases:

  1. Getting access to webcam
  2. As you can see below, the first step is to get the video capture device and stream its feed into a pre-viewing Rectangle i.e., rectangle1. This is done by painting or "Fill"ing rectangle1 by a VideoBrush whose content source has been set to the video capture device. 

    Keep in mind also that rectangle2 has been filled with an image brush the reason for which will be discussed shortly.

    Once that's done, the RequestDeviceAccess() method asks for user permission to access the webcam, which if gets approved starts the webcam and live-feed appears in rectangle1.

    C#
    private void btnActivate_Click(object sender, RoutedEventArgs e)
    {
        source = new CaptureSource();
        VideoCaptureDevice vcd = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice();
        source.VideoCaptureDevice = vcd;
        VideoBrush vb = new VideoBrush();
        ib = new ImageBrush();
        vb.SetSource(source);
        rectangle1.Fill = vb;
        rectangle2.Fill = ib;
    
        if (CaptureDeviceConfiguration.RequestDeviceAccess())
        {
            source.Start();
        }
    }
  3. Freezing a frame
  4. Attach the CaptureImageCompleted event handler to the click event of the "Freeze Frame" button like so: 

    C#
    private void btnFreeze_Click(object sender, RoutedEventArgs e)
    {
        source.CaptureImageCompleted += new EventHandler<CaptureImageCompletedEventArgs>(source_CaptureImageCompleted);
        source.CaptureImageAsync();
    }

    and call the CaptureImageAsync() method which is an asynchronous method which fires and continues with the rest of the code without having to block and wait for a response. When the method returns, the event handler gets fired and the result is collected like so: 

    C#
    void source_CaptureImageCompleted(object sender, CaptureImageCompletedEventArgs e)
    {
        ib.ImageSource = e.Result;
        CapturedImage = e.Result;
    }

    If you remember, moments ago we had filled rectangle2 with an image brush "ib" and at that point it was empty i.e., it had no source to paint an image from. Well, now it does. As can be seen above, I am setting the ImageSource of ImageBrush "ib" to be the result of the CaptureImageCompleted event. This results in a "frame" being frozen from the live video feed and appearing in rectangle2 as shown in the GUI screenshot previously. 

    Also notice, I am setting another property, CapturedImage with the same result. What about it? Well, CapturedImage is defined as follows:  

    C#
    private WriteableBitmap _capimage;
    public WriteableBitmap CapturedImage
    {
        get 
        {              
            return _capimage; 
        }
        set { _capimage = value; }
    }

    It is a WriteableBitmap object that will help in saving the frame to an actual image which is what I talk about in the penultimate phase. 

  5. Saving the frame to PNG
  6. Now, this is where you are going to need some third party open source library support. ImageTools is just the library for this job. It provides Encoders/Decoders for a couple of image formats, PNG being one of them.

    You will need to reference the following DLLs in your Silverlight project:

    1. ImageTools.dll
    2. ImageTools.IO.PNG.dll
    3. ImageTools.Utils.dll

    Include the following namespaces as well if not already there:

    C#
    using System.Windows.Media;
    using System.Windows.Media.Effects;
    using System.Windows.Media.Animation;
    using System.Windows.Media.Imaging;

    ImageTools also provides an extension method: ToImage(WriteableBitmap wmp) which converts a WriteableBitmap object to an ExtendedImage object (part of the ImageTools library). 

    Save this frame to PNG on the click of "Save Shot" button like so:

    C#
    private void btnSave_Click(object sender, RoutedEventArgs e)
    {
        SaveFileDialog sfd = new SaveFileDialog();
        sfd.Filter = "PNG files (*.PNG)|*.png|All Files (*.*)|*.*";
        var enc = new PngEncoder();
        if ((bool)sfd.ShowDialog())
        {
            Stream stream = sfd.OpenFile();
            var image = Imager.ToImg(CapturedImage);
            enc.Encode(image, stream);
            stream.Close();
        }
    }

    [N.B.] : I, for some unknown reason, could not access the ToImage() extension method directly so I de-compiled the ImageTools DLL using IL-Spy and copied the ToImage() method to a separate class in my Silverlight project and named it ToImg(). I just used the original method "as-is" and did not modify it in anyway, its original authors are the guys who built the ImageTools library not me. Just so you know Smile.

    Anyway, getting back, as you can see above, I am opening a SaveFileDialog to create an empty PNG file, open it into a Stream, convert the CapturedImage i.e.n WriteableBitmap to an ExtendedImage typen and then call the Encode() method defined in the PngEncoder class in ImageTools.IO.PNG.dll to encode the image into PNG format and write back to the stream. Since the stream is directly connected with the actual file, the encoded data gets written to the file as soon as the stream is closed and voila! You have successfully captured an image from your webcam in a Silverlight web app into a PNG file.

Points of Interest   

I would be honest, I did try some weird hacks to write my own PngEncoder (this was way before I had even heard of ImageTools and the "build-my-own" desire was at toxic levels Smile) but I couldn't really make much headway into it. Finally, I just decided to bite the bullet and go for the third party library way. But studying this library, one can begin to understand how various image formats work and how to approach writing an encoder for them. 

The next steps for this code could be to wrap it into a nice Silverlight user control that can be plugged into any application and it will work right out of the box (though that remains to be seen). 

If it gets too complex for a control then it can even remain as a standalone application that can then be embedded into another Silverlight application and loaded dynamically from the host app. I discuss how to do that in my blog here.

As to the use case of such a control, I am sure people can use their imaginations and find ways to use it. I have already mentioned a couple off the top of my head in the beginning of this article but they are by no means all.

Thanks for considering this article worth your reading.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United Kingdom United Kingdom
A software developer in pursuit of craftsmanship and the zen of software.

Comments and Discussions

 
QuestionAsus notebook webcam does not work / Porting to VS2013 Pin
RickZeeland1-Mar-15 1:30
mveRickZeeland1-Mar-15 1:30 
AnswerRe: Asus notebook webcam does not work / Porting to VS2013 Pin
I.explore.code20-Mar-15 1:01
I.explore.code20-Mar-15 1:01 
GeneralRe: Asus notebook webcam does not work / Porting to VS2013 Pin
RickZeeland20-Mar-15 22:57
mveRickZeeland20-Mar-15 22:57 
GeneralRe: Asus notebook webcam does not work / Porting to VS2013 Pin
I.explore.code21-Mar-15 2:05
I.explore.code21-Mar-15 2:05 
QuestionHow can i save a picture to a default location. Pin
Member 113981483-Feb-15 7:37
Member 113981483-Feb-15 7:37 
AnswerRe: How can i save a picture to a default location. Pin
I.explore.code3-Feb-15 22:55
I.explore.code3-Feb-15 22:55 
GeneralMy vote of 2 Pin
Lyle1231325-Aug-14 11:00
Lyle1231325-Aug-14 11:00 
GeneralRe: My vote of 2 Pin
I.explore.code26-Aug-14 8:53
I.explore.code26-Aug-14 8:53 
GeneralRe: My vote of 2 Pin
Lyle1231326-Aug-14 9:02
Lyle1231326-Aug-14 9:02 
GeneralRe: My vote of 2 Pin
I.explore.code26-Aug-14 10:03
I.explore.code26-Aug-14 10:03 
GeneralRe: My vote of 2 Pin
Lyle1231326-Aug-14 11:34
Lyle1231326-Aug-14 11:34 
Questionissues Pin
Lyle1231321-Aug-14 5:24
Lyle1231321-Aug-14 5:24 
QuestionCommercial ?? Pin
Member 1035464327-Oct-13 4:24
Member 1035464327-Oct-13 4:24 
AnswerRe: Commercial ?? Pin
I.explore.code11-Nov-13 22:07
I.explore.code11-Nov-13 22:07 
QuestionStuck at the Webcam permission Pin
Ba Love16-Oct-13 12:39
Ba Love16-Oct-13 12:39 
AnswerRe: Stuck at the Webcam permission Pin
I.explore.code11-Nov-13 22:09
I.explore.code11-Nov-13 22:09 
QuestionImage encoding process Pin
javqui2227-Jul-13 2:10
javqui2227-Jul-13 2:10 
AnswerRe: Image encoding process Pin
I.explore.code28-Jul-13 0:49
I.explore.code28-Jul-13 0:49 
Hi, its ok...i m not an expert on Silverlight either Wink | ;) .

the image encoding happens on client side since Silverlight is a client side technology. All the Silverlight dlls and all the code that you write on the GUI code behind gets executed on client side so you won't be sending live bytes over to the server. The camera snapshots would be stored client side as well. Silverlight downloads all the dlls that it needs to function on client side in a .xap file and uses them locally (think of it like caching) so only the dlls i.e. class libraries that you have created in separate project in VS would be accessed over the wire via a service call.

If this application was to be deployed on an actual server and used by a client, the user would have to explicitly allow webcam access to the application when it asks for it, but that's from security standpoint.

Hope this helps. Thanks.
GeneralRe: Image encoding process Pin
javqui2228-Jul-13 3:16
javqui2228-Jul-13 3:16 
QuestionUnable to open solution in Windows 8 64bit system Pin
Shitiz Bansal16-May-13 18:43
Shitiz Bansal16-May-13 18:43 
AnswerRe: Unable to open solution in Windows 8 64bit system Pin
I.explore.code17-May-13 0:16
I.explore.code17-May-13 0:16 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.