Skip to content

secile/UsbCamera

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

65 Commits
 
 
 
 
 
 
 
 

Repository files navigation

UsbCamera

C# source code for using usb camera and web camera in WinForms/WPF.
With only single CSharp source code. No external library required.

How to use

Add UsbCamera.cs to your project.
Following is how to use. see also SampleProject.

// [How to use]
// check USB camera is available.
string[] devices = UsbCamera.FindDevices();
if (devices.Length == 0) return; // no camera.
            
// get video format.
var cameraIndex = 0;
var formats = UsbCamera.GetVideoFormat(cameraIndex);

// select the format you want.
foreach (var item in formats) Console.WriteLine(item);
// for example, video format is like as follows.
// 0:[Video], [MJPG], {Width=1280, Height=720}, 333333, [VideoInfo], ...
// 1:[Video], [MJPG], {Width=320, Height=180}, 333333, [VideoInfo], ...
// 2:[Video], [MJPG], {Width=320, Height=240}, 333333, [VideoInfo], ...
// ...
var format = formats[0];
            
// create instance.
var camera = new UsbCamera(cameraIndex, format);
// this closing event handler make sure that the instance is not subject to garbage collection.
this.FormClosing += (s, ev) => camera.Release(); // release when close.

// show preview on control.
camera.SetPreviewControl(pictureBox1.Handle, pictureBox1.ClientSize);
pictureBox1.Resize += (s, ev) => camera.SetPreviewSize(pictureBox1.ClientSize); // support resize.

// start.
camera.Start();
            
// get image.
// Immediately after starting the USB camera,
// GetBitmap() fails because image buffer is not prepared yet.
var bmp = camera.GetBitmap();

WPF support.

By default, GetBitmap() returns image of System.Drawing.Bitmap.
In WPF, define 'USBCAMERA_WPF' symbol that makes GetBitmap() returns image of BitmapSource.

Get image data as byte array (Experimental)

If 'USBCAMERA_BYTEARRAY' symbol defined, GetBitmap() returns image data as byte array.
This is intended to be used with machine learning.
GetBitmap function returns IEnumerable<byte> as a signature, but it actually returns byte array.
So, please cast it to 'byte[]' before use.

button1.Click += (s, ev) =>
{
    var buf = (byte[])camera.GetBitmap(); // cast to byte[] before use.
    var bmp = BufferToBitmap(buf, camera.Size.Width, camera.Size.Height);
    pictureBox2.Image = bmp;
};

private static Bitmap BufferToBitmap(byte[] buffer, int width, int height)
{
    var result = new Bitmap(width, height);
    var bmpData = result.LockBits(new Rectangle(Point.Empty, result.Size), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
    System.Runtime.InteropServices.Marshal.Copy(buffer, 0, bmpData.Scan0, buffer.Length);
    result.UnlockBits(bmpData);
    return result;
}

Show preview.

There are 3 ways to show preview.

  1. use SetPreviewControl.
    in WinForms, this works light, less GC, and recommended way.
    in WPF, SetPreviewControl requires window handle but WPF control does not have handle. it is recommended to use PictureBox with WindowsFormsHost.
var handle = pictureBox.Handle;
camera.SetPreviewControl(handle, new Size(320, 240));
  1. subscribe PreviewCaptured.
    in WPF with data binding, this is less GC, and recommended way.
camera.PreviewCaptured += (bmp) =>
{
    Preview = bmp;
    OnPropertyChanged("Preview");
};
  1. use Timer and GetBitmap().
    Use this if you modify acquired image and show it. (e.g. face detection.)
    in WinForms, use System.Timers.Timer.
    in WPF, use DispatcherTimer.
var timer = new System.Timers.Timer(1000 / 30) { SynchronizingObject = this };
timer.Elapsed += (s, ev) => pictureBox.Image = camera.GetBitmap();
timer.Start();
this.FormClosing += (s, ev) => timer.Stop();

Note

Allocating bitmap so high frequency, esspecially large bitmap, can lead to exceptions bacause of out-of-memory. Basically, bitmap object is disposed automatically by GC, so it is not occur in normal situation.
In my environment, using VideoFormat that image size is larger than 1920×1080 cause exception. In case of the situation, you have to dispose bitmap by yourself.

var timer = new System.Timers.Timer(1000 / 30) { SynchronizingObject = this };
timer.Elapsed += (s, ev) =>
{
    var oldImage = pictureBox1.Image;
    pictureBox1.Image = camera.GetBitmap();
    oldImage?.Dispose();
};
timer.Start();

Still image capture.

Some cameras can produce a still image separate from the capture stream,
and often the still image is of higher quality than the images produced by the capture stream.
If your camera has a hardware button, your camera might supports still image capture. Push it, or call StillImageTrigger().
When you capture still image, you receive StillImageCaptured call back.

if (camera.StillImageAvailable)
{
    button.Click += (s, ev) => camera.StillImageTrigger();
    camera.StillImageCaptured += bmp => pictureBox.Image = bmp;
}

Adjust Tilt, Zoom, Exposure, Brightness, Contrast, etc...

// adjust properties.
UsbCamera.PropertyItems.Property prop;
prop = camera.Properties[DirectShow.CameraControlProperty.Exposure];
if (prop.Available)
{
    // get current value
    var val = prop.GetValue();
    // set new value
    var min = prop.Min;
    var max = prop.Max;
    var def = prop.Default;
    var step = prop.Step;
    prop.SetValue(DirectShow.CameraControlFlags.Manual, def);
}

prop = camera.Properties[DirectShow.VideoProcAmpProperty.WhiteBalance];
if (prop.Available && prop.CanAuto)
{
    prop.SetValue(DirectShow.CameraControlFlags.Auto, 0);
}

Special Thanks.

This project make use of a part of source code of the project below. Thank you!

Example.

You can make H264 recorder by using UsbCamera and OpenH264Lib.NET and AviWriter(in MotionJPEGWriter).
See README.md in OpenH264Lib.NET.

You can make MotionJPEG movie with audio, see README.md in AudioIO.

About

C# source code for using usb camera and web camera in WinForms/WPF. With only single CSharp source code. No external library required.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages