Tạo mã vạch PDF417 chỉ cần bốn dòng Python. Đọc lại mã từ ảnh điện thoại, bản quét 200 DPI, hoặc thẻ lên máy bay đã qua một ngày trong túi của ai đó là nơi công việc thực sự bắt đầu, và cũng là nơi hầu hết các tích hợp PDF417 thực sự thất bại. Trong bài viết này, bạn sẽ học cách đọc mã vạch PDF417 bằng Python khi hình ảnh nguồn không hoàn hảo. Nếu bạn đang tìm kiếm phần tạo mã, hướng dẫn trước đây về cách tạo mã vạch PDF417 bằng Python bao gồm việc tạo các ký hiệu PDF417 cơ bản và tùy chỉnh, bao gồm kiểm soát hàng và cột, và hướng dẫn đọc mã vạch Python đề cập đến việc quét đa mục đích trên các loại mã vạch. Những gì tiếp theo ở đây sẽ đi sâu và chi tiết vào việc nhận dạng PDF417.

Mỗi đoạn mã dưới đây đã được chạy trên Aspose.BarCode for Python via .NET 26.7 trên Linux với Python 3.12. Thời gian và kết quả đọc/thiếu được đo lường, không ước tính, và script tạo ra chúng nằm ở cuối để bạn có thể chạy lại trên các hình ảnh của mình.

Điều gì thực sự làm gián đoạn nhận dạng PDF417

PDF417 là một ký hiệu xếp chồng: các hàng của các codeword, mỗi codeword được tạo thành từ bốn thanh và bốn khoảng trống trải dài 17 mô-đun. Cấu trúc đó mang lại khả năng sửa lỗi Reed‑Solomon, vì vậy một góc bị rách hoặc một vết cà phê thường có thể phục hồi. Điều không thể phục hồi được là mất lưới mô-đun.

Ba điều phá hủy lưới, theo thứ tự xấp xỉ tần suất xuất hiện trong môi trường sản xuất:

  • Chiều rộng mô-đun hiệu quả dưới hai pixel. Đây là lỗi chi phối. Nó xảy ra do thu nhỏ, do khoảng cách máy ảnh, và do mờ, khiến mực của một mô-đun lan sang các mô-đun lân cận. Một mã vạch được tạo ở ba pixel mỗi mô-đun rồi bị mờ về mặt chức năng giống như mã vạch ở một pixel mỗi mô-đun.
  • Góc nhìn và xoay. Một mã vạch được chụp ở góc độ sẽ có các hàng không còn song song với các đường quét. Bộ phát hiện xử lý được điều này, nhưng nó tốn một lượt phát hiện mà cài đặt nhanh nhất sẽ bỏ qua.
  • Sụp độ tương phản. Giấy nhiệt đã phai màu, màn hình được chụp dưới ánh chói, hoặc bản quét với độ sáng cố định. Ít nghiêm trọng hơn so với vẻ ngoài, như các số dưới đây cho thấy.

Hệ quả thực tế là các cài đặt nhận dạng là một cơ chế khôi phục, không phải là sự thay thế cho chất lượng chụp. Chúng giúp bạn lấy lại dải trung bình của chất lượng hình ảnh. Chúng không giúp bạn lấy lại phần thấp nhất.

Cài đặt Trình đọc PDF417 Python

Cài đặt thư viện từ PyPI:

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

API nhận dạng nằm trong aspose.barcode.barcoderecognition. Hai lớp quan trọng cho bài viết này: BarCodeReader, lớp chịu trách nhiệm phát hiện và giải mã, và QualitySettings, lớp kiểm soát mức độ nỗ lực của trình đọc.

Đọc mã vạch PDF417 trong Python

Đọc tối thiểu khả thi là hai đối số và một vòng lặp:

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)
Đọc mã vạch PDF417 trong Python.

Đọc mã vạch PDF417 trong Python.

Kết quả trên hình ảnh sạch:

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

Tham số thứ hai không phải là tùy chọn trong thực tế. Bỏ qua nó và BarCodeReader sẽ quay lại DecodeType.ALL_SUPPORTED_TYPES, cái sẽ thực hiện phát hiện hơn sáu mươi loại mã vạch trên mọi vùng ứng cử trong hình ảnh. Trong một quy trình chỉ xử lý PDF417, điều này hoàn toàn lãng phí, và nó mở ra khả năng một kết quả dương tính giả của mã vạch tuyến tính trong cấu trúc hàng PDF417. Đặt tên loại.

