5.18. היסטוגרמות וסטטיסטיקות¶
לצד הפעולות שמשנות את הפיקסלים של תמונה, המחלקה Image נושאת משפחה של מתודות אשר מודדות אותם – מסכמות את התפלגות ערכי הפיקסלים, מחזירות את הבהירות הממוצעת והחציונית, מאתרות את נקודת החיתוך האופטימלית בין פיקסלים כהים לבהירים, ומדווחות על הפיזור של ערוצי הצבע. המדידות מזינות יישומים בשתי דרכים: כקלט לקוד שמחליט באיזה סף להשתמש, איזה הגבר (gain) להגדיר, וכיצד נראה הפרופיל הגוני של הסצנה; וכאותות אבחון – ”האם הסצנה בהירה מספיק?“ – שיישום יכול לפעול לפיהם מבלי לקבל החלטה לגבי פיקסל מסוים כלשהו.
נקודת המוצא כמעט לכל מדידה היא ה-היסטוגרמה.
5.18.1. ההיסטוגרמה¶
היסטוגרמה של תמונה היא ספירה של כמה פיקסלים יש לכל ערך בהירות אפשרי. עבור תמונה בגווני אפור, זוהי רשימה של ספירות הממופתחת לפי הערכים 0 עד 255. עבור תמונת צבע, אלו שלוש רשימות כאלה – אחת לכל ערוץ.
get_histogram() מחשבת אחת כזו:
h = img.get_histogram()
האובייקט המוחזר הוא תוצאת histogram החושפת את רשימות התאים (bins) לכל ערוץ וכמה שאילתות ברמה גבוהה עליהן. ספירות התאים מנורמלות כך שסכומן הוא 1.0 – ההיסטוגרמה מתארת את פרופיל ההתפלגות ולא את ספירת הפיקסלים המוחלטת, מה שהופך את המדידות לברות-השוואה בין תמונות בגדלים שונים.
עבור תמונות בגווני אפור להיסטוגרמה יש ערוץ אחד של תאים, הזמין דרך h.bins() (או באופן שקול h[0]). עבור תמונות RGB565 ההיסטוגרמה מחושבת במרחב הצבע LAB שהוצג בעמוד יצירת הסף הבינארי, עם שלושה ערוצי תאים הזמינים דרך h.l_bins(), h.a_bins(), h.b_bins() (או h[0], h[1], h[2]). LAB הוא אותה בחירה שבה משתמשות מתודות הסף והמעקב; היסטוגרמות מסכימות עם הספים לגבי המרחב שבו נמדד הצבע.
5.18.2. תאים וספירת התאים¶
להיסטוגרמת ברירת המחדל יש תא אחד לכל ערך פיקסל אפשרי – 256 תאים עבור ערוץ של 8 ביט. לעיתים זוהי רזולוציה דקה יותר ממה שהיישום צריך. מסווג שאכפת לו רק מהפרופיל הגס של ההתפלגות עשוי להיות מטופל טוב יותר עם ספירת תאים קטנה יותר – 32 או אפילו 8 תאים – מה שגם רץ מהר יותר וגם מפיק תוצאה נקייה יותר מול רעש. מילת המפתח bins (וכן l_bins, a_bins, b_bins לכל ערוץ עבור צבע) קובעת את הספירה:
h = img.get_histogram(bins=32)
תיחום ROI וסף עובד באותו אופן כמו בכל מתודת מדידה אחרת. העבירו roi כדי לצמצם את ההיסטוגרמה למלבן של פיקסלים; העבירו רשימת thresholds כדי לכלול רק פיקסלים שתואמים לטווחים אלו. צורת הסף היא מה שהופך את ”חישוב ההיסטוגרמה של הפיקסלים התואמים בלבד“ לפעולה בקריאה אחת – תבנית נפוצה כאשר יישום מעוניין לאפיין את המרקם של אזור שכבר זוהה מבלי שיצטרך לעבור על הפיקסלים בעצמו.
היסטוגרמה בגווני אפור עם שלוש מדידות סיכום מוטלות מעל: סף Otsu (נקודת החיתוך המפצלת בצורה הטובה ביותר את האשכולות הכהים והבהירים), הממוצע, והחציון. כל מדידה אומרת משהו שונה על אותה התפלגות.¶
5.18.3. סטטיסטיקות¶
היסטוגרמה היא תיאור של השכיחות של כל ערך; סטטיסטיקות הן הסיכומים המספריים הנגזרים ממנה. אובייקט ה-statistics המוחזר על ידי get_statistics() נושא את הקבוצה הסטנדרטית:
mean– הממוצע החשבוני של ערכי הפיקסלים.median– הערך שמתחתיו נמצאים מחצית מהפיקסלים.mode– הערך היחיד הנפוץ ביותר.stdev– סטיית התקן, מדד לפיזור סביב הממוצע.minו-max– ערכי הפיקסלים הבהירים והכהים ביותר הקיימים.lqו-uq– נקודות החיתוך של הרבעון התחתון והעליון.
עבור תמונת RGB565 הצורות לכל ערוץ (l_mean, a_median, b_mode, וכן הלאה) מספקות את אותן מדידות ערוץ אחר ערוץ.
רוב המספרים הללו עולים בהקשרים מסוימים. mean ו-stdev יחד נותנים אומדן רעש: סצנה שאמורה להיות אחידה תהיה בעלת stdev קטן, בעוד שחיישן רועש ייתן לאותה סצנה stdev גדול יותר. min ו-max נותנים את ה-ניגודיות של התמונה: ככל שהם קרובים יותר, כך הסצנה שטוחה יותר; ככל שהם רחוקים יותר, כך יש לאלגוריתם יותר טווח דינמי לעבוד איתו. median הוא המרכז העמיד כאשר להתפלגות יש ערכים חריגים (כמה פיקסלים בהירים מאוד אינם מושכים את החציון כפי שהם מושכים את הממוצע). mode הוא הערך היחיד הנפוץ ביותר, שימושי למציאת רמת הרקע של תמונה שהרקע שלה מכסה את רוב הפיקסלים.
get_statistics() מריצה את מעבר ההיסטוגרמה באופן פנימי ואז מסכמת אותו; העברת אותם ארגומנטים thresholds ו-roi כמו של היסטוגרמה שחושבה קודם מפיקה את הסטטיסטיקות עבור אותה קבוצת פיקסלים.
5.18.4. אחוזונים וחיפושי CDF¶
אובייקט ה-histogram חושף מתודה get_percentile() שהופכת שבר לערך פיקסל – הערך שמתחתיו נמצא השבר המבוקש של הפיקסלים. h.get_percentile(0.5) הוא החציון; h.get_percentile(0.05) ו-h.get_percentile(0.95) יחד נותנים min/max עמיד שמתעלם מ-5% התחתונים והעליונים כערכים חריגים.
זוהי הצורה שבה יישום משתמש כאשר הוא רוצה לאפיין את ה-טווח של ערכי הפיקסלים מבלי לאפשר לקומץ פיקסלים בהירים או כהים תועים להטות את התשובה. ה-min/max העמיד מהאחוזון ה-5 וה-95 הוא גם הקלט הטבעי למעבר של מתיחת ניגודיות – המיפוי-מחדש לכל פיקסל שמכוסה בעמוד תיקוני גוון.
5.18.5. שיטת Otsu¶
היסטוגרמות עונות על שאלה נוספת ששווה להזכיר בפני עצמה: בהינתן תמונה שהפיקסלים שלה מתפצלים לאשכול ”כהה“ ואשכול ”בהיר“, מהי נקודת החיתוך ביניהם? עמוד יצירת הסף כבר ציין את המנגנון לפי תוצאתו – סף גלובלי יחיד שהיישום יכול למסור ל-binary() – אך דחה את ה-כיצד. ה-כיצד הוא שיטת Otsu, והוא שוכן בהיסטוגרמה.
האינטואיציה: תמונה עם חזית ורקע ברורים בעלת שני אשכולות בהיסטוגרמת הבהירות שלה, עם עמק ביניהם. המקום הנכון ליצור את הסף הוא תחתית העמק – הערך שבו שני האשכולות מופרדים בצורה הטובה ביותר. שיטת Otsu מחפשת כל נקודת חיתוך אפשרית ובוחרת את זו שבה השונויות בתוך האשכולות הן הקטנות ביותר (מה שזהה לאמירה שהשונות בין האשכולות היא הגדולה ביותר), והתוצאה היא הפיצול הבינארי האופטימלי עבור התפלגות התמונה הספציפית הזו.
אובייקט ה-histogram חושף את Otsu דרך get_threshold:
h = img.get_histogram()
t = h.get_threshold()
לאובייקט ה-threshold המוחזר יש את התכונות value (עבור גווני אפור) או l_value / a_value / b_value (עבור צבע) הנושאות את נקודת החיתוך הנבחרת. הזנת התוצאה ישירות בחזרה ל-binary() נותנת סף גלובלי שמכוונן את עצמו ושנקודת החיתוך שלו נבחרת על ידי התמונה עצמה:
img.binary([(t.value, 255)])
תבנית זו אינה פותרת את בעיית התאורה הלא-אחידה שהסף האדפטיבי מבוסס-הפילטר פותר; מה שהיא פותרת הוא השאלה ”באיזה ערך עליי לחתוך?“ כאשר יצירת סף גלובלית היא כבר הגישה הנכונה. עבור סצנה שבה ההבחנה בין חזית לרקע מוגדרת היטב, הערך ש-Otsu בוחר נמצא בדרך כלל בטווח של כמה יחידות ממה שאדם היה בוחר בעין.
5.18.6. חישוב על תמונת הפרש¶
פרט שימושי לגבי get_histogram() ו-get_statistics(): שתיהן מקבלות מילת מפתח difference שמקבלת Image נוספת ומחשבת את ההיסטוגרמה (או הסטטיסטיקות) של ההפרש לכל פיקסל בין המקור לבין אותה תמונה, מבלי להקצות תמונת הפרש נפרדת. זוהי הדרך הזולה לשאול ”כמה השתנתה הסצנה מאז פריים ההתייחסות?“ מבלי לשלם עבור קריאת difference() מפורשת שמייצרת תמונה שכל מטרתה היא להימדד. עבור סקריפט זיהוי תנועה הרץ ברציפות, החיסכון מצטבר.