如何用DirectShow替代付费的摄像头SDK

雨燕双飞 提交于 2020-04-08 17:35:04

Dynamsoft Barcode SDK安装包里自带了一个功能强大的扫码Demo,这个Demo支持的条形码扫描功能包括文件读取,扫描仪图像读取,以及摄像头视频流读取。

在这里插入图片描述

然而扫描仪和摄像头的调用功能并不是免费的,需要用到Dynamic .NET TWAIN这个商用SDK。这篇文章分享下如何去掉扫描仪功能,并把Webcam调用接口替换成DirectShow。

Windows桌面条形码扫描应用

安装Dynamsoft Barcode Reader之后,找到工程<Dynamsoft Barcode Reader>\Samples\Desktop\C#\BarcodeReaderDemo,并导入Visual Studio

这个工程依赖的DLL包括Dynamsoft.BarcodeReader.dll, Dynamsoft.ImageCore.dll,Dynamsoft.Forms.Viewer.dll, Dynamsoft.Camera.dll,Dynamsoft.PDF.dll,Dynamsoft.Twain.dll。

扫码工程修改

去掉扫描仪和摄像头依赖的DLL:Dynamsoft.Camera.dll, Dynamsoft.PDF.dll ,Dynamsoft.Twain.dll。

App.config文件中去掉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>

BarcodeReaderDemo.cs中去掉scanner选项:

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

调整一下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);

删除Dynamic .NET TWAIN相关代码:

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

Build一下工程会报出相关的错误,把对应的代码都删除。

调整后的界面:

在这里插入图片描述

使用DirectShowNet控制Webcam

创建一个DSManager.cs用于控制DirectShow的逻辑。

定义两个结构体存放摄像头相关的参数:

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; }
}

枚举所有的摄像头:

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));
    }
}

查找每个摄像头对应的分辨率:

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>();
    }
}

把摄像头的名字和分辨率绑定到UI上显示。当设置UI索引的时候,对应的事件函数会被触发:

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;
}

设置回调函数用于接收视频帧做条形码识别:

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 });
    }
}

改造完成。以下是摄像头扫码功能的运行效果:

在这里插入图片描述

在这里插入图片描述

源码

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!