Click here to Skip to main content
Email Password   helpLost your password?
Sample Image - WebCamService.jpg

Update #1

Please let me know if you run into any bugs or if you have any questions. I would be happy to help you.

Introduction

For a long time, I have been looking for a good way to capture images without too much trouble. All you need to do is call one method to get the image.

I have used Windows Image Acquisition (WIA) to capture images. WIA provides a great deal of compatibility with webcams already running on Microsoft Windows XP.

This is my first posting on The Code Project, please do not hesitate to comment or give any suggestions. I would be very thankful if you provide any feedback.

WIA

Improved Image Capture Technologies: WIA

Windows XP supports still-image devices through Windows Image Acquisition (WIA), which uses the Windows Driver Model (WDM) architecture. WIA provides robust communication between applications and image-capture devices, allowing you to capture images efficiently and transfer them to your computer for editing and use.

WIA supports small computer system interface (SCSI), IEEE 1394, USB, and serial digital still image devices. Support for infrared, parallel, and serial still-image devices—which are connected to standard COM ports—comes from the existing infrared, parallel, and serial interfaces. Image scanners and digital cameras are examples of still image devices. WIA also supports Microsoft DirectShow®-based webcams and digital video (DV) camcorders to capture frames from video.

Windows Image Acquisition Architecture

WIA architecture is both an Application Programming Interface (API) and a Device Driver Interface (DDI). The WIA architecture includes components provided by the software and hardware vendor, as well as by Microsoft. Figure 1 below illustrates the WIA architecture.

Figure 1: The components of WIA architecture.
Figure 1: The components of WIA architecture.

Click here to see full-sized image.

The DLL Fix

I have included all the required references in the source code. You don't need to do this, but if you wish to know how you may read this section.

Reference

You want to add a reference to Microsoft Windows Image Acquisition type library.

Reference2

You also want to add a reference to WiaVideo Type Library. However, after some trouble I read about a bug and its fix that occurs while importing the type library.

Use ILDASM to dump the type library Interop.WIAVIDEOLib.dll, then use Notepad to replace occurrences of valuetype _RemotableHandle& to native int. Then compile the iL dump file you fixed using ILASM in the CMD ilasm /DLL WIAVIDEOLib.il. Add a reference to the new DLL and you are set to go.

The Code

Please keep in mind that the first image you take will initialize the camera. The initialization process takes a few seconds. You may notice the Join(3000) I added when activating the webcam. I added the join in order to avoid exceptions and allow enough time for the camera to do its thing. It was necessary to use the join. I think this delay is because USB protocol is slow or maybe it is just my camera. After the first image is taken, images start flying so fast it is going to look like a live video feed!!

