WPF Webcam Control part 2

by Geert 8. January 2009 21:45

Some time ago, I wrote an article about how to capture images from a webcam. The article contained some customized code that was originally posted by Tamir Khason.

On January 7th, 2009, Edgar commented that he wanted to control the device or selected camera via WPF bindings. I agreed that if the blog entry promised to give a WPF Webcam Control, it should support WPF bindings as well.

So, I have rewritten some parts of the webcam control so that fully supports WPF. If have also written a simple sample application that allows users that download the control to easily decide whether this control is useful or not.

I have implemented code that you can easily change the MonikerString of a CapDevice. This means that you can set one device to a CapPlayer object and simply set the device via WPF bindings. The example application shows how to bind a combobox to the available devices on the system and how to set the values via dependency properties.

You can see a screenshot of the example application below:

webcamplayer_example

 

Update (2011-01-13):

Recently, I received an e-mail from Haris Omeragic with an explanation on how to flip the image horizontally (both in the capture as preview). Here is the code he sent me:

<!-- Webcamp preview -->
<webcam:CapPlayer Grid.Row="2" x:Name="webcamPlayer" Stretch="Fill"
Rotation="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:PhotoCaptureView}}, Path=WebcamRotation}"
Height="{Binding ElementName=webcamPlayer, Path=ActualWidth, Converter={StaticResource ThreeFourthConverter}}"
Device="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:PhotoCaptureView}}, Path=SelectedWebcam}"
Style="{StaticResource DefaultCapPlayer}">
 
<webcam:CapPlayer.RenderTransform>
<
TransformGroup>
<
ScaleTransform ScaleX="-1" ScaleY="1" />
<
TranslateTransform X="{Binding ElementName=webcamPlayer, Path=ActualWidth}" Y="0" />
</
TransformGroup>
 
</webcam:CapPlayer.RenderTransform>
</
webcam:CapPlayer>

As you can see I added a RenderTransform element to the webcam control.
But, I also needed to flip the image itself before it's added to the SelectedImages collection:
 
 
private void CaptureImage_Executed(object sender, ExecutedRoutedEventArgs e)
{
//// Store current image in the webcam
BitmapSource bitmap = webcamPlayer.CurrentBitmap;
if (bitmap != null)
{
 
Transform tr = new System.Windows.Media.ScaleTransform(-1, 1);
var transformedBmp = new TransformedBitmap();
transformedBmp.BeginInit();
transformedBmp.Source = bitmap;
transformedBmp.Transform = tr;
transformedBmp.EndInit();
bitmap = transformedBmp;
 
SelectedImages.Add(bitmap);
 
}
}

 

WebcamPlayer_1.1.zip (118.49 kb) [Downloads: 8892]

Update (2011-11-03): I received an e-mail from Sylvain MAHE with the following comments:

When call Stop(), webcam is not released. (the Lamp of webcam not turned off)
Thred is Abort and the last action control.StopWhenReady(); is not called.

Update this file: CapDevice.cs (23.14 kb) [Downloads: 303] 

kick it on DotNetKicks.com

Open source WPF control to view webcam video and capture webcam images

Tags:

C# | WPF

Comments (27) -

Aaditya
Aaditya
1/21/2009 2:03:43 PM #

Hello Geert,

'm developing an application which captures and saves images from a web cam. i am using WPF. 'm pretty new to both WPF and C#. so 'm finding it difficult to understand the code. Can u suggest a way to save the image as a file on local hard disk.

Geert van Horrik
Geert van Horrik Netherlands
1/21/2009 2:06:41 PM #

Well, the example application has a dependency property SelectedImages. This is a collection of BitmapSource.

Searching for "Save BitmapSource" gave me the following result:

social.msdn.microsoft.com/.../

oded
oded
2/15/2009 2:49:02 PM #

Hi,
Thanks for the great sample project, is there a way to control the Framerate? I want a lower framerate for a client/server application...
Thanks,
oded

Geert van Horrik
Geert van Horrik Netherlands
2/15/2009 4:12:15 PM #

You can control the framerate (or any webcam properties) with this sample project.

However, you can easily control the number of images that are passed to your client application (downgrade the framerate) by storing the time that you captured the last image and check if that value is larger than (1 second / required framerate).

Best regards,

Ricky
Ricky India
2/27/2009 5:00:33 PM #


Hi Geert,

This is probably one of the best samples i could find for capturing images from a web cam. I have a problem though. I am using this sample as a part of a bigger project wherein i send the captured image via web services. I have a number of windows. so once i have captured the image, i want to call a 'destructor' of the screen housing your webcam capturing code. This is because
a) I want to free up the resources
b) I somehow can't capture the images once i navigate off from the webcam window. The 'SelectedWebcam' property returns false.

