Generare un codice a barre PDF417 richiede quattro righe di Python. Leggerne uno da una foto scattata con il telefono, da una scansione a 200 DPI o da una carta d’imbarco che ha trascorso una giornata in tasca a qualcuno è dove inizia il vero lavoro, ed è dove la maggior parte delle integrazioni PDF417 fallisce realmente. In questo articolo imparerai come leggere i codici a barre PDF417 in Python quando l’immagine di origine è imperfetta. Se invece sei interessato alla parte di generazione, la guida precedente su come generare PDF417 barcodes using Python copre la creazione di simboli PDF417 di base e personalizzati, inclusi il controllo di righe e colonne, e la Python barcode reader guide tratta la scansione di uso generale su diverse simbologie. Quello che segue qui è un approfondimento specifico e dettagliato sul riconoscimento PDF417.

Ogni frammento qui sotto è stato eseguito con Aspose.BarCode for Python via .NET 26.7 su Linux con Python 3.12. I tempi e i risultati di lettura/mancata lettura sono misurati, non stimati, e lo script che li ha generati è alla fine così puoi rieseguirlo sulle tue immagini.

Cosa rompe effettivamente il riconoscimento PDF417

PDF417 è una simbologia impilata: righe di codeword, ciascuna codeword costruita da quattro barre e quattro spazi che coprono 17 moduli. Questa struttura incorpora la correzione di errori Reed‑Solomon, quindi un angolo strappato o una macchia di caffè di solito è sopravvivibile. Ciò che non è sopravvivibile è perdere la griglia dei moduli stessa.

Tre cose distruggono la griglia, in ordine approssimativo di frequenza con cui compaiono in produzione:

  • Larghezza efficace del modulo inferiore a due pixel. Questo è il fallimento dominante. Si verifica tramite riduzione, distanza della fotocamera e sfocatura, che diffonde l’inchiostro di un modulo sui suoi vicini. Un codice a barre generato a tre pixel per modulo e poi sfocato è funzionalmente un codice a barre a un pixel per modulo.
  • Prospettiva e rotazione. Un codice a barre fotografato da un angolo ha righe che non sono più linee di scansione parallele. Il rilevatore gestisce questo, ma richiede un passaggio di rilevamento che il preset più veloce salta.
  • Collasso del contrasto. Carta termica sbiadita, uno schermo fotografato sotto abbagliamento o una scansione con la luminosità fissata. Meno fatale di quanto sembri, come mostrano i numeri sotto.

La conseguenza pratica è che le impostazioni di riconoscimento sono un meccanismo di recupero, non un sostituto della qualità di acquisizione. Esse ti restituiscono la fascia intermedia della qualità dell’immagine. Non restituiscono la fascia inferiore.

Configura il lettore PDF417 Python

Installa la libreria da PyPI:

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

L’API di riconoscimento si trova in aspose.barcode.barcoderecognition. Due classi sono importanti per questo articolo: BarCodeReader, che gestisce il rilevamento e la decodifica, e QualitySettings, che controlla quanto intensamente il lettore tenta.

Leggi un codice a barre PDF417 in Python

La lettura minima fattibile richiede due argomenti e un ciclo:

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)
Leggi un codice a barre PDF417 in Python.

Leggi un codice a barre PDF417 in Python.

Output su un’immagine pulita:

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

Il secondo argomento non è opzionale in pratica. Se lo si omette, BarCodeReader ricade in DecodeType.ALL_SUPPORTED_TYPES, che esegue il rilevamento di più di sessanta simbologie su ogni regione candidata nell’immagine. Su una pipeline esclusivamente PDF417, ciò è puro spreco e apre la porta a un falso positivo di simbologia lineare all’interno della struttura di riga PDF417. Specifica il tipo.

Se il tuo input arriva come byte da un upload anziché come file su disco, passa uno stream e imposta un timeout in modo che un’immagine patologica non possa bloccare un worker:

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()]

Confronta le impostazioni di qualità di riconoscimento PDF417 in Python

QualitySettings offre quattro preset da conoscere. Assegnarne uno al lettore è una singola riga:

reader = rec.BarCodeReader("scan.png", rec.DecodeType.PDF417)
reader.quality_settings = rec.QualitySettings.high_quality
PresetDestinato aCosto
high_performanceImmagini pulite generate dalla macchinaIl più veloce, salta i passaggi di recupero
normal_qualityPredefinito. Scansioni ed esportazioni regolariBilanciato
high_qualityAcquisizioni con fotocamera, scansioni degradateModerato
max_qualityPassaggio di ritentativo su immagini già falliteIl più lento di gran lunga