//WebCam.cs
using System;
using System.Collections.Generic;
using System.Text;
using WIALib;
using WIAVIDEOLib;
using System.Runtime.InteropServices;
namespace WebCamLibrary
{
    /// <SUMMARY>
    /// This Class will initialize the camera using Windows Image Acquisition (WIA).
    /// Also, provides methods to view all connected cameras, capture single frame.
    /// </SUMMARY>
    public class WebCam
    {
        private static WebCam WebCamObj;
        /// <SUMMARY>
        ///  variables needed 
        /// </SUMMARY>
        private WIAVIDEOLib.WiaVideo WiaVideoObj;
        private WIALib.Wia WiaObj;
        private WIALib.DeviceInfo DefaultDevice;
        private WIALib.DeviceInfo[] Devices;
        private bool DeviceIsOpen;
        /// <SUMMARY>
        /// Initialize The WebCam Class
        /// </SUMMARY>
        private WebCam()
        {
            DeviceIsOpen = false;
            Initialize();
            SetDefaultDevice();
            OpenDefaultDevice();
        }
        /// <SUMMARY>
        /// Please use this method to create a WebCam Object.
        /// </SUMMARY>
        /// <RETURNS>WebCam Object</RETURNS>
        public static WebCam NewWebCam()
        {
            if (WebCam.WebCamObj == null)
                WebCam.WebCamObj = new WebCam();

            return WebCam.WebCamObj;
        }
        private void Initialize()
        {
            if (this.WiaObj == null)
            {
                this.WiaObj = new WiaClass();
            }
            if (this.WiaVideoObj == null)
            {
                this.WiaVideoObj = new WiaVideoClass();
                this.WiaVideoObj.ImagesDirectory = System.IO.Path.GetTempPath();
            }
        }
        /// <SUMMARY>
        /// Use it to close any open resources.
        /// </SUMMARY>
        public void CloseResources()
        {
            try
            {
                if (WiaObj != null)
                    Marshal.FinalReleaseComObject(WiaObj);
                if (WiaVideoObj != null)
                    Marshal.FinalReleaseComObject(WiaVideoObj);
                if (DefaultDevice != null)
                    Marshal.FinalReleaseComObject(DefaultDevice);
                if (Devices != null)
                    Marshal.FinalReleaseComObject(Devices);

                DeviceIsOpen = false;
                GC.Collect();
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.Message);
            }
        }
        private void SetDefaultDevice()
        {
            CloseDefaultDevice();

            System.Collections.Generic.List<WIALIB.DEVICEINFOCLASS> devs = 
                                        new List<DEVICEINFOCLASS>();
            WIALib.Collection devsCol = 
                            this.WiaObj.Devices as WIALib.CollectionClass;
            foreach (object obj in devsCol)
            {
                WIALib.DeviceInfoClass dev = (WIALib.DeviceInfoClass)
                  System.Runtime.InteropServices.Marshal.CreateWrapperOfType(
                  obj, typeof(WIALib.DeviceInfoClass));
                if (dev.Type.Contains("Video") == true)
                {
                    devs.Add(dev);
                }
                else
                {
                    Marshal.FinalReleaseComObject(obj);
                    Marshal.FinalReleaseComObject(dev);
                }
            }
            Devices = devs.ToArray();
            if (Devices.Length > 0)
            {
                DefaultDevice = Devices[0];
            }
            else
            {
                throw new Exception("No Cameras Detected");
            }

            Marshal.FinalReleaseComObject(devsCol);
            GC.ReRegisterForFinalize(devs);
        }
        /// <SUMMARY>
        /// Get Connected Cameras
        /// </SUMMARY>
        /// <RETURNS>string[] contains names of connected cameras</RETURNS>
        public string[] GetConnectedCameras()
        {
            string[] devs = new string[this.Devices.Length];
            for (int i = 0; i < devs.Length; i++)
            {
                devs[i] = this.Devices[i].Name;
            }
            return devs;
        }
        private void CloseDefaultDevice()
        {
            if (this.DeviceIsOpen == false)
                return;
            try
            {
                if (this.WiaVideoObj != null)
                {
                    this.WiaVideoObj.DestroyVideo();
                    Marshal.FinalReleaseComObject(this.DefaultDevice);
                    DeviceIsOpen = false;
                }
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.Message);
            }
            finally
            {
                DeviceIsOpen = false;
            }
        }
        /// <SUMMARY>
        /// Use this method to set the camera to capture 
        /// from if you have more than one camera.
        /// </SUMMARY>
        /// Name of the camera device.
        /// Get name from GetConnectedCameras() 
        /// <RETURNS></RETURNS>
        public bool SetDefaultDevice(string name)
        {
            CloseDefaultDevice();

            for (int i = 0; i < Devices.Length; i++)
            {
                if (Devices[i].Name.Equals(name))
                {
                    DefaultDevice = Devices[i];
                    return true;
                }
            }
            return false;
        }
        private bool OpenDefaultDevice()
        {
            CloseDefaultDevice();

            try
            {
                this.WiaVideoObj.PreviewVisible = 0;
                this.WiaVideoObj.CreateVideoByWiaDevID(this.DefaultDevice.Id,
                                                       IntPtr.Zero, 0, 0);
                System.Threading.Thread.CurrentThread.Join(3000);
                this.DeviceIsOpen = true;
                this.WiaVideoObj.Play();
                System.Threading.Thread.CurrentThread.Join(3000);
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.Message);
                CloseDefaultDevice();
                return false;
            }

            return true;
        }
        /// <SUMMARY>
        /// Use it to grab a frame. Use System.IO.MemoryStream to load image
        /// </SUMMARY>
        /// <RETURNS>byte array of the captured image</RETURNS>
        public byte[] GrabFrame()
        {
            string imagefile;
            this.WiaVideoObj.TakePicture(out imagefile);
            return ReadImageFile(imagefile);
        }
        private byte[] ReadImageFile(string img)
        {
            System.IO.FileInfo fileInfo = new System.IO.FileInfo(img);
            byte[] buf = new byte[fileInfo.Length];
            System.IO.FileStream fs = new System.IO.FileStream(img, 
                      System.IO.FileMode.Open,System.IO.FileAccess.Read);
            fs.Read(buf, 0, buf.Length);
            fs.Close();
            fileInfo.Delete();
            GC.ReRegisterForFinalize(fileInfo);
            GC.ReRegisterForFinalize(fs);
            return buf;
        }
    }
}
//WebCamService.cs
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;