Nếu đầu vào của bạn đến dưới dạng byte từ một tải lên thay vì một tệp trên đĩa, hãy truyền một luồng và đặt thời gian chờ để một hình ảnh bất thường không thể làm treo 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()]

So sánh cài đặt chất lượng nhận dạng PDF417 trong Python

QualitySettings cung cấp bốn cài đặt trước đáng biết. Gán một trong số chúng cho trình đọc chỉ cần một dòng duy nhất.

reader = rec.BarCodeReader("scan.png", rec.DecodeType.PDF417)
reader.quality_settings = rec.QualitySettings.high_quality
Cài đặt trướcDành choChi phí
high_performanceHình ảnh sạch, được tạo bởi máyNhanh nhất, bỏ qua các lần phục hồi
normal_qualityMặc định. Quét và xuất thườngCân bằng
high_qualityẢnh chụp bằng máy ảnh, bản quét giảm chất lượngVừa phải
max_qualityThử lại trên các hình ảnh đã thất bạiChậm nhất nhiều lần

Để tìm hiểu ý nghĩa của những mô tả đó trong thực tế, tôi đã tạo một PDF417 với ba pixel mỗi mô-đun, làm giảm chất lượng theo sáu cách bằng Pillow, và chạy mọi cài đặt trước đối với mọi biến thể. Trung vị của ba lần chạy:

Hình nguồnhigh_performancenormal_qualityhigh_qualitymax_quality
Sạchđọc, 35 msđọc, 50 msđọc, 45 msđọc, 106 ms
Xoay 12°, mờbỏ lỡ, 15 msđọc, 74 msđọc, 67 msđọc, 157 ms
Nhiễu Gaussian (σ 40)đọc, 31 msđọc, 49 msđọc, 52 msđọc, 123 ms
Nửa độ phân giảiđọc, 22 msđọc, 37 msđọc, 35 msđọc, 86 ms
Độ tương phản thấpđọc, 24 msđọc, 38 msđọc, 43 msđọc, 112 ms
Mờ nặng (σ 2.2)bỏ lỡ, 5 msbỏ lỡ, 25 msbỏ lỡ, 85 msbỏ lỡ, 180 ms

Bốn điều rút ra từ bảng này, và chúng hữu ích hơn các số riêng lẻ:

  1. Tiếng ồn và độ tương phản thấp không phải là vấn đề như mọi người nghĩ. Reed-Solomon cộng với bộ phát hiện đã hấp thụ tiếng ồn Gaussian mạnh và giảm độ tương phản 82% trên preset nhanh nhất. Ngừng tinh chỉnh cho những thứ này.
  2. Xoay cộng với mờ là trường hợp phân biệt các preset. Nó cũng là hồ sơ chính xác của việc chụp bằng điện thoại cầm tay, vì vậy high_performance là mặc định sai cho bất kỳ quy trình nguồn từ di động nào.
  3. max_quality tốn ba lần thời gian của normal_quality và không đọc thêm gì. Nó xứng đáng có vị trí là đường đi thử lần thứ hai, không phải mặc định.
  4. Khi lưới mô-đun biến mất, không có preset nào có thể khôi phục lại. Hàng mờ mạnh là một lỗi trên toàn bộ, và max_quality đã tiêu tốn 180 ms để chứng minh điều đó. Đó là vấn đề chụp ảnh với giải pháp chụp: nhiều pixel hơn, tiêu điểm tốt hơn, x_dimension lớn hơn tại thời điểm tạo.

Điều chỉnh QualitySettings để Đọc Mã vạch PDF417 mờ trong Python

Một preset là một tập hợp các thuộc tính riêng lẻ, và bạn có thể bắt đầu từ một preset và ghi đè một thuộc tính. Đây là nơi mà những lợi ích thực sự xuất hiện cho một lỗi đã biết, có thể lặp lại.

Hình ảnh đã quay và làm mờ ở trên là một minh họa tốt. Dưới high_performance nó bị thiếu. Kích hoạt deconvolution trên cùng preset đó và nó sẽ hiển thị:

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)
Tinh chỉnh QualitySettings để đọc mã vạch PDF417 mờ trong Python.

