1. 程式人生 > >winform 掃碼識別二維碼

winform 掃碼識別二維碼

因為公司業務需求,需要在Windows系統下呼叫攝像頭識別二維碼需求,就有了這個功能。

我根據網上網友提供的一些資料,自己整合應用到專案中,效果還不錯(就是感覺畫素不是太好)

現在將呼叫攝像頭+識別二維碼這兩個功能單獨出來寫到這裡,供大家討論和參考。

有什麼不足或者問題大家可以提出來,共同改進共同進步

 

建立一個空的winform專案解決方案,我起名叫他:ScanQRCode

將Form1作為主窗體,設定相關屬性:

  StartPosition:CenterScreen (窗體居中)

  新增一個居中標題:

 1   private void LoadTitleCenterData()
 2  {
 3             string titleMsg ="二維碼識別主介面";
 4             Graphics g = this.CreateGraphics();
 5             Double startingPoint = (this.Width / 2) - (g.MeasureString(titleMsg, this.Font).Width / 2);
 6             Double widthOfASpace = g.MeasureString(" ", this.Font).Width;
 7             String tmp = " ";
 8             Double tmpWidth = 0;
 9 
10             while ((tmpWidth + widthOfASpace) < startingPoint)
11             {
12                 tmp += " ";
13                 tmpWidth += widthOfASpace;
14             }
15             this.Text = tmp + titleMsg;
16  }

最大最小化禁用:

 

1  public Form1()
2 {
3    this.MinimizeBox = false; 
4    this.MaximizeBox = false; 
5    InitializeComponent();
6    LoadTitleCenterData();
7 }

 

 

 

Form1中新增一個TableLayoutPanel,三行三列,比例按照百分比:10%,80%,10%這樣

在TableLayoutPanel的80%中再新增一個TableLayoutPanel,還是行比例:20%,80%這樣(二八定律)

在TableLayoutPanel中新增Panel,在其中手動在新增幾個按鈕和label

最終介面這樣(能看就行):

新增一個二維碼識別介面CameraQR:

使用Nuget新增引用,搜尋AForge,將如下程式包引入:

 

新增一個識別二維碼的窗體,命名名稱為:CameraQR

將VideoSourcePlayer新增到窗體中,Fill顯示:

窗體中定義幾個私有變數:

1 private AForge.Video.DirectShow.FilterInfoCollection _videoDevices;//攝像裝置
2 System.Timers.Timer timer;//定時器
3 CameraHelper _cameraHelper = new CameraHelper();//視屏裝置操作類

 

窗體Load事件中獲取拍照裝置列表,並將第一個裝置作為攝像裝置(如有前後兩個或多個攝像頭,自己去改一下程式碼,設定成可以選擇的,在CameraHelper中的CreateFilterInfoCollection()中):

 1  private void CameraQR_Load(object sender, EventArgs e)
 2 {
 3             // 獲取視訊輸入裝置
 4             _videoDevices = _cameraHelper.CreateFilterInfoCollection();//獲取拍照裝置列表
 5             if (_videoDevices.Count == 0)
 6             {
 7                 MessageBox.Show("無裝置");
 8                 this.Dispose();
 9                 this.Close();
10                 return;
11             }
12             resultStr = "";//二維碼識別字符串清空
13             _cameraHelper.ConnectDevice(videoSourcePlayer1);//連線開啟裝置
14 }

元件初始化完成之後,新增一個定時任務,用來階段性識別攝像裝置中的圖片資源,我寫的是每200毫秒去識別一次,如果圖片中有二維碼,就識別二維碼;識別成功之後,關閉窗體,將識別結果返回給上一個介面,此處需要一個有識別二維碼程式包

使用Nuget新增引用,搜尋ZXing,將如下程式包引入:

 

 

 程式碼如下(核心程式碼基本就這些):

public CameraQR()
{
   this.MinimizeBox = false;
   this.MaximizeBox = false;
   InitializeComponent();
   LoadTitleCenterData();
   CheckForIllegalCrossThreadCalls = false;//多執行緒中訪問窗體控制元件資源不會異常
   AddTimer();//定時識別圖片
}

