生成 PDF417 條碼只需要四行 Python 程式碼。從手機照片、200 DPI 掃描件,或是已在口袋中放置一天的登機證中讀取條碼,才是真正的挑戰,也是大多數 PDF417 整合實際失敗的地方。在本文中,您將學習在來源影像不完美的情況下,如何使用 Python 讀取 PDF417 條碼。如果您想了解生成方面,之前的教學「使用 Python 生成 PDF417 條碼」涵蓋了建立基本和自訂 PDF417 符號,包括行列控制,而「Python 條碼閱讀器指南」則介紹了跨符號的通用掃描。本節將深入且聚焦於 PDF417 識別。
以下每個程式碼片段皆在 Linux 上使用 Python 3.12,針對 Aspose.BarCode for Python via .NET 26.7 執行。計時與讀取/遺失結果為實測值,而非估計值,產生這些結果的腳本位於最後,您可以自行在自己的圖像上重新執行。
實際上會破壞 PDF417 識別的因素
PDF417 是一種堆疊式符號:由多行代碼字組成,每個代碼字由四條條形和四個空白組成,跨越 17 個模組。此結構包含 Reed‑Solomon 錯誤更正,因此撕裂的角落或咖啡污漬通常仍能被讀取。無法容忍的是失去模組格線本身。
有三件事會破壞網格,按它們在生產環境中出現頻率的大致順序排列:
- 有效模組寬度低於兩像素。 這是主要的失敗原因。它會因縮小、相機距離以及模糊而發生,模糊會將一個模組的墨水擴散到相鄰模組。以每模組三像素生成的條碼再經過模糊,實際上相當於每模組一像素的條碼。
- 透視與旋轉。 以角度拍攝的條碼,其行不再是平行的掃描線。偵測器能處理此情況,但會增加一次偵測過程,而最快的預設會跳過此步驟。
- 對比度崩潰。 已褪色的熱感紙、在眩光下拍攝的螢幕,或亮度被固定的掃描。其致命程度不如看起來那麼嚴重,正如下方數據所示。
實際的結果是,識別設定是一種恢復機制,而不是取代捕獲品質的方案。它們可以挽回中等層次的影像品質,但無法挽回底層的品質。
設定 Python PDF417 閱讀器
從 PyPI 安裝庫:
pip install aspose-barcode-for-python-via-net
辨識 API 位於 aspose.barcode.barcoderecognition。本文涉及兩個類別:BarCodeReader,負責驅動偵測與解碼;以及 QualitySettings,控制讀取器的嘗試力度。
在 Python 中讀取 PDF417 條碼
最小可行的讀取是兩個參數和一個迴圈:
from aspose.barcode import barcoderecognition as rec
reader = rec.BarCodeReader("clean.png", rec.DecodeType.PDF417)
for result in reader.read_bar_codes():
print("Code text:", result.code_text)
print("Symbology:", result.code_type_name)
print("Reading quality:", result.reading_quality)