Tinh chỉnh QualitySettings để đọc mã vạch PDF417 mờ trong Python.

Được đo: bỏ lỡ trong 12 ms mà không có ghi đè, đọc trong 54 ms có ghi đè. Một thuộc tính đã làm thay đổi kết quả, và kết quả vẫn nhanh hơn so với thiết lập sẵn max_quality.

Các thuộc tính đáng biết:

Thuộc tínhGiá trịKhi nào nên sử dụng
deconvolutionFAST, NORMAL, SLOWHiệu ứng mờ chuyển động và ảnh không lấy nét
barcode_qualityHIGH, NORMAL, LOWCác khuyết điểm in, phai nhiệt, hiện tượng fax
x_dimensionAUTO, SMALL, NORMAL, LARGE, USE_MINIMAL_X_DIMENSIONMã vạch dày đặc, hoặc kích thước mô-đun cố định đã biết
minimal_x_dimensionfloatKết hợp với USE_MINIMAL_X_DIMENSION để đặt mức tối thiểu
complex_backgroundAUTO, DISABLED, ENABLEDMã vạch được in trên hình ảnh nghệ thuật hoặc mẫu có họa tiết
inverse_imageAUTO, DISABLED, ENABLEDMã vạch trắng trên nền đen, chụp màn hình
allow_incorrect_barcodesboolChỉ dùng cho chẩn đoán, không bao giờ dùng trong sản xuất

Cái cuối cùng này đáng để đưa ra một cảnh báo. allow_incorrect_barcodes trả về các ký hiệu không vượt qua kiểm tra checksum. Nó là công cụ gỡ lỗi giúp trả lời “bộ phát hiện có thực sự tìm thấy gì ở đây không?” Việc đưa nó vào sản phẩm có nghĩa là phát hành các chuỗi đã giải mã sai thay vì không có, điều này tệ hơn rất nhiều so với việc bỏ lỡ.

Một chiến lược phân lớp hoạt động tốt trong môi trường sản xuất: thử normal_quality trước, và khi không thành công, thử lại một lần với high_quality cộng deconvolution = SLOW. Bạn chỉ trả phí cho đường đi tốn kém đối với những hình ảnh cần nó.

Xác thực kết quả giải mã PDF417 trong Python

Một chuỗi đã giải mã không tự động là một chuỗi đúng. Ba trường trên BarCodeResult giúp:

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

Ghép lại một Macro PDF417 bị chia thành nhiều hình ảnh

Macro PDF417 chia một thông điệp logic thành nhiều ký hiệu, điều này xuất hiện trong các bản kê vận chuyển và tài liệu đa trang. Siêu dữ liệu đoạn vẫn tồn tại qua vòng quay, vì vậy việc lắp lại là quyết định được.

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

Trang 1.

Trang 2.

Trang 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

Lưu ý rằng macro_pdf_417_file_id là một số nguyên, không phải chuỗi, ở cả hai phía tạo và nhận dạng. Cùng một đối tượng cũng sẽ hiển thị macro_pdf_417_file_name, macro_pdf_417_sender, macro_pdf_417_addressee, macro_pdf_417_time_stamp và macro_pdf_417_checksum khi bộ mã hoá đã điền chúng.

Đánh giá nhận dạng PDF417 trên hình ảnh của riêng bạn

Lựa chọn preset nên là một phép đo, không phải một ước đoán. Hướng công cụ này tới một thư mục chứa các bản ghi đại diện từ quy trình thực tế của bạn và nó sẽ cho bạn biết preset nào xứng đáng với chi phí của nó:

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

Chạy nó một lần với năm mươi bản ghi thực và cuộc tranh luận đã được thiết lập sẽ kết thúc.