private void AddTimer()
{
  timer = new System.Timers.Timer();
  timer.Enabled = true;
  timer.Interval = 200;
  timer.Start();
  timer.Elapsed += new ElapsedEventHandler(PicToQRCode);
}


private void PicToQRCode(object sender, ElapsedEventArgs e) { if (_cameraHelper.img == null) return; BinaryBitmap bitmap = null; try { MemoryStream ms = new MemoryStream(); _cameraHelper.img.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp); byte[] bt = ms.GetBuffer(); ms.Close(); LuminanceSource source = new RGBLuminanceSource(bt, _cameraHelper.img.Width, _cameraHelper.img.Height); bitmap = new BinaryBitmap(new ZXing.Common.HybridBinarizer(source)); } catch (Exception ex) { return; } Result result=null; try { //開始解碼 result = new MultiFormatReader().decode(bitmap); } catch (ReaderException ex) { resultStr = ex.ToString(); } if (result != null) { resultStr = result.Text; this.DialogResult = DialogResult.OK; this.Close(); }
}

窗體關閉時,記得釋放定時器 關閉攝像頭(不然異常滿天飛):

private void CameraQR_FormClosing(object sender, FormClosingEventArgs e)
{
      if (timer != null)
      {
          timer.Dispose();
      }
       _cameraHelper.CloseDevice();
 }

CameraHelper類:

 1 public class CameraHelper
 2 {
 3     public FilterInfoCollection _videoDevices;//本機攝像硬體裝置列表
 4     public VideoSourcePlayer _videoSourcePlayer;//視訊畫布
 5     public Bitmap img = null;//全域性變數,儲存每一次捕獲的影象
 6     public System.Drawing.Image CaptureImage(VideoSourcePlayer sourcePlayer = null)
 7     {
 8 
 9         if (sourcePlayer == null || sourcePlayer.VideoSource == null)
10         {
11             if (_videoSourcePlayer == null)
12                 return null;
13             else
14             {
15                 sourcePlayer = _videoSourcePlayer;
16             }
17         }
18 
19         try
20         {
21             if (sourcePlayer.IsRunning)
22             {
23                 System.Drawing.Image bitmap = sourcePlayer.GetCurrentVideoFrame();
24                 return bitmap;
25             }
26             return null;
27 
28         }
29         catch (Exception ex)
30         {
31             return null;
32         }
33     }
34 
35     public FilterInfoCollection CreateFilterInfoCollection()
36     {
37         if (_videoDevices != null)
38             return _videoDevices;
39         _videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
40         return _videoDevices;
41     }
42 
43     public VideoCaptureDevice ConnectDevice(VideoSourcePlayer videoSourcePlayer, FilterInfo filterInfo = null)
44     {
45         VideoCaptureDevice videoSource = new VideoCaptureDevice();
46         if (filterInfo == null)
47         {
48             videoSource = new VideoCaptureDevice(_videoDevices[_videoDevices.Count - 1].MonikerString);
49         }
50         else
51         {
52             videoSource = new VideoCaptureDevice(filterInfo.MonikerString);
53         }
54 
55         videoSource.NewFrame += new NewFrameEventHandler(video_NewFrame);
56         videoSourcePlayer.VideoSource = videoSource;
57         videoSourcePlayer.Start();
58         _videoSourcePlayer = videoSourcePlayer;
59         return videoSource;
60     }
61 
62     private void video_NewFrame(object sender, NewFrameEventArgs eventArgs)
63     {
64         img = (Bitmap)eventArgs.Frame.Clone();
65     }
66 
67     public void CloseDevice(VideoSourcePlayer videoSourcePlayer = null)
68     {
69         if (videoSourcePlayer == null)
70         {
71             if (_videoSourcePlayer == null)
72                 return;
73             _videoSourcePlayer.SignalToStop();
74         }
75         else
76         {
77             videoSourcePlayer.SignalToStop();
78         }
79     }
80 }

我用的測試二維碼是:

最終的別結果為:

 

 

 程式碼:https://github.com/Binzm/ScanQRCode.git