Please suggest some way to do this.

Regard,

Ricky

elwolv
elwolv United States
3/4/2009 4:44:44 AM #

excellent!!  i just run the code demonstration with the ability to capture still image from the video stream.
now i will read your article/code

my complement

elwolv


Geert van Horrik
Geert van Horrik Netherlands
3/4/2009 4:19:12 PM #

Hi Ricky,

Did you check whether your destructor is actually called before you try to use the device again? Maybe the device is still in use. For one of my clients, I have created a picture import wizard that is able to import multiple images from webcam, digital camera, disk, scanner, etc. We are not having any problems with the webcam being in use or not allowing to capture again.

elwolv
elwolv United States
3/4/2009 6:22:09 PM #

hello Geert

the camplayer references has 2 references that are not in the original code   J832.common, and J832.wpf.bagotrickslib

what are those and i did not see such file/code with such names
however, references is accessing them?

Geert van Horrik
Geert van Horrik Netherlands
3/4/2009 6:30:40 PM #

See http://j832.com/. It is a library written by Kevin Moore.

I use only one part, and that is to insert the images in a nice transition. The control is used in the MainWindow class for the selected images control.

Regis Hanol
Regis Hanol France
4/15/2009 10:36:32 PM #

Hi Geert,

I've tried your application and it is definitively not taking any CPU power! Awesome!
But it is also really really slow!... Not awesome ;)

I mean the frame rate of the webcam is like 1 frame per 5 seconds or so...

Any thoughts ?

I'm running Windows 7 Beta 1 on a Macbook if this is important.

Thanks a lot !

Geert
Geert Netherlands
4/16/2009 8:49:59 AM #

Hi Regis,

Are you sure your webcam supports that much frames? At the moment, the software tries to read as much frames as possible from the webcam. A nice additional feature would be to extend the software with a framerate control.

Did you try to view the webcam results in Windows Explorer (you can view the video there)? What framerate does it support there?

Best regards,

Geert

Regis Hanol
Regis Hanol France
4/16/2009 9:43:20 AM #

Hi Geert,

Yes the webcam works. I've been using the code you can find there www.brains-n-brawn.com/default.aspx and I get a decent 30 FPS.

Anyway, I tried to use your software with another webcam (a USB one) and it worked fine, but used 40% of the CPU...

Regis

Geert van Horrik
Geert van Horrik Netherlands
4/22/2009 11:48:06 AM #

You have to understand that this software is not very optimized. I think if you only use the webcam part (and not the demo application), the CPU will go down a bit.

Kyle Egbert
Kyle Egbert United States
5/20/2009 8:15:06 PM #

Nice work!  I was trying to use your control and was wondering if there is support to change the resolution of the captured image... I have a nice webcam which supports 960*720 output but the captured image always seems to be much lower quality.

Thanks,
Kyle

Gatt
Gatt
5/25/2009 4:43:21 PM #

Hi !!
It's a really nice work !
But I'm wondering how can I change the resolution, I have a Webcam which can show 960x720 and I've only 640x480.
I tried to change
header.BmiHeader.Width = 960;
header.BmiHeader.Height = 720;
but this doesn't make a good picture

Thanks

Geert
Geert Netherlands
5/26/2009 6:37:19 PM #

Hi,

Sorry for my "late" reply, I have been out-of-office for the weekend.

Anyway, this control doesn't directly support changing the resolution. Changing the size of the BmiHeader is useless since the image is already captured (and you are simply resizing a bitmap in that case).

I suggest you take a took at the Device class.

Best regards,

Geert

Gatt
Gatt
5/27/2009 11:20:04 AM #

Hi,
Thanks. This is what I was thinking.
In order to change the resolution, tell me if I'm wrong, I have to work on the _sourceObject in the RunWorker Method when the graph is created (but I don't know what to do for the moment).

Thanks.

Geert
Geert
5/27/2009 11:50:29 AM #

What you might try to do is set the requested size in the mediaType variable.

Please take a look at the documentation:

code.snapstream.com/.../...AMMediaTypeMembers.html

As you can see in the Structures file, the FixedSizeSamples is set to true by default.

Gatt
Gatt
5/27/2009 12:07:51 PM #

I've already tried this, and this change nothing. But there is something strange, when I set imagesize/samplesize or something else in mediatype, the BufferLen in BufferCB method doesn't change, and it's always the imagesize in 640x480 (the bad resolution).

Geert
Geert
5/27/2009 12:25:25 PM #

