יצירת ברקוד PDF417 דורשת ארבע שורות של Python. קריאת ברקוד חזרה מתמונה שצולמה בטלפון, סריקה ברזולוציה של 200 DPI, או מכרטיס טיסה שבילה יום בכיס של מישהו היא המקום שבו העבודה האמיתית מתחילה, וזה המקום שבו רוב האינטגרציות של PDF417 נכשלות בפועל. במאמר זה תלמדו כיצד לקרוא ברקודי PDF417 ב-Python כאשר תמונת המקור אינה מושלמת. אם אתם מחפשים את צד היצירה במקום זאת, המדריך הקודם על איך ליצור ברקודי PDF417 באמצעות Python מכסה יצירת סמלים בסיסיים ומותאמים של PDF417, כולל שליטה בשורות ועמודות, והמדריך קורא הברקוד ב-Python מכסה סריקה כללית של סימבולוגיות שונות. מה שמגיע כאן הוא ניתוח ממוקד ועמוק של זיהוי PDF417.

כל קטע קוד למטה הורץ נגד Aspose.BarCode for Python via .NET 26.7 על לינוקס עם Python 3.12. זמני הריצה ותוצאות הקריאה/החסרה נמדדו, ולא הוערכו, והסקריפט שייצר אותם נמצא בסוף כך שתוכל להריץ אותו מחדש על התמונות שלך.

מה בעצם פוגע בזיהוי PDF417

PDF417 הוא סימבולוגיה מרובדת: שורות של קוד‑מילים, כל קוד‑מילה בנויה מארבעה פסים וארבעה רווחים המתפרסים על פני 17 מודולים. המבנה הזה כולל תיקון שגיאות ריד‑סולומון, ולכן פינה קרועה או כתם קפה בדרך כלל ניתנים לשחזור. מה שלא ניתן לשחזור הוא איבוד רשת המודולים עצמה.

שלושה דברים משבשים את הרשת, בסדר גס של תדירות ההופעה שלהם בייצור:

  • רוחב מודול אפקטיבי שנופל מתחת לשני פיקסלים. זהו הכשל השולט. זה קורה דרך הקטנה, דרך מרחק המצלמה, ודרך טשטוש, שמפיץ את הדיו של מודול אחד על השכנים שלו. ברקוד שנוצר בשלושה פיקסלים למודול ולאחר מכן מטושטש הוא בפועל ברקוד של פיקסל אחד למודול.
  • פרספקטיבה וסיבוב. ברקוד שצולם בזווית יש שורות שאינן עוד קווי סריקה מקבילים. הגלאי מתמודד עם זה, אך זה דורש מעבר זיהוי שההגדרה המהירה ביותר מדלגת עליו.
  • קריסת ניגודיות. נייר תרמי שהדהה, מסך שצולם תחת הילה, או סריקה עם הבהירות נעולה. פחות קטלני ממה שנראה, כפי שמראים המספרים למטה.

ההשלכה המעשית היא שהגדרות הזיהוי הן מנגנון התאוששות, ולא תחליף לאיכות הצילום. הן מחזירות לך את רמת האיכות האמצעית של התמונה. הן אינן מחזירות את הרמה התחתונה.

הגדרת קורא PDF417 ב-Python

התקן את הספרייה מ‑PyPI:

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

ממשק ה‑API לזיהוי נמצא ב-aspose.barcode.barcoderecognition. שני מחלקות חשובות למאמר זה: BarCodeReader, שמבצע גילוי ופענוח, ו‑QualitySettings, ששולטת על כמה המזהה מתאמץ.

קריאת ברקוד 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)
קרא ברקוד PDF417 בפייתון.

קרא ברקוד 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()]

השוואת הגדרות איכות זיהוי PDF417 ב-Python

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מעבר ניסיון נוסף על תמונות שכבר נכשלוהכי איטי בפער רחב

כדי לגלות מה המשמעות של התיאורים האלה בפועל, ייצרתי PDF417 בשלושה פיקסלים לכל מודול, הפחתתי אותו בשישה דרכים עם Pillow, והפעלתי כל הגדרה מראש על כל גרסה. ממוצע של שלוש ריצות:

Source imagehigh_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 מ״ש להוכיח זאת. זוהי בעיית צילום עם תיקון צילום: יותר פיקסלים, פוקוס טוב יותר, 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 לקריאת קודי PDF417 מטושטשים ב-Python.

כוון את QualitySettings לקריאת קודי PDF417 מטושטשים ב-Python.

נמדד: כשל ב‑12 מ״ש ללא ההחלפה, קריאה ב‑54 מ״ש עם ההחלפה. תכונה אחת הפכה את התוצאה, והתוצאה עדיין חזרה מהר יותר מהקבוע max_quality היה מצפה.

המאפיינים שכדאי לדעת:

מאפייןערכיםמתי להשתמש בזה
deconvolutionFAST, NORMAL, SLOWטשטוש תנועה ותמונות מחוץ למיקוד
barcode_qualityHIGH, NORMAL, LOWפגמים בהדפסה, דעיכה תרמית, ארטיפקטים בפקס
x_dimensionAUTO, SMALL, NORMAL, LARGE, USE_MINIMAL_X_DIMENSIONקודי ברקוד צפופים, או גודל מודול קבוע ידוע
minimal_x_dimensionfloatלהצמד עם USE_MINIMAL_X_DIMENSION כדי להגדיר מינימום
complex_backgroundAUTO, DISABLED, ENABLEDקוד ברקוד מודפס על גרפיקה או על טופס עם תבנית
inverse_imageAUTO, DISABLED, ENABLEDקודי ברקוד לבן על שחור, צילום מסך
allow_incorrect_barcodesboolלצורכי דיאגנוסטיקה בלבד, לעולם לא בייצור

האחרון הזה ראוי לאזהרה. allow_incorrect_barcodes מחזיר סמלים שנכשלו באימות סכום הביקורת. זהו כלי ניפוי באגים למענה על השאלה “האם הגלאי מצא כאן משהו בכלל?”. הפצת זאת משמעותה לשגר מחרוזות מפוענחות שגויות במקום שלא קיימות, מה שמחמיר את המצב יותר מאיבוד.

אסטרטגיית רמת שכבות שעובדת היטב בייצור: נסו תחילה normal_quality, ובמקרה של כשל נסו שוב פעם אחת עם high_quality בתוספת deconvolution = SLOW. אתם משלמים את הנתיב היקר רק עבור התמונות שזקוקות לכך.

אימות תוצאות פענוח 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)]

איסוף מחדש של Macro 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

הפעל אותו פעם אחת נגד חמישים הקלטות אמיתיות והדיון המוגדר מראש מסתיים.

ההנחיות המעשיות

  • הגבל את DecodeType ל-PDF417 אלא אם אתה באמת מצפה לסימבוליות משולבות. השתמש ב-MACRO_PDF417, COMPACT_PDF417 או MICRO_PDF417 כאשר אתה יודע איזו גרסה.
  • חתוך לפני שאתה מפענח. שליחת סריקה מלאה של A4 כאשר הברקוד תופס רק 5% ממנה מבזבזת זמן זיהוי ומוסיפה משטח של חיוביות שגויה.
  • שמור קבצים ביניים ללא אובדן. PNG או TIFF. JPEG עם רינגינג בהגדרות איכות נמוכות תוקף בדיוק את קצוות הקו שהמפענח צריך.
  • סדר את הניסיונות שלך ברמות במקום להשתמש בברירת המחדל האיטית ביותר.
  • תקן את הייצור לפני כוונון הזיהוי. אם אתה שולט במקודד, העלאת x_dimension אינה עולה על שום דבר ופותרת יותר תקלות מאשר כל הגדרת קורא. ה-מאמר על יצירת PDF417 מכסה את הפרמטרים האלה.
  • הגדר timeout על כל קורא שנוגע בתמונות שמסופקות על ידי המשתמש.

קבל רישיון חינמי

הגרסה ההערכית מוסיפה סימני מים על הטקסט המפוענח עבור סימבולוגיות שאינן Code 39, מה שעלול להפריע לכל בדיקת סיבוב שאתה מבצע. רישיון זמני חינמי מסיר זאת עבור ההערכה.

משאבים נוספים בחינם

סיכום

קריאת ברקוד PDF417 בפייתון היא פעולה של שתי שורות על תמונות נקיות ובעיית הנדסה על תמונות אמיתיות. המדידות שלמעלה מצביעות על גישה פשוטה: שם את DecodeType, השתמש בברירת המחדל normal_quality, נסה שוב פעם אחת עם high_quality והפעל דקונבולוציה, ולוודא כל תוצאה לפני הפעולה. שמור את הפרמטרים היקרים לנתיב הניסיון מחדש, וכאשר מחלקה שלמה של תמונות נכשלת בכל הגדרה, תקן את הלכידה במקום הקורא. שאלות מוזמנות בפורום התמיכה החינמי.

שאלות נפוצות

  1. למה ברקוד PDF417 זהה נקרא בתמונה אחת ונכשל בתמונה אחרת?
    ההכרה תלויה במספר הפיקסלים שכל מודול תופס לאחר הצילום. טשטוש, הקטנה ודחיסת JPEG מצמצמים את רוחב המודול האפקטיבי, וברגע שמודול נופל מתחת לכשניים פיקסלים נקיים, אף פריסט אינו יכול לשחזר אותו.

  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. איך אני יודע אם תוצאה מפוענחת ניתנת לאמון?
    בדוק את reading_quality ו‑confidence ב‑BarCodeResult, והשתמש בריבוע region כדי לאשר שהברקוד נמצא במיקום הצפוי בתמונה.

  6. האם ניתן לקרוא PDF417 מתמונה של רישיון נהיגה או כרטיס עלייה?
    כן, בתנאי שהצילום בפוקוס והברקוד אינו נחתך. חתוך לאזור הברקוד לפני הקריאה, והעדף PNG על פני JPEG לקבצים ביניים.

קרא עוד