«Cloud Optimized GeoTIFF» یا به اختصار COG قالبی از GeoTIFF است که برای خواندن کارآمد روی شبکه و فضای ابری طراحی شده؛ یعنی کلاینت فقط همان تکههایی از فایل را که لازم دارد با استفاده از HTTP Range Requests دریافت میکند. در این آموزش با اصول، مزایا و سناریوهای واقعی استفاده از COG و همچنین مراحل ساخت، انتشار، مصرف و عیبیابی آن آشنا میشوید.
COG چیست و چگونه کار میکند؟
COG همان GeoTIFF است که با چند قاعده پیادهسازی میشود تا قابل «استریم» باشد:
- Tile/Block داخلی: تصویر به بلاکهای کوچک (مثلاً 256×256 یا 512×512 پیکسل) تقسیم و بهصورت tiled ذخیره میشود.
- Overviews داخلی: نسخههای رزولوشن پایینتر (سطوح بزرگنمایی کمتر) داخل خود فایل قرار میگیرند تا در زومهای پایین، درخواستها کوچک و سریع باشند.
- فهرستهای ساختاری (IFD/Offsets) در ابتدای فایل: آدرس بلاکها و overviewها طوری چیده میشود که کلاینت با چند درخواست محدودهای (Range) بتواند به داده برسد.
- پشتیبانی از HTTP Range Requests در سمت میزبان: سرور ابری باید هدرهای Range را بپذیرد و پاسخ 206 Partial Content بدهد.
نکته: COG یک فرمت جدید نیست؛ یک نحوه چیدمان استاندارد در GeoTIFF است. بنابراین با اکثر ابزارهای مبتنی بر GDAL، QGIS، rasterio و … سازگار است.
اجزای کلیدی COG
- Tiles/Blocks: اندازه بلاک ثابت و توانی از 2 (معمولاً 256 یا 512) برای تعادل سرعت/حجم.
- Overviews: معمولاً سطوحی با کاهش ابعاد در ضرایب 2 (1/2، 1/4، 1/8 …) و فشردهسازی جداگانه.
- Compression: بسته به نوع داده: DEFLATE/LZW/ZSTD برای دادههای پیوسته یا طبقهای، JPEG برای RGB طبیعی (با تنزل کیفیت)، LERC/LERC_ZSTD برای خطای کنترلشده در Float.
- NoData/Alpha: تعریف مشخص برای پیکسلهای فاقد داده (NoData) یا باند Alpha جهت شفافیت.
- CRS و GeoTransform: سیستم مختصات و تبدیل مکانی استاندارد GeoTIFF.
مزایا، محدودیتها و زمان استفاده
- مزایا:
- بارگذاری سریع نمایهها (overviews) در زومهای پایین؛ دانلود فقط تکههای لازم.
- سازگاری گسترده با ابزارهای متنباز و تجاری.
- مقیاسپذیری بدون سرور کاشیساز (serverless) با اتکا به S3/GCS و CDN.
- مدیریت ساده بهعنوان یک فایل منفرد قابل حمل و بایگانی.
- محدودیتها:
- برای خواندن بسیار بهینه است، نه برای بهروزرسانیهای ریزدانه و مکرر.
- نیازمند میزبانی با پشتیبانی از Range Requests.
- ساخت اولیه (tiled + overviews) زمان/منابع محاسباتی میطلبد.
- زمان استفاده: زمانی که رستر نسبتاً ایستا است و قرار است بارها از راه دور و بهصورت بخشی خوانده شود؛ مانند تصویربرداری ماهوارهای، DEM، شاخصهای پوشش زمین، محصولات تحلیلی در پورتالهای وب.
سناریوی واقعی: نقشهبرداری سریع سیلاب با Sentinel‑2 روی S3
فرض کنید تیم مدیریت بحران میخواهد پس از رخداد سیل، نقشه نواحی آبگرفته را سریع به اشتراک بگذارد. داده Sentinel‑2 L2A تهیه میشود، شاخص NDWI محاسبه و محصول بهصورت COG روی S3 منتشر میگردد. کاربران وبنقشه و تحلیلگران، فقط تکههای مورد نیاز را با تأخیر کم دریافت میکنند؛ بدون راهاندازی سرور tile اختصاصی.
جریان کار: دریافت باندهای B03 (Green) و B08 (NIR) → محاسبه NDWI → بازفرافکنی به EPSG:3857 برای وب → تبدیل به COG → بارگذاری روی S3 → مصرف در QGIS/وب/پایتون.
مراحل گامبهگام ساخت COG
۱) آمادهسازی و محاسبه شاخص
# فرض: فایلهای Sentinel-2 لایهبندی و برش خوردهاند
# محاسبه NDWI = (G - NIR) / (G + NIR)
# برای جلوگیری از تقسیم بر صفر، یک تلرانس کوچک اضافه شده است
gdal_calc.py \
-A S2_B03.tif -B S2_B08.tif \
--calc="(A.astype(float)-B)/(A+B+1e-6)" \
--outfile=ndwi.tif \
--type=Float32 \
--NoDataValue=-9999
نکته: برای دادههای پیوسته (Float)، مقادیر NoData را صریح تنظیم کنید تا در فشردهسازی و تولید overviews درست مدیریت شوند.
۲) بازفرافکنی برای وبنقشه (اختیاری اما رایج)
# تبدیل به EPSG:3857 و تعیین NoData
# انتخاب bilinear برای دادههای پیوسته
gdalwarp \
-t_srs EPSG:3857 \
-r bilinear \
-dstnodata -9999 \
ndwi.tif ndwi_3857.tif
۳) تبدیل به COG با GDAL
# استفاده از درایور COG در gdal_translate
# ZSTD برای ترکیب سرعت/حجم عالی، Predictor=3 مناسب Float
# TILING_SCHEME=GoogleMapsCompatible برای همتراز شدن سطوح با وبنقشهها
gdal_translate ndwi_3857.tif flood_ndwi_cog.tif \
-of COG \
-co COMPRESS=ZSTD \
-co ZSTD_LEVEL=9 \
-co PREDICTOR=3 \
-co BLOCKSIZE=512 \
-co NUM_THREADS=ALL_CPUS \
-co BIGTIFF=IF_SAFER \
-co RESAMPLING=AVERAGE \
-co OVERVIEW_COMPRESS=ZSTD \
-co SPARSE_OK=YES \
-co TILING_SCHEME=GoogleMapsCompatible
نکته: برای دادههای طبقهای از RESAMPLING=NEAREST استفاده کنید تا مرز کلاسها مخدوش نشود. برای RGB طبیعی، COMPRESS=JPEG با JPEG_QUALITY مناسب پیشنهاد میشود.
۴) بررسی سریع ساختار
# وجود Block و Overviews را چک کنید
# (خروجی باید خطوطی با Block=... و Overviews نشان دهد)
gdalinfo flood_ndwi_cog.tif | grep -E "Block|Overviews|Compression|Predictor"
۵) اعتبارسنجی با rio-cogeo
# نصب: pip install rio-cogeo
rio cogeo validate flood_ndwi_cog.tif
rio cogeo info flood_ndwi_cog.tif
۶) بارگذاری روی S3 (یا GCS)
# نمونه بارگذاری روی S3 (بدون تغییر ACL؛ سیاست دسترسی را جداگانه تنظیم کنید)
aws s3 cp flood_ndwi_cog.tif s3://my-bucket/data/flood_ndwi_cog.tif \
--only-show-errors \
--metadata-directive REPLACE \
--cache-control "public, max-age=31536000, immutable"
- Blocksize و Overviews داخلی ایجاد شدهاند.
- NoData/Alpha بهدرستی تنظیم است.
- CRS درست و با کاربرد شما سازگار است.
- Bucket/Host از Range Requests پشتیبانی میکند.
انتشار در ابر و تنظیم دسترسی
برای استفاده مستقیم در کلاینتها، هاست باید HTTP Range Requests را بپذیرد. در S3 معمولاً کافی است از آدرس REST استاندارد استفاده کنید و CORS را طوری تنظیم کنید که هدرهای لازم در دسترس باشند.
# نمونه CORS برای S3 (JSON)
[
{
"AllowedHeaders": ["*"],
"AllowedMethods": ["GET", "HEAD"],
"AllowedOrigins": ["*"],
"ExposeHeaders": ["ETag", "Accept-Ranges", "Content-Range", "Content-Length"],
"MaxAgeSeconds": 3000
}
]
# آزمون Range Request
curl -I -H "Range: bytes=0-1023" \
https://my-bucket.s3.amazonaws.com/data/flood_ndwi_cog.tif
# باید 206 Partial Content و Accept-Ranges: bytes ببینید
هشدار: اگر هاست شما پاسخ 200 OK به درخواستهای Range بدهد (یا Range را نپذیرد)، عملکرد COG از بین میرود و کل فایل ممکن است دانلود شود.
مصرف COG در QGIS، GDAL و Python
QGIS
- در QGIS (نسخههای جدید)، افزودن «Raster layer» از طریق URL مستقیم COG ممکن است؛ QGIS با GDAL از Range پشتیبانی میکند.
- برای تجربه بهتر، کش QGIS را فعال و محدودیت حافظه را متناسب افزایش دهید.
مثال: Layer → Add Layer → Add Raster Layer → وارد کردن URL: https://my-bucket.s3.amazonaws.com/data/flood_ndwi_cog.tif
GDAL CLI
# برش بخشی از رستر بهصورت راه دور با vsicurl
# ترتیب projwin: ulx uly lrx lry
gdal_translate \
/vsicurl/https://my-bucket.s3.amazonaws.com/data/flood_ndwi_cog.tif \
out_clip.tif \
-projwin 569000 4005000 572000 4002000 \
-r bilinear
Python (rasterio)
import rasterio as rio
from rasterio.windows import from_bounds
from rasterio.enums import Resampling
url = "https://my-bucket.s3.amazonaws.com/data/flood_ndwi_cog.tif"
with rio.open(url) as src:
xmin, ymin, xmax, ymax = 569000, 4002000, 572000, 4005000
win = from_bounds(xmin, ymin, xmax, ymax, src.transform)
data = src.read(1, window=win, out_shape=(512, 512), resampling=Resampling.bilinear)
print(data.shape, data.dtype)
اعتبارسنجی و سنجش عملکرد
- ساختاری: با
rio cogeo validateوgdalinfoوجود tiles/overviews و ترتیب صحیح را بررسی کنید. - شبکه: با
curl -I -H "Range: ..."از پشتیبانی Range مطمئن شوید. - کارایی: یک پنجره کوچک را چندبار بخوانید و زمان را بسنجید؛ باید سریع و بدون دانلود کامل فایل باشد.
# آزمایش ساده زمان خواندن یک پنجره
import time, rasterio as rio
from rasterio.windows import from_bounds
from rasterio.enums import Resampling
url = "https://my-bucket.s3.amazonaws.com/data/flood_ndwi_cog.tif"
with rio.open(url) as src:
win = from_bounds(569000, 4002000, 572000, 4005000, src.transform)
t0 = time.time()
_ = src.read(1, window=win, out_shape=(512, 512), resampling=Resampling.bilinear)
print("elapsed s:", time.time() - t0)
خطاهای رایج و رفع اشکال
- عدم وجود overviews داخلی: فایل کند در زومهای پایین. راهکار: از درایور COG برای ایجاد overviews یا
gdaladdoداخلی استفاده کنید. - Tiles نامناسب (Blocksize کوچک/بزرگ): Block خیلی کوچک باعث افزایش تعداد درخواستها، خیلی بزرگ باعث انتقال داده اضافی میشود. معمولاً 256 یا 512 مناسب است.
- فشردهسازی نامتناسب: استفاده از
COMPRESS=JPEGبرای Float یا دادههای طبقهای خطاست. برای Float: ZSTD/DEFLATE/LERC، برای RGB: JPEG، برای کلاسها: LZW/DEFLATE/ZSTD. - Predictor اشتباه: برای Float از
PREDICTOR=3و برای Int ازPREDICTOR=2استفاده کنید (وقتی از DEFLATE/LZW/ZSTD استفاده میشود). - NoData تنظیم نشده: مرزها و کاشیهای تهی در overviews بد دیده میشوند. با
gdal_edit.py -a_nodataیا هنگام تولید آن را تعیین کنید. - عدم پشتیبانی Range در هاست: نتیجه، دانلود کامل فایل. راهکار: هاست/پروکسی را اصلاح کنید یا از سرویس سازگار استفاده کنید.
- رزَمپلینگ نامناسب: برای دادههای طبقهای حتماً
NEARESTو برای پیوستهAVERAGE/BILINEARرا بهکار ببرید. - Palette/RGB بدون Photometric درست: برای JPEG در RGB،
PHOTOMETRIC=YCBCRمعمولاً حجم بهتر میدهد.
نکات بهینهسازی و هزینه
- CDN و کش: فعالسازی کش و CDN نزدیک کاربر، تعداد و تأخیر درخواستها را کاهش میدهد.
- تنظیم سطح overviews: سطوح کافی برای پوشش زومهای کمجزئیات بسازید تا به بلوکهای ریز در سطح اصلی نیاز نشود.
- SPARSE_OK: اگر مناطق وسیعی NoData دارید، با
SPARSE_OK=YESاز ذخیره بلوکهای تهی صرفنظر کنید. - هزینه درخواستها: هر پنجره خواندن به چند Range GET تبدیل میشود؛ طراحی کاشیها و overviews باید توازنی بین تعداد درخواست و حجم داده برقرار کند.
- تنظیمات کلاینت: در محیطهای GDAL، مقدار کش داخلی (مثلاً
--config GDAL_CACHEMAX) را متناسب با رم افزایش دهید.
جدول راهنمای انتخاب فشردهسازی
| نوع داده | فشردهسازی پیشنهادی | تنظیمات تکمیلی | توضیح |
|---|---|---|---|
| پیوسته Float (NDWI/NDVI و شاخصها) | ZSTD یا DEFLATE | PREDICTOR=3، BLOCKSIZE=256/512، OVERVIEW_COMPRESS=ZSTD/DEFLATE | کیفیت بدون اتلاف، حجم مناسب و سرعت خواندن خوب |
| کلاسبندی 8/16 بیت | LZW/DEFLATE/ZSTD | PREDICTOR=2، RESAMPLING=NEAREST | حفظ مرز کلاسها و عدم ایجاد مقادیر بینابینی |
| RGB طبیعی (تصاویر ماهواره/هوایی) | JPEG (lossy) | JPEG_QUALITY≈85–95، PHOTOMETRIC=YCBCR، BLOCKSIZE=256/512 | حجم بسیار کم، مناسب نمایش وب؛ نه برای تحلیل دقیق طیفی |
| DEM/Float با تحمل خطا | LERC یا LERC_ZSTD | MAX_Z_ERROR متناسب (مثلاً 0.01) | کاهش حجم با خطای کنترلشده برای ارتفاع/عمق |
جمعبندی
COG راهی عملی و استاندارد برای ارائه و تحلیل رستر در مقیاس وب و ابر است: با تایلبندی داخلی، overviews و فهرستهای بهینه، کلاینتها فقط بخشهای لازم را با Range Requests میخوانند. در سناریوهای دادههای نسبتاً ایستا (تصاویر ماهوارهای، DEM، شاخصها)، COG هزینه زیرساخت را کاهش و سرعت تجربه کاربر را افزایش میدهد. با انتخاب درست فشردهسازی، اندازه بلاک، رزَمپلینگ و تنظیمات میزبانی (CORS/Range)، میتوانید یک زنجیره تولید تا مصرف قابل اتکا بسازید؛ از ساخت با GDAL/rio-cogeo تا انتشار روی S3 و مصرف در QGIS و Python.