How to replace the paid camera SDK with DirectShow

Keywords: Programming SDK Windows xml encoding

Dynamsoft Barcode SDK includes a powerful barcode scanning Demo, which supports barcode scanning functions such as file reading, scanner image reading, and camera video stream reading.

However, the calling function of scanner and camera is not free. Dynamic. Net Twain is a commercial SDK. This article shares how to remove the scanner function and replace the Webcam calling interface with DirectShow.

Windows Desktop barcode scanning application

After installing the Dynamsoft Barcode Reader, locate the project < Dynamsoft Barcode Reader > \ samples \ desktop \ C ා \ barcodereaderdemo and import it into Visual Studio.

The project depends on DLLs including Dynamsoft.BarcodeReader.dll, Dynamsoft.ImageCore.dll, Dynamsoft.Forms.Viewer.dll, Dynamsoft.Camera.dll, Dynamsoft.PDF.dll, Dynamsoft.Twain.dll.

Code scanning engineering modification

Remove the DLLs that the scanner and camera depend on: Dynamsoft.Camera.dll, Dynamsoft.PDF.dll, Dynamsoft.Twain.dll.

In the App.config file, remove the key ="DNTLicense" value ="LICENSE-KEY":

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key ="DBRLicense" value ="LICENSE-KEY"/>
    <add key ="DNTLicense" value ="LICENSE-KEY"/>
  </appSettings>
</configuration>

Remove the scanner option in BarcodeReaderDemo.cs:

// remove
mRoundedRectanglePanelAcquireLoad.Controls.Add(mThAcquireImage);

Adjust the UI:

// before
mThLoadImage.Size = new Size(103, 40);
mThWebCamImage.Location = new Point(207, 1);
mThWebCamImage.Size = new Size(103, 40);
// after
mThLoadImage.Size = new Size(156, 40);
mThWebCamImage.Location = new Point(157, 1);
mThWebCamImage.Size = new Size(156, 40);

To delete dynamic. Net Twain related codes:

// remove
mTwainManager = new TwainManager(dntLicenseKeys);
mCameraManager = new CameraManager(dntLicenseKeys);
mPDFRasterizer = new PDFRasterizer(dntLicenseKeys);
...

Build project will report relevant errors and delete corresponding codes.

Adjusted interface:

Using DirectShowNet to control Webcam

Create a DSManager.cs logic to control DirectShow.

Two structures are defined to store camera related parameters:

public struct Resolution
{
    public Resolution(int width, int height)
    {
        Width = width;
        Height = height;
    }
 
    public int Width { get; }
    public int Height { get; }
 
    public override string ToString() => $"({Width} x {Height})";
}
 
public struct CameraInfo
{
    public CameraInfo(DsDevice device, List<Resolution> resolutions)
    {
        Device = device;
        Resolutions = resolutions;
    }
 
    public DsDevice Device { get; }
    public List<Resolution> Resolutions { get; }
}

Enumerate all cameras:

DsDevice[] devices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
if (devices != null)
{
    cameras = new List<CameraInfo>();
    foreach (DsDevice device in devices)
    {
        List<Resolution> resolutions = GetAllAvailableResolution(device);
        cameras.Add(new CameraInfo(device, resolutions));
    }
}

Find the resolution of each camera:

private List<Resolution> GetAllAvailableResolution(DsDevice vidDev)
{
    try
    {
        int hr, bitCount = 0;
 
        IBaseFilter sourceFilter = null;
 
        var m_FilterGraph2 = new FilterGraph() as IFilterGraph2;
        hr = m_FilterGraph2.AddSourceFilterForMoniker(vidDev.Mon, null, vidDev.Name, out sourceFilter);
        var pRaw2 = DsFindPin.ByCategory(sourceFilter, PinCategory.Capture, 0);
        var AvailableResolutions = new List<Resolution>();
 
        VideoInfoHeader v = new VideoInfoHeader();
        IEnumMediaTypes mediaTypeEnum;
        hr = pRaw2.EnumMediaTypes(out mediaTypeEnum);
 
        AMMediaType[] mediaTypes = new AMMediaType[1];
        IntPtr fetched = IntPtr.Zero;
        hr = mediaTypeEnum.Next(1, mediaTypes, fetched);
 
        while (fetched != null &amp;&amp; mediaTypes[0] != null)
        {
            Marshal.PtrToStructure(mediaTypes[0].formatPtr, v);
            if (v.BmiHeader.Size != 0 &amp;&amp; v.BmiHeader.BitCount != 0)
            {
                if (v.BmiHeader.BitCount > bitCount)
                {
                    AvailableResolutions.Clear();
                    bitCount = v.BmiHeader.BitCount;
                }
                AvailableResolutions.Add(new Resolution(v.BmiHeader.Width, v.BmiHeader.Height));
            }
            hr = mediaTypeEnum.Next(1, mediaTypes, fetched);
        }
        return AvailableResolutions;
    }
    catch (Exception ex)
    {
        //MessageBox.Show(ex.Message);
        Console.WriteLine(ex.ToString());
        return new List<Resolution>();
    }
}

Bind the camera name and resolution to the UI for display. When the UI index is set, the corresponding event function will be triggered:

private void InitCameraSource()
{
    cbxWebCamSrc.Items.Clear();
    foreach (CameraInfo camera in mDSManager.GetCameras())
    {
        cbxWebCamSrc.Items.Add(camera.Device.Name);
    }
 
    cbxWebCamSrc.SelectedIndex = 0;
}
private void cbxWebCamSrc_SelectedIndexChanged(object sender, EventArgs e)
{
    picBoxWebCam.Visible = true;
    picBoxWebCam.BringToFront();
    EnableControls(picboxReadBarcode);
    EnableControls(pictureBoxCustomize);
 
    InitCameraResolution();
}
private void InitCameraResolution()
{
    cbxWebCamRes.Items.Clear();
    foreach (Resolution resolution in mDSManager.GetCameras()[cbxWebCamSrc.SelectedIndex].Resolutions)
    {
        cbxWebCamRes.Items.Add(resolution.ToString());
    }
 
    cbxWebCamRes.SelectedIndex = 0;
}

Set callback function to receive video frame for barcode recognition:

TaskCompletedCallBack callback = FrameCallback;
private volatile bool isFinished = true;
public void FrameCallback(Bitmap bitmap)
{
    if (isFinished)
    {
        this.BeginInvoke((MethodInvoker)delegate
        {
            isFinished = false;
            ReadFromFrame(bitmap);
            isFinished = true;
        });
}
 
private void ReadFromFrame(Bitmap bitmap)
{
    UpdateRuntimeSettingsWithUISetting();
    TextResult[] textResults = null;
    int timeElapsed = 0;
 
    try
    {
        DateTime beforeRead = DateTime.Now;
 
        textResults = mBarcodeReader.DecodeBitmap(bitmap, "");
 
        DateTime afterRead = DateTime.Now;
        timeElapsed = (int)(afterRead - beforeRead).TotalMilliseconds;
 
        if (textResults == null || textResults.Length <= 0)
        {
            return;
        }
 
        if (textResults != null)
        {
            mDSManager.StopCamera();
            Bitmap tempBitmap = ((Bitmap)(bitmap)).Clone(new Rectangle(0, 0, bitmap.Width, bitmap.Height), bitmap.PixelFormat);
            this.BeginInvoke(mPostShowFrameResults, tempBitmap, textResults, timeElapsed, null);
        }
 
    }
    catch (Exception ex)
    {
        this.Invoke(mPostShowFrameResults, new object[] { bitmap, textResults, timeElapsed, ex });
    }
}

The transformation is completed. The following is the operation effect of the camera scanning function:

Source code

https://github.com/yushulx/dotnet-webcam-barcode-reader

Posted by mmorton on Wed, 08 Apr 2020 01:07:19 -0700