مقدمه
سلام به همه علاقهمندان به سنجش از دور و تحلیل دادههای مکانی! اگر تا به حال به فکر تحلیل تصاویر ماهوارهای در مقیاس جهانی افتادهاید، حتماً نام Google Earth Engine (GEE) به گوشتان خورده است. این پلتفرم فوقالعاده قدرتمند، ترکیبی از یک دیتابیس عظیم از تصاویر ماهوارهای و یک موتور پردازش ابری است که به شما امکان میدهد تحلیلهای پیچیده را بدون نگرانی از قدرت سختافزار انجام دهید.
نکته کلیدی و جذاب این است که در GEE تقریباً همه چیز یک شیء (Object) است. این مفهوم، سنگ بنای کار با این پلتفرم محسوب میشود و درک آن، مسیر پیشرفت شما را هموار میکند. در این مقاله، قصد داریم به زبانی ساده و صمیمی، اصول برنامهنویسی JavaScript در GEE را آموزش دهیم. فرقی نمیکند یک مبتدی مطلق هستید یا تجربه کدنویسی دارید، این راهنما برای شماست .
پس با ما همراه باشید تا دنیای شگفتانگیز GEE را با هم کشف کنیم.
اولین قدم: آشنایی با محیط و «سلام دنیا!»
قبل از هر چیز، به کد ادیتور (Code Editor) GEE در آدرس زیر بروید:
code.earthengine.google.com
این محیط کار شماست. اولین کد خود را در بخش کد (Code Editor) تایپ کرده و دکمه Run (اجرا) را بزنید:
// My first program in GEE
print('Hello World!');
مشاهده میکنید که عبارت «سلام دنیا!» در زبانه کنسول (Console) چاپ میشود. تبریک میگویم، شما اولین قدم را برداشتید! .
نکته: در JavaScript، دستورات با ; (نقطهویرگول) پایان مییابند و برای نوشتن کامنت (توضیح) در کد، از // استفاده میشود. کامنتها به خوانایی و درک بهتر کد کمک شایانی میکنند .
متغیرها و انواع داده در GEE
در برنامهنویسی، متغیرها مانند ظرفهایی برای نگهداری دادهها هستند. در GEE، شما با دو دسته کلی از دادهها روبرو هستید: دادههای سمت کاربر (Client-side) و دادههای سمت سرور (Server-side). برای دسته دوم، یعنی دادههایی که روی سرورهای گوگل پردازش میشوند، از پیشوند ee. استفاده میکنیم .
بیایید با انواع دادههای اصلی آشنا شویم:
۱. رشتهها (Strings)
برای ذخیره متن از رشتهها استفاده میشود. در GEE میتوانید هم از رشتههای معمولی JavaScript و هم از رشتههای مخصوص سرور (ee.String) استفاده کنید.
// A simple client-side string
var myName = 'Ali';
print(myName);
// A server-side string
var serverString = ee.String('This is a server-side string');
print(serverString);
بهترین روش این است که از کوتیشن تکی (') برای تعریف رشتهها استفاده کنید .
۲. اعداد (Numbers)
اعداد نیز مانند رشتهها، هم به صورت معمولی و هم به صورت شیء سرور (ee.Number) تعریف میشوند.
// A regular number
var myNumber = 42;
print('My number:', myNumber);
// A server-side number
var serverNumber = ee.Number(10);
print(serverNumber);
۳. لیستها (Lists)
لیستها، آرایههایی از دادهها هستند که با کروشه [] تعریف میشوند. لیستها میتوانند شامل انواع مختلف داده (اعداد، رشتهها و حتی لیستهای دیگر) باشند.
// A simple list of numbers
var numberList = [1, 2, 3, 4, 5];
print('Number list:', numberList);
// A list of strings
var stringList = ['a', 'b', 'c'];
print('String list:', stringList);
// A server-side list
var serverList = ee.List([10, 20, 30, 40]);
print('Server list:', serverList);
با لیستهای سرور، میتوانید کارهای جالبی انجام دهید، مانند تولید دنبالهای از اعداد با تابع ee.List.sequence:
// Generate a sequence of years from 1980 to 2020 with step 5
var years = ee.List.sequence(1980, 2020, 5);
print('Selected years:', years);
این تابع در تحلیل سریهای زمانی بسیار کاربرد دارد .
۴. دیکشنریها (Dictionaries) یا اشیاء (Objects)
دیکشنریها، دادههایی از نوع کلید (Key): مقدار (Value) هستند که با آکولاد {} تعریف میشوند. این ساختار برای ذخیره اطلاعات توصیفی بسیار مفید است.
// A simple client-side dictionary
var myDict = {
name: 'Tehran',
population: 8000000,
country: 'Iran'
};
print('Dictionary:', myDict);
// Access values using keys (two different methods)
print('City name:', myDict['name']);
print('Country:', myDict.country);
// A server-side dictionary
var serverDict = ee.Dictionary({
'band1': 'Red',
'band2': 'NIR',
'scale': 30
});
print('Server dictionary:', serverDict);
همانطور که میبینید، برای دسترسی به مقدار یک کلید در دیکشنری، هم میتوان از براکت ([]) و هم از نقطه (.) استفاده کرد .
ساختارهای کنترلی: شرط (If) و حلقه (Loop)
ساختارهای شرطی و حلقهها به شما امکان میدهند تا کنترل بیشتری روی جریان برنامه خود داشته باشید. اما در GEE، یک نکته بسیار مهم وجود دارد: تا حد امکان از این ساختارها در سمت سرور استفاده نکنید و به جای آن از توابع map() و filter() بهره ببرید که در ادامه به آنها میپردازیم. با این حال، برای آشنایی اولیه، نمونههایی از کاربرد آنها را در سمت کاربر (Client-side) بررسی میکنیم.
دستور شرطی (If)
دستور if به شما اجازه میدهد بر اساس یک شرط، تصمیمگیری کنید.
var age = 25;
if (age >= 18) {
print('You are an adult.');
} else {
print('You are under 18.');
}
در تحلیلهای مکانی، ممکن است از شرط برای فیلتر کردن دادهها بر اساس ویژگیهایشان استفاده کنید، اما به یاد داشته باشید که روش صحیحتر در GEE، استفاده از ee.Filter است.
حلقهها (Loops)
حلقه for برای تکرار یک دستور، تعداد دفعات مشخصی به کار میرود.
// Print numbers 1 to 5 (client-side)
for (var i = 1; i <= 5; i++) {
print('Number:', i);
}
هشدار جدی: استفاده از حلقههای for در GEE برای پردازش روی دادههای سرور (مانند تصاویر) بسیار خطرناک است و میتواند باعث قفل شدن مرورگر شما شود. در بخشهای بعدی، روشهای اصولیتر مانند map() را معرفی خواهیم کرد .
کار با دادههای ساختاریافته: List و Array
شاید برایتان سوال باشد که تفاوت بین List و Array در GEE چیست. به زبان ساده:
- List: یک ساختار دادهای عمومی و انعطافپذیر است که میتواند عناصر با انواع مختلف را در خود نگه دارد.
- Array: یک ساختار دادهای ریاضیاتیتر است که برای انجام محاسبات برداری و ماتریسی بهینه شده و تمام عناصر آن باید از یک نوع باشند.
کار با ee.List
لیستها در GEE بسیار کاربرد دارند. برای مثال، میتوانید با استفاده از ee.Reducer.toList()، مقادیر پیکسلهای یک منطقه را در یک لیست ذخیره کنید و سپس نمودارهای مختلفی از آنها رسم کنید. این کار برای تحلیل توزیع دادهها بسیار مفید است .
// A simple list of numbers
var simpleList = ee.List([1, 2, 3, 4, 5]);
// Apply a function to all items using map()
var doubledList = simpleList.map(function(item) {
return ee.Number(item).multiply(2);
});
print('Doubled list:', doubledList);
کار با ee.Array
اگر با ماتریسها و محاسبات پیشرفتهتر سروکار دارید، ee.Array انتخاب مناسبتری است. برای مثال، میتوانید یک ماتریس دو بعدی ایجاد کرده و اعمالی مانند ترانهاده (Transpose) روی آن انجام دهید .
// Create a 2D array
var myArray = ee.Array([
[1, 2, 3],
[4, 5, 6]
]);
print('Original array:', myArray);
// Calculate the transpose of the array
var transposedArray = myArray.transpose();
print('Transposed array:', transposedArray);
قدرت پردازش با توابع (Functions)
توابع، قطعه کدهایی هستند که یک کار خاص را انجام میدهند. آنها به شما کمک میکنند تا کد خود را ماژولارتر، خواناتر و قابل استفادهتر کنید.
تعریف یک تابع ساده در سمت کاربر
// Function to calculate the area of a rectangle
var calculateArea = function(width, height) {
var area = width * height;
return area;
};
// Calling the function
var myArea = calculateArea(10, 5);
print('Rectangle area:', myArea);
توابع در سمت سرور و نقش حیاتی آنها
در GEE، توابع نقش بسیار مهمی در پردازش مجموعههای داده (Collections) ایفا میکنند. اغلب شما یک تابع تعریف میکنید و آن را روی تکتک اعضای یک ImageCollection یا FeatureCollection اعمال میکنید.
// A function to add a timestamp band to each image
var addTimeBand = function(image) {
// Extract the image timestamp from metadata
var time = image.get('system:time_start');
// Add the time as a new band to the image
return image.addBands(ee.Image.constant(time).rename('timestamp'));
};
// Note: This function is typically used with the map() method on a collection
متدهای قدرتمند: Map و Filter
اینجا قلب برنامهنویسی در GEE است! به جای استفاده از حلقههای for، روش استاندارد و کارآمد در GEE، استفاده از متدهای map() و filter() است. این متدها به صورت موازی روی سرورهای گوگل اجرا میشوند و عملکردی فوقالعاده سریع و بهینه دارند .
متد map()
این متد یک تابع را روی همه اعضای یک مجموعه (مانند ImageCollection یا List) اعمال میکند و یک مجموعه جدید برمیگرداند.
// Assume we have an ImageCollection of MODIS images
var modisCollection = ee.ImageCollection('MODIS/006/MOD09A1')
.filterDate('2020-01-01', '2020-12-31');
// Function to calculate NDVI on each image
var calculateNDVI = function(image) {
var nir = image.select('sur_refl_b02');
var red = image.select('sur_refl_b01');
var ndvi = nir.subtract(red).divide(nir.add(red)).rename('NDVI');
return image.addBands(ndvi);
};
// Apply the function to all images using map()
var collectionWithNDVI = modisCollection.map(calculateNDVI);
print('Collection with NDVI band:', collectionWithNDVI);
متد filter()
این متد برای فیلتر کردن اعضای یک مجموعه بر اساس یک شرط خاص استفاده میشود.
// An ImageCollection of Landsat 8 images
var landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2');
// Filtering by date and location (path and row)
var filteredCollection = landsat8
.filterDate('2019-06-01', '2019-09-01')
.filter(ee.Filter.eq('WRS_PATH', 168))
.filter(ee.Filter.eq('WRS_ROW', 34));
print('Number of images after filtering:', filteredCollection.size());
این دو متد، پایه و اساس پردازشهای پیچیده در GEE را تشکیل میدهند. با تسلط بر آنها، میتوانید تحلیلهای بسیار پیشرفتهای را انجام دهید .
تفاوت حیاتی: سمت کاربر (Client) در مقابل سمت سرور (Server)
این یکی از مهمترین مفاهیم در GEE است و درک آن، شما را از بسیاری از خطاها نجات میدهد.
- سمت کاربر (Client-side): کدهایی که در مرورگر شما اجرا میشوند. متغیرها و توابع معمولی JavaScript در این دسته قرار میگیرند.
- سمت سرور (Server-side): کدهایی که روی سرورهای قدرتمند گوگل اجرا میشوند. تمام اشیایی که با
ee.شروع میشوند (ee.Image,ee.Number,ee.Reducerو ...) در این دسته هستند.
قانون طلایی: هرگز اشیاء سمت سرور را با عملگرها و متدهای سمت کاربر ترکیب نکنید!
برای مثال، کد زیر اشتباه است:
// This code DOES NOT WORK and produces incorrect results!
var image = ee.Image('USGS/SRTMGL1_003');
var wrongResult = image + 2; // Mixing server-side object with client-side operator
print(wrongResult);
این کد سعی دارد یک عدد (۲) را به کل تصویر اضافه کند، اما این کار به روش اشتباهی انجام شده و نتیجه، یک رشته متنی بیمعنی خواهد بود .
راه درست این است که همیشه از توابع سمت سرور برای کار با اشیاء سمت سرور استفاده کنید:
// Correct approach
var image = ee.Image('USGS/SRTMGL1_003');
var correctResult = image.add(2); // Using the server-side add() method
Map.addLayer(correctResult, {min: 0, max: 9000}, 'Correct image');
تابع getInfo() و تابع print()
گاهی اوقات نیاز دارید تا نتیجه یک محاسبه سمت سرور را در کنسول (سمت کاربر) ببینید. تابع print() در کد ادیتور GEE این کار را به صورت خودکار و ایمن انجام میدهد. اما اگر در پایتون یا جاوااسکریپت خارج از محیط کد ادیتور کار میکنید، باید از تابع getInfo() استفاده کنید. اما توجه داشته باشید که استفاده از getInfo() در کد ادیتور، به خصوص درون حلقهها، به شدت منع شده و میتواند عملکرد مرورگر شما را به شدت کاهش دهد یا آن را قفل کند .
جمعبندی و نکات پایانی
در این مقاله، با مفاهیم پایه و کلیدی برنامهنویسی JavaScript در Google Earth Engine آشنا شدیم. به طور خلاصه:
- همه چیز شیء است: این اصل بنیادین را همیشه به خاطر داشته باشید .
- متغیرها و دادهها: با استفاده از
varمتغیر تعریف کنید و از انواع دادههایString,Number,List, وDictionary(Object) استفاده کنید. برای کار با دادههای سرور، از نسخههایee.آنها استفاده کنید. - ساختارهای کنترلی:
ifوforکاربرد دارند، اما برای پردازش مجموعهها در سرور، به سراغmap()وfilter()بروید تا کدی بهینه و سریع داشته باشید. - توابع (
Function): برای سازماندهی کد و تکرارپذیری، توابع تعریف کنید. توابع، قلب پردازشهایmap()هستند. map()وfilter(): این دو متد، ابزارهای اصلی شما برای پردازش دستهجمعی و فیلتر کردن مجموعههای داده هستند.- Client vs. Server: این تفاوت را جدی بگیرید. از ترکیب اشیاء سمت سرور با عملگرهای سمت کاربر خودداری کنید. برای مشاهده نتایج از
print()استفاده کنید و ازgetInfo()پرهیز کنید.
این مفاهیم، پایه و اساس کار شما با GEE را تشکیل میدهند. در گامهای بعدی، میتوانید به سراغ مباحث پیشرفتهتر مانند کار با ImageCollection، استفاده از Reducerهای مختلف برای محاسبات آماری، و تحلیلهای سریزمانی بروید.
اگر این مقاله برایتان مفید بود، آن را با دوستان خود به اشتراک بگذارید و سوالات خود را در بخش نظرات مطرح کنید.