Per scoprire cosa significano in pratica quelle descrizioni, ho generato un PDF417 a tre pixel per modulo, l’ho degradato in sei modi con Pillow e ho eseguito ogni preset su ogni variante. Mediana di tre esecuzioni:

Immagine di originehigh_performancenormal_qualityhigh_qualitymax_quality
Pulitaletto, 35 msletto, 50 msletto, 45 msletto, 106 ms
Ruotata 12°, sfocatamancato, 15 msletto, 74 msletto, 67 msletto, 157 ms
Rumore gaussiano (σ 40)letto, 31 msletto, 49 msletto, 52 msletto, 123 ms
Mezza risoluzioneletto, 22 msletto, 37 msletto, 35 msletto, 86 ms
Basso contrastoletto, 24 msletto, 38 msletto, 43 msletto, 112 ms
Sfocatura forte (σ 2.2)mancato, 5 msmancato, 25 msmancato, 85 msmancato, 180 ms

Quattro cose emergono da questa tabella e sono più utili dei singoli numeri:

  1. Il rumore e il basso contrasto non sono il problema che la gente pensa siano. Reed‑Solomon più il rilevatore hanno assorbito un forte rumore gaussiano e una riduzione del contrasto dell'82 % nella preset più veloce. Smetti di ottimizzare per questi.
  2. Rotazione più sfocatura è il caso che separa le preset. È anche il profilo esatto di una cattura con telefono portatile, motivo per cui high_performance è l’impostazione predefinita sbagliata per qualsiasi pipeline di origine mobile.
  3. max_quality costa tre volte il tempo di normal_quality e non legge nulla di extra. Si guadagna il suo posto come percorso di secondo tentativo, non come predefinito.
  4. Una volta che la griglia del modulo è sparita, nessuna preset la recupera. La riga con forte sfocatura è un errore in tutti i casi, e max_quality ha impiegato 180 ms a dimostrarlo. È un problema di cattura con una correzione di cattura: più pixel, migliore messa a fuoco, x_dimension più grande al momento della generazione.

Regola QualitySettings per leggere i codici a barre PDF417 sfocati in Python

Un preset è un insieme di proprietà individuali e puoi partire da un preset e sovrascriverne una. È qui che si trovano i reali vantaggi per un difetto noto e ripetibile.

L’immagine ruotata e sfocata sopra è una buona dimostrazione. Sotto high_performance non la rileva. Abilita la deconvoluzione sopra lo stesso preset e leggerà:

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)
Regola QualitySettings per leggere i codici a barre PDF417 sfocati in Python.

Regola QualitySettings per leggere i codici a barre PDF417 sfocati in Python.

Misurato: mancato in 12 ms senza l’override, letto in 54 ms con esso. Una proprietà ha invertito l’esito e il risultato è tornato comunque più veloce rispetto al preset max_quality.

Le proprietà da conoscere:

ProprietàValoriQuando usarla
deconvolutionFAST, NORMAL, SLOWSfocatura da movimento e catture fuori fuoco
barcode_qualityHIGH, NORMAL, LOWDifetti di stampa, sbiadimento termico, artefatti fax
x_dimensionAUTO, SMALL, NORMAL, LARGE, USE_MINIMAL_X_DIMENSIONCodici a barre densi, o una dimensione di modulo fissa conosciuta
minimal_x_dimensionfloatUsare insieme a USE_MINIMAL_X_DIMENSION per impostare un valore minimo
complex_backgroundAUTO, DISABLED, ENABLEDCodice a barre stampato su un’opera d’arte o su un modulo a motivo
inverse_imageAUTO, DISABLED, ENABLEDCodici a barre bianco su nero, catture schermo
allow_incorrect_barcodesboolSolo per diagnostica, mai in produzione

Quest’ultimo merita un avviso. allow_incorrect_barcodes restituisce simboli che non hanno superato la convalida del checksum. È uno strumento di debug per rispondere a “il rilevatore ha effettivamente trovato qualcosa qui?” Distribuirlo significa distribuire stringhe decodificate errate anziché assenti, il che è decisamente peggiore di una mancanza.

Una strategia a livelli che funziona bene in produzione: prova normal_quality per primo, e in caso di mancato risultato riprova una volta con high_quality più deconvolution = SLOW. Paghi il percorso costoso solo per le immagini che ne hanno bisogno.

Convalida i risultati della decodifica PDF417 in Python

Una stringa decodificata non è automaticamente una stringa corretta. Tre campi su BarCodeResult aiutano:

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)]

Ricomporre un Macro PDF417 diviso tra immagini

Macro PDF417 suddivide un messaggio logico in più simboli, che appare nei manifesti di spedizione e nei documenti multipagina. I metadati del segmento sopravvivono al viaggio di andata e ritorno, quindi il riassemblaggio è deterministico:

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")
Pagina 1.

Pagina 1.

