PDF417 바코드를 생성하는 데는 Python 네 줄이면 충분합니다. 휴대폰 사진, 200 DPI 스캔, 혹은 누군가의 주머니에서 하루 동안 있었던 탑승권에서 바코드를 다시 읽어내는 것이 실제 작업이 시작되는 지점이며, 대부분의 PDF417 통합이 실제로 실패하는 지점입니다. 이 기사에서는 원본 이미지가 완벽하지 않을 때 Python으로 PDF417 바코드를 읽는 방법을 배웁니다. 대신 생성 측면을 찾고 있다면, 이전에 다룬 generate PDF417 barcodes using Python 가이드에서는 행 및 열 제어를 포함한 기본 및 맞춤형 PDF417 심볼 생성 방법을 다루며, Python barcode reader guide 가이드는 다양한 심볼에 대한 일반적인 스캔을 다룹니다. 여기서 이어지는 내용은 PDF417 인식에 대해 좁고 깊게 파고듭니다.

아래의 모든 스니펫은 Linux에서 Python 3.12와 함께 Aspose.BarCode for Python via .NET 26.7을 사용하여 실행되었습니다. 타이밍 및 읽기/실패 결과는 추정이 아니라 측정된 것이며, 이를 생성한 스크립트는 끝부분에 있어 직접 이미지로 다시 실행할 수 있습니다.

PDF417 인식이 실제로 깨지는 경우

PDF417은 스택형 심볼리티로, 코드워드 행으로 구성되며 각 코드워드는 4개의 바와 4개의 스페이스로 이루어져 17개의 모듈을 차지합니다. 이러한 구조는 리드-솔로몬 오류 정정을 포함하고 있어, 찢어진 모서리나 커피 얼룩은 보통 복구가 가능합니다. 복구가 불가능한 경우는 모듈 그리드 자체가 손실될 때입니다.

그리드를 파괴하는 세 가지 요인은 생산 환경에서 나타나는 빈도 순서대로 대략 다음과 같습니다:

  • 모듈 너비가 두 픽셀 이하로 떨어지는 경우. 이는 가장 흔한 실패입니다. 다운스케일링, 카메라 거리, 그리고 블러로 인해 발생하는데, 블러는 한 모듈의 잉크가 이웃 모듈로 퍼지게 합니다. 모듈당 3픽셀로 생성된 바코드를 블러 처리하면 실제로는 모듈당 1픽셀인 바코드와 동일합니다.
  • 원근 및 회전. 각도에서 촬영된 바코드는 행이 더 이상 평행 스캔 라인이 아니게 됩니다. 탐지기는 이를 처리하지만, 가장 빠른 프리셋이 건너뛰는 탐지 과정을 추가로 소요합니다.
  • 대비 감소. 색이 바랜 열전지, 눈부심 아래 촬영된 화면, 혹은 밝기가 고정된 스캔이 해당됩니다. 아래 숫자가 보여주듯, 겉보기에 생각보다 치명적이지 않습니다.

실용적인 결과는 인식 설정이 복구 메커니즘이며, 캡처 품질을 대체하는 것이 아니라는 것입니다. 이는 이미지 품질의 중간 대역을 회복시켜 줍니다. 하위 대역은 회복되지 않습니다.

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 바코드 읽기.

Python에서 PDF417 바코드 읽기.

깨끗한 이미지에 대한 출력:

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

실제 사용에서는 두 번째 인수가 선택 사항이 아닙니다. 제외하면 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는 알아두면 좋은 네 가지 프리셋을 제공합니다. 리더에 하나를 할당하는 것은 한 줄로 할 수 있습니다:

reader = rec.BarCodeReader("scan.png", rec.DecodeType.PDF417)
reader.quality_settings = rec.QualitySettings.high_quality
PresetIntended forCost
high_performance깨끗한 기계 생성 이미지가장 빠름, 복구 패스를 건너뜀
normal_quality기본값. 일반 스캔 및 내보내기균형 잡힌
high_quality카메라 촬영, 저품질 스캔보통
max_quality이미 실패한 이미지에 대한 재시도 패스큰 차이로 가장 느림

실제로 이러한 설명이 의미하는 바를 알아보기 위해, 모듈당 3픽셀인 PDF417을 생성하고 Pillow로 6가지 방식으로 저하시킨 뒤, 모든 프리셋을 모든 변형에 대해 실행했습니다. 세 번 실행한 중간값:

원본 이미지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

이 표에서 도출되는 네 가지 항목은 개별 숫자보다 더 유용합니다:

  1. 노이즈와 낮은 대비는 사람들이 생각하는 문제가 아닙니다. Reed‑Solomon과 검출기가 강한 가우시안 노이즈와 가장 빠른 프리셋에서 82% 대비 감소를 흡수했습니다. 이에 대한 튜닝을 중단하십시오.
  2. 회전과 흐림은 프리셋을 구분하는 경우입니다. 또한 이는 손에 들고 촬영한 휴대폰 캡처의 정확한 프로파일이며, 따라서 high_performance가 모바일 소스 파이프라인의 기본값으로 잘못된 이유입니다.
  3. max_quality는 normal_quality보다 세 배의 시간이 소요되며 추가적인 읽기가 없습니다. 이는 기본값이 아니라 두 번째 시도 경로로서의 위치를 차지합니다.
  4. 모듈 그리드가 사라지면 어떤 프리셋도 이를 복구할 수 없습니다. 강한 흐림 행은 전반적으로 실패이며, max_quality가 이를 증명하는 데 180 ms가 소요되었습니다. 이는 캡처 문제이며 해결 방법은 캡처 시 더 많은 픽셀, 더 나은 초점, 더 큰 x_dimension을 사용하는 것입니다.

