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
下一篇: C#在WINForm程序中创建XML文件