I have a little personal project I working on that does some image processing from a webcam captured via DirectShow.Net and displays it in a winforms apps.
I'm just starting to look into moving that app to WPF and as DirectShow.NET isn't really a support product and is causing me know end of pain with regards to changing the capture resolution I was wondering what the best way to get a video stream from a webcam,
process each frame, extract some data from that frame and display in in WPF is these days staying a much as possible inside c#.
Cheers,
Stephen.
-
-
I did a small bit of looking at a camera thing and it's a PIA
there are only a few ways to go:
1) DirectShow -- works with a number of cameras.
2) there is a spec from MSFT that if the cam supports it is easy but I did not find any cameras using it
3) get an SDK from the maker of the camera
seems like they feel the api to work with a camera is private property, several folks have asked on vendor boards and got the brush off -
WIA?figuerres said:I did a small bit of looking at a camera thing and it's a PIA
there are only a few ways to go:
1) DirectShow -- works with a number of cameras.
2) there is a spec from MSFT that if the cam supports it is easy but I did not find any cameras using it
3) get an SDK from the maker of the camera
seems like they feel the api to work with a camera is private property, several folks have asked on vendor boards and got the brush off
http://msdn.microsoft.com/en-us/library/aa139779.aspx -
Hey Stephen,
This is not something I have tried myself but it looks like some other people have been doing this and may be it can help you:
Webcam control for WPF (does not use DirectShow)
WPF DirectShow workaround
If you have already looked at these, my apologies
Best of luck!
ulas -
ZippyV said:
Need to do 30fps video, so WIA is out, but thanks for the suggestion. -
ulas said:Hey Stephen,
This is not something I have tried myself but it looks like some other people have been doing this and may be it can help you:
Webcam control for WPF (does not use DirectShow)
WPF DirectShow workaround
If you have already looked at these, my apologies
Best of luck!
ulas
I've nothing really against DirectShow.Net, but in these days of WPF I would have thought there might be a more managed friendly way of doing this.
I think I'm going to stick with dshow and VideoRendererElement seems to work. Also GraphEditPlus seems to be a good tool to work out how dshow fits together without reading reams of MSDN docs. -
Yeah WIA, could not recall the name at the time, and I have not found any low cost web cams that say they support it.ZippyV said: -
I would also look into my WPF MediaKit. It is 100% C# (so it supports 32/64bit any cpu compiles) and use the D3DImage class in .NET 3.5 SP1, so I feel its a step up from my VideoRendererElement. I include a VideoCaptureElement control that works with web cameras. You would just have to extend on that to add the SampleGrabber if you need to do any modifications to the pixels before it's rendered. Depending on what you are doing with the image processing, maybe the built in support for pixel shaders would work for you.figuerres said:
Yeah WIA, could not recall the name at the time, and I have not found any low cost web cams that say they support it.ZippyV said:*snip*
-Jer
-
Took me a while to get that far, most solutions you find do not work for all kinds of reasons, this one finally worked.
Most of the work is shown on this link:
http://www.codeproject.com/KB/cpp/webcamcsharp.aspx
The code failed as an aspx file because the CAMSERVERLib.Camera line gave an error of some sorts. So, I wanted to see what it was (probably some security thing on IE) and went to a local C# program with C# Express. These were my steps:
1. Download the zipped project file in the link. Laurent Kempe was nice enough to include the CamServer.dll in the zip.
2. Move the CamServer.dll to C:\Windows\System32 directory
3. Run a command prompt as Administrator and register the dll: regserv32 CamServer.dll
4. Now the file should be available as a reference in C# as a COM reference.
5. Change the Import lines in the aspx file to using in C#
6.Copy and paste the rest of the code. Start from the short nQuality=45; to the </script> (not including)
7. I put mine in the test module called from Main
8. Change: Response.OutputStream in the bmp.Save line to a filename string i.e.@"C:\\MyDocuments\Test.jpg"
c'est tout.
-
//This what my test looks like
public void TakeAPictureTest()
{
short nQuality = 45;
CAMSERVERLib.Camera cam = new CAMSERVERLib.CameraClass();
MemoryStream ms = new MemoryStream( picture );
Bitmap bmp = new Bitmap( ms );Graphics g = Graphics.FromImage( bmp );
string strDate = DateTime.Now.ToLongDateString() + " - " +
DateTime.Now.ToLongTimeString();
StringFormat drawFormat = new StringFormat();
drawFormat.Alignment = StringAlignment.Center;g.DrawString( strDate,
new Font( FontFamily.GenericSansSerif, 12 ),
new SolidBrush( Color.Black ),
new RectangleF( 1,1,320,240 ),
drawFormat
);g.DrawString( strDate,
new Font( FontFamily.GenericSansSerif, 12 ),
new SolidBrush( Color.White ),
new RectangleF( 0,0,320,240 ),
drawFormat
);
EncoderParameters encps = new EncoderParameters( 1 );
EncoderParameter encp = new EncoderParameter( System.Drawing.Imaging.Encoder.Quality,
(long) nQuality );
@"C:\\MyDocuments\\Test.jpg", icf[1], encps);bmp.Save(
g.Dispose();
bmp.Dispose();
}
-
criollo said:
//This what my test looks like
public void TakeAPictureTest()
{
short nQuality = 45;
CAMSERVERLib.Camera cam = new CAMSERVERLib.CameraClass();
MemoryStream ms = new MemoryStream( picture );
Bitmap bmp = new Bitmap( ms );Graphics g = Graphics.FromImage( bmp );
string strDate = DateTime.Now.ToLongDateString() + " - " +
DateTime.Now.ToLongTimeString();
StringFormat drawFormat = new StringFormat();
drawFormat.Alignment = StringAlignment.Center;g.DrawString( strDate,
new Font( FontFamily.GenericSansSerif, 12 ),
new SolidBrush( Color.Black ),
new RectangleF( 1,1,320,240 ),
drawFormat
);g.DrawString( strDate,
new Font( FontFamily.GenericSansSerif, 12 ),
new SolidBrush( Color.White ),
new RectangleF( 0,0,320,240 ),
drawFormat
);
EncoderParameters encps = new EncoderParameters( 1 );
EncoderParameter encp = new EncoderParameter( System.Drawing.Imaging.Encoder.Quality,
(long) nQuality );
@"C:\\MyDocuments\\Test.jpg", icf[1], encps);bmp.Save(
g.Dispose();
bmp.Dispose();
}
This code worked well with Microsoft VX-3000 Webcam but failed when I switched cameras to VX-5000. As a cut and paste programmer I couldn't find a way to get CAMERASERVERLib to work with this camera. Managed to get DirectShow to capture avi videos but not still frames. So I kept looking for webcam picture taker C# code. I found this gem at:
http://www.planet-source-code.com/vb/scripts/showcode.asp?lngWId=10&txtCodeId=1339
Original Code by Phillip Pierce
----------------
(modified to take out all the clicks)---
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Net;
using System.Drawing.Imaging;
using System.Text;
using System.Threading;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.IO;
using System.Drawing.Drawing2D;
using System.ComponentModel;
using System.Data;
using System.Drawing;
namespace ClaretBasicModule
{class MyProgram : System.Windows.Forms.Form
{private System.ComponentModel.IContainer components;
private System.Windows.Forms.Timer timer1;
//CONSTANTS
public const int WM_USER = 1024;
public const int WM_CAP_CONNECT = 1034;
public const int WM_CAP_DISCONNECT = 1035;
public const int WM_CAP_GET_FRAME = 1084;
public const int WM_CAP_COPY = 1054;
public const int WM_CAP_START = WM_USER;
public const int WM_CAP_DLG_VIDEOFORMAT = WM_CAP_START + 41;
public const int WM_CAP_DLG_VIDEOSOURCE = WM_CAP_START + 42;
public const int WM_CAP_DLG_VIDEODISPLAY = WM_CAP_START + 43;
public const int WM_CAP_GET_VIDEOFORMAT = WM_CAP_START + 44;
public const int WM_CAP_SET_VIDEOFORMAT = WM_CAP_START + 45;
public const int WM_CAP_DLG_VIDEOCOMPRESSION = WM_CAP_START + 46;
public const int WM_CAP_SET_PREVIEW = WM_CAP_START + 50;
public bool PictureTaken = false;
public bool PictureDone = false;
public bool SecondPicture = false;
private bool bStopped = true;
private System.Windows.Forms.NumericUpDown numCaptureTime;
private System.Windows.Forms.PictureBox pictureBox1;private ulong m_FrameNumber = 0;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr FindWindow(
[MarshalAs(UnmanagedType.LPTStr)] string lpClassName,
[MarshalAs(UnmanagedType.LPTStr)] string lpWindowName
);
private WebCam_Capture.WebCamCapture WebCamCapture;
private WebCam_Capture.WebcamEventArgs x = new WebCam_Capture.WebcamEventArgs();
private int m_Width = 320;
private int m_Height = 240;
private int mCapHwnd;
public Bitmap bmp = new Bitmap(320, 240, PixelFormat.Format32bppRgb);
public Bitmap bmp2 = new Bitmap(320, 240, PixelFormat.Format32bppRgb);
private IDataObject tempObj;
// event delegate
public delegate void WebCamEventHandler(object source, WebCam_Capture.WebcamEventArgs e);
// fired when a new image is captured
public event WebCamEventHandler ImageCaptured;[DllImport("user32", EntryPoint = "SendMessage")]
public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);[DllImport("avicap32.dll", EntryPoint = "capCreateCaptureWindowA")]
public static extern int capCreateCaptureWindowA(string lpszWindowName, int dwStyle, int X, int Y, int nWidth, int nHeight, int hwndParent, int nID);[DllImport("user32", EntryPoint = "OpenClipboard")]
public static extern int OpenClipboard(int hWnd);[DllImport("user32", EntryPoint = "EmptyClipboard")]
public static extern int EmptyClipboard();[DllImport("user32", EntryPoint = "CloseClipboard")]
public static extern int CloseClipboard();
//CONSTRUCTOR
public MyProgram()
{InitializeComponent();
this.WebCamCapture.CaptureHeight = this.pictureBox1.Height;
this.WebCamCapture.CaptureWidth = this.pictureBox1.Width;
FormReplacer();
}
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}/// <param name="e">WebCamEventArgs</param>
private void WebCamCapture_ImageCaptured(object source, WebCam_Capture.WebcamEventArgs e)
{
// set the picturebox picture
// this.pictureBox1.Image = e.WebCamImage;
if (!SecondPicture)
{
SecondPicture = true;
bmp = (Bitmap)e.WebCamImage;
}
else
{
bmp2 = (Bitmap)e.WebCamImage;
PictureDone = true;
}
PictureTaken = true;
timer1.Start();
}
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.WebCamCapture = new WebCam_Capture.WebCamCapture();
this.WebCamCapture.ImageCaptured += new WebCam_Capture.WebCamCapture.WebCamEventHandler(this.WebCamCapture_ImageCaptured);
this.pictureBox1 = new System.Windows.Forms.PictureBox();this.numCaptureTime = new System.Windows.Forms.NumericUpDown();
((System.ComponentModel.ISupportInitialize)(this.numCaptureTime)).BeginInit();this.SuspendLayout();
// WebCamCapture
//
this.WebCamCapture.CaptureHeight = 240;
this.WebCamCapture.CaptureWidth = 320;
// TODO: Code generation for 'this.WebCamCapture.FrameNumber' failed because of Exception 'Invalid Primitive Type: System.UInt64. Only CLS compliant primitive types can be used. Consider using CodeObjectCreateExpression.'.
this.WebCamCapture.Location = new System.Drawing.Point(17, 17);
this.WebCamCapture.Name = "WebCamCapture";
this.WebCamCapture.Size = new System.Drawing.Size(342, 252);
this.WebCamCapture.TabIndex = 0;
this.WebCamCapture.TimeToCapture_milliseconds = 100;
this.WebCamCapture.ImageCaptured += new WebCam_Capture.WebCamCapture.WebCamEventHandler(this.WebCamCapture_ImageCaptured);
//// pictureBox1
//
this.pictureBox1.Location = new System.Drawing.Point(6, 6);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(320, 240);
this.pictureBox1.TabIndex = 0;
this.pictureBox1.TabStop = false;
//this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(358, 357);
this.Name = "ClaretBasicForm";
this.Text = "WebCam Capture";
//TWO EVENT HANDLERS ONE FOR LOADING THE FORM THE OTHER ONE FOR CLOSING
this.Closing += new System.ComponentModel.CancelEventHandler(this.ClaretBasicForm_Closing);
this.Load += new System.EventHandler(this.ClaretBasicForm_Load);
this.ResumeLayout(false);
this.SuspendLayout();
//
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(597, 453);
this.Name = "MyProgram";
this.Text = "ClaretBasicForm";
this.ResumeLayout(false);
this.numCaptureTime.Location = new System.Drawing.Point(162, 306);
this.numCaptureTime.Maximum = new System.Decimal(new int[] {
32000,
0,
0,
0});
this.numCaptureTime.Minimum = new System.Decimal(new int[] {
1,
0,
0,
0});this.numCaptureTime.Name = "numCaptureTime";
this.numCaptureTime.Size = new System.Drawing.Size(66, 20);
this.numCaptureTime.TabIndex = 4;
this.numCaptureTime.Value = new System.Decimal(new int[] {
20,
0,
0,
0});
this.timer1 = new System.Windows.Forms.Timer(this.components);
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
this.Name = "WebCamCapture";
this.Size = new System.Drawing.Size(342, 252);
}public void Start(ulong FrameNum)
{
try
{
// for safety, call stop, just in case we are already running
this.Stop();// setup a capture window
mCapHwnd = capCreateCaptureWindowA("WebCap", 0, 0, 0, m_Width, m_Height, this.Handle.ToInt32(), 0);// connect to the capture device
Application.DoEvents();
SendMessage(mCapHwnd, WM_CAP_CONNECT, 0, 0);
SendMessage(mCapHwnd, WM_CAP_SET_PREVIEW, 0, 0);// set the frame number
m_FrameNumber = FrameNum;// set the timer information
this.timer1.Interval = 500;
bStopped = false;
this.timer1.Start();
}catch (Exception excep)
{
MessageBox.Show("An error ocurred while starting the video capture. Check that your webcamera is connected properly and turned on.\r\n\n" + excep.Message);
this.Stop();
}
}/// </summary>
public void Stop()
{
try
{
// stop the timer
bStopped = true;
this.timer1.Stop();// disconnect from the video source
Application.DoEvents();
SendMessage(mCapHwnd, WM_CAP_DISCONNECT, 0, 0);
}catch (Exception excep)
{ // don't raise an error here.
}}
public void FormReplacer()
{
this.WebCamCapture.TimeToCapture_milliseconds = (int)this.numCaptureTime.Value;// start the video capture. let the control handle the
// frame numbers.
// Start(0);
this.WebCamCapture.Start(0);}
private void ClaretBasicForm_Closing(object sender, System.EventArgs e)
{
this.WebCamCapture.Stop();}
public ulong FrameNumber
{
get
{ return m_FrameNumber; }set
{ m_FrameNumber = value; }
}public void WinampTest(){}
private void timer1_Tick(object sender, System.EventArgs e)
{
try
{
// pause the timer
this.timer1.Stop();// get the next frame;
SendMessage(mCapHwnd, WM_CAP_GET_FRAME, 0, 0);// copy the frame to the clipboard
SendMessage(mCapHwnd, WM_CAP_COPY, 0, 0);// paste the frame into the event args image
if (PictureTaken = true)
{
// get from the clipboard
PictureTaken = false;
if (PictureDone) WinampTest();
tempObj = Clipboard.GetDataObject();
// tempImg = (System.Drawing.Bitmap)tempObj.GetData(System.Windows.Forms.DataFormats.Bitmap);
// Bitmap bmp = (Bitmap)tempObj.GetData(System.Windows.Forms.DataFormats.Bitmap);
if (File.Exists(@"C:\\MyDocuments\\Test7.bmp"))
{
File.Delete(@"C:\\MyDocuments\\Test7.bmp");
}
bmp.Save(@"C:\\MyDocuments\\Test7.bmp");
}// restart the timer
Application.DoEvents();
if (!bStopped)
this.timer1.Start();
}catch (Exception excep)
{
MessageBox.Show("An error ocurred while capturing the video image. The video capture will now be terminated.\r\n\n" + excep.Message);
this.Stop(); // stop the process
}
}private void ClaretBasicForm_Load(object sender, System.EventArgs e)
{
timer1.Interval = 500;
}}
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyProgram());
}
}
} -
Try here : this site have C# and VB in WPF and WinForm ,it great !!.
http://sites.google.com/site/webcamlibrarydotnet/system/app/pages/sitemap/hierarchy">http://sites.google.com/site/webcamlibrarydotnet/
Thread Closed
This thread is kinda stale and has been closed but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.