5.19. תיקוני גוון

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

התיקונים שייכים לשתי משפחות: התאמות בהירות-וניגודיות שמחלקות מחדש את הבהירות, והתאמות צבע שמשנות את הצבע שכל פיקסל נקרא כמותו. לשתיהן יש מקבילות ב-ISP של החיישן, שמתקן כל פריים בדרכו פנימה; המתודות כאן חלות על Image שכבר נלכד, בדיעבד, עבור המקרים שבהם הפריים זקוק ליותר תיקון מכפי שה-ISP סיפק.

5.19.1. השוואת היסטוגרמה

פעולת מתיחת הניגודיות הפשוטה ביותר היא השוואת היסטוגרמה. הרעיון הוא למפות מחדש את ערכי הפיקסלים כך שההיסטוגרמה של הפלט תהיה שטוחה ככל האפשר – כל ערך מופיע בערך באותה תדירות. האפקט החזותי הוא שתמונה בעלת ניגודיות נמוכה (כזו שההיסטוגרמה שלה מרוכזת ברצועה צרה) הופכת לתמונה בעלת ניגודיות גבוהה שהפיקסלים שלה מכסים את כל הטווח 0255.

histeq() מריץ את ההשוואה:

img.histeq()

המנגנון ישיר. פונקציית ההתפלגות המצטברת (CDF) של ההיסטוגרמה של המקור מחושבת; כל ערך פיקסל קלט ממופה למיקומו ב-CDF, מותאם לסקאלת הפלט. במקום שבו הפיקסלים כבר היו פרוסים באופן אחיד, המיפוי קרוב לזהות; במקום שבו הפיקסלים נערמו בבהירות אחת, המיפוי פורש אותם על ידי מתיחת אותה בהירות על פני טווח רחב יותר של ערכי פלט.

התוצאה דרמטית בסצנות בעלות ניגודיות נמוכה – ההבדל בין צילום פנים עמום לבין אותו צילום לאחר histeq הוא לעיתים קרובות ההבדל בין ”בלתי קריא“ לבין ”קריא לחלוטין“. הפשרה היא שהפעולה מגבירה הכול, כולל רעש חיישן. בסצנה עם פרטי ניגודיות נמוכה אמיתיים שצריך לשחזר, histeq הוא התשובה הנכונה; בסצנה נקייה וחשופה היטב שפשוט אינה זקוקה לכך, histeq מכניס רעש נראה לעין.

5.19.2. CLAHE: השוואה אדפטיבית

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

הווריאנט האדפטיבי הוא Contrast Limited Adaptive Histogram Equalisation, המכונה בדרך כלל CLAHE. במקום CDF גלובלי אחד, CLAHE מחשב CDF נפרד עבור כל אריח קטן של התמונה, משווה כל אריח כנגד ה-CDF שלו עצמו, וממזג יחד את גבולות האריחים. התוצאה היא שהתאמות הבהירות מתרחשות מקומית – הפינה המוצללת מקבלת השוואה משלה מבלי שהפינה הבהירה תמשוך אותה לכיוון השגוי.

הדגל adaptive=True מעביר את histeq() למצב CLAHE:

img.histeq(adaptive=True, clip_limit=10)

הפרמטר clip_limit הוא החלק ב-CLAHE שאליו מתייחס ”contrast limited“ שבשם. השוואה מקומית עלולה להגביר יתר על המידה רעש באזורים שטוחים שבהם ל-CDF יש מעט מאוד ערכים נבדלים; מגבלת הקיטום מגבילה כמה אגרסיבית כל סל בודד יכול להתחלק מחדש, מה שמונע את הגברת הרעש תוך כדי מתן אפשרות למתיחת הניגודיות במקום שזה חשוב. ערך סביב 10 הוא נקודת התחלה סבירה; ערכים גדולים יותר מאפשרים ל-CLAHE לעבוד קשה יותר במחיר של רעש נראה יותר, ערכים קטנים יותר הופכים אותו לעדין יותר.

