I'm trying to remove clouds from Landsat 5,7 and 8 data. I'm also trying to do this using only open source options, avoiding ArcGIS. I'm familiar with python and have some QGIS experience. Originally, I was trying to use the Semi-Automatic Classification model in QGIS, but it is giving me a lot of problems, and doesn't always output actual classifications (it often just returns a uniformly valued square...). Can anyone point me in the direction of a better option?


May I suggest taking a look at fmask by Zhe Zhu


  • neither Python nor QGIS


  • availlable as matlab or C executable
  • great performance in detecting clouds as well as cloud shadows
  • straightforward use

I highly recommend giving it a try. The executables can be obtained from the links and so far our team hasn't found a superior product which is distributed free of charge.

| improve this answer | |
  • Would people be interested in a python version? I have got pretty good results from a python version of fmask that I've built. If there is a need for it I could publish the code. – nicholaschris Jan 12 '15 at 13:07
  • Is it the code working for LT8 before failure of the TIRS or the one allready built for Sentinel-2 (fmask version 3.2 and higher)? Anyway: I'm interested. – Kersten Jan 12 '15 at 13:15
  • I am busy implementing the use of the 'cirrus' band in L8. I'll let you know how it goes. The failure of the TIRS meant a bit of a rewrite. I'm glad there is some interest. – nicholaschris Jan 12 '15 at 14:03

I have managed to identify cloud pixels in Landsat 8 scenes using the following code. I have included some python / pseudo-code below which will return possible cloud pixels. This is the first pass of identifying the potential cloud layer taken from this paper by Zhu and Woodcock (2014).

The paper also details a second pass that further refines the result by excluded misidentified cloud pixels. You should have a look at that too. The method was developed for Landsat 7 so it should work for all Landsat cases.

def calc_ndsi():
     green = get_green_band()
     swir = get_swir_band()
     return (green - swir)/(green + swir)

def calc_ndvi():
    nir = get_nir_band()
    red = get_red_band()
    return (nir - red)/(nir + red)

def calc_basic_test():
    band_7_test = get_band_seven()
    temp_test = where temp is less than 27 deg C
    ndsi_test = where calc_ndsi < 0.8
    ndvi_test = where calc_ndvi < 0.8
    basic_test = np.logical_and.reduce((band_7_test,
    return basic_test

def calc_whiteness():
    blue = get blue
    green = get green
    red = get red
    mean_vis = (blue + green + red) / 3
    whiteness = (np.abs((blue - mean_vis)/mean_vis) + 
             np.abs((green - mean_vis)/mean_vis) +
             np.abs((red - mean_vis)/mean_vis))
    whiteness[np.where(whiteness>1)] = 1
    return whiteness

def calc_whiteness_test():
    whiteness_test = where calc_whiteness() < 0.7
    return whiteness_test

def calculate_hot_test():
    band = 'rtoa_'
    blue = get blue
    red = get red
    hot_test = (blue - 0.5*red - 0.08) > 0
    return hot_test

def swirnir_test():
    nir = get NIR
    swir = get SWIR
    return (nir/swir) > 0.75

def calc_pcp():
    return np.logical_and.reduce((calc_basic_test(),

So, calc_pcp() will identify the potential cloud pixels in your image.

Note that this method uses the TIRS bands (to get the temperature) in Landsat 8 which are currently not working. Additionally, this method uses data which has already undergone atmospheric correction.

Identifying clouds in remote sensing images is more than a colour processing issue, although calculating the 'whiteness' of the cloud is included in the test.

You should compare the results you get with the Landsat 8 Quality Assessment band.

| improve this answer | |

You might try this solution :


I've never removed cloud data before.


It seems like a color processing issue: clouds are a white-gray color. As long as you don't have snow or other large white objects in your ground plane, you could do a search for all pixels that match a criteria of having full red AND full green AND and full blue colors. as to how to do this... try the solution posted above.

| improve this answer | |
  • 1
    There are many other objects in these images which can be as white as clouds. Using this method would not be sufficient in identifying cloud pixels. – nicholaschris Jan 8 '15 at 11:25

take a look at this page http://gistack.rozblog.com/post/32/qa_cloudmask_ports.html at the bottom of this page you can download an erdas imagine model it takes landsat8 QA band and replace cloud pixel values with 0

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.