Python에서 흐릿한 PDF417 바코드를 읽기 위해 QualitySettings 조정

프리셋은 개별 속성들의 번들이며, 프리셋에서 시작하여 하나를 재정의할 수 있습니다. 이는 알려진 반복 가능한 결함에 대해 실제 이점을 얻을 수 있는 부분입니다.

위의 회전 및 흐림 처리된 이미지는 좋은 시연입니다. 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를 조정합니다.

Measured: 오버라이드 없이 12 ms에 놓쳤고, 오버라이드와 함께 54 ms에 읽었습니다. 하나의 속성이 결과를 바꾸었으며, 그 결과는 max_quality 프리셋보다도 여전히 더 빨리 반환되었습니다.

알아두면 좋은 속성:

속성값언제 사용해야 하는지
deconvolutionFAST, NORMAL, SLOW모션 블러 및 초점이 맞지 않은 캡처
barcode_qualityHIGH, NORMAL, LOW인쇄 결함, 열 퇴색, 팩스 아티팩트
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는 체크섬 검증에 실패한 기호를 반환합니다. 이는 “detector가 여기서 무언가를 찾았는가?” 라는 질문에 답하기 위한 디버깅 도구입니다. 이를 배포한다는 것은 누락되는 대신 잘못된 디코드 문자열을 배포하는 것이며, 이는 놓치는 것보다 훨씬 나쁩니다.

프로덕션에서 잘 작동하는 티어링 전략: 먼저 normal_quality를 시도하고, 실패하면 high_quality와 deconvolution = SLOW를 한 번 재시도합니다. 비용이 많이 드는 경로는 필요한 이미지에만 적용됩니다.

Python에서 PDF417 디코딩 결과 검증

디코딩된 문자열이 자동으로 올바른 문자열이 되는 것은 아닙니다. 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.

페이지 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 생성 기사에서 해당 매개변수를 다룹니다.
  • timeout을 설정하십시오, 사용자 제공 이미지를 다루는 모든 리더에 대해.

무료 라이선스 받기

평가 빌드에서는 Code 39을 제외한 다른 심볼에 대해 디코딩된 텍스트에 워터마크가 표시되며, 이는 수행하는 모든 라운드‑트립 테스트에 영향을 줄 수 있습니다. 무료 임시 라이선스를 사용하면 평가 시 이를 제거할 수 있습니다.

무료 추가 리소스

결론

Reading PDF417 바코드를 Python에서 읽는 것은 깨끗한 이미지에서는 두 줄의 작업이며 실제 이미지에서는 엔지니어링 문제입니다. 위의 측정값은 간단한 접근 방식을 제시합니다: DecodeType을 지정하고, 기본값을 normal_quality로 설정한 뒤, high_quality와 디컨볼루션을 활성화하여 한 번 재시도하며, 결과를 적용하기 전에 모든 결과를 검증하십시오. 재시도 경로를 위해 비용이 많이 드는 프리셋을 저장하고, 모든 설정에서 전체 이미지 클래스가 실패할 경우, 리더기가 아니라 캡처를 수정하십시오. 질문은 무료 지원 포럼에서 환영합니다.

FAQs

  1. 왜 동일한 PDF417 바코드가 한 이미지에서는 읽히고 다른 이미지에서는 실패할까요?
    인식은 캡처 후 각 모듈이 차지하는 픽셀 수에 따라 달라집니다. 흐림, 다운스케일링 및 JPEG 압축은 모두 유효 모듈 너비를 줄이며, 모듈이 대략 두 개의 깨끗한 픽셀 이하로 감소하면 어떤 프리셋도 이를 복구할 수 없습니다.

  2. PDF417에 사용할 인식 프리셋은 무엇인가요?
    normal_quality(기본값)부터 시작하십시오. 카메라 촬영 및 스캔의 경우 high_quality로 전환하고, max_quality는 재시도 시에만 사용하십시오. max_quality는 읽는 속도가 여러 배 느리지만 읽는 정확도가 크게 향상되지는 않습니다.

  3. DecodeType을 PDF417로 제한하면 실제로 읽는 속도가 빨라지나요?
    예. 기본값은 DecodeType.ALL_SUPPORTED_TYPES이며, 이는 지원되는 모든 심볼에 대해 탐지기를 실행합니다. PDF417을 명시적으로 지정하면 해당 작업이 제거되고 다른 심볼에서 발생할 수 있는 오탐 가능성도 사라집니다.

  4. Aspose.BarCode가 여러 이미지에 걸쳐 분할된 매크로 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를 사용하는 것이 좋습니다.

더 읽기