CLAHE יקר יותר מ-histeq הגלובלי, אך מפיק תוצאות נקיות יותר בסצנות שבהן הבהירות מחולקת באופן לא אחיד – שזה רוב הסצנות בעולם האמיתי.

5.19.3. גמא, ניגודיות ובהירות

השוואת היסטוגרמה היא הדרך מונחית-הנתונים למפות מחדש בהירות. הדרך הבלתי-תלויה-בנתונים היא ליישם עקומה נבחרת, המתופרמטרת על ידי כמה כפתורי כוונון קלים. gamma() מספק שלושה:

img.gamma(gamma=1.0, contrast=1.0, brightness=0.0)

כל פרמטר מיישם טרנספורמציה ספציפית אחת על כל פיקסל:

gamma מריץ את ערכו של כל פיקסל דרך פונקציית החזקה output = input ** (1 / gamma). המשמעות הסטנדרטית: ערכים גדולים מ-1.0 מבהירים את התמונה ומרימים גווני ביניים (תיקון ”גמא הצג“ הקלאסי); ערכים קטנים מ-1.0 מכהים אותה. הפרמטר אינו ליניארי – הוא משמר את נקודות השחור והלבן ורק מעצב מחדש את ההתפלגות שביניהן, וזו ההתנהגות הנכונה כאשר המטרה היא לשחזר פרטים באזורי צל או אזורים בהירים מבלי למחוץ את הקצוות הקיימים.

contrast מריץ כל פיקסל דרך הכפלה ישירה סביב נקודת האפור-בינוני. ערכים גדולים מ-1.0 מגבירים את הניגודיות (הכהה נעשה כהה יותר, הבהיר נעשה בהיר יותר, האפור-בינוני נשאר זהה); ערכים קטנים מ-1.0 מפחיתים את הניגודיות.

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

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

5.19.4. איזון לבן אוטומטי

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

img.awb()

ברירת המחדל משתמשת באלגוריתם gray-world: הצבע הממוצע של התמונה כולה מונח כניטרלי אפור, וההגברים לכל ערוץ מותאמים כדי שכך יהיה. הצורה החלופית max=True משתמשת באלגוריתם white-patch: הפיקסלים הבהירים ביותר מונחים כלבן ניטרלי, וההגברים מותאמים כדי שכך יהיה. שניהם עובדים על RGB565 ועל Bayer גולמי; אף אחד מהם לא עובד על גווני אפור (שבהם אין צבע לאזן) או YUV (שבו ייצוג הצבע אינו זה שעליו אלגוריתמים אלו פועלים).

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

5.19.5. מטריצת תיקון הצבע

כאשר תיקון הצבע שהתמונה זקוקה לו אינו השינוי לכל ערוץ שאיזון הלבן נותן, אלא ערבוב ערוצים כללי יותר, הפעולה שאליה יש לפנות היא מטריצת תיקון הצבע. המתודה ccm() מיישמת מטריצה 3 על 3 (או 3 על 4 עם היסט) שמכפילה את הווקטור (r, g, b) של כל פיקסל כדי לייצר וקטור (r, g, b) חדש:

img.ccm([[1.1, -0.05, -0.05],
        [-0.05, 1.1, -0.05],
        [-0.05, -0.05, 1.1]])

המטריצה מאפשרת לאפליקציה לתקן הפרעה צולבת בין ערוצי הצבע – כאשר תגובת חיישן האדום כוללת מעט אור ירוק, למשל, המטריצה יכולה להחסיר חלק מהערוץ הירוק מפלט האדום כפיצוי. בשילוב עם היסט לכל ערוץ, הצורה 3 על 4 מאפשרת לאפליקציה גם לאפס מחדש כל ערוץ.

החומר על צינור ה-ISP מכסה את המדוע של מטריצות תיקון הצבע. הצורה שלאחר-הלכידה על Image היא בדיוק אותה פעולה, מיושמת בדיעבד.