eMapR / LT-GEE

Google Earth Engine implementation of the LandTrendr spectral-temporal segmentation algorithm. For documentation see:
https://emapr.github.io/LT-GEE
Apache License 2.0
193 stars 65 forks source link

Band 4 returning negative spectral response #20

Closed Walshe-d closed 3 years ago

Walshe-d commented 3 years ago

I'm using Landtrendr to get the spectral response per pixel per year to map historical forest fires. Before I do any of this I want to validate it for an area I know was burned in May 2017. In doing so I noticed that the raw spectral response from band 4 for my area of interest (bounds3 in the script) was returning negative values for all pixels for all years I was investigating. I have no idea why. I don't think it is an image issue as it is present in all pixels for all years.

This is my first github issue so please let me know if I left any info out. Thanks.

GEE code

jdbcode commented 3 years ago

Without looking too closely I think I see what is happening: in short, the ltgee.runLT function inverts B4 (NIR) when used as the segmentation index. Much of the LandTrendr segmentation algorithm was developed using TM band 5 (SWIR1), which increases in reflectance response following loss of vegetation i.e. the algorithm is coded to interpret input gain as disturbance, loss as recovery. So, inputs used for segmentation need to be inverted in some cases to ensure that positive delta equals vegetation loss. The solution is to multiply the LT source and fitted values e.g. in your table construction:

spectral_response: arr.cut([1, -1]).project([1]).multiply(-1),
fitted: arr.cut([2, -1]).project([1]).multiply(-1),

Note that you are going to get terrible results by including only 5 years. LT uses statistics for segmentation, so with only 5 observations there is not much to work with.

Also, exporting every pixel's time series is not great. Why not do a mean reduction of all the pixels in the ROI or a sample a small number of individual pixels?

Here are the "indices" that get inverted (-1) - inversion is mentioned in the buildLTcollection function result section and in the last paragraph of the Running LT-GEE page. The runLT function wraps buildLTcollection, but I should mention the inversion in its description (see #21).

{
    'NBR': -1,
    'NDVI': -1,
    'NDSI': -1,  // ???? this is a tricky one
    'NDMI': -1,
    'EVI': -1,  
    'TCB': 1,
    'TCG': -1,
    'TCW': -1,
    'TCA': -1,
    'B1': 1,
    'B2': 1,
    'B3': 1,
    'B4': -1,
    'B5': 1,
    'B7': 1,
    'ENC': 1,
    'ENC1': 1,
    'TCC': 1,  
    'NBRz': 1,
    'B5z': 1
 }
jdbcode commented 3 years ago

Test code: https://code.earthengine.google.com/087f8823da4eb84f46ecd25635c1939a

Walshe-d commented 3 years ago

Hi @jdbcode ,

Sorry for the delay in responding. Okay that's perfect, I understand what is happening with it now, thank you very much.

Yeah using using each pixels time series will be a lot of work but I want to try identify pixels that have been burned previously but have not been recorded. So if they have not been recorded it is unlikely they have affected the majority of a forest stand and so using the mean or median reduction for an ROI will mask these pixels that have been burned.

Some pixels may show up as noise so I plan to use a minimum mapping unit i.e. if 5 adjoining pixels are identified as burned I will include them but if it is only one pixel and no adjoining pixels have been identified as burned, that will be excluded. Hope that makes sense. If you have any other suggestions for a better way to do this I would really appreciate it!

jdbcode commented 3 years ago

Makes sense. Regarding single pixel time series table export. It may give errors if you are trying to inspect it in an interactive Code Editor session, use export first and then import the asset to inspect. Also, possibly break up the region into a few exports if the entire area export fails.