5.27. מציאת עיגולים ומלבנים¶
קווים וקטעים מכסים את הקצוות הישרים בפריים שנלכד, אך רבים מהמאפיינים בעולם האמיתי שהמצלמה מחפשת אינם ישרים. מטבע המונח על שולחן הוא עיגול. תווית מודפסת, פתק דביק, או חלקו העליון של ארגז הנצפה מזווית הם מרובע. מודול image חושף גלאי ייעודי לכל אחד: חיפוש בסגנון Hough לעיגולים וחיפוש שמקורו ב-AprilTag לצורות בעלות ארבע צלעות.
שתי המתודות עוקבות אחר אותו תבנית כמו גלאי הקווים – threshold שולט בכמה קולות זיהוי צריך, roi מצמצם את החיפוש, והאובייקטים המוחזרים נושאים גם מיקום וגם עוצמת ביטחון – אך מרחבי הפרמטרים והערכים המהוונים הנכונים שונים מספיק כדי להצדיק כיסוי מפורש.
5.27.1. עיגולי Hough¶
find_circles() מריצה את הווריאנט המעגלי של התמרת Hough. כל פיקסל קצה ממעבר ה-Sobel המקדים מצביע עבור כל עיגול שעשוי לעבור דרכו; עיגולים שצוברים מספיק קולות מוחזרים.
circles = img.find_circles(threshold=3500,
x_margin=10, y_margin=10, r_margin=10,
r_min=10, r_max=80, r_step=2)
for c in circles:
img.draw_circle((c.x, c.y, c.r), color=(255, 0, 0))
threshold הוא סכום המינימום של עוצמות קצה Sobel לאורך העיגול המועמד. עיגולים גדולים יותר משרטטים יותר פיקסלים ולכן זקוקים לספים גבוהים יותר כדי לעבור; ערך שמוצא מטבע ברדיוס של 20 פיקסלים יופעל גם על רעש סביב קצה של 100 פיקסלים, בעוד ערך שכוונן עבור המטבע הגדול יחמיץ את הקטן. כאשר טווח הרדיוס המבוקש ידוע, הסף הנכון מתאים את עצמו להיקף – בקירוב threshold = 50 * 2 * pi * r נותן נקודת התחלה סבירה, והערך הנכון נובע ממעבר כיוונון קצר.
r_min, r_max ו-r_step מגדירים את חיפוש הרדיוס. ללא גבולות, הגלאי היה מחפש כל רדיוס מכמה פיקסלים ועד מחצית רוחב התמונה, מה שגם איטי וגם מתכון לתוצאות שגויות. הגדרת r_min ו-r_max כך שיתחמו את גודל היעד הצפוי במרווח נדיב (למשל r_min=15, r_max=25 עבור מטבע שידוע כי הוא סביב 20 פיקסלים) מצמצמת את העבודה משמעותית ומשפרת את יחס האות לרעש של הקולות. r_step שולט ברזולוציה של החיפוש; צעדים גדולים יותר רצים מהר יותר ועלולים להחמיץ עיגול שהרדיוס האמיתי שלו נופל בין שני ערכים שנדגמו. ברירת המחדל r_step=2 היא פשרה סבירה.
x_margin, y_margin ו-r_margin שולטים במיזוג של זיהויים סמוכים, כפי ש-theta_margin ו-rho_margin עושים עבור זיהוי קווים. עיגול פיזי יחיד בתמונה מצביע עבור אשכול של עיגולים מועמדים שמרכזיהם ורדיוסיהם תואמים זה לזה בטווח של כמה פיקסלים; השוליים מכווצים כל אשכול לשיא שלו לפני שרשימת התוצאות נבנית. שוליים גדולים יותר מחזירים פחות זיהויים, בטוחים יותר; שוליים קטנים יותר מחזירים יותר זיהויים עם כפילויות אפשריות.
x_stride ו-y_stride מתקדמים בסריקת ההצבעה, באותה דרך שהם עושים זאת בגלאים האחרים. ברירת המחדל של 2 ו-1 מתאימה לרוב התמונות; העלאת שניהם ל-4 היא פשרת המהירות הסטנדרטית עבור תמונה שידוע כי היא מכילה עיגולים גדולים.
כל Circle מוחזר נושא x, y, r (המרכז והרדיוס) ו-magnitude (סך הקולות, שימושי כציון ביטחון למיון או סינון). ציור הזיהוי בחזרה לתוך הפריים הוא קריאה אחת – draw_circle() מקבלת את השלשה (x, y, r), הזמינה כ-(c.x, c.y, c.r) ישירות מהתוצאה.
5.27.2. מלבנים¶
find_rects() שואלת את גלאי המרובעים מצינור העיבוד של AprilTag – אותה שגרה שמאתרת את הריבוע השחור סביב תג נחשפת בנפרד כמאתר מלבנים לשימוש כללי.
rects = img.find_rects(threshold=12000)
for r in rects:
img.draw_rectangle(r.rect, color=(0, 255, 0))
for corner in r.corners:
img.draw_circle((corner[0], corner[1], 4),
color=(0, 255, 0))
threshold הוא סכום המינימום של עוצמות קצה סביב היקף המלבן. מלבן מודפס שחור-על-לבן בפריים מואר היטב חוצה בקלות את 10000; מלבן חיוור על רקע בעל מרקם עשוי להזדקק לירידה ל-2000 – תוך החלפת תוצאות שגויות ברגישות. כמו גלאי העיגולים, הערך הנכון נובע ממעבר כיוונון מהיר כאשר היעדים המיועדים בשדה הראייה.
הגלאי הוא הטלתי – הוא מוצא מרובעים שצלעותיהם ישרות אך לא בהכרח מקבילות או מיושרות לצירים. תווית הנצפית מזווית נראית כמו טרפז בתמונה, וגלאי המלבנים מוצא אותה כראוי; מלבן מיושר לצירים הוא פשוט המקרה המנוון שבו ארבע הפינות במקרה יוצרות תיבה ישרת זווית. roi מגביל את החיפוש; שאר ארגומנטי מילות המפתח לוקחים את ברירות המחדל שלהם מצינור העיבוד של AprilTag ולעיתים רחוקות זקוקים לכיוונון.
כל Rect מוחזר נושא את התיבה התוחמת המיושרת לצירים – x, y, w, h, בתוספת השלשה הרביעיה rect ש-draw_rectangle() מצפה לה – וגם את ארבע הפינות שזוהו כ-corners. התיבה התוחמת היא מה שהיישום משתמש בו עבור מיקום וגודל גסים; הפינות מתארות את המרובע ההטלתי עצמו. כאשר המצלמה צופה ביעד שטוח מזווית והיישום צריך לבטל את עיוות הטרפז – לקרוא טקסט על תווית, לדגום צבע מאזור שטוח – הפינות מוזנות ישירות אל rotation_corr() עם מילת המפתח corners= (ראו תיקון עדשה ופרספקטיבה), והפלט הוא המלבן המתוקן המוכן לכל ניתוח שיבוא בהמשך.
אזהרה
מכיוון שהגלאי מכוונן עבור מה שצינור העיבוד של AprilTag צריך – מרובעים בעלי גבולות חזקים ובניגודיות גבוהה, כמו מתאר תג שחור על נייר לבן – הוא אינו מעבר שמוצא-כל-מלבן. מלבנים בעלי ניגודיות רכה, קצוות בעלי מרקם, או סביבה עמוסה עלולים להישאר בלתי מזוהים לחלוטין. עד כמה הוא עובד טוב תלוי במצב: בדקו אותו מול היעדים האמיתיים מוקדם, לפני בניית צינור עיבוד סביבו.
5.27.3. כאשר הגלאי טועה¶
עיגולים בפרט נהנים ממסנן-מקדים על הקלט. פריים רועש מניב הרבה פיקסלי קצה תועים שכולם מצביעים, ומרחב Hough שנוצר כתוצאה מכך בעל שיאים רחבים ומטושטשים שלממזג קשה להפריד ביניהם. מעבר gaussian() או mean() לפני find_circles() מחליק את הרעש ומשאיר את הקצוות האמיתיים שלמים; הגלאי מחזיר שיאים נקיים יותר בפחות זמן.
עבור מלבנים, מצב הכשל הנפוץ הוא ההפוך: ניגודיות נמוכה בין המלבן לרקע שלו פירושה שסכום עוצמות הקצה לעולם אינו חוצה את threshold. מעבר histeq() כדי לפזר מחדש את טווח הבהירות על פני כל המרחב מ-0 עד 255 משחזר את הניגודיות שהגלאי צריך. (הניגודיות חייבת להתקיים היכנשהו בתמונה; השוואת היסטוגרמה יכולה רק להגביר את מה שכבר קיים שם.)