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.
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, temp_test, ndsi_test, ndvi_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(), calc_whiteness_test(), calculate_hot_test(), swirnir_test()))
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.
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.
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