Pagina 2.

Pagina 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

Nota che macro_pdf_417_file_id è un intero, non una stringa, sia sul lato di generazione che di riconoscimento. Lo stesso oggetto espone anche macro_pdf_417_file_name, macro_pdf_417_sender, macro_pdf_417_addressee, macro_pdf_417_time_stamp e macro_pdf_417_checksum quando l’encoder li ha popolati.

Benchmark del riconoscimento PDF417 sulle tue immagini

La scelta del preset dovrebbe essere una misurazione, non un’ipotesi. Puntalo a una cartella di catture rappresentative dal tuo pipeline reale e ti dirà quale preset giustifica il suo costo:

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

Eseguilo una volta contro cinquanta catture reali e il dibattito predefinito termina.

Linee guida pratiche

  • Limita DecodeType a PDF417 a meno che non ti aspetti realmente simbologie miste. Usa MACRO_PDF417, COMPACT_PDF417 o MICRO_PDF417 quando conosci la variante.
  • Ritaglia prima di decodificare. Inviare una scansione A4 completa quando il codice a barre occupa solo il 5 % spreca tempo di rilevamento e aggiunge falsi positivi.
  • Mantieni i file intermedi senza perdita. PNG o TIFF. JPEG con artefatti a impostazioni di bassa qualità colpisce proprio i bordi del codice di cui il decoder ha bisogno.
  • Scala i tuoi tentativi invece di usare il preset più lento per impostazione predefinita.
  • Correggi la generazione prima di ottimizzare il riconoscimento. Se controlli l’encoder, aumentare x_dimension non costa nulla e risolve più errori rispetto a qualsiasi impostazione del lettore. L’articolo sulla generazione di PDF417 copre questi parametri.
  • Imposta timeout su qualsiasi lettore che elabora immagini fornite dall’utente.

Ottieni una licenza gratuita

La build di valutazione aggiunge filigrane al testo decodificato per le simbologie diverse da Code 39, il che interferirà con qualsiasi test di round‑trip che esegui. Una licenza temporanea gratuita rimuove questo per la valutazione.

Risorse aggiuntive gratuite

Conclusione

La lettura dei codici a barre PDF417 in Python è un’operazione a due righe su immagini pulite e un problema ingegneristico su quelle reali. Le misurazioni sopra indicano una postura semplice: specifica il tuo DecodeType, usa normal_quality come predefinito, riprova una volta con high_quality e deconvolution abilitata, e valida ogni risultato prima di agire su di esso. Conserva le impostazioni costose per il percorso di retry e, quando un’intera classe di immagini fallisce in ogni impostazione, correggi la cattura anziché il lettore. Le domande sono benvenute sul forum di supporto gratuito.

Domande frequenti

  1. Perché lo stesso codice a barre PDF417 viene letto in un’immagine e fallisce in un’altra?
    Il riconoscimento dipende da quanti pixel occupa ogni modulo dopo l’acquisizione. Sfocatura, ridimensionamento e compressione JPEG riducono tutti la larghezza effettiva del modulo e, una volta che un modulo scende al di sotto di circa due pixel puliti, nessun preset può recuperarlo.

  2. Quale preset di riconoscimento dovrei usare per PDF417?
    Inizia con normal_quality, che è quello predefinito. Passa a high_quality per acquisizioni con fotocamera e scansioni, e riserva max_quality per i tentativi di ripetizione perché è diverse volte più lento senza leggere molto di più.

  3. Limitare DecodeType a PDF417 rende effettivamente la lettura più veloce?
    Sì. Il valore predefinito è DecodeType.ALL_SUPPORTED_TYPES, che esegue il rilevatore per ogni simbologia supportata. Specificare esplicitamente PDF417 elimina quel lavoro e rimuove anche la possibilità di un falso positivo da un’altra simbologia.

  4. Aspose.BarCode può leggere un messaggio Macro PDF417 suddiviso in più immagini?
    Sì. Leggi ogni segmento con DecodeType.MACRO_PDF417 e utilizza macro_pdf_417_file_id, macro_pdf_417_segment_id e macro_pdf_417_segments_count nel risultato esteso per ricomporre il payload in ordine.

  5. Come posso sapere se un risultato decodificato è affidabile?
    Controlla reading_quality e confidence sul BarCodeResult e utilizza il quadrilatero region per confermare che il codice a barre sia stato trovato dove ti aspettavi nell’immagine.

  6. Può leggere PDF417 da una foto di una patente di guida o di una carta d’imbarco?
    Sì, a condizione che l’acquisizione sia a fuoco e il codice a barre non sia tagliato. Ritaglia l’area del codice a barre prima della lettura e preferisci PNG rispetto a JPEG per i file intermedi.

Leggi di più