Hướng dẫn thực tiễn

  • Giới hạn DecodeType thành PDF417 trừ khi bạn thực sự mong đợi các ký hiệu hỗn hợp. Sử dụng MACRO_PDF417, COMPACT_PDF417 hoặc MICRO_PDF417 khi bạn biết biến thể.
  • Cắt ảnh trước khi giải mã. Việc truyền một bản quét A4 đầy đủ khi mã vạch chỉ chiếm 5 % sẽ lãng phí thời gian phát hiện và tạo ra nhiều kết quả dương tính giả.
  • Giữ các tệp trung gian không mất dữ liệu. PNG hoặc TIFF. JPEG với chất lượng thấp gây hiện tượng ringing ngay tại các cạnh thanh mã mà bộ giải mã cần.
  • Phân cấp các lần thử lại thay vì luôn dùng cài đặt chậm nhất.
  • Sửa việc tạo mã trước khi tinh chỉnh nhận dạng. Nếu bạn kiểm soát bộ mã hoá, tăng x_dimension không tốn chi phí và giải quyết nhiều lỗi hơn bất kỳ cài đặt đọc nào. Bài viết bài viết về tạo PDF417 đề cập đến các tham số này.
  • Đặt timeout cho bất kỳ trình đọc nào xử lý hình ảnh do người dùng cung cấp.

Nhận giấy phép miễn phí

Bản dựng đánh giá sẽ chèn watermark vào văn bản đã giải mã cho các loại mã vạch ngoại trừ Code 39, điều này sẽ gây cản trở cho bất kỳ thử nghiệm vòng lặp nào bạn thực hiện. Một giấy phép tạm thời miễn phí sẽ loại bỏ điều đó trong quá trình đánh giá.

Tài Nguyên Bổ Sung Miễn Phí

Kết luận

Đọc mã vạch PDF417 trong Python là một thao tác hai dòng trên hình ảnh sạch và là một vấn đề kỹ thuật trên các hình ảnh thực tế. Các đo lường ở trên chỉ ra một cách tiếp cận đơn giản: đặt tên cho DecodeType của bạn, mặc định là normal_quality, thử lại một lần với high_quality và bật deconvolution, và xác thực mọi kết quả trước khi thực hiện. Lưu các preset tốn kém cho đường dẫn thử lại, và khi một lớp hình ảnh toàn bộ không thành công ở mọi cài đặt, hãy sửa cách chụp thay vì bộ đọc. Mọi câu hỏi đều được chào đón trên diễn đàn hỗ trợ miễn phí.

Câu hỏi thường gặp

  1. Tại sao cùng một mã vạch PDF417 có thể đọc được trong một hình ảnh mà lại không đọc được trong hình ảnh khác?
    Việc nhận dạng phụ thuộc vào số pixel mà mỗi mô-đun chiếm sau khi chụp. Độ mờ, giảm kích thước và nén JPEG đều làm giảm chiều rộng mô-đun thực tế, và khi một mô-đun giảm xuống dưới khoảng hai pixel sạch, không có preset nào có thể khôi phục lại.

  2. Tôi nên sử dụng preset nhận dạng nào cho PDF417?
    Bắt đầu với normal_quality, đây là mặc định. Chuyển sang high_quality cho các ảnh chụp bằng máy ảnh và quét, và chỉ dùng max_quality cho các lần thử lại vì nó chậm hơn nhiều lần mà không đọc được nhiều hơn đáng kể.

  3. Việc giới hạn DecodeType chỉ cho PDF417 thực sự làm cho việc đọc nhanh hơn không?
    Có. Mặc định là DecodeType.ALL_SUPPORTED_TYPES, chạy bộ phát hiện cho mọi ký hiệu được hỗ trợ. Đặt rõ PDF417 loại bỏ công việc đó và cũng loại bỏ khả năng phát hiện sai từ ký hiệu khác.

  4. Aspose.BarCode có thể đọc một tin nhắn Macro PDF417 được chia thành nhiều hình ảnh không?
    Có. Đọc từng đoạn bằng DecodeType.MACRO_PDF417 và sử dụng macro_pdf_417_file_id, macro_pdf_417_segment_id, và macro_pdf_417_segments_count trên kết quả mở rộng để lắp ráp lại dữ liệu theo thứ tự.

  5. Làm sao tôi biết kết quả giải mã có thể tin cậy không?
    Kiểm tra reading_quality và confidence trên BarCodeResult, và sử dụng hình tứ giác region để xác nhận mã vạch được tìm thấy ở vị trí bạn mong đợi trong ảnh.

  6. Nó có thể đọc PDF417 từ ảnh giấy phép lái xe hoặc thẻ lên máy bay không?
    Có thể, với điều kiện ảnh được chụp nét và mã vạch không bị cắt. Cắt vùng mã vạch trước khi đọc, và ưu tiên PNG hơn JPEG cho các tệp trung gian.

Đọc thêm