קומפוזיציה, מסקינג ופסיפס

אחרי שטענתם את אוסף ההחזרות של Landsat 8 TOAלתוך משתנה בשם l8, ראיתם שהקוד הבא יוצר קומפוזיציה של ערכים עדכניים:

עורך הקוד (JavaScript)

var l8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA');
var landsat2016 = l8.filterDate('2016-01-01', '2016-12-31');
Map.addLayer(landsat2016, visParams, 'l8 collection');

אחת הבעיות בתמונה המורכבת הזו היא שהיא מלאה בעננים. במקום רק לקחת את הפיקסל האחרון באוסף (כשמוסיפים אוסף למפה, Earth Engine קורא באופן מרומז ל-mosaic()), אפשר לצמצם את ImageCollection (מידע נוסף על צמצום אוספים של תמונות).

שילוב תמונות באמצעות רכיבי Reducer

הסבר על פונקציות לצמצום נתונים ניתן לכם לראשונה בקטע קבלת נתונים סטטיסטיים באזור של תמונה. זה היה צמצום מרחבי. צמצום של אוסף תמונות לתמונה אחת הוא צמצום זמני אם האוסף מייצג תמונות שצולמו לאורך זמן. סוג ה-Reducer שבו אתם משתמשים מגדיר איך Earth Engine מטפל בפיקסלים חופפים. לוויין Landsat 8 מבקר באותה נקודה על פני כדור הארץ כל 16 ימים. המשמעות היא שבמהלך תקופה של 6 חודשים, יהיו בערך 12 תמונות (ועוד תמונות במקומות שבהם הסצנות חופפות). כל פיקסל במפה נגזר מערימה של פיקסלים – אחד מכל תמונה באוסף שמוצג.

אם רק מוסיפים את האוסף למפה, הפיקסל האחרון נבחר – הפיקסל מהתמונה האחרונה בערימה. אפשר לשנות את ההתנהגות הזו באמצעות פונקציות לצמצום נתונים ב-Earth Engine. לדוגמה, במקום לקחת את הפיקסל האחרון מהמערך, אפשר להנחות את Earth Engine לבחור את ערך החציון במערך. היתרון בכך הוא הסרת עננים (בעלי ערך גבוה) וצללים (בעלי ערך נמוך). כשמצמצמים אוסף תמונות באמצעות פונקציית ה-reducer של החציון, הערך המורכב הוא החציון בכל פס, לאורך זמן. לדוגמה, שימוש בסצנות של Landsat בשנת 2016:

עורך הקוד (JavaScript)

// Get the median over time, in each band, in each pixel.
var median = l8.filterDate('2016-01-01', '2016-12-31').median();

// Make a handy variable of visualization parameters.
var visParams = {bands: ['B4', 'B3', 'B2'], max: 0.3};

// Display the median composite.
Map.addLayer(median, visParams, 'median');

הדבר החדש בקוד הזה הוא השיטה median() שמוחלת על אוסף תמונות. בדומה לשיטות הסינון, זוהי קיצור דרך לשיטה הכללית יותר reduce() בנוגע לאוספי תמונות, שמקבלת ee.Reducer() כארגומנט. אפשר לראות את חבילת ee.Reducer בכרטיסייה Docs של עורך הקוד כדי לראות רשימה של כל הפונקציות של Earth Engine לצמצום נתונים. כשחושבים על שימוש בפונקציית reducer באוסף תמונות, חשוב לזכור שהפלט הוא תמונה, ולכן פונקציות reducer עם פלט לא מספרי, כמו histogram או toList, לא יפעלו עם אוסף תמונות.

Tutorial_api_06_median_composite
איור 6. ‫Landsat 8 median composite.

כשמבצעים הרחקה של התצוגה המקדימה של הממוצע המשוקלל, אמור להופיע משהו כמו איור 6. התוצאה צריכה להיות טובה יותר באופן משמעותי מהערך המורכב האחרון שיצרתם קודם. בשלב הזה, כדאי לעצור לרגע ולחשוב מה נעשה כדי ליצור את המדד המורכב הזה. מערכת Earth Engine טענה את כל אוסף Landsat 8 מעל ארה"ב היבשתית, וחישבה את החציון לכל פיקסל. זו כמות עצומה של נתונים! כמובן שאפשר לחשב את ערכי החציון השנתיים, קודם מסננים את האוסף, כמו שעשיתם קודם. הנקודה היא שאם הייתם צריכים להוריד את כל התמונות האלה וליצור את התמונה המורכבת הזו, זה היה פרויקט גדול. עם Earth Engine, מקבלים תוצאה תוך שניות!

