• Python程序设计实例 | 条形码图片识别


     * 本系列推文案例中,建议Python采用3.10及以上版本,NumPy采用1.22.3及以上版本,Matplotlib采用3.5.1及以上版本,Pandas采用1.4.2及以上版本。Python从3.10这个版本开始,标准发行版本中自带的IDLE交互式环境中输入提示符>>>单独放在左侧,不能随输入语句一起复制。为了清晰区分实例在交互环境中的输入和输出,本系列推文在每个输入语句的开头依然保留输入提示符>>>。

    01、应用实例背景

    有位朋友开了一家淘宝商店,每天都会发出很多快递,并拍照记录,于是就有很多快递单的图片。每晚有个重复性的工作,就是把图片一张张打开,摘录其中条形码的编号,将其保存在Excel中,并把图片的名称改为“条形码编号.jpg”保存,如图1所示。

    ■ 图1 快递单条形码识别

    这位朋友的生意越来越好,所以这个工作量就变得越来越大(每天可能有几百张图片需要识别)。他希望开发一个能自动识别条形码并修改文件名的应用程序。

    图片都是jpg格式的,但快递单因为源自不同的快递公司,所以样子千奇百怪。拍照片的人也不同,所以拍出的照片不一定工整。唯一可以确定的是,每张照片都有条形码,且有良好的清晰度。

    02、条形码识别程序

    该应用的难点在于条形码识别,若从头开发,则工作量太大。我们找到了可以识别条形码和二维码的开源软件zbar(http://zbar.sourceforge.net/,大家当然也可以选择其他软件)。下载、安装后,就可以打开命令行,在软件安装目录的bin下输入zbarimg -h,得到如下结果:

    1. C: work Python barcodes ZBar bin>zbarimg -h
    2. usage: zbarimgoptions] <image >...
    3. scan and decode bar codes from one or more image files
    4. options:
    5. h--help display this help text
    6. --version display version information and exit
    7. -q,-- quiet minimal output,only print decoded symbol data
    8. -V,--verbose increase debug output level
    9. -- verbose=N set specific debug output level
    10. -d,-- display enable display of following images to the screen
    11. -D,--nodisplay disable display of following images (default)
    12. --xml,--nodisplay enable/disable XML output format-- noxm]
    13. -- raw output decoded symbol data without symbology prefix
    14. --S < CONFIG>=< VALUE >],
    15. -set < CONFIG>=< VALUE >],
    16. set decoder/scanner < CONFIG> to < VALUE> (or 1)

     这就说明安装成功了。用手机拍下一本书的ISBN条形码,如图2所示,保存为isbn.jpg。

    ■ 图2 ISBN条形码的图片

    在操作系统的命令行窗口中运行以下代码,即可成功识别出图2所示的条形码所对应的ISBN编号。

    1. EAN-13:9780521865715
    2. C: work Python barcodes ZBar bin>zbarimg isbn.jpg
    3. scanned 1 barcode symbols from 1 images

    识别的关键问题解决了,接着就可以编写GUI界面了,然后通过调用zbar来解决问题。

    03、界面设计

    前期工作准备完毕后,就是正式的软件设计编码了。构思GUI,有以下要求。

    (1) 有一个“打开”按钮,可以选择需要识别的图片;一个导出数据按钮。

    (2) 数据展示窗口,可以以表格的形式呈现。

    (3) 一个多行文本框,用于输出一些调试数据,如错误反馈、无法识别等信息。

    利用wxFormBuilder来设计GUI。在如图3所示的GUI设计界面中,先创建一个Frame窗口。添加一个垂直的BoxSizer,加入一个ToolBar工具条和一个1行2列的GridSizer。在ToolBar工具条中,添加两个Tool按钮,选择合适的图标(source选Load From Art Provider,id选wxART_FILE_OPEN和wxART_FILE_SAVE)。在界面的左下部添加一个DataViewListCtrl用于显示数据,右下部添加一个TextCtrl用于输出调试信息。软件运行结果如图4所示。

     ■ 图3 设计软件界面

     ■ 图4 软件运行结果

    04、完整代码

    程序保存在barcodes.py文件中,全部代码如下:

    1. #-*- coding:utf-8 -*
    2. import wx
    3. import wx.xrc
    4. import wx.dataview
    5. import os
    6. import csv
    7. from datetime import datetime
    8. class MyFramel (wx.Frame):
    9. definit (self,parent) :
    10. wx.Frame.__init__(self,parent,id= wx.ID_ANY,title= u"条形码识别程序"pos = wx.DefaultPosition,size = wx.Size866302)style = WX.DEFAULT FRAME STYLEWX.TAB TRAVERSAL)self.SetSizeHints(wx.DefaultSize,wx.DefaultSize)bSizer5 = wx.BoxSizer(wx.VERTICAL)self.m toolBar2 = wx,ToolBar(self,WX.ID ANY,wx,DefaultPosition,wx.DefaultSize,wX.TB HORIZONTAL)self.m_open = self.m toolBar2.AddTool(wx.ID ANY,u"打开”
    11. wx.ArtProvider.GetBitmap(wx.ART FILE OPEN
    12. WX.ART TOOLBAR),wx.NullBitmap,wX.ITEM NORMAL,
    13. wx.EmptyString,wx.EmptyString,None)
    14. self.m_export = self.m toolBar2.AddTool(wx.ID ANY,u"导出”wX.ArtProvider.GetBitmap(wx.ART FILE SAVEWX.ART TOOLBAR),wX.NullBitmap,wX.ITEM NORMALwx.EmptyString,wx.EmptyString,None)self.m toolBar2.Realize()bSizer5.Add(self.m toolBar20,WX.EXPAND,5)gSizer1 = wx.GridSizer(1200)self.m dvc = wx.dataview.DataViewListCtrl(self,wx.ID ANY
    15. wx.DefaultPosition,wx.DefaultSize,
    16. wx.dataview.DV MULTIPLE wx.dataview.DV ROW LINES)
    17. qSizer1.Add(self.m dvc,0,wx.EXPAND,5)self.m out = wx.TextCtrl(self,wX.ID ANY,wx.EmptyString,
    18. wx.DefaultPosition,wx.DefaultSize,
    19. WX.TE MULTILINE)
    20. 0,WX.EXPAND,5)gSizer1.Add(self.m out,bSizer5.Add(gSizer11,WX.EXPAND,5)
    21. self.SetSizer(bSizer5)
    22. self.Layout(
    23. self.Centre(wx.BOTH)
    24. # Connect Events
    25. self.Bind(wx.EVT_TOOL,self.openimgs,id = self.m open.GetId())self.Bind(wx.EVT TOOL,self.export2csv,id= self.m export.GetId())#Mycode
    26. self.m dvc.AppendTextColumn(u'日期
    27. self.m dvc.AppendTextColumn(u'条形码',width = 120)self.m_dvc.AppendTextColumn(u'文件地址 width = 400)
    28. del (self):def
    29. pass
    30. #Virtual event handlersdef openimgs(self,event)dlg = wx.FileDialog(
    31. self,message =“Choose some images"
    32. defaultDir = os.getcwd()
    33. defaultFile =n
    34. wildcard=wildcard
    35. style = Wx.FD OPENWX.FD MULTIPLE WX.FD CHANGE DIR
    36. if dlq.ShowModal() == wx.ID OK:
    37. self.m out.WriteText( Recognizing!n')paths = dlg.GetPaths()
    38. for path in paths:
    39. tmp = os.popen%s -- raw %s'%(cmd,path)).readlines()barN
    40. while barNum == and i< len(tmp)barNum = tmp[i].strip()
    41. i +=1
    42. if barNum == .
    43. self.m out.WriteText('% s recognize fails! n'% path)continuenewname ='%sss' (os.path.dirname(path),barNum,os.path.splitext(path)[ -1:][0])
    44. try:
    45. os.rename(path,newname)item = [datetime.now().strftime('%Y-%m-%d'),s” barNum,newname]self.m dvc.AppendItem( item)
    46. csvdata.append( item)
    47. self.m out.WriteText( %s Recognize Done! n'% barNumexcept Exception as e:self.m out.WriteText( %s rename fails! n' path)self.m out.WriteText(str(e))
    48. dlg.Destroy()
    49. def export2csv(self,event):
    50. dlg = wx.FileDialog(self,message ="Save file as ...",defaultDir = os.getcwd()defaultFile=wildcard = wildcard2,style = wx.FD SAVE
    51. dlg.SetFilterIndex(2)
    52. if dlg.ShowModal() == wX.ID OK:
    53. self.m out.WriteText(Exporting! n')path = dlg.GetPath()
    54. try:with open(path,w',newline =) as csvfile:writer = csv.writer(csvfile,dialect =excel',quoting = csV.OUOTE ALL)for row in csvdata:writer.writerow(row)
    55. self.m out.WriteText( s Export Done! n' path)except Exception as e:
    56. self.m out.WriteText(str(e))
    57. dlg.Destroy()
    58. wildcard = "Pictures ( *.jpg,*.png)*.jpg;*.png All files (*.*)*.*"
    59. wildcard2 ="CSV files (*.csv) *.csv"
    60. cmd = os.path.realpath('Zbar/bin/zbarimq.exe')
    61. csvdata = []
    62. app= wX.App()
    63. win = MyFramel(None)
    64. win.Show()
    65. app.MainLoop()

    说明: 由于以上代码中的某些行过长,所以在代码的前端加上了数字表示行号。

    注意事项:

    (1) zbar软件安装在上述程序的当前目录下,可以通过Zbar\bin\zbarimg.exe运行。

    (2) 目录中有中文可能会出错。

    (3) 用FileDialog打开文件时会改变当前目录,所以在最初就要保存zbar命令的绝对路径。

    (4) 由于条形码有以0开头的数字,用Excel打开时会自动省略,所以在数字前加了一个“'”符号。

  • 相关阅读:
    Highcharts 条形图:数据可视化的利器
    Webmin -- Backup Configuration Files模块
    全球无人机灯光秀预计2028年将达到7.19亿美元,年复合增长率(CAGR)为21.46%
    腾讯云部署DevOps
    安装部署 Kubernetes 仪表板(Dashboard)
    Golang小数点保留
    【Spring boot 普通类调用 Bean】
    LeetCode C++ 28.实现strStr()
    Linux开发——Linux 文件系统简介(四)
    给定两个单链表,编写算法找出两个单链表的公共结点(暴力解题,优化解题)
  • 原文地址:https://blog.csdn.net/qq_41640218/article/details/132754477