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

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

Code Editor (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 (מידע נוסף על צמצום אוספי תמונות).

הרכבה עם Reducers

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

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

Code Editor (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() כארגומנט. כדי לראות רשימה של כל המפחיתים של Earth Engine, עיינו בחבילה ee.Reducer בכרטיסייה Docs של Code Editor. כשבוחרים פונקציית צמצום לאוסף תמונות, חשוב לזכור שהפלט הוא תמונה, ולכן פונקציות צמצום עם פלט לא מספרי, כמו 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. משתמשים בקצת לוגיקה כדי ליצור תמונת מסכה עם אפסים במקומות שבהם אין יבשה:

Code Editor (JavaScript)

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

// 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.

יצירת פסיפס

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

Code Editor (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() פועלת על אוסף תמונות, אנחנו מעבירים רשימה של תמונות שאנחנו רוצים לשלב ב-constructor של אוסף התמונות, ואז קוראים לפונקציה mosaic() כשלב האחרון. סדר התמונות ברשימה הזו חשוב. באופן ספציפי, תמונת הפלט תכיל את הפיקסל האחרון שלא הוסתר מהמקבץ של התמונות באוסף הקלט. במקרה הזה, זה עובד כי שכבת המים היא התמונה האחרונה (העליונה) באוסף, והיא מכילה רק פיקסלים לא מוסתרים שבהם יש מים.

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

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

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