Streaming Webcam Video with Dynamic .NET TWAIN

C# is the preferred programming language for developing Windows applications. However, Microsoft only provides .NET camera APIs for UWP applications. If you plan to write a classic Windows desktop application using a webcam, it will be complicated to create a C/C++ wrapper for DirectShow Win32 APIs. Dynamic .NET TWAIN is an SDK that supports programming for both scanner and webcam. In this article, you will see how easy to build a webcam application with the SDK. In addition, you can learn how to detect and recognize barcodes from the video stream with Dynamsoft Barcode Reader SDK.

This article has been published on CodeProject.

dotnet webcam barcode reader

Using Webcam and Barcode APIs

Webcam Video Viewer

Open Visual Studio to Create a Windows Forms Application.

Install Dynamic .NET TWAIN and Dynamsoft Barcode Reader via NuGet Package Manager:

install sdk via nuget

Initialize DotNet TWAIN object:

private Dynamsoft.DotNet.TWAIN.DynamicDotNetTwain dynamicDotNetTwain = new Dynamsoft.DotNet.TWAIN.DynamicDotNetTwain();
dynamicDotNetTwain.LicenseKeys = "*******";
dynamicDotNetTwain = "dynamicDotNetTwain";
dynamicDotNetTwain.Visible = true;dynamicDotNetTwain.OnFrameCapture += new Dynamsoft.DotNet.TWAIN.Delegate.OnFrameCaptureHandler(this.dynamicDotNetTwain_OnFrameCapture);

The OnFrameCaptureHandler event will be triggered when captured video frames are ready. If you want to do something for the video stream, such as processing image and reading barcode, you can put your code into the function dynamicDotNetTwain_OnFrameCapture.

Use a PictureBox to show the video stream:

dynamicDotNetTwain.SupportedDeviceType = EnumSupportedDeviceType.SDT_WEBCAM;

SetWebCamAsDntSrc(cbxWebCamSrc.Text);

dynamicDotNetTwain.SetVideoContainer(picBoxWebCam);

dynamicDotNetTwain.OpenSource();

dynamicDotNetTwain.IfShowUI = true;

ResizeVideoWindow(0);

picBoxWebCam.Visible = true;

picBoxWebCam.BringToFront();

panelResult.BringToFront();

So far, a simple webcam viewer is done. Let’s take a further step to process the frames.

Barcode Reader

Initialize the barcode reader object:

private readonly BarcodeReader _br = new BarcodeReader { LicenseKeys = "<Put your license key here>" };
Create an event handler for rendering UI:
private delegate void PostShowFrameResultsHandler(Bitmap _bitmap, BarcodeResult[] _bars);
private PostShowFrameResultsHandler _postShowFrameResults = new PostShowFrameResultsHandler(this.postShowFrameResults);
private void postShowFrameResults(Bitmap _bitmap, BarcodeResult[] _bars)
        {
            this.TurnOnWebcam(false);

            if (_bars == null)
                panelResult.Visible = false;
            else
            {
                picBoxWebCam.Image = null;
                rtbBarcodeResult.Text = "Total barcodes: " + _bars.Length + "\n";
               var tempBitmap = new Bitmap(_bitmap.Width, _bitmap.Height);
                using (var g = Graphics.FromImage(tempBitmap))
                {
                    g.DrawImage(_bitmap, 0, 0);
                    foreach (BarcodeResult result in _bars)
                    {
                        g.DrawRectangle(new Pen(Color.FromArgb(255, 0, 0), 2), result.BoundingRect);
                        rtbBarcodeResult.Text += "Barcode Format: " + result.BarcodeFormat + "\n";
                        rtbBarcodeResult.Text += "Barcode Value: " + result.BarcodeText + "\n";
                    }
                }
                picBoxWebCam.Image = tempBitmap;
                panelResult.Location = picBoxWebCam.Location;
                panelResult.Height = 100;
                panelResult.Visible = true;
            }
        }

Get the video frames from the callback function:

        private Bitmap _tmpBitmap = null;
        private void dynamicDotNetTwain_OnFrameCapture(Dynamsoft.DotNet.TWAIN.Interface.OnFrameCaptureEventArgs arg)
        {
            if (_bTurnOnWebcam)
            {
                lock (this)
                {
                    Rectangle rect = new Rectangle(0, 0, arg.Frame.Width, arg.Frame.Height);
                    if (_tmpBitmap == null)
                    {
                        _tmpBitmap = new Bitmap(rect.Width, rect.Height);
                    }
                    CopyTo(arg.Frame, _tmpBitmap, rect);
                }
            }
        }

A function for copying bitmap in C#:

static public void CopyTo(Bitmap srcBitmap, Bitmap Dest, Rectangle section)
        {
            Graphics g = Graphics.FromImage(Dest);
            // Draw the specified section of the source bitmap to the new one
            g.DrawImage(srcBitmap, 0, 0, section, GraphicsUnit.Pixel);
            // Clean up
            g.Dispose();
        }

In case of blocking UI thread, create a worker thread to invoke barcode detection API:

private volatile bool _isThreadRunning = true;
private Thread _dbrThread = new Thread(new ThreadStart(run));
_dbrThread.Start();

public void run()
        {
            while (_tmpBitmap == null)
            {
                Thread.Sleep(30);
                continue;
            }

            Bitmap bitmap = null;
            Rectangle rect = new Rectangle(0, 0, _tmpBitmap.Width, _tmpBitmap.Height);
            while (_isThreadRunning)
            {
                lock (this)
                {
                    if (bitmap == null)
                    {
                        bitmap = new Bitmap(rect.Width, rect.Height);
                    }
                    CopyTo(_tmpBitmap, bitmap, rect);
                }
                ReadFromFrame(bitmap);
            }
        }

Read barcodes and draw returned results:

        private void ReadFromFrame(Bitmap bitmap)
        {
            BarcodeResult[] bars = null;
            try
            {
                bars = _br.DecodeBitmap(bitmap);
                if (bars == null || bars.Length <= 0)
                {
                    return;
                }
                this.BeginInvoke(_postShowFrameResults, new object[] { bitmap, bars });
            }
            catch (Exception ex)
            {
                this.BeginInvoke(_postShowFrameResults, new object[] { bitmap, bars });
                MessageBox.Show(ex.Message);
            }
        }

Connect a USB webcam to your PC.

Build and run the application.

Source Code

https://github.com/dynamsoft-dnt/DotNet-Webcam-Video-Streaming