Keep in mind that this sample is not a DirectShow example. Please see the documentation:

msdn.microsoft.com/.../dd319784(VS.85).aspx

A good C# version of DirectShow (that contains all the interfaces definitions, etc) is http://directshownet.sourceforge.net/.

Gatt
Gatt
5/27/2009 12:41:05 PM #

Your first link is exactly what I'm trying to do, to set the output format thanks to IAMStreamConfig Interface.
I know that your sample isn't a directshow example, but to my mind, it's a very good sample, and changinig is the only thing which is missing, is the webcam resolution.
I have directshow examples and it's easy to change the webcam resolution.
So I would like to add the resolution support to your code, to have a complete wpf webcam control.

Gatt
Gatt
5/27/2009 4:52:50 PM #

It's works !!

you just have to add (And implement IAMStreamConfig, and make the code prettier)

IEnumPins _enumPin;
_sourceObject.EnumPins(out _enumPin);
IPin[] _IPP = new IPin[3];
int pt = -1;
_enumPin.Next(3, _IPP, out pt);
                
IAMStreamConfig st;
st = (IAMStreamConfig)_IPP[0];
                
AMMediaType med = new AMMediaType();
st.GetFormat(out med);
VideoInfoHeader head = (VideoInfoHeader)Marshal.PtrToStructure(med.FormatPtr, typeof(VideoInfoHeader));

head.BmiHeader.Width = 960;
head.BmiHeader.Height = 720;

Marshal.StructureToPtr(head, med.FormatPtr, false);
st.SetFormat(med);

Geert
Geert
5/27/2009 5:08:10 PM #

Great to hear! Thank you for posting this fix!

I have received more fixes during the weeks, so I will try to post and update with all fixes as soon as I have some time left...

Gatt
Gatt
6/2/2009 2:51:05 PM #

Hi,

Is somebody succeed in recording webcam in a file (toto.avi for example) thanks to this control?
With a ICaptureGraphBuilder it's easy to record and preview the webcam stream, but we have a "simple" GraphBuilder ...

Thanks

syeed
syeed India
6/4/2009 1:10:56 PM #

Hi,

iam saving the image from list,

FileStream stream1 = new FileStream("1.jpg", FileMode.Create);
            JpegBitmapEncoder encoder1 = new JpegBitmapEncoder();
            TextBlock myTextBlock = new TextBlock();
            myTextBlock.Text = "Codec Author is: " + encoder.CodecInfo.Author.ToString();
            encoder1.FlipHorizontal = true;
            encoder1.FlipVertical = false;
            encoder1.QualityLevel = 30;
            encoder1.Rotation = Rotation.Rotate90;
            encoder1.Frames.Add(BitmapFrame.Create(webcamPlayer.CurrentBitmap.Clone()));
            encoder1.Save(stream1);

but the image  is storing in TransformedBitmap mode and the view is no priview image....
please i need solution for this

syeed
syeed India
6/4/2009 2:51:51 PM #


Thanks (advancely)

my aim is to store these images in hard disk,

i used another code also

Image image1 = new  Image();
            image1.Source = SelectedImages[0] ;
            int width = 100;
            int height = 100;
            int stride = width / 8;

            RenderTargetBitmap rtb = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
            rtb.Render(image1);
            FileStream stream = new FileStream("1.gif" , FileMode.Create);
            BitmapEncoder encoder = new GifBitmapEncoder();
            //JpegBitmapEncoder encoder = new JpegBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(rtb));
            encoder.Save(stream);



but the result is same, image able to stor but in "no image prive" mode

please help me

Gatt
Gatt
6/5/2009 9:43:36 AM #


In Capture_Executed, you just have to add
FileStream stream1 = new FileStream("1.jpg", FileMode.Create);
            JpegBitmapEncoder encoder1 = new JpegBitmapEncoder();
            
            encoder1.FlipHorizontal = true;
            encoder1.FlipVertical = false;
            encoder1.QualityLevel = 30;
            
            encoder1.Frames.Add(BitmapFrame.Create(Bitmap));
            encoder1.Save(stream1);

then close the encoder if you want to open your image when your application is running

Pingbacks and trackbacks (1)+

Comments are closed

About the Author

Geert van Horrik is a independent freelance software developer since January 1st, 2007. Since then he was been working on several projects from C++ to C# (WPF, ASP.NET, etc). Currently he loves to write his software using WPF (or Silverlight if WPF isn't an option).

Lately, Geert is spending a lot of time on Catel, a free open-source MVVM Framework for WPF and Silverlight. Actually, it's more than "just" an MVVM Framework, it's a complete application library!