5.20. רגרסיה ודמיון¶
שתי מדידות נוספות במחלקה Image מסכמות את התמונה כמשהו שונה מהתפלגות של ערכי פיקסלים. רגרסיה לינארית של פיקסלים שעברו סף נותנת ליישום קו שהוא יכול לפעול לפיו – הקלט הקלאסי לרובוט עוקב-קו. מדידת דמיון נותנת ליישום מספר יחיד המתאר עד כמה שתי תמונות דומות – הקלט הטבעי לבדיקת רגרסיה של תמונת-זהב או לגלאי שינויים גסים.
5.20.1. רגרסיה לינארית¶
כאשר פיקסלי החזית של תמונה במקרה יוצרים קו לרוחב הפריים – הסרט על מסלול שרובוט עוקב אחריו, קו האופק, קצה כביש או מסדרון – היישום בדרך כלל אינו רוצה כל פיקסל חזית בודד. הוא רוצה את קו ההתאמה הטוב ביותר דרך כולם, מפורמט כך שיוכל להחליט כיצד הקו מכוון והיכן הוא חוצה את הפריים.
get_regression() מבצעת התאמה זו. היא מקבלת את אותה צורת tuple של סף שבה משתמשות binary() ו-find_blobs(), מזהה כל פיקסל שתואם לסף, ומחזירה תוצאת line יחידה המתארת את קו ההתאמה הטוב ביותר דרך אותם פיקסלים:
line = img.get_regression([(0, 60)])
if line:
img.draw_line((line.x1(), line.y1(),
line.x2(), line.y2()),
color=(255, 0, 0))
ההתאמה היא רגרסיה לינארית מסוג Theil-Sen – שיטה עמידה שסובלת ערכים חריגים טוב יותר מהתאמת הריבועים הפחותים המוכרת יותר. קומץ קטן של פיקסלים רחוקים מהקו האמיתי אינם מטים את התוצאה כפי שהיו עושים עם ריבועים פחותים, מה שתואם את מציאות החזית הרועשת של פלט סף אמיתי.
תוצאת ה-line נושאת את נקודות הקצה החתוכות למלבן התמונה (x1, y1, x2, y2), את אורך הקו וגודלו (length, magnitude), ואת התיאור הגיאומטרי של הקו בצורה קוטבית (theta, rho) – הזווית של הקו מהאופקי ומרחקו האנכי מהראשית. הצורה הקוטבית היא מה שלולאת בקרה בדרך כלל רוצה: theta אומר לרובוט לאיזה כיוון הקו נוטה, rho אומר לו היכן הקו חוצה את התמונה, ולולאת משוב על השניים שומרת את הרובוט ממורכז על הקו.
קומץ ארגומנטי מילת מפתח מכווננים את העמידות והעלות. x_stride ו-y_stride מדלגים על פיקסלים במהלך ההתאמה – צעדים גדולים יותר הופכים את הרגרסיה לזולה יותר במחיר התאמת פחות פיקסלים. area_threshold ו-pixels_threshold דוחים קווים שאין מאחוריהם מספיק פיקסלים תואמים. target_size מקטין מחדש את הקלט לגודל קטן יותר לפני ההתאמה – הרגרסיה רצה מהר יותר על תחליף 80-על-60 של התמונה ללא אובדן רב בדיוק כיוון הקו.
אם לא ניתן היה להתאים קו מקובל – אם הסף לא תאם אף פיקסל, או תאם תבנית שאינה נראית כמו קו – המתודה מחזירה None. קוד עקיבת-קו אמיתי מגן על כל קריאת get_regression() בבדיקת None לפני שהוא ניגש לתכונות הקו.
5.20.2. דמיון תמונות¶
סוג שונה של מדידה: במקום לשאול ”מה התמונה מכילה?“, שואלים ”עד כמה שתי התמונות הללו דומות?“. הפעולה שאליה פונים היא get_similarity(), אשר מחשבת את מדד הדמיון המבני (SSIM) בין תמונת המקור לבין תמונת התייחסות.
s = img.get_similarity(reference)
print(s.mean, s.stdev)
SSIM הוא מדד הדמיון התקני בין תמונות הנמצא בשימוש לרוחב עיבוד התמונה משום שהוא מתנהג כפי שהאינטואיציה האנושית לגבי דמיון מתנהגת – הסטה קטנה או שינוי קטן בבהירות מורידים את הציון מעט, בעוד ששינוי מבני גדול (אובייקט חסר, סצנה שונה) מוריד אותו באופן דרמטי. הציון נע בין -1 לבין +1: +1 משמעו ששתי התמונות זהות, 0 משמעו שהן אינן קשורות, ו--1 משמעו שהן הפוכות מבחינה מבנית. אובייקט similarity מוחזר חושף את ה-SSIM הממוצע על פני התמונה, בנוסף לסטיית התקן, ה-min וה-max של הציונים לכל אריח.
עבור סוג ההשוואה שבו מספר קטן טוב יותר ממספר גדול – בדיקת רגרסיה שאמורה לדווח אפס על ”שום דבר לא השתנה“ ולעלות ככל שהשינויים מצטברים – הדגל dssim=True מחזיר את אי-הדמיון המבני: ה-SSIM הממוצע מחוסר מ-1, כך שערך ההחזרה הוא 0.0 עבור תמונות זהות ועולה ככל שהן נבדלות.
5.20.3. מקרי שימוש ל-SSIM¶
שני היישומים הנפוצים:
בדיקת רגרסיה של תמונת-זהב. מסגרת בדיקה לוכדת פריים התייחסות בתנאים ידועים-תקינים ושומרת אותו כתמונת הזהב. ריצות בדיקה עוקבות לוכדות באותם תנאים ומשוות מול תמונת הזהב בעזרת SSIM. ציון מעל סף כלשהו (0.95 או 0.98 בהתאם לסבילות) הוא הצלחה; מתחת הוא כישלון. מסגרת הבדיקה אינה צריכה לדעת מה השתנה – ציון ה-SSIM הוא האות.
זיהוי שינוי גס. יישום שרוצה גרסה גסה יותר של חישוב הפרש פריימים – כזו שמתעלמת משינויי בהירות קטנים אך מגיבה לשינויים מבניים גדולים – יכול להשתמש ב-SSIM מול פריים התייחסות במקום ב-difference() לכל פיקסל ואחריו סף. SSIM רגיש פחות לסחיפת תאורה מאשר חישוב הפרש לכל פיקסל, מה שהופך אותו לבחירה הטובה יותר כאשר המטרה היא לזהות ”הסצנה נראית שונה מהותית“ במקום ”פיקסל בודד כלשהו השתנה.“
שני היישומים משתמשים באותה קריאה – img.get_similarity(reference) – ומופעלים על סף של הציון המוחזר. ההבדל הוא רק האם הסף גבוה (בדיקת רגרסיה, מחפשת התאמה כמעט-זהה) או נמוך (זיהוי שינוי, מחפש כל שינוי מבני גדול).
5.20.4. צורת ה-transform-and-compare¶
דקות שימושית: get_similarity() מקבלת את אותם פרמטרים x, y, x_scale, y_scale, roi, rgb_channel, alpha, color_palette, alpha_palette, hint, ו-transform כמו draw_image(). תמונת ההתייחסות ממוקמת, מותאמת בקנה מידה, ועוברת טרנספורמציה על ידי אותם פרמטרים לפני שהשוואת ה-SSIM רצה.
משמעות הדבר היא שיישום יכול לשאול ”עד כמה הסצנה הזו דומה לפריים התייחסות לאחר היסט / סיבוב / שינוי קנה מידה ידוע“ מבלי להכין תמונת התייחסות שעברה טרנספורמציה מראש. זוהי הדרך הזולה לבנות עוקב שמחפש במרחב פרמטרים ומדווח איזו טרנספורמציה של ההתייחסות תואמת בצורה הטובה ביותר את הפריים הנוכחי.