מידע נוסף על שילוב תמונות ועל יצירת פסיפס

מסקינג

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

לדוגמה, נניח שאתם רוצים להסתיר את כל הפיקסלים של המים בחישוב הממוצע. אפשר ליצור מסכת מים באמצעות מערך הנתונים שמתואר במאמר של Hansen et al. (2013), שזמין בקטלוג הנתונים של Earth Engine. (במדריך הזה יש מידע נוסף על מערך הנתונים של Hansen et al.) במערך הנתונים הזה, למים יש ערך של 2, ליבשה יש ערך של 1, ול 'אין נתונים' יש ערך של 0. משתמשים בהיגיון כדי ליצור תמונת מסכה עם אפסים במקומות שבהם אין יבשה:

עורך הקוד (JavaScript)

// Load or import the Hansen et al. forest change dataset.
var hansenImage = ee.Image('UMD/hansen/global_forest_change_2015');

// Select the land/water mask.
var datamask = hansenImage.select('datamask');

// Create a binary mask.
var mask = datamask.eq(1);

// Update the composite mask with the water mask.
var maskedComposite = median.updateMask(mask);
Map.addLayer(maskedComposite, visParams, 'masked');

יש כמה דברים חדשים בקוד הזה שכדאי להזכיר בפירוט. קודם כל, הפונקציה select() שימושית לחילוץ הפסים הרלוונטיים מתמונה. כאן אנחנו בוחרים רק את הטווח שמעניין אותנו: datamask. הדבר החדש הבא הוא האופרטור הלוגי eq() שמייצג 'שווה ל'. אנחנו משתמשים ב-eq(1) כדי ליצור תמונה בינארית שבה כל הפיקסלים שלא מקבלים את הערך 1 בפס datamask (הפיקסלים של מים או של אזורים ללא נתונים) מקבלים את הערך 0 בתמונה שמתקבלת.

כתוצאה מהמיסוך הזה, כל הפיקסלים בקומפוזיציה החציונית שנמצאים מעל היבשה (לפי מערך הנתונים של Hansen et al. ‎) גלויים, אבל הפיקסלים שנמצאים מעל המים (או nodata) שקופים ויוחרגו מכל ניתוח שתבצעו בתמונה maskedComposite.

פסיפס

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

עורך הקוד (JavaScript)

// Make a water image out of the mask.
var water = mask.not();

// Mask water with itself to mask all the zeros (non-water).
water = water.mask(water);

// Make an image collection of visualization images.
var mosaic = ee.ImageCollection([
  median.visualize(visParams),
  water.visualize({palette: '000044'}),
]).mosaic();

// Display the mosaic.
Map.addLayer(mosaic, {}, 'custom mosaic');

יש הרבה דברים בקוד הזה, אז בואו ננתח אותו. קודם כל, אנחנו משתמשים באופרטור הלוגי not() כדי להפוך את המסכה שיצרנו קודם. באופן ספציפי, הפונקציה not() משנה את כל האפסים לאחדים ואת כל המספרים שאינם אפסים לאפסים. ההגדרה של המשתנה הזה כ-water לא מדויקת לגמרי כי הוא כולל גם כמה פיקסלים של nodata, אבל זה בסדר בהקשר הקרטוגרפי הנוכחי. הדבר הבא הוא להסתיר את המילה water בעצמה. התוצאה היא תמונה שבה כל הפיקסלים של המים הם 1, וכל השאר מוסתר. השלב האחרון הוא לשלב את התמונות עם mosaic(). מכיוון שהפונקציה mosaic() פועלת על אוסף תמונות, אנחנו מעבירים רשימה של תמונות שאנחנו רוצים לשלב בבונה של אוסף התמונות, ואז קוראים לפונקציה mosaic() כשלב הסופי. הסדר של התמונות ברשימה הזו חשוב. באופן ספציפי, תמונת הפלט תכיל את הפיקסל האחרון שלא הוסרה ממנו המסכה מתוך ערימת התמונות באוסף הקלט. במקרה הזה, זה עובד כי שכבת המים היא התמונה האחרונה (העליונה) באוסף, והיא מכילה רק פיקסלים לא מוסווים שבהם יש מים.

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

Tutorial_api_07_mosaic.png
איור 7. פסיפס בהתאמה אישית שבו אזורי המים הם בצבע אחיד.

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