diff --git a/README.md b/README.md index b894880..b6f1184 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,10 @@ You can learn more about the products on the [product page](https://mapsplatform [Docs](https://developers.google.com/maps/documentation/population-dynamics-insights) +### Custom Satellite Embeddings + +[Docs](https://developers.google.com/maps/documentation/custom-satellite-embeddings) + ## Available Recipe Collections * [`places_insights/`](places_insights/): Samples for analyzing the Places Insights BigQuery dataset. @@ -48,4 +52,4 @@ See [`SECURITY.md`](SECURITY.md) for details on how to report security vulnerabi ## Contributing -See [`CONTRIBUTING.md`](CONTRIBUTING.md) for details on how to contribute to this project. \ No newline at end of file +See [`CONTRIBUTING.md`](CONTRIBUTING.md) for details on how to contribute to this project. diff --git a/custom_satellite_embeddings/notebooks/ee_classification/Custom_Satellite_Embeddings_Classification.ipynb b/custom_satellite_embeddings/notebooks/ee_classification/Custom_Satellite_Embeddings_Classification.ipynb new file mode 100644 index 0000000..09242db --- /dev/null +++ b/custom_satellite_embeddings/notebooks/ee_classification/Custom_Satellite_Embeddings_Classification.ipynb @@ -0,0 +1,349 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "toc_visible": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "96k7JUiHDEv2" + }, + "outputs": [], + "source": [ + "# Copyright 2026 Google LLC\n", + "#\n", + "# Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "source": [ + "\n", + " \n", + "
\n", + " \n", + " \"Google
Open in Colab Enterprise\n", + "
\n", + "
" + ], + "metadata": { + "id": "Kmf1K3lUDnPr" + } + }, + { + "cell_type": "markdown", + "source": [ + "# Custom Satellite Embeddings Supervised and Unsupervised Classification\n", + "\n", + "Custom satellite embeddings imagery is delivered as [Cloud Optimized Geotiffs](https://cogeo.org/) (COGs) in [Google Cloud Storage](https://cloud.google.com/storage). This guide assumes that [Google Earth Engine](https://earthengine.google.com) `ImageCollection`s of COG-backed images are already created. See the Custom Satellite Embeddings Data Exploration guide for more information about the embeddings and COGs in Earth Engine.\n", + "\n", + "In this guide, supervised and unsupervised classifications are fitted to a time series of six monthly satellite embeddings images in an agricultural area of the California, USA central valley. Use these methods to indentify areas of agricultural change or temporal trajectories of particular crop types. An animated visualizion is produced to illustrate change over time." + ], + "metadata": { + "id": "NKzgZyG8K-Se" + } + }, + { + "cell_type": "markdown", + "source": [ + "## Earth Engine Authentication and Initialization\n", + "\n", + "To use Earth Engine, you must have a Cloud Project with the Earth Engine API activated." + ], + "metadata": { + "id": "HGoBIB4GN9F-" + } + }, + { + "cell_type": "code", + "source": [ + "import ee\n", + "import geemap\n", + "\n", + "from IPython.display import Image, display\n", + "from pprint import pprint" + ], + "metadata": { + "id": "LSoNkZrkWoCC" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Your project with the Earth Engine API activated.\n", + "PROJECT = \"YOUR-PROJECT\"" + ], + "metadata": { + "id": "JpJ-w6dDHYCL" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Initialize Earth Engine (Assumes you have already authenticated via gcloud)\n", + "try:\n", + " ee.Initialize(project=PROJECT)\n", + "except Exception:\n", + " ee.Authenticate()\n", + " ee.Initialize(project=PROJECT)" + ], + "metadata": { + "id": "0XT8DsPROapQ" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Load the satellite embeddings `ImageCollection`\n", + "\n", + "This sample is a time series of monthly images, centered on the 15th of the month, and spanning six months between 2025-11-15 and 2026-05-15. The data covers an area of ~18,000 hectares of mostly cropland in California." + ], + "metadata": { + "id": "6e1dQHpoOnoI" + } + }, + { + "cell_type": "code", + "source": [ + "meloland_california_2026_crop_cycles = ee.ImageCollection()" + ], + "metadata": { + "id": "-6tnd_TzOmt2" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Spatial mosaicking\n", + "\n", + "Since Satellite embeddings are tiled, first aggregate the collection spatially, such that each image in the collection represents one time. Here `mosaic()` is used to spatially aggregate the imagery." + ], + "metadata": { + "id": "CBEBYfRrS9Yu" + } + }, + { + "cell_type": "code", + "source": [ + "# Spatial mosaicking.\n", + "time_starts = meloland_california_2026_crop_cycles.aggregate_histogram('system:time_start')\n", + "\n", + "def mosaic_function(time):\n", + " time_start = ee.Number.parse(time)\n", + " date = ee.Date(time_start)\n", + " filtered = meloland_california_2026_crop_cycles.filterDate(date)\n", + " # Transfer time and geographic properties.\n", + " return filtered.mosaic().set('system:time_start', time_start).clip(filtered.geometry(100))\n", + "\n", + "c = ee.ImageCollection.fromImages(time_starts.keys().map(mosaic_function))" + ], + "metadata": { + "id": "15F9O5vZT3R1" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Unsupervised Classification\n", + "\n", + "### Stack the entire time series in a single image\n", + "\n", + "Stack each of the six 64-band images into a single image. Use clusters in this space to represent temporal trajectories of different crops through time. Earth Engine has native methods for sampling and clustering. Here Weka's k-means clusterer with seven clusters is used." + ], + "metadata": { + "id": "1E_5ChrkQvHQ" + } + }, + { + "cell_type": "code", + "source": [ + "# K-means on the 6x64D stack.\n", + "k = 7\n", + "n = 1000\n", + "\n", + "# Temporal trajectory clusters.\n", + "big_stack = c.toBands()\n", + "training = big_stack.sample(\n", + " region=c.first().geometry(),\n", + " numPixels=n,\n", + " scale=10,\n", + ")\n", + "training = training.filter(ee.Filter.notNull(big_stack.bandNames()))\n", + "\n", + "clusterer = ee.Clusterer.wekaKMeans(k).train(training, big_stack.bandNames())\n", + "clustered = big_stack.cluster(clusterer)" + ], + "metadata": { + "id": "Cj5VTspSXArV" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Use `geemap` to visualize the results interactively." + ], + "metadata": { + "id": "oqNYdrp1rDLZ" + } + }, + { + "cell_type": "code", + "source": [ + "Map = geemap.Map(center=(32.8287, -115.45131), zoom=13)\n", + "roygbiv = [\"FFFFFF\", \"#F60000\", \"#FF8C00\", \"#FFEE00\", \"#4DE94C\", \"#3783FF\", \"#4815AA\"]\n", + "cluster_vis = {\"min\": 0, \"max\": k-1, \"palette\": roygbiv}\n", + "Map.addLayer(clustered, cluster_vis, 'clustered')\n", + "Map" + ], + "metadata": { + "id": "-FGSbmU3opE9" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Or request a thumbnail URL, which you can display using an IPython widget, download with `curl`, copy/paste, etc. These URLs are temporary and should not be used for long term access." + ], + "metadata": { + "id": "cIQ4daz1iWwu" + } + }, + { + "cell_type": "code", + "source": [ + "thumb_clusters_vis = cluster_vis.copy()\n", + "thumb_clusters_vis[\"dimensions\"] = \"512x512\"\n", + "thumb_url = clustered.clip(c.first().geometry()).getThumbUrl(thumb_clusters_vis)\n", + "display(Image(url=thumb_url))" + ], + "metadata": { + "id": "YwLDKVLvgtBY" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Supervised Classification\n", + "\n", + "### Use the annual USDA Cropland Data Layer (CDL) as reference labels\n", + "\n", + "For reference labels, overlay the annual CDL crop type map with annual satellite embeddings to get a training dataset. Train a Random Forest classifier to predict the top five crops in the specified region. Classify every image in the custom satellite embeddings time series, then make an animated thumbnail of the time series of classifications." + ], + "metadata": { + "id": "JSdbl0cOZizs" + } + }, + { + "cell_type": "code", + "source": [ + "# CDL classification for 2025.\n", + "cdl = ee.ImageCollection(\"USDA/NASS/CDL\")\n", + "cdl_2025 = cdl.filter(ee.Filter.calendarRange(2025, 2025, 'year')).first()\n", + "\n", + "# Sample the CDL and annual embeddings for the same year.\n", + "aef = ee.ImageCollection(\"GOOGLE/SATELLITE_EMBEDDING/V1/ANNUAL\")\n", + "aef_2025 = aef.filter(ee.Filter.calendarRange(2025, 2025, 'year')).mosaic()\n", + "sample = aef_2025.addBands(cdl_2025).sample(\n", + " region=c.first().geometry(),\n", + " numPixels=n,\n", + " scale=10,\n", + ")\n", + "\n", + "# Dominant classes only, the top five.\n", + "cropland = 'cropland'\n", + "histo = ee.Dictionary(sample.aggregate_histogram(cropland))\n", + "keys = histo.keys().sort(histo.values())\n", + "top_classes = keys.slice(keys.length().subtract(5))\n", + "\n", + "def remap_class(f: ee.Feature) -> ee.Feature:\n", + " \"\"\"Remap the top five classes to consecutive integers, all else to 0.\"\"\"\n", + " old_class = f.get(cropland)\n", + " new_class = top_classes.indexOf(ee.String(old_class)).add(1)\n", + " return f.set(cropland, new_class)\n", + "\n", + "training = sample.map(remap_class)\n", + "rf = ee.Classifier.smileRandomForest(10).train(training, cropland, aef_2025.bandNames())" + ], + "metadata": { + "id": "xW8MWoMovF2A" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Display an animation of the classificatons." + ], + "metadata": { + "id": "RxSK8VMU3Otq" + } + }, + { + "cell_type": "code", + "source": [ + "rf_vis = {\"min\": 0, \"max\": 5, \"palette\": roygbiv[0:6]}\n", + "# Classify and visualize each image in the time series.\n", + "classified = c.map(lambda image: image.classify(rf).visualize(**rf_vis))\n", + "# Get a URL for the animation and use an IPython widget to display it.\n", + "anim_url = classified.getVideoThumbURL({ \"framesPerSecond\": 3, \"dimensions\": \"512x512\" })\n", + "display(Image(url=anim_url))" + ], + "metadata": { + "id": "3pP7IXU-0KOl" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## What's next?\n", + "\n", + "Explore [other Custom Satellite Embeddings samples](https://developers.devsite.corp.google.com/maps/documentation/custom-satellite-embeddings/samples)." + ], + "metadata": { + "id": "tt2vtzYSjvFN" + } + } + ] +} diff --git a/custom_satellite_embeddings/notebooks/ee_classification/README.md b/custom_satellite_embeddings/notebooks/ee_classification/README.md new file mode 100644 index 0000000..0e97ee9 --- /dev/null +++ b/custom_satellite_embeddings/notebooks/ee_classification/README.md @@ -0,0 +1,12 @@ +# Custom Satellite Embeddings Supervised and Unsupervised Classification in Earth Engine + +In this guide, supervised and unsupervised classifications are fitted to a time series of +six monthly satellite embeddings images in an agricultural area of the California, USA central valley. +Use these methods to indentify areas of agricultural change or temporal trajectories of +particular crop types. An animated visualizion is produced to illustrate change over time. + +This guide demonstrates: + +- Unsupervised classification in Earth Engine +- Supervised Classification (Random Forest) in Earth Engine +- Making an animation of a time series of classifications diff --git a/custom_satellite_embeddings/notebooks/ee_data_exploration/Custom_Satellite_Embeddings_Data_Exploration.ipynb b/custom_satellite_embeddings/notebooks/ee_data_exploration/Custom_Satellite_Embeddings_Data_Exploration.ipynb new file mode 100644 index 0000000..4a9dd0e --- /dev/null +++ b/custom_satellite_embeddings/notebooks/ee_data_exploration/Custom_Satellite_Embeddings_Data_Exploration.ipynb @@ -0,0 +1,374 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "toc_visible": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "96k7JUiHDEv2" + }, + "outputs": [], + "source": [ + "# Copyright 2026 Google LLC\n", + "#\n", + "# Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "source": [ + "\n", + " \n", + "
\n", + " \n", + " \"Google
Open in Colab Enterprise\n", + "
\n", + "
" + ], + "metadata": { + "id": "Kmf1K3lUDnPr" + } + }, + { + "cell_type": "markdown", + "source": [ + "# Custom Satellite Embeddings Data Exploration\n", + "\n", + "Custom satellite embeddings imagery is delivered as [Cloud Optimized Geotiffs](https://cogeo.org/) (COGs) in [Google Cloud Storage](https://cloud.google.com/storage). COGs in Cloud Storage can be loaded into [Google Earth Engine](https://earthengine.google.com) for visualization and analysis. They can be loaded directly using [ee.Image.loadGeoTIFF](https://developers.google.com/earth-engine/apidocs/ee-image-loadgeotiff). Or you can create Earth Engine `Image` assets backed by COGs in Cloud Storage. The advantage of creating COG-backed assets is that indices on spatial and metadata properties make collections of COG-backed assets performant. See [this guide](https://developers.google.com/earth-engine/Earth_Engine_asset_from_cloud_geotiff) for information on creating COG-backed Earth Engine assets. This guide assumes that Earth Engine `ImageCollection`s of COG-backed images are already created.\n", + "\n", + "In this guide, you can explore a time series of six monthly satellite embeddings images in an agricultural area of the California, USA central valley. Like the [annual embeddings](https://developers.google.com/earth-engine/datasets/catalog/GOOGLE_SATELLITE_EMBEDDING_V1_ANNUAL), each image has 64 information-dense bands." + ], + "metadata": { + "id": "NKzgZyG8K-Se" + } + }, + { + "cell_type": "markdown", + "source": [ + "## Earth Engine Authentication and Initialization\n", + "\n", + "To use Earth Engine, you must have a Cloud Project with the Earth Engine API activated." + ], + "metadata": { + "id": "HGoBIB4GN9F-" + } + }, + { + "cell_type": "code", + "source": [ + "import ee\n", + "import geemap\n", + "\n", + "from IPython.display import Image, display\n", + "from pprint import pprint" + ], + "metadata": { + "id": "LSoNkZrkWoCC" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Your project with the Earth Engine API activated.\n", + "PROJECT = \"YOUR-PROJECT\"" + ], + "metadata": { + "id": "JpJ-w6dDHYCL" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Initialize Earth Engine (Assumes you have already authenticated via gcloud)\n", + "try:\n", + " ee.Initialize(project=PROJECT)\n", + "except Exception:\n", + " ee.Authenticate()\n", + " ee.Initialize(project=PROJECT)" + ], + "metadata": { + "id": "0XT8DsPROapQ" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Load the satellite embeddings `ImageCollection`\n", + "\n", + "This sample is a time series of monthly images, centered on the 15th of the month, and spanning six months between 2025-11-15 and 2026-05-15. The data covers an area of ~18,000 hectares of mostly cropland in California." + ], + "metadata": { + "id": "6e1dQHpoOnoI" + } + }, + { + "cell_type": "code", + "source": [ + "meloland_california_2026_crop_cycles = ee.ImageCollection()" + ], + "metadata": { + "id": "-6tnd_TzOmt2" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Examine a single image\n", + "\n", + "Use `getInfo()` to request information about the Earth Engine object to the client (this notebook). This will print information about the properties (metadata) of the image, bands of the image and backing COGs." + ], + "metadata": { + "id": "-iZ9_doRdJBM" + } + }, + { + "cell_type": "code", + "source": [ + "pprint(meloland_california_2026_crop_cycles.first().getInfo())" + ], + "metadata": { + "id": "_km51o8idN2v" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Spatial mosaicking\n", + "\n", + "Since Satellite embeddings are tiled, first aggregate the collection spatially, such that each image in the collection represents one time. Here `mosaic()` is used to spatially aggregate the imagery." + ], + "metadata": { + "id": "CBEBYfRrS9Yu" + } + }, + { + "cell_type": "code", + "source": [ + "# Spatial mosaicking.\n", + "time_starts = meloland_california_2026_crop_cycles.aggregate_histogram('system:time_start')\n", + "\n", + "def mosaic_function(time):\n", + " time_start = ee.Number.parse(time)\n", + " date = ee.Date(time_start)\n", + " filtered = meloland_california_2026_crop_cycles.filterDate(date)\n", + " # Transfer time and geographic properties.\n", + " return filtered.mosaic().set('system:time_start', time_start).clip(filtered.geometry(100))\n", + "\n", + "c = ee.ImageCollection.fromImages(time_starts.keys().map(mosaic_function))" + ], + "metadata": { + "id": "15F9O5vZT3R1" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Make a multi-temporal RGB visualization of one band\n", + "\n", + "Each satellite embeddings image has 64 bands and each band may or may not have a physical interpretation. The following is just a visualization to illustrate change over the six month period. Use the `geemap` library for display." + ], + "metadata": { + "id": "1E_5ChrkQvHQ" + } + }, + { + "cell_type": "code", + "source": [ + "# Three 64D temporal slices.\n", + "r = c.filterDate('2025-11-01', '2025-12-31').mean()\n", + "g = c.filterDate('2026-01-01', '2026-02-28').mean()\n", + "b = c.filterDate('2026-03-01', '2026-04-30').mean()\n", + "# Band 45 RGB.\n", + "b_index = 45\n", + "rgb1 = ee.Image.cat(r.select(b_index), g.select(b_index), b.select(b_index))" + ], + "metadata": { + "id": "Cj5VTspSXArV" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Display the image interactively with `geemap`." + ], + "metadata": { + "id": "eSJpbY-RiRqV" + } + }, + { + "cell_type": "code", + "source": [ + "Map = geemap.Map(center=(32.8287, -115.45131), zoom=13)\n", + "Map.addLayer(rgb1, {\"min\": -0.36, \"max\": 0.03}, \"rgb1\")\n", + "Map" + ], + "metadata": { + "id": "RAp4Ch2mXUXN" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Or request a thumbnail URL, which you can display using an IPython widget, download with `curl`, copy/paste, etc. These URLs are temporary and should not be used for long term access." + ], + "metadata": { + "id": "cIQ4daz1iWwu" + } + }, + { + "cell_type": "code", + "source": [ + "thumb_url = rgb1.clip(c.first().geometry()).getThumbUrl({\"min\": -0.36, \"max\": 0.03, \"dimensions\": \"512x512\"})\n", + "display(Image(url=thumb_url))" + ], + "metadata": { + "id": "YwLDKVLvgtBY" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Make a multi-temporal RGB visualization of change\n", + "\n", + "Here we'll represent change as the dot product (similarity) between mean slices of the time series and a reference year. To create a visualization, use the three dot products (from different times) as three bands in an RGB image. Redder pixels indicate greater similarity to reference conditions at the start of the period, greener pixels indicate greater similarity to reference conditions in the middle of the period, etc.\n", + "\n", + "Note that the 64D satellite embeddings are length-1 until you take the mean of a bunch of vectors. The functions needed to compute those dot products are defined here." + ], + "metadata": { + "id": "JSdbl0cOZizs" + } + }, + { + "cell_type": "code", + "source": [ + "def dot(im1: ee.Image, im2: ee.Image) -> ee.Image:\n", + " \"\"\"Dot product of length-1 images.\"\"\"\n", + " return im1.multiply(im2).reduce(\"sum\")\n", + "\n", + "\n", + "def scaled_dot(im1: ee.Image, im2: ee.Image) -> ee.Image:\n", + " \"\"\"Dot product of images that might not be length 1.\"\"\"\n", + " return dot(im1, im2).divide(dot(im1, im1).sqrt()).divide(dot(im2, im2).sqrt())\n", + "\n", + "\n", + "# Similarities of the means to a reference year (2024).\n", + "aef = ee.ImageCollection(\"GOOGLE/SATELLITE_EMBEDDING/V1/ANNUAL\")\n", + "aef_2024 = aef.filter(ee.Filter.calendarRange(2024, 2024, 'year')).mean()\n", + "rgb2 = ee.Image.cat(\n", + " scaled_dot(aef_2024, r),\n", + " scaled_dot(aef_2024, g),\n", + " scaled_dot(aef_2024, b)\n", + ")\n", + "Map.addLayer(rgb2, {\"min\": 0.42, \"max\": 0.95}, \"rgb2\")\n", + "Map" + ], + "metadata": { + "id": "SkXbjwXWa7t1" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Make a multi-temporal RGB visualization of similarity\n", + "\n", + "To find the pixels most similar to a single location over time, first compute the reference embedding at a single location. Then compute the dot product between that one reference and the pixels in the three temporal slices. Use a point in an arbitrary field in the image." + ], + "metadata": { + "id": "ss0RmRIQaI-1" + } + }, + { + "cell_type": "code", + "source": [ + "point = ee.Geometry.Point([-115.47235642112162, 32.83620978393891])\n", + "Map.addLayer(point, {}, \"point\")" + ], + "metadata": { + "id": "1C1izmrWaI-1" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# One (user specified) point overlaid on the first image.\n", + "mean_aef = c.first().reduceRegion(\n", + " reducer=\"mean\",\n", + " geometry=point,\n", + " scale=10\n", + ")\n", + "\n", + "# Mean similarities to the one point.\n", + "similarities = c.map(\n", + " lambda image: scaled_dot(image, mean_aef.toImage()).set('system:time_start', image.date().millis()))\n", + "rgb3 = ee.Image.cat(\n", + " similarities.filterDate('2025-11-01', '2025-12-31').mean(),\n", + " similarities.filterDate('2026-01-01', '2026-02-28').mean(),\n", + " similarities.filterDate('2026-03-01', '2026-04-30').mean())\n", + "Map.addLayer(rgb3, {\"min\": 0.2, \"max\": 0.8}, \"rgb3\")\n", + "Map" + ], + "metadata": { + "id": "vEVWcV5zaPeF" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## What's next?\n", + "\n", + "Explore [other Custom Satellite Embeddings samples](https://developers.devsite.corp.google.com/maps/documentation/custom-satellite-embeddings/samples)." + ], + "metadata": { + "id": "tt2vtzYSjvFN" + } + } + ] +} diff --git a/custom_satellite_embeddings/notebooks/ee_data_exploration/README.md b/custom_satellite_embeddings/notebooks/ee_data_exploration/README.md new file mode 100644 index 0000000..c2085aa --- /dev/null +++ b/custom_satellite_embeddings/notebooks/ee_data_exploration/README.md @@ -0,0 +1,15 @@ +# Custom Satellite Embeddings Data Exploration in Earth Engine + +In this guide, you can explore a time series of six monthly satellite embeddings images in an agricultural area of the California, USA central valley. Like the [annual embeddings](https://developers.google.com/earth-engine/datasets/catalog/GOOGLE_SATELLITE_EMBEDDING_V1_ANNUAL), +each custom satellite embeddings image has 64 information-dense bands. + +This notebook demonstrates how to: + +- Examine a single image +- Make a spatial mosaic +- Make a multi-temporal RGB visualization of one band +- Make a multi-temporal RGB visualization of change +- Make a multi-temporal RGB visualization of similarity + +For more information about Custom Satellite Embeddings, see +[the documentation](https://developers.google.com/maps/documentation/custom-satellite-embeddings).