PDF417 バーコードの生成は、Python の 4 行で行えます。電話の写真、200 DPI のスキャン、または誰かのポケットで一日過ごした搭乗券からそれを読み取ることが、本格的な作業の開始点であり、ほとんどの PDF417 統合が実際に失敗する場所です。この記事では、ソース画像が不完全な場合に Python で PDF417 バーコードを読み取る方法を学びます。生成側をお探しの場合は、以前の Python を使用した PDF417 バーコードの生成 に関するウォークスルーで、基本的およびカスタムの PDF417 シンボルの作成(行と列の制御を含む)について説明しています。また、Python バーコードリーダー ガイド では、さまざまなシンボルに対応した汎用スキャンについて解説しています。以下では、PDF417 認識に関して、より狭く深く掘り下げます。

以下のすべてのスニペットは、Linux 上で Python 3.12 を使用し、Aspose.BarCode for Python via .NET 26.7 に対して実行されました。タイミングと読み取り/ミス結果は測定されたものであり、推定ではありません。また、これらを生成したスクリプトは最後に掲載されているので、独自の画像で再実行できます。

実際にPDF417認識を壊すもの

PDF417 はスタック型シンボリティです。コードワードの行で構成され、各コードワードは 4 本のバーと 4 本のスペースで構成され、17 モジュールにまたがります。この構造は Reed‑Solomon エラー訂正を備えているため、角が破れたりコーヒーのシミがついたりしても通常は復元可能です。復元できないのは、モジュールグリッド自体が失われた場合です。

グリッドを破壊するものは3つあり、実運用で現れる頻度の大まかな順序は次の通りです:

  • 有効モジュール幅が2ピクセル未満になる。これは支配的な失敗です。ダウンスケーリング、カメラ距離、そしてブラーによって起こります。ブラーは1つのモジュールのインクを隣接モジュールに広げます。モジュールあたり3ピクセルで生成されたバーコードをブラー処理すると、実質的にはモジュールあたり1ピクセルのバーコードになります。
  • パースペクティブと回転。角度を付けて撮影されたバーコードは、行がもはや平行な走査線ではなくなります。検出器はこれに対応しますが、最速のプリセットがスキップする検出パスが必要になります。
  • コントラスト崩壊。色あせた熱感紙、グレア下で撮影されたスクリーン、または明るさが固定されたスキャン。以下の数値が示すように、見たほど致命的ではありません。

実際の結果として、認識設定は回復メカニズムであり、キャプチャ品質の代替手段ではありません。画像品質の中間帯域を取り戻すことができますが、下位帯域は取り戻せません。

Python PDF417 リーダーのセットアップ

PyPI からライブラリをインストールします:

pip install aspose-barcode-for-python-via-net

認識 API は aspose.barcode.barcoderecognition にあります。この記事で重要な 2 つのクラスは、検出とデコードを実行する BarCodeReader と、リーダーの試行の厳しさを制御する QualitySettings です。

PythonでPDF417バーコードを読み取る

最小限の実装は2つの引数とループです:

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バーコードを読み取る。

PythonでPDF417バーコードを読み取る。

クリーンな画像の出力:

Code text: PASSENGER|KHAN/M|SEAT14C|LHE-DXB
Symbology: Pdf417
Reading quality: 100.0

実際には第2引数は省略できません。 省略すると BarCodeReader は DecodeType.ALL_SUPPORTED_TYPES にフォールバックし、画像内のすべての候補領域に対して60以上のシンボルを検出します。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 は、知っておくべき4つのプリセットを提供します。リーダーに1つを割り当てるのは1行で済みます:

reader = rec.BarCodeReader("scan.png", rec.DecodeType.PDF417)
reader.quality_settings = rec.QualitySettings.high_quality
プリセット用途コスト
high_performanceクリーンで機械生成された画像最速、リカバリーパスをスキップ
normal_qualityデフォルト。通常のスキャンとエクスポートバランスが取れた
high_qualityカメラ撮影、劣化したスキャン中程度
max_qualityすでに失敗した画像に対する再試行パス圧倒的に遅い

