標籤:mat 資料 out group rar turn mvn parse html
??需要實現Python讀取圖片中二維碼、條碼資訊。前段時間研究使用zbarlight模組,費了很大功夫安裝調試好,但是發現有些圖片讀取不正確,而且如果圖片中二維碼傾斜,就讀取不了,不能滿足要求。昨天琢磨著試一試ZXing,下載ZXing模組安裝後,卻一直報錯。開啟模組源碼仔細分析,原來該模組是通過調用java程式,使用ZXing的java庫來實現的,通過分析命令列輸出得到解碼結果。忙活了一天多,各種測試、查資料,終於解決了問題。調試過程非常艱辛,現將做法整理如下(Windows 10系統):
?一、 因為需要調用java程式,必須安裝jdk。
:http://www.oracle.com/technetwork/java/javase/downloads/index.html。
添加JAVA_HOME環境變數,其值設定為jdk安裝目錄。將java運行程式所在目錄(%JAVA_HOME%\bin)添加到PATH。
- 在命令列輸入
java -version
並執行,如果沒有問題則說明安裝成功。
?二、下載ZXing的jar庫檔案,以及所需java庫檔案。
- 下載ZXing Core和ZXing Java SE Extensions庫檔案。
登入網址http://www.mvnrepository.com,在搜尋欄中輸入"zxing"並尋找,就能找到這兩個庫,下載庫檔案並將其分別改名為core.jar和javase.jar。
在測試中,安裝了上面兩個庫以後,仍然報錯,錯誤資訊中提示JCommander模組找不到,後來下載了這個庫檔案,經過多番調試,終於成功。登入網址http://www.mvnrepository.com,在搜尋欄中輸入"jcommander"並尋找,就能找到這個庫,下載庫檔案並將其改名為jcommander.jar。
這個目錄可以建立在java安裝目錄下。我是在java目錄下建了一個名為jar的檔案夾,將上面三個檔案複製到裡面。
添加ZXING_JAR_PATH環境變數,將其值設為上面建立的那個檔案夾的絕對路徑,我的路徑是“d:\java\jar”。
?三、在ZXing原始碼基礎上進行修改,實現二維碼、條碼解碼功能;增加了兩個函數,解決了不支援圖片Windows格式絕對路徑的問題。
#匯入模組import subprocess, re, osclass BarCodeReader(): """ 解碼器類,調用java執行ZXing庫命令實現解碼,通過分析輸出獲得結果。 此模組在ZXing源碼基礎上修改,改動較大。 """ #ZXing庫路徑 location = "" #ZXing庫 libs = ["javase.jar", "core.jar", "jcommander.jar"] #subprocess.Popen參數 args = ["java", "-cp", "LIBS", "com.google.zxing.client.j2se.CommandLineRunner"] def __init__(self, loc=None): """ 初始化函數,參數loc設定ZXing庫所在位置 """ #如果loc為空白或者不是字串對象,讀取環境變數ZXING_JAR_PATH的值(沒找到就設為空白字串) if not loc or not isinstance(loc,str): loc = os.environ.get("ZXING_JAR_PATH", "") #如果loc不為空白,在末尾加上‘\‘,否則設為預設值(即在目前的目錄的zxing子目錄下) if loc: loc = loc.rstrip("\\") + "\\" else: loc = "zxing\\" #設定location self.location = loc def decode(self, files, try_harder = False, qr_only = False): """ 解碼方法,參數files可以是一個檔案名稱(字串),也可以是一個檔案名稱列表。 """ #根據try_harder和qr_only參數設定,添加相應選項 if try_harder: self.args.append("--try_harder") if qr_only: self.args.append("--possibleFormats=QR_CODE") #為ZXing庫加上路徑 libraries = [self.location + lib for lib in self.libs] #產生命令列表 cmd = [ c if c != "LIBS" else os.pathsep.join(libraries) for c in self.args ] #單檔案標誌設為False SINGLE_FILE = False #如果files不是列表,將檔案files添加到cmd列表,單檔案標誌設為True if not isinstance(files, list): cmd.append(files) SINGLE_FILE = True #否則,將檔案清單files添加到cmd列表 else: cmd += files #利用subprocess.Popen函數執行命令 (stdout, stderr) = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True).communicate() #初始化編碼列表 codes = [] #分析輸出內容 file_results = stdout.split("\nfile:") for result in file_results: lines = result.split("\n") if re.search("No barcode found", lines[0]): codes.append(None) else: codes.append(BarCode(result)) #如果是單檔案,返回第一個BarCode對象;否則,返回BarCode對象列表 if SINGLE_FILE: return codes[0] else: return codesclass BarCode: """ BarCode資訊類,包含解碼所得各項資訊。 此模組基本使用了ZXing源碼,為方便使用,添加了幾個屬性。 """ format = "" points = [] data = "" raw = "" def __init__(self, zxing_output): lines = zxing_output.split("\n") raw_block = False parsed_block = False point_block = False self.points = [] for l in lines: m = re.search("format:\s([^,]+)", l) if not raw_block and not parsed_block and not point_block and m: self.format = m.group(1) continue if not raw_block and not parsed_block and not point_block and l == "Raw result:": raw_block = True continue if raw_block and l != "Parsed result:": self.raw += l + "\n" continue if raw_block and l == "Parsed result:": raw_block = False parsed_block = True continue if parsed_block and not re.match("Found\s\d\sresult\spoints", l): self.data += l + "\n" continue if parsed_block and re.match("Found\s\d\sresult\spoints", l): parsed_block = False point_block = True continue if point_block: m = re.search("Point\s(\d+):\s\(([\d\.]+),([\d\.]+)\)", l) if (m): self.points.append((float(m.group(2)), float(m.group(3)))) #去除多餘分行符號 self.raw = self.raw.rstrip("\n") self.data = self.data.rstrip("\n") @property def Format(self): """ 返回編碼格式 """ return self.format @property def Data(self): """ 返回編碼資料 """ return self.data @property def Points(self): """ 返回座標點 """ return self.points @property def RawData(self): """ 返回解碼所得未經處理資料 """ return self.rawdef GetCodeString(filename): """ 解碼函數,只處理單個檔案,參數為檔案名稱(含路徑)。 返回編碼字串,如果未能成功解碼或未找到條碼,返回Null 字元串。 """ #將‘\‘替換成‘/‘ filename = filename.replace("\\", "/") #如果帶有盤符(絕對路徑),前面加上‘file:/‘ if re.match(‘^[A-Za-z]:‘, filename): filename = "file:/" + filename #建立解碼器對象 zxcode = BarCodeReader() #解碼,並將結果儲存到barcode barcode = zxcode.decode(filename) #如果結果為None,返回空串,否則返回編碼字串 if barcode is None: return "" else: return barcode.Datadef GetCodeObject(filename): """ 解碼函數,只處理單個檔案,參數為檔案名稱(含路徑)。 返回編碼對象,其屬性如下: Data,編碼資訊; Format,編碼類別; Points,座標點; RawData,未處理的編碼資訊。 如果未能成功解碼或未找到條碼,返回None """ #將‘\‘替換成‘/‘ filename = filename.replace("\\", "/") #如果帶有盤符(絕對路徑),前面加上‘file:/‘ if re.match(‘^[A-Za-z]:‘, filename): filename = "file:/" + filename #建立解碼器對象 zxcode = BarCodeReader() #解碼,並將結果儲存到barcode barcode = zxcode.decode(filename) #返回結果 return barcode
?四、測試。將上述代碼儲存到zxing.py檔案中,編輯測試代碼如下:
from zxing import GetCodeString,GetCodeObjectresult = GetCodeString("d:\\barcode.png")print(result)result = GetCodeObject("d:\\qr.png")if result: print("Format:", result.Format) print("Data: ", result.Data) print("Points:") for point in result.Points: print(point)
?五、可以將以上面的代碼安裝到Python庫(註冊為
zxing
模組)。
下載python-zxing模組。為https://github.com/oostendo/python-zxing。
解壓縮到python-zxing檔案夾。
將python-zxing\zxing檔案夾內__init__.py檔案的內容替換成第三步的代碼。
在python-zxing檔案夾下開啟命令列,運行python setup.py install
即可。
同樣可以使用第四步的代碼進行測試。
[Python]在Windows系統中使用ZXing模組實現二維碼、條碼讀碼