Esteban Chamard
Esteban Chamard

Reputation: 100

Displaying a videostream from my webcam in WPF?

I have a question, how can I display the stream from my webcam in a Image container in WPF ? I already get the stream with Emgu and converted it to an BitmapSource, but now I don't understand how to bind an Image from my webcam to WPF, with caliburn (MVVM) , every X ms ....

 <Image x:Name="imageWebcam" />

Upvotes: 2

Views: 14646

Answers (4)

Alon Catz
Alon Catz

Reputation: 2530

Here's a solution I ended up with based on WritableBitmap. I have a web cam that streams images at 30 FPS. I need to process those images real time and display them. CameraOnFrame is an event handler which fires 30 times per second on a non-UI thread, so Dispatcher.Invoke is needed. Image<Bgr, byte> is an Emgu.CV image, but it's basically a wrapper for 24 bit BGR image.

XAML:

<Image x:Name="ImageDisplay"/>

Code:

_writableBitmap = new WriteableBitmap(_imageWidth, _imageHeight, 96, 96, PixelFormats.Bgr24, null);
ImageDisplay.Source = _writableBitmap;
...
private void CameraOnFrame(object sender, Image<Bgr, byte> img)
{
    if (!Dispatcher.CheckAccess())
    {
        Dispatcher.Invoke(() => CameraOnFrame(sender, img));
        return;
    }

    _writableBitmap.WritePixels(new Int32Rect(0, 0, img.Width, img.Height), img.MIplImage.ImageData, img.MIplImage.ImageSize, img.MIplImage.WidthStep);
}

Upvotes: 2

Esteban Chamard
Esteban Chamard

Reputation: 100

Ok solution found. I can't show the whole code but I can explain a little bit, to bind wpf View:

<Image x:Name="ImageWebcam" />

To my ViewModel (using Caliburn FrameWork, but this can be easily adapted to an MVVM pattern) I must bind the Image with a function having the same name :

    public WriteableBitmap ImageWebcam
    {
        get
        {
            return this.imageWebcam;
        }
        set
        {
            this.imageWebcam = value;
            this.NotifyOfPropertyChange(() => this.ImageWebcam);
        }
    }

And to update this Image I use a Timer, that must be initialize into the ViewModel constructor :

public MachinBidule()
{
    timeIsRunningOut= new System.Timers.Timer();
    timeIsRunningOut.AutoReset = true;
    timeIsRunningOut.Interval = 10;
    timeIsRunningOut.Elapsed += (sender, e) => { UpdateImage(); };
    capture = new Capture();   // Capture the webcam using EmguCV
}

And now you can manage the update using a dispatcher :

// Update the image, method called by the timer every 10 ms 
private void UpdateImage()
{
    // If capture is working
    if(capture.QueryFrame()!= null)
    {
        //capture an Image from webcam stream and 
        Image<Bgr, Byte> currentFrame = capture.QueryFrame().ToImage<Bgr, Byte>();
        if (currentFrame != null)
        {
            Application.Current.Dispatcher.BeginInvoke(new System.Action(() => { imageWebcam = new WriteableBitmap(BitmapSourceConvert.ToBitmapSource(currentFrame)); NotifyOfPropertyChange(() => ImageWebcam); }));
        }
    }
}

You can notice that we need to convert from emguCV Image<Bgr,Byte> to WPF WriteableBitmap and notify the update with NotifyOfPropertyChange(() => ImageWebcam).

Please feel free to contact me or comment if you have any questions. If you've noticed any mistake don't hesitate to correct me (grammar & code).

Upvotes: 2

Simon Wood
Simon Wood

Reputation: 634

Use a WriteableBitmap as the source of your image element. You should provide a callback in your view model that passes the frame data for each new frame. Subscribe to this callback from your view in the code behind. You can then write each frame to the bitmap. I don't think data binding is a good approach in this case.

When dealing with a stream of video frames WriteableBitmap is by far the best option in WPF:

WriteableBitmap

Upvotes: 0

StepUp
StepUp

Reputation: 38114

You should use MediaElement to show video, not Image control:

XAML:

<MediaElement Source="{Binding VideoAddress}" />

viewModel:

private URI videoAddress=new URI("C:\video.wmv");
public URI VideoAddress
{
   get { return videoAddress; }
   set
   {
       videoAddress = value; 
       OnPropertyChanged("LeafName");
   }
}

Also, you can use WPF-MediaKit to show video from WebCam. Or see this tutorial.

Update:

You should use Image, to show an image:

<Image x:Name="imageWebcam" />

and C#:

BitmapImage logo = new BitmapImage();
logo.BeginInit();
logo.UriSource = new Uri("C:/1.png");
logo.EndInit();

imageWebcam.Source = logo;

Upvotes: 0

Related Questions