実際にそれらの説明が何を意味するかを確認するため、モジュールあたり 3 ピクセルの PDF417 を生成し、Pillow で 6 通りに劣化させ、すべてのプリセットをすべてのバリアントで実行しました。3 回の実行の中央値:

ソース画像high_performancenormal_qualityhigh_qualitymax_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

この表から得られる4つのことは、個々の数値よりも有用です。

  1. ノイズと低コントラストは、人々が考えているほど問題ではありません。 Reed‑Solomon と検出器は、重いガウスノイズと最速プリセットでの 82% のコントラスト低下を吸収しました。これらの調整はやめてください。

  2. 回転とぼかしは、プリセットを分けるケースです。 これはハンドヘルドの電話撮影の正確なプロファイルでもあり、そのため high_performance はモバイル由来のパイプラインのデフォルトとして間違っています。

  3. max_quality は normal_quality の 3 倍の時間がかかり、追加の読み取りはありません。 それはデフォルトではなく、二度目の試みのパスとして位置づけられます。

  4. モジュールグリッドが失われると、どのプリセットもそれを復元できません。 重いぼかしの行は全体的に失敗であり、max_quality はそれを証明するために 180 ms を費やしました。これはキャプチャの問題であり、キャプチャの修正策は次のとおりです:ピクセル数を増やす、フォーカスを改善する、生成時に x_dimension を大きくする。

PythonでぼやけたPDF417バーコードを読み取るためにQualitySettingsを調整

プリセットは個々のプロパティのバンドルであり、プリセットから開始してそのうちの1つをオーバーライドすることができます。これが、既知で再現可能な欠陥に対して実際の効果が得られる場所です。

上の回転してぼやけた画像は良いデモンストレーションです。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)
Python でぼやけた PDF417 バーコードを読み取るために QualitySettings を調整する。

Python でぼやけた PDF417 バーコードを読み取るために QualitySettings を調整する。

測定結果: オーバーライドなしでは12 msでミス、オーバーライドありでは54 msで読み取りました。1つのプロパティが結果を逆転させましたが、結果は max_quality プリセットよりも速く返ってきました。

知っておくべきプロパティ:

プロパティ値使用する場面
deconvolutionFAST, NORMAL, SLOWモーションブラーやピントが合っていない撮影
barcode_qualityHIGH, NORMAL, LOW印刷欠陥、熱による退色、FAXのアーティファクト
x_dimensionAUTO, SMALL, NORMAL, LARGE, USE_MINIMAL_X_DIMENSION密集したバーコード、または既知の固定モジュールサイズ
minimal_x_dimensionfloatUSE_MINIMAL_X_DIMENSION と組み合わせて下限を設定
complex_backgroundAUTO, DISABLED, ENABLEDアートワークやパターン化されたフォーム上に印刷されたバーコード
inverse_imageAUTO, DISABLED, ENABLED白黒反転のバーコード、スクリーンキャプチャ
allow_incorrect_barcodesbool診断目的のみ、実運用では使用しない

最後のものは警告が必要です。allow_incorrect_barcodes はチェックサム検証に失敗したシンボルを返します。これは「検出器はここで何かを見つけたのか?」という質問に答えるためのデバッグ支援です。これを出荷すると、欠如しているのではなく間違ったデコード文字列が出荷されることになり、単なる見逃しよりもはるかに悪い結果になります。

本番環境でうまく機能する階層化戦略: まず normal_quality を試し、失敗した場合は high_quality と deconvolution = SLOW を使って一度だけ再試行します。高コストのパスは必要な画像に対してのみ支払います。

PythonでPDF417デコード結果を検証する

デコードされた文字列が自動的に正しい文字列になるわけではありません。BarCodeResult の 3 つのフィールドが役立ちます:

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 は、1 つの論理メッセージを複数のシンボルに分割します。これにより、出荷明細書や複数ページの文書に表示されます。セグメント メタデータは往復で保持されるため、再構築は決定的です:

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.

