前言
因公司業(yè)務(wù)需求,需要在Windows系統(tǒng)下調(diào)用攝像頭識(shí)別二維碼需求,就有了這個(gè)功能。根據(jù)網(wǎng)上網(wǎng)友提供的一些資料,自己整合應(yīng)用到項(xiàng)目中,效果還不錯(cuò)(就是感覺(jué)像素不是太好)。現(xiàn)在將調(diào)用攝像頭+識(shí)別二維碼這兩個(gè)功能單獨(dú)出來(lái)寫(xiě)到這里,供大家討論和參考。
有什么不足或者問(wèn)題大家可以提出來(lái),共同改進(jìn)共同進(jìn)步。
一、創(chuàng)建項(xiàng)目解決方案
1、創(chuàng)建一個(gè)空的Winform項(xiàng)目解決方案,我起名叫他:ScanQRCode
2、將Form1作為主窗體,設(shè)置相關(guān)屬性:
private void LoadTitleCenterData()
{
string titleMsg ="二維碼識(shí)別主界面";
Graphics g = this.createGraphics();
Double startingPoint = (this.Width / 2) - (g.MeasureString(titleMsg, this.Font).Width / 2);
Double widthOfASpace = g.MeasureString(" ", this.Font).Width;
String tmp = " ";
Double tmpWidth = 0;
while ((tmpWidth + widthOfASpace) < startingPoint)
{
tmp += " ";
tmpWidth += widthOfASpace;
}
this.Text = tmp + titleMsg;
}
public Form1()
{
this.MinimizeBox = false;
this.MaximizeBox = false;
InitializeComponent();
LoadTitleCenterData();
}
Form1中添加一個(gè)TableLayoutPanel,三行三列,比例按照百分比:10%,80%,10%。
在TableLayoutPanel的80%中再添加一個(gè)TableLayoutPanel,還是行比例:20%,80%這樣(二八定律)。
在TableLayoutPanel中添加Panel,在其中手動(dòng)在添加幾個(gè)按鈕和label。
最終界面這樣(能看就行):

二、添加一個(gè)二維碼識(shí)別界面CameraQR
使用Nuget添加引用,搜索AForge,將如下程序包引入:

添加一個(gè)識(shí)別二維碼的窗體,命名名稱(chēng)為:CameraQR
將VideoSourcePlayer添加到窗體中,F(xiàn)ill顯示:

窗體中定義幾個(gè)私有變量:
private AForge.Video.DirectShow.FilterInfoCollection _videoDevices;//攝像設(shè)備
System.Timers.Timer timer;//定時(shí)器
CameraHelper _cameraHelper = new CameraHelper();//視屏設(shè)備操作類(lèi)
窗體Load事件中獲取拍照設(shè)備列表,并將第一個(gè)設(shè)備作為攝像設(shè)備(如有前后兩個(gè)或多個(gè)攝像頭,自己去改一下代碼,設(shè)置成可以選擇的,在CameraHelper中的createFilterInfoCollection()中):
private void CameraQR_Load(object sender, EventArgs e)
{
// 獲取視頻輸入設(shè)備
_videoDevices = _cameraHelper.createFilterInfoCollection();//獲取拍照設(shè)備列表
if (_videoDevices.Count == 0)
{
MessageBox.Show("無(wú)設(shè)備");
this.Dispose();
this.Close();
return;
}
resultStr = "";//二維碼識(shí)別字符串清空
_cameraHelper.ConnectDevice(videoSourcePlayer1);//連接打開(kāi)設(shè)備
}
組件初始化完成之后,添加一個(gè)定時(shí)任務(wù),用來(lái)階段性識(shí)別攝像設(shè)備中的圖片資源,我寫(xiě)的是每200毫秒去識(shí)別一次,如果圖片中有二維碼,就識(shí)別二維碼;識(shí)別成功之后,關(guān)閉窗體,將識(shí)別結(jié)果返回給上一個(gè)界面,此處需要一個(gè)有識(shí)別二維碼程序包。
使用Nuget添加引用,搜索ZXing,將如下程序包引入:

代碼如下(核心代碼基本就這些):
public CameraQR()
{
this.MinimizeBox = false;
this.MaximizeBox = false;
InitializeComponent();
LoadTitleCenterData();
CheckForIllegalCrossThreadCalls = false;//多線(xiàn)程中訪問(wèn)窗體控件資源不會(huì)異常
AddTimer();//定時(shí)識(shí)別圖片
}
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
{
//開(kāi)始解碼
result = new MultiFormatReader().decode(bitmap);
}
catch (ReaderException ex)
{
resultStr = ex.ToString();
}
if (result != null)
{
resultStr = result.Text;
this.DialogResult = DialogResult.OK;
this.Close();
}
}
窗體關(guān)閉時(shí),記得釋放定時(shí)器 關(guān)閉攝像頭(不然異常滿(mǎn)天飛):
private void CameraQR_FormClosing(object sender, FormClosingEventArgs e)
{
if (timer != null)
{
timer.Dispose();
}
_cameraHelper.CloseDevice();
}
CameraHelper類(lèi):
public class CameraHelper
{
public FilterInfoCollection _videoDevices;//本機(jī)攝像硬件設(shè)備列表
public VideoSourcePlayer _videoSourcePlayer;//視頻畫(huà)布
public Bitmap img = null;//全局變量,保存每一次捕獲的圖像
public System.Drawing.Image CaptureImage(VideoSourcePlayer sourcePlayer = null)
{
if (sourcePlayer == null || sourcePlayer.VideoSource == null)
{
if (_videoSourcePlayer == null)
return null;
else
{
sourcePlayer = _videoSourcePlayer;
}
}
try
{
if (sourcePlayer.IsRunning)
{
System.Drawing.Image bitmap = sourcePlayer.GetCurrentVideoFrame();
return bitmap;
}
return null;
}
catch (Exception ex)
{
return null;
}
}
public FilterInfoCollection createFilterInfoCollection()
{
if (_videoDevices != null)
return _videoDevices;
_videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
return _videoDevices;
}
public VideoCaptureDevice ConnectDevice(VideoSourcePlayer videoSourcePlayer, FilterInfo filterInfo = null)
{
VideoCaptureDevice videoSource = new VideoCaptureDevice();
if (filterInfo == null)
{
videoSource = new VideoCaptureDevice(_videoDevices[_videoDevices.Count - 1].MonikerString);
}
else
{
videoSource = new VideoCaptureDevice(filterInfo.MonikerString);
}
videoSource.NewFrame += new NewFrameEventHandler(video_NewFrame);
videoSourcePlayer.VideoSource = videoSource;
videoSourcePlayer.Start();
_videoSourcePlayer = videoSourcePlayer;
return videoSource;
}
private void video_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
img = (Bitmap)eventArgs.Frame.Clone();
}
public void CloseDevice(VideoSourcePlayer videoSourcePlayer = null)
{
if (videoSourcePlayer == null)
{
if (_videoSourcePlayer == null)
return;
_videoSourcePlayer.SignalToStop();
}
else
{
videoSourcePlayer.SignalToStop();
}
}
}
我用的測(cè)試二維碼是:

最終的別結(jié)果為:

代碼:https://github.com/Binzm/ScanQRCode.git
- EOF -
該文章在 2023/7/28 15:53:43 編輯過(guò)