Automated generation of Swiss-style topographic maps from aerial imagery using Google’s Gemini AI (NanoBanana).
This project originated from exploring whether generative AI could transform aerial photographs into professional topographic map renderings that match Swiss cartographic standards. The initial LinkedIn experiment demonstrated promising results for single images. This repository extends that work to test scalability, consistency, and automation across larger map areas. With all the feedback I got and a deep dive in the Gemini API for image style transfer, I adapted the prompt which you can use directly in an AI which has NanoBanana integerated such GEMINI. In GEMINI make sure, you activated "Create Image" when processing the Input
Can we reliably generate Swiss-style topographic map visualizations from SWISSIMAGE aerial photography using AI, maintaining cartographic consistency across multiple map tiles?
✅ Geometric Precision: The AI maintains high positional accuracy, correctly placing geographic features
✅ Style Recognition: Strong fidelity to cartographic conventions (colors, symbols, layering)
✅ Information Extraction: Good detection of roads, trees and buildings
✅ Automation Feasibility: Workflow is reproducible and can process multiple tiles systematically
fixed in release v1.0.0
The approach shows significant potential for automated cartographic visualization. While not production-ready, results demonstrate that AI can understand and translate aerial imagery into recognizable map styles with reasonable accuracy... and definitely gives a taste of things to come in the coming months (not years!)
For an approx 500x500m Area in Switzerland
| Aerial Photo | Generated Map | Notes |
|---|---|---|
![]() |
![]() |
|
![]() |
![]() |
|
![]() |
![]() |
A complete hallucination |
![]() |
![]() |
|
![]() |
![]() |
|
![]() |
![]() |
|
![]() |
![]() |
|
![]() |
![]() |
|
![]() |
![]() |
|
![]() |
![]() |
|
![]() |
![]() |
|
![]() |
![]() |
|
![]() |
![]() |
|
![]() |
![]() |
|
![]() |
![]() |
|
![]() |
![]() |
Using SSIM (Structural Similarity Index) to compare original satellite images with generated maps helps detect if transformation actually occurred or if output is too similar to input (This is a common issue and well understood Nano Banana performs better on cold starts and degrades over multiple iterations ). High SSIM values (>0.35) indicate potential failed generations where the AI didn't properly transform the image.
- ✅ SUCCESS: Image successfully transformed (SSIM < threshold)
- ❌ FAILED: Generated image too similar to input (transformation did not occur)
- SSIM Score: Structural Similarity Index (0-1, higher = more similar)
These tiles required reprocessing .
- AI Model: Google Gemini (Nano Banana) - available in free tier
- Data Source: swisstopo SWISSIMAGE WMTS
- Coordinate System: Swiss LV95 (EPSG:2056)
- Optimal Scale: Zoom level 26 (~1:2000 scale)
- Define Area in Switzerland: Draw a polygon on map.geo.admin.ch and grab the link to the KML
- Download Tiles: Script fetches WMTS tiles (256×256 px) covering the area. swisstopo data are open
- AI Processing: Each tile is processed through Gemini with a custom cartographic prompt based on swisstopo's Basemap Style. Using SSIM (Structural Similarity Index) we check if the transformation was successfull and rerun it with a rerun prompt we try it at least 3 times
- Output: Generated map tiles saved alongside original aerial photos
Gemini's Nano Banana model has AFAIK an input limit of 1024×1024 pixels. Breaking large areas into WMTS tiles (256×256 px at zoom 26) allows:
- Processing of arbitrarily large regions
- Staying within API constraints
- Maintaining sufficient detail
Before you begin, ensure you have:
- Python 3.8+ installed on your computer
- A Google account for API access
- Basic familiarity with running Python scripts (no coding knowledge required)
- Visit Google AI Studio
- Sign in with your Google account
- Click "Get API key" in the sidebar
- Create a new API key (choose "Create API key in new project")
- Important: Enable billing if prompted (free tier available, but billing must be configured)
- Copy your API key
# Clone the repository
git clone https://github.com/davidoesch/ai-topographic-maps.git
cd ai-topographic-mapsOr download as ZIP and extract to a folder.
Open a terminal/command prompt in the project folder and run:
pip install requests pillow google-genai pyproj numpy scikit-image- Create a folder named
secretsin the project directory - Inside
secrets, create a text file namedgenai_key.txt - Paste your API key into this file (nothing else, just the key)
- Save and close the file
Your folder structure should look like:
ai-topographic-maps/
├── style_transfer_swissimage.py
├── prompt.txt
├── prompt_restart.txt
├── secrets/
│ └── genai_key.txt
└── README.md
- Go to map.geo.admin.ch
- Click the drawing tools (pencil icon)
- Draw a polygon around your desired area
- Click "Share" → Copy the link
- Extract the KML URL from the link (looks like:
https://public.geo.admin.ch/api/kml/files/...) - Open
style_transfer_swissimage.pyin a text editor - Find the line at the top in the configuration section with
AREA_URL = = "https://public.geo.admin.ch/..." - Replace with your KML URL
Tip: Start with a small area (a few city blocks) for your first test!
Open terminal in the project folder and run:
python style_transfer_swissimage.pyThe script will:
- Download and parse your KML area
- Calculate required map tiles
- Download aerial photos from swisstopo
- Process each tile through Gemini AI
- Save results to
output_tiles_ssmi_fixed/folder
Processing time: ~5-10 seconds per tile (depending on API response time)
Generated files are saved in the output_tiles_ssmi_fixed/ directory:
{col}_{row}.jpeg- Original aerial photo{col}_{row}_map.jpeg- AI-generated topographic rendering
The cartographic style is defined in prompt.txt. You can edit this file to:
- Change color schemes
- Adjust symbol styles
- Add/remove map features
- Modify abstraction levels
Example prompt snippet:
Transform this aerial photograph into a Swiss topographic map style:
- Buildings: Light gray with subtle shadows
- Roads: Yellow for main roads, white for minor roads
- Vegetation: Green gradients based on density
- Water: Light blue with darker outlines
...
- Start small: Test with 4-9 tiles before processing large areas
- Optimal scale: Zoom level 26 works best (~1:2000)
- Check API limits: Free tier has daily quotas - monitor usage
- Iterate prompts: Experiment with different style instructions
Error: 429 RESOURCE_EXHAUSTED
- You've hit API rate limits. Wait 1 minute and try again
- Check billing is enabled in Google Cloud Console
Error: No coordinates found in KML
- Verify your KML URL is correct
- Ensure you drew a polygon (not just a marker) on map.geo.admin.ch
Poor quality results
- Try adjusting the prompt in
prompt.txt - Ensure zoom level 26 is being used
- Check that original tiles downloaded correctly
Potential enhancements for more robust results:
- Add hillshade/terrain as background layer
- Implement post-processing for consistency across tiles
- Better automatic removal of cars and transient objects
- Batch processing with progress indicators
- Quality metrics for generated tiles
- Mosaic stitching for seamless map output
- Support for multiple style presets
- Web interface for non-technical users
- Original LinkedIn Post
- swisstopo WMTS API Documentation
- Google Gemini API - Image Generation
- Swisstop BaseMaps (for style reference)
Contributions are welcome! Areas particularly helpful:
- Improving prompt engineering for better consistency
- Developing post-processing algorithms for tile harmonization
- Creating quality assessment metrics
- Adding support for different cartographic styles
- swisstopo: For providing excellent WMTS aerial imagery services
- Google: For making Gemini AI accessible through free tier
- Community: For inspiration and feedback on initial experiments
Questions or feedback? Open an issue or reach out on LinkedIn.
Note: This is an experimental project exploring AI capabilities in cartography. Generated maps are for research and visualization purposes, not for official or navigation use.































