[WebService(Namespace = "www.codeproject.com")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WebCamService : System.Web.Services.WebService
{
    private WebCamLibrary.WebCam cam;

    public WebCamService()
    {
        //Uncomment the following line if using designed components 
        //InitializeComponent(); 
        cam = WebCamLibrary.WebCam.NewWebCam();      
    }
    [WebMethod]
    public byte[] GrabFrame() {
        return cam.GrabFrame();
    }
    [WebMethod]
    public string[] GetConnectedCameras()
    {
        return cam.GetConnectedCameras();
    } 
}

Future Features

Notes

Fixed article layout

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralHelp!!!
dustinkbaker
6:45 21 Dec '09  
I am trying to run the project, but ran into [System.Net.WebException] = {"Unable to connect to the remote server"}.

All that I need is to connect a webcam to the computer and take pictures with the camera and place them in the picture box. Is this application able to do this?
Generalgrab the frame to disk and read....... not good idea
reborn_zhang
0:54 6 Dec '09  
I found the image was grab to file. and read to client..

is there any possibility that just grab the frame from memory, and directly return to client?

not from clipboard, but directly memory.
GeneralMy vote of 1
criollo0
19:47 2 Dec '09  
code has errors
GeneralMy vote of 1
Priyank Bolia
5:57 13 Nov '09  
Doesn't work
QuestionIt seems many errors there?
satigv
1:11 1 Apr '09  
Here is a great software but there are some errors. Can you please fix and upload again?
GeneralInside a thread
brousse123
3:01 26 Mar '09  
hi! When I try to initialize the camera inside a thread, it gives me this error: Unable to cast COM object of type 'WIAVIDEOLib.WiaVideoClass' to interface type 'WIAVIDEOLib.IWiaVideo'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{D52920AA-DB88-41F0-946C-E00DC0A19CFA}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).

Am I missing something? Everything is working perfectly if I use it from the Form.

Thanks
GeneralRe: Inside a thread
brousse123
9:15 26 Mar '09  
I manage to bypass this problem...

I use the StartCapture() function instead and all I have to do in the thread is read the byte[] returning from the callback function.

Thanks!
QuestionError using the code "unable to connect to remote server"
xicorete
6:56 23 Feb '09  
Hi

I just want to use this code to gram a frame fromn the Webcam and convert it to a Bitmap object.

But when I run this line:

System.IO.MemoryStream st = new System.IO.MemoryStream(WebCam.GrabFrame());

It throws an exception. Unable to connect to remore server

Am i missing something?
GeneralI have Error In This Code
Member 4182278
16:28 27 Jan '09  
I Would to use this code but when i use it i have a error


cannt convert from System.IntPtr.Zero into WiaVideo._something ,, please can u help me in this
im really need this code to my project ,,
GeneralRe: I have Error In This Code
Großvesir
0:22 20 Feb '09  
Did you fixed the DLL as described above?