ページ 1.

ページ 2.

ページ 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

実際のキャプチャを50件に対して一度実行すれば、プリセットの議論は終了します。

実用的なガイドライン

  • DecodeType を PDF417 に制限 ただし、混在したシンボリズムが本当に必要な場合を除きます。バリアントが分かっている場合は MACRO_PDF417、COMPACT_PDF417、または MICRO_PDF417 を使用してください。
  • デコード前にトリミング。バーコードが全体の 5% しか占めていない A4 スキャン全体を渡すと、検出時間が無駄になり、誤検出が増えます。
  • 中間ファイルはロスレスで保持。PNG または TIFF を使用してください。低品質設定の JPEG のリングは、デコーダが必要とするバーのエッジを直接攻撃します。
  • リトライを段階的に設定 して、最も遅いプリセットをデフォルトにしないようにします。
  • 認識の調整前に生成を修正。エンコーダを制御できる場合、x_dimension を上げてもコストはかからず、どのリーダー設定よりも多くのミスを解消します。 PDF417 generation article でこれらのパラメータを解説しています。
  • timeout を設定 ユーザー提供画像に触れるすべてのリーダーで。

無料ライセンスを取得する

評価ビルドでは、Code 39 以外のシンボロジーに対してデコードされたテキストに透かしが入ります。これにより、実施するラウンドトリップテストが妨げられます。評価版では、無料の一時ライセンスでこれを解除できます。

無料の追加リソース

結論

Reading PDF417 バーコードを Python で読み取ることは、クリーンな画像では2行の操作で済み、実際の画像ではエンジニアリングの課題です。上記の測定結果はシンプルな姿勢を示しています:DecodeType を指定し、デフォルトは normal_quality、high_quality とデコンボリューションを有効にして一度リトライし、結果を使用する前にすべて検証します。高コストのプリセットはリトライパス用に保存し、すべての設定で画像のクラス全体が失敗する場合は、リーダーではなくキャプチャを修正してください。質問は無料サポートフォーラムで受け付けています。

よくある質問

  1. 同じ PDF417 バーコードがある画像では読み取れ、別の画像では失敗するのはなぜですか?
    認識は、キャプチャ後に各モジュールが占めるピクセル数に依存します。ぼやけ、縮小、JPEG 圧縮はすべて実効モジュール幅を縮小させ、モジュールが約 2 ピクセル未満になると、どのプリセットでも復元できなくなります。

  2. PDF417 に使用すべき認識プリセットはどれですか?
    デフォルトの normal_quality から開始します。カメラ撮影やスキャンの場合は high_quality に切り替え、読み取り速度が数倍遅くなるものの、効果が大きくない max_quality は再試行時にのみ使用してください。

  3. DecodeType を PDF417 に限定すると実際に読み取りが速くなりますか?
    はい。デフォルトは DecodeType.ALL_SUPPORTED_TYPES で、サポートされているすべてのシンボロジーに対して検出器が実行されます。PDF417 を明示的に指定することでその処理が省かれ、他のシンボロジーによる誤検出の可能性もなくなります。

  4. Aspose.BarCode は複数の画像に分割された Macro PDF417 メッセージを読み取れますか?
    はい。各セグメントを DecodeType.MACRO_PDF417 で読み取り、拡張結果の macro_pdf_417_file_id、macro_pdf_417_segment_id、macro_pdf_417_segments_count を使用してペイロードを順番に再構成します。

  5. デコード結果が信頼できるかどうかはどう判断すればよいですか?
    BarCodeResult の reading_quality と confidence を確認し、region の四角形でバーコードが画像内の期待位置に検出されたことを確認します。

  6. 運転免許証や搭乗券の写真から PDF417 を読み取れますか?
    可能です。ただし、撮影がフォーカスされており、バーコードが切り取られていないことが前提です。読み取り前にバーコード領域を切り抜き、途中のファイルは JPEG より PNG を使用することを推奨します。

続きを読む