I set out to calculate NDVI and visualize vegetation in Finland using satellite imagery. But before I could get anything meaningful on the screen, everything broke, and every fix taught me something new.
This post is a breakdown of what I got wrong, what didn’t make sense, and how I eventually got it working.
1. I Downloaded the Wrong Data Over and Over
I started by downloading Sentinel-2 .tiff
files from Copernicus. They looked fine, no errors, so I loaded them into QGIS.
What I saw: a completely dark image.
I assumed the darkness was normal because it was “raw data.” But something didn’t feel right.
I deleted the files and downloaded another set, same issue. I tried different pixels, formats, even downloaded 32-bit, then 16-bit versions.
Still dark.
2. CRS Confusion Made It Worse
When I first loaded the raster in QGIS, the project was set to EPSG:3857 (Web Mercator). The raster wasn’t distorted — it just appeared much larger in scale compared to the base map. It didn’t fit well within the map canvas, and the proportions felt off.
Thinking the issue was related to projection, I changed the project CRS to EPSG:4326. But that actually made things worse — the raster became distorted, and the base map was visibly stretched.
That’s when I realized something important:
My raster’s pixel values were too high, and it couldn’t display correctly over the default basemap.
3. 8-Bit Fixed the Fit, Finally!
I went back and downloaded the 8-bit version of the data — and suddenly, it snapped into place on the map.
For the first time, it aligned properly with the basemap in QGIS.
That’s when it clicked: the issue wasn’t just the CRS, it was the raster’s bit depth and how QGIS handles rendering.
High-bit-depth rasters (16-bit or 32-bit) are designed for analysis, not visualization. They carry more numerical precision but often appear black, washed out, or oversized when layered over a map — especially without stretching or resampling.
Lesson learned:
If you’re doing visual mapping or quick previews, use 8-bit data.
If you’re doing NDVI, classification, or scientific analysis — 16-bit or 32-bit is fine, and you don’t even need a basemap.
Not everything needs to look good on a map — especially when the goal is analysis.
4. NDVI Calculation Gave Me... a Black Block
Now confident I had good data, I calculated NDVI in Python:
ndvi = (nir - red) / (nir + red)
Plotted it, and saw nothing but a solid black rectangle.
No zones, no variation, just... black.
5. Identify Tool Showed Nothing
I opened the NDVI result in QGIS and used the Identify Tool.
The values? Completely empty.
I ran the same raster through a Python check:
print(np.nanmin(ndvi), np.nanmax(ndvi))
→ Both returned NaN
.
The entire image was full of NaNs.
At that point, I had tried almost every combination of download and reprocessing. Nothing was working.
6. Clipping and Vectorizing Worked, But the Result Was Weird
Next, I clipped the NDVI raster using a farm boundary and then vectorized the classified result (low, medium, high vegetation).
It worked — technically — but the output looked strange.
In QGIS, I saw massive red, yellow, and green blocks. The low NDVI zone appeared as a huge red shape across the map.
It didn’t look wrong, but it didn’t look quite right either.
7. I Asked for Help And Got the Real Data
Finally, I posted a quick question on r/gis:
The responses pointed me to USGS EarthExplorer, and this changed everything.
I downloaded Landsat 8 Level-2 Surface Reflectance, Bands 4 and 5 — full-resolution, proper metadata, 80–100MB each.
I re-ran my workflow. Everything clicked:
- QGIS rendered the bands clearly
- Python returned actual NDVI values
- The visualization was clean and detailed
8. Saving as GeoJSON Was the Final Trap
With a great result in hand, I decided to export the classified NDVI zones to GeoJSON.
gdf.to_file("classified_ndvi.geojson", driver="GeoJSON")
It saved, but the file was 352MB.
When I tried to load it into QGIS, it froze. Or loaded partially. Or refused to render at all.
9. Shapefiles and GeoPackages Saved the Day
After some quick Googling, I realized GeoJSON doesn’t handle large vector data well.
So I re-exported the same data:
# Save as Shapefile
gdf.to_file("classified_ndvi.shp")
# Save as GeoPackage
gdf.to_file("classified_ndvi.gpkg", driver="GPKG")
Both formats worked flawlessly. QGIS loaded them in seconds, with smooth rendering and no crashing.
Final Thought
This was my first real geospatial project. I thought it would be simple. It wasn’t but that’s what made it valuable.
Every “wrong” step helped me understand something no tutorial could fully explain.
If you're working with satellite data: check your CRS, validate your inputs, and don’t be afraid to start over.
And when in doubt? Ask a community. A single Reddit reply saved this entire project.
Top comments (0)