Otherwise, use the WIAVIDEOLib.dll used in this article.
GeneralUpdate for .Net 2.0+?
williamhix
5:34 21 Jan '09  
On my vs2008 system, the Image Acquistion Type library is now 2.0 and 1.0 does not exist. Any change you can update this with 2.0 library? tia
GeneralInitialize?
Ton_B
12:09 5 Jan '09  
I had the same E_FAIL message, but when I added a call to the "Initialize()" method, it works perfectly. Have I missed something?
GeneralRe: Initialize?
Murlakatamus
8:15 18 Jan '09  
What method call did you add? Confused
GeneralRe: Initialize?
Ton_B
9:39 18 Jan '09  
Well, in the code library there is an Initialize() method that does important things. So, to capture a frame, the minimum code you need is:

	WebCam = WebCamLibrary.WebCam.NewWebCamWIA();
WebCam.Initialize();
MemoryStream st = new MemoryStream(WebCam.GrabFrame());
picture.Image = Image.FromStream(st);

The call to Initialize() is missing in the updated code I downloaded. On retrospect, I can see it in the webcam constructor in the original text of this article. It probably got lost during the refactoring.
Generalhow to configure with iis
amol gathale
3:16 26 Nov '08  
i got the error while configure with iis :Creating an instance of the COM component with CLSID {4EC4272E-2E6F-4EEB-91D0-EBC4D58E8DEE} from the IClassFactory failed due to the following error: 8007000.

Please Help me


Thanks in Advance.
GeneralRe: how to configure with iis
Murlakatamus
7:14 10 Jan '09  
U need to switch off the firewall
GeneralConfused beginner
bambrose
12:52 10 Nov '08  
hi oz,
i am obvioulsy way over my head because i assumed running WebCamServiceSample.exe would produce an image from my webcam, or at least a error of some type. i didn't get either.
i gather from the other posts there is a web server involved. so as you can see i am totally lost.
you mentioned instructions in one of your posts but i didn't see any bundled in when i extracted the files.
any help would be greatly appreciated
thanks,
billy
wambrose@gmail.com
Questioncode in C++ for controlling the maximum number of frames/sec [modified]
stephen_777
11:48 28 Oct '08  
Hi,

The code for capturing the images with webcam is really helped me to proceed my project. Thanks a lot for that code. I am still trying to develop a code that can controll the maximum number of frames/sec from the captured image to get a better image. Could you help me with the sample code in C++ that can meet my requirements. My E-mail address: ricky5118@yahoo.com

Thank you.

modified on Tuesday, October 28, 2008 5:24 PM

QuestionReleasing WebCam Resource :
Ruchit Surati
6:27 30 Sep '08  
Hi,

Thanks for this Great Component.

I'm happily using your lib.

I want to explicitly release the WebCam object and the underlying Camera H/w Resource.

My purpose is to quickly take a picture and release object. I can take the picture but camera is not released till I exit the applicaiton..

How do I do that ? Sample code would help.



Thanks.

Ruchit S.
http://ruchitsurati.net
******************************************

Questionvideo
jajjssddd
22:07 23 Sep '08  
hi
good work
i used this application
but i get one problem while capture image
in the picture box the capture frame show but not like a video
and where these images are stored?
GeneralWIA IN ASP.NET
jmeljurado
10:30 15 Aug '08  
I can use WIA LIBRARY in APS.NET, for scan documents on the client side?

thank you
AnswerWindows Vista 64x
Member 3986991
1:18 18 Jul '08  
Hi,
I've tried to use the code you suggested within a .net 3.5 project running on Windows Vista system but it didn't work.

Can you help me?

Thanks
GeneralRe: Windows Vista 64x
Yifeng Ding
5:27 2 Sep '08  
I have the same problem.
Vista (32) SP1, VS 2008 RTM, .NET 2.0
GeneralError HRESULT E_FAIL
shama3
6:03 6 Jul '08  
Hi,
Takepicture works fine sometimes but then i get this error "Error HRESULT E_FAIL has been returned from a call to a COM component."

I am having a web application. I have been trying to fix this for days..any help in this regard will be great. Thanks!
QuestionRe: Error HRESULT E_FAIL
joshijimit
23:53 9 Feb '10  
Hello,

Have you find the solution related to the problem of "Error HRESULT E_FAIL has been returned from a call to a COM component".
I stucked with the same and desperately needed help from any one.
great


Last Updated 18 Aug 2006 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010