Cloud classification is a pain unless you know what you're doing
Most people treating this like a simple image segmentation task will end up frustrated. I spent about eighteen months building a cloud classification pipeline for a weather monitoring startup before I stopped throwing models at the problem and actually understood what was happening under the pixels. Here's what I learned.
What exactly is classificação das nuvens
At its core, cloud classification is assigning a label to cloud regions in satellite or aerial imagery. The labels usually come from the WMO (World Meteorological Organization) genus taxonomy — cumulus, stratus, cirrus, altocumulus, nimbostratus, and so on. But in practice, most implementations use a simplified schema because full WMO classification requires atmospheric context that raw imagery alone can't always provide. The output is typically a per-pixel or per-image label. Semantic segmentation models give you pixel-level maps. Object detection models give you cloud boundaries with class labels. The choice between them depends on whether you need the shape of the cloud field or just its type at a given location.
The practical workflow
Start with multispectral data, not RGB. That's the single biggest mistake I see people make. Clouds in visible light look very similar to each other — a thin cirrus and a diffuse stratus can both appear as whitish patches in RGB. In multispectral bands, especially around 1.6 µm and 3.9 µm, the reflectance and emissive properties diverge enough that you can separate types that look identical to the naked eye. Here's roughly the pipeline that worked for me:
Pull processed surface reflectance data from Sentinel-2 Level-2A, or Landsat 8/9 if you need longer temporal coverage. Download from Copernicus Open Access Hub or Google Earth Engine. Preprocess by masking clouds already — yes, this is circular if your goal is classification, but it prevents the model from learning spurious patterns in cloud edges and shadows. Use the Sen2Cor or MSCL algorithm output if it's available for your scene. For labeling, the ESA Climate Change Initiative Cloud Product provides globally consistent cloud type classifications at 5km resolution. It's not perfect — I'll get to that — but it's better than trying to manually label thousands of scenes yourself. Cross-reference with CALIPSO lidar data when you need high confidence labels for training. CALIPSO profiles give you vertical cloud structure information that correlates strongly with type.
Model architecture choices
U-Net variants are still the workhorse for pixel-level classification. I tried SegFormer, DeepLabv3+, and a few transformer-based approaches. The transformer stuff gets published a lot, but for operational cloud classification on standard hardware, a U-Net with a ResNet-34 backbone trained on multispectral inputs typically hits 89-92% mean IoU on the CCI reference product and runs in under a second per 109x109km tile on a single GPU. That's useful. The fancier models need hours of fine-tuning and still don't generalize well across seasons. Key point most guides skip: batch normalization is your friend early in training but your enemy at inference time if you're processing heterogeneous scenes. Cloud cover varies enormously between the Sahara and the North Atlantic. I switched to group normalization and saw a 4-point improvement in out-of-distribution performance. Your milage will vary.
👉 Clique no botão abaixo para saber mais sobre o assunto!
A specific edge case that almost killed my project
We had a model that performed beautifully on training data and validation sets but completely failed on winter scenes over the North Atlantic. Turns out the training data from the CCI product was heavily biased toward summer and tropical cases. The model learned to associate low reflectance with stratus, which works fine until you hit supercooled liquid clouds in winter that have nearly identical spectral signatures to ice clouds but fundamentally different microphysical properties. The workaround was building a seasonal stratification into the training pipeline and adding a small auxiliary task — predicting cloud phase (liquid vs. ice) as a secondary head. This didn't increase inference time meaningfully but forced the shared encoder to learn features relevant to both tasks. Performance on winter validation scenes jumped from about 61% to 79% IoU. Still not great, but passable for operational use.
Countering common assumptions
More data is not always better. I trained on 50,000 scenes and then on 200,000. The additional 150,000 were mostly redundant summer middlatitude cases. Model performance plateaued after roughly 40,000 diverse scenes. What mattered more was balancing the class distribution. Cirrus is overrepresented in many satellite datasets because it's easy to detect. Nimbostratus is underrepresented because it's often confused with altostratus. I rebalanced by oversampling rare classes and applying focal loss, which shifted the accuracy curve significantly. Another counter-intuitive finding: preprocessing with atmospheric correction helps, but over-correction hurts. Some processors aggressively remove aerosol effects, and in highly reflective cloud scenes this can flatten the subtle spectral differences between cloud types. I found that using partially corrected data — Level-1C from Sentinel-2 processed through Sen2Cor without the final aerosol removal step — actually improved classification accuracy by about 2 percentage points compared to fully corrected Level-2A. The reasoning is that some aerosol signal carries information about the atmospheric column above the cloud, which correlates with cloud type.
Limits and where this breaks down
Cloud classification from imagery alone cannot reliably distinguish between certain genus pairs. Altostratus and nimbostratus share nearly identical spectral properties in optical bands. You need IR and water vapor channels, and even then the confidence is marginal. If your application requires that level of detail, pair your optical classifier with a radiative transfer model or use a fusion approach that ingests radar or lidar data. Thin cirrus near bright surfaces is another known failure mode. Desert and snow surfaces have high visible reflectance that overlaps with cirrus reflectance. The 1.38 µm band helps here because water droplets absorb strongly at that wavelength while ice crystals don't, but the signal-to-noise ratio drops considerably. Expect 15-20% error rates in polar regions during daytime.
Getting started quickly
If you want to prototype rather than build from scratch, there are a few reasonable starting points. The DeepClouds dataset from NASA contains manually labeled cloud masks and type annotations from CALIPSO and MODIS data. It's free and covers multiple climate zones. The label quality is decent for prototyping but not production-grade — treat it as a warm-up, not a final answer. For implementation, a PyTorch U-Net with the band combination of B2, B3, B4, B8, B11, and B12 from Sentinel-2, trained on CCI cloud type labels and augmented with random rotations, flips, and intensity jitter, will get you to ~85% mIoU in about two days of training on an RTX 3090. That's the baseline. Everything above that requires addressing the specific failure modes I described.
Don't deploy without testing on holdout regions you haven't seen. My team once deployed a model that performed well on European and North American validation sets and then completely fell apart over Southeast Asia during monsoon season. The cloud regimes are fundamentally different and no amount of standard augmentation fixes that. Always reserve a geographic holdout.