在 Python 中讀取 PDF417 條碼。
在乾淨圖像上的輸出:
Code text: PASSENGER|KHAN/M|SEAT14C|LHE-DXB
Symbology: Pdf417
Reading quality: 100.0
在實務上,第二個參數不是可選的。 如果省略它,BarCodeReader 會回退到 DecodeType.ALL_SUPPORTED_TYPES,它會對圖像中的每個候選區域執行超過六十種條碼符號的檢測。在僅使用 PDF417 的管線中,這純屬浪費,且會在 PDF417 行結構內引發線性條碼的偽陽性。請命名此類型。
如果您的輸入是從上傳的位元組而不是磁碟上的檔案傳入,請傳遞一個串流並設定逾時,以防止異常圖像卡住工作執行緒:
import io
from aspose.barcode import barcoderecognition as rec
def decode_pdf417(image_bytes, timeout_ms=2000):
reader = rec.BarCodeReader(io.BytesIO(image_bytes), rec.DecodeType.PDF417)
reader.timeout = timeout_ms
return [r.code_text for r in reader.read_bar_codes()]
比較 Python 中的 PDF417 識別品質設定
QualitySettings 提供四個值得了解的預設。將其中一個指派給讀取器只需一行:
reader = rec.BarCodeReader("scan.png", rec.DecodeType.PDF417)
reader.quality_settings = rec.QualitySettings.high_quality
| 預設 | 用途 | 成本 |
|---|---|---|
high_performance | 乾淨、機器生成的圖像 | 最快,跳過恢復傳遞 |
normal_quality | 預設。常規掃描與匯出 | 平衡 |
high_quality | 相機拍攝,品質下降的掃描 | 中等 |
max_quality | 對已失敗的圖像重新嘗試傳遞 | 最慢,差距甚大 |
為了了解這些描述在實際中的含義,我以每模組三像素的解析度生成了一個 PDF417,使用 Pillow 以六種方式降級,並對每個變體運行所有預設。三次執行的中位數:
| Source image | high_performance | normal_quality | high_quality | max_quality |
|---|---|---|---|---|
| 乾淨 | 讀取, 35 ms | 讀取, 50 ms | 讀取, 45 ms | 讀取, 106 ms |
| 旋轉 12°,模糊 | 未命中, 15 ms | 讀取, 74 ms | 讀取, 67 ms | 讀取, 157 ms |
| 高斯噪聲 (σ 40) | 讀取, 31 ms | 讀取, 49 ms | 讀取, 52 ms | 讀取, 123 ms |
| 半解析度 | 讀取, 22 ms | 讀取, 37 ms | 讀取, 35 ms | 讀取, 86 ms |
| 低對比度 | 讀取, 24 ms | 讀取, 38 ms | 讀取, 43 ms | 讀取, 112 ms |
| 強模糊 (σ 2.2) | 未命中, 5 ms | 未命中, 25 ms | 未命中, 85 ms | 未命中, 180 ms |
從此表格中可以得出四件事,它們比單個數字更有用:
- 噪聲與低對比度並非人們所想的問題。 Reed‑Solomon 加上偵測器吸收了大量高斯噪聲,且在最快的預設下對比度下降了 82%。不要再為此調整。
- 旋轉加模糊是區分預設的情況。 它也是手持手機拍攝的精確情況,這就是為什麼
high_performance對任何來自行動裝置的流程都是錯誤的預設值。 max_quality耗時是normal_quality的三倍,且沒有額外的讀取。 它應作為第二次嘗試的路徑,而非預設。- 一旦模組網格消失,沒有任何預設能恢復它。 整體而言,重度模糊行都是失敗,而
max_quality花了 180 毫秒證明了這點。這是拍攝問題,需要透過拍攝解決:更多像素、更好的對焦、在生成時使用更大的x_dimension。
調整 QualitySettings 以讀取模糊的 PDF417 條碼(Python)
預設是一組單獨的屬性,您可以從預設開始並覆寫其中一個。這正是已知且可重複的缺陷中實際收益所在。
上方旋轉且模糊的圖像是一個很好的示例。 在 high_performance 下它會遺漏。 在相同的預設上啟用去卷積,結果如下:
from aspose.barcode import barcoderecognition as rec
reader = rec.BarCodeReader("rotated.png", rec.DecodeType.PDF417)
quality = rec.QualitySettings.high_performance
quality.deconvolution = rec.DeconvolutionMode.NORMAL
reader.quality_settings = quality
for result in reader.read_bar_codes():
print(result.code_text)

調整 QualitySettings 以在 Python 中讀取模糊的 PDF417 條碼。
測量結果:未使用覆寫時在 12 毫秒內未命中,使用覆寫時在 54 毫秒內讀取。僅有一個屬性改變了結果,且結果仍比 max_quality 預設值更快返回。
值得了解的屬性:
| 屬性 | 值 | 何時使用 |
|---|---|---|
deconvolution | FAST, NORMAL, SLOW | 動態模糊和失焦的影像 |
barcode_quality | HIGH, NORMAL, LOW | 列印缺陷、熱衰減、傳真雜訊 |
x_dimension | AUTO, SMALL, NORMAL, LARGE, USE_MINIMAL_X_DIMENSION | 密集條碼,或已知的固定模組尺寸 |
minimal_x_dimension | float | 與 USE_MINIMAL_X_DIMENSION 搭配使用以設定下限 |
complex_background | AUTO, DISABLED, ENABLED | 條碼印在藝術作品或圖案表單上 |
inverse_image | AUTO, DISABLED, ENABLED | 白底黑條碼、螢幕截圖 |
allow_incorrect_barcodes | bool | 僅用於診斷,絕不在生產環境使用 |
最後那個值得警告。 allow_incorrect_barcodes 會返回未通過校驗和驗證的符號。它是一個除錯輔助,用於回答「偵測器真的在這裡找到什麼嗎?」。將其發布意味著發布錯誤的已解碼字串,而不是缺失,這比漏檢更糟。
在生產環境中效果良好的分層策略:首先嘗試 normal_quality,若未命中則重新嘗試一次使用 high_quality 並加上 deconvolution = SLOW。只有在需要時才走昂貴的路徑。
驗證 PDF417 解碼結果(Python)
解碼後的字串並不一定正確。BarCodeResult 上的三個欄位可以協助:
for result in reader.read_bar_codes():
print("Text:", result.code_text)
print("Reading quality:", result.reading_quality)
print("Confidence:", result.confidence)
print("Region:", [(p.x, p.y) for p in result.region.points])
Text: PASSENGER|KHAN/M|SEAT14C|LHE-DXB
Reading quality: 100.0
Confidence: 100
Region: [(7, 6), (261, 7), (261, 276), (7, 277)]
重新組合跨圖像分割的宏 PDF417
Macro PDF417 將單一邏輯訊息分割成多個符號,這在裝運清單和多頁文件中會出現。段元資料在往返過程中得以保留,因此重新組合是確定性的:
from aspose.barcode import barcoderecognition as rec
segments = {}
total = None
for path in ["page1.png", "page2.png"]:
reader = rec.BarCodeReader(path, rec.DecodeType.MACRO_PDF417)
for result in reader.read_bar_codes():
meta = result.extended.pdf417
segments[meta.macro_pdf_417_segment_id] = result.code_text
total = meta.macro_pdf_417_segments_count
print(f"{path}: segment {meta.macro_pdf_417_segment_id + 1} of {total}, "
f"file id {meta.macro_pdf_417_file_id}")
if total and len(segments) == total:
payload = "".join(segments[i] for i in sorted(segments))
print("Reassembled:", payload)
else:
print("Incomplete: missing segments")

第 1 頁。

第 2 頁。
Output:
Data\pdf417\page1.png: segment 1 of 2, file id 42
Data\pdf417\page2.png: segment 2 of 2, file id 42
Reassembled: SEGMENT-A-DATASEGMENT-B-DATA
請注意,
macro_pdf_417_file_id在生成和識別兩端都是整數,而不是字串。當編碼器填充它們時,同一物件還會公開macro_pdf_417_file_name、macro_pdf_417_sender、macro_pdf_417_addressee、macro_pdf_417_time_stamp和macro_pdf_417_checksum。
在您自己的圖像上對 PDF417 識別進行基準測試
預設選擇應該是一種測量,而不是猜測。將其指向實際管道中具代表性的捕獲資料夾,它會告訴您哪個預設值得其成本:
import time, statistics, pathlib
from aspose.barcode import barcoderecognition as rec
PRESETS = ["high_performance", "normal_quality", "high_quality", "max_quality"]
def probe(path, preset, reps=3):
times, found = [], False
for _ in range(reps):
reader = rec.BarCodeReader(str(path), rec.DecodeType.PDF417)
reader.quality_settings = getattr(rec.QualitySettings, preset)
start = time.perf_counter()
results = list(reader.read_bar_codes())
times.append((time.perf_counter() - start) * 1000)
found = found or bool(results)
return found, statistics.median(times)
for image in sorted(pathlib.Path("samples").glob("*.png")):
row = []
for preset in PRESETS:
found, ms = probe(image, preset)
row.append(f"{preset}: {'read' if found else 'miss'} {ms:.0f}ms")
print(f"{image.name:28} " + " | ".join(row))
clean.png high_performance: read 32ms | normal_quality: read 48ms | high_quality: read 51ms | max_quality: read 130ms
faded_thermal.png high_performance: read 26ms | normal_quality: read 43ms | high_quality: read 46ms | max_quality: read 144ms
half_resolution.png high_performance: read 27ms | normal_quality: read 41ms | high_quality: read 41ms | max_quality: read 89ms
heavy_blur.png high_performance: miss 7ms | normal_quality: miss 24ms | high_quality: miss 69ms | max_quality: miss 180ms
noisy_scan.png high_performance: read 26ms | normal_quality: read 42ms | high_quality: read 47ms | max_quality: read 116ms
Page1.png high_performance: read 21ms | normal_quality: read 34ms | high_quality: read 38ms | max_quality: read 90ms
Page2.png high_performance: read 21ms | normal_quality: read 33ms | high_quality: read 38ms | max_quality: read 89ms
rotated.png high_performance: miss 16ms | normal_quality: read 43ms | high_quality: read 57ms | max_quality: read 147ms
只需執行一次,對五十個真實捕獲進行測試,預設的爭論就結束了。
實用指南
- 將
DecodeType限制為PDF417,除非您真的預期混合符號。當您知道變體時,使用MACRO_PDF417、COMPACT_PDF417或MICRO_PDF417。 - 在解碼前先裁剪。 當條碼僅佔掃描圖像的 5% 時,傳遞整張 A4 掃描會浪費偵測時間並增加偽陽性。
- 保持中間檔案無損。 使用 PNG 或 TIFF。低品質設定的 JPEG 會在條碼邊緣產生環狀失真,影響解碼器。
- 分層設定重試次數,而不是預設使用最慢的預設值。
- 在調整辨識之前先修正產生方式。 如果您能控制編碼器,提升
x_dimension不會增加成本,且能解決比任何讀取器設定更多的錯過。此PDF417 產生文章 介紹了這些參數。 - 在任何處理使用者提供圖像的讀取器上設定
timeout。
取得免費授權
評估版會在除 Code 39 之外的條碼符號上添加水印,解碼的文字會受到影響,這會干擾您執行的任何往返測試。使用 免費臨時許可證 可在評估期間移除該水印。
免費額外資源
結論
在 Python 中讀取 PDF417 條碼在乾淨的圖像上只需兩行操作,而在真實圖像上則是一個工程問題。上述測量指向一個簡單的姿態:為你的 DecodeType 命名,預設為 normal_quality,在啟用去卷積的情況下再嘗試一次 high_quality,並在採取行動前驗證每個結果。將昂貴的預設保留給重試路徑,當整類圖像在所有設定下都失敗時,修復捕獲而不是讀取器。歡迎在 免費支援論壇 提問。
常見問題
為什麼相同的 PDF417 條碼在一張圖片中能讀取,而在另一張圖片中失敗?
識別取決於捕獲後每個模組佔據的像素數量。模糊、縮小以及 JPEG 壓縮都會縮小實際模組寬度,一旦模組降至大約兩個乾淨像素以下,任何預設都無法恢復。我應該使用哪個 PDF417 識別預設?
從normal_quality(預設)開始。對於相機拍攝和掃描,切換到high_quality,而將max_quality留作重試使用,因為它速度慢數倍,卻只能稍微提升讀取率。將 DecodeType 限制為 PDF417 真能加快讀取速度嗎?
會。預設值是DecodeType.ALL_SUPPORTED_TYPES,會對所有支援的符號執行偵測。明確指定 PDF417 可省去這些工作,同時也避免了來自其他符號的誤判。Aspose.BarCode 能讀取跨多張圖片的 Macro PDF417 訊息嗎?
能。使用DecodeType.MACRO_PDF417讀取每個段,並在擴充結果中使用macro_pdf_417_file_id、macro_pdf_417_segment_id與macro_pdf_417_segments_count依序重組有效負載。我如何判斷解碼結果是否可信?
檢查BarCodeResult上的reading_quality與confidence,並利用region四邊形確認條碼在影像中出現在預期的位置。它能從駕照或登機證的照片中讀取 PDF417 嗎?
能,只要拍攝對焦且條碼未被裁切。讀取前先裁切至條碼區域,且在中間檔案上建議使用 PNG 而非 JPEG。
