kappazeta / km_predict

S2 full image prediction
Apache License 2.0
21 stars 9 forks source link

Individuals jp2 as an input? #25

Closed caviri closed 1 year ago

caviri commented 1 year ago

Hello,

First of all thanks a lot for making this project open, it looks awesome. I was wondering if a list of bands can be provided instead of the .SAFE folder. In my case, I have a list of jp2 for each band of L2A.

Otherwise, If I replicate the folder structure will it works?

Thanks

indrek-sunter commented 1 year ago

Hello,

Thank you! There's still a lot of work to be done to improve it but it has been difficult to find the time.

Yes, it should work with a replicated folder structure. From an L2A product, KappaMask expects the following bands: "AOT", "B01", "B02", "B03", "B04", "B05", "B06", "B07", "B08", "B8A", "B09", "B11", "B12", "WVP" from an L1C product it expects: "B01", "B02", "B03", "B04", "B05", "B06", "B07", "B08", "B8A", "B09", "B10", "B11", "B12"

If you're using the sentinelhub[AWS] python package to fetch the rasters, then with the safe_format=True argument it would replicate the .SAFE directory structure.

For example, https://github.com/kappazeta/km_predict/blob/main/docker/km_predict/get_s3.py

Best regards

caviri commented 1 year ago

Thanks a lot. I did not know about the safe_format parameter. However, I'm downloading the assets directly using pystac_client. I'll try to write a script for the L2A product to create the folder structure. As soon as I have it, I will leave here in this issue.

caviri commented 1 year ago

Hello, I got a hacky method working I would like to share. I have been doing test with assets downloaded using pystac_client from aws and microsoft planetary computer. The former doesn't work as AOT band is not at the correct resolution (A solution for this will be to download directly the .SAFE folder as suggested by @indrek-sunter above. On the other hand MS contains all the bands in the correct resolution. However, we need to "fake" the folder structure on ".SAFE".

Here you can find the script I use to generate the folder and then create the symbolic links to the jp2 files. Assuming you have all JP2s in a folder named like the Sentinel 2 product, you can execute this like createFolderSymbolicsLinks({FolderContainingJP2s}, "/home/km_predict/data")

import os 
import subprocess

def getAllJP2(folder):
    jp2s = [file for file in os.listdir(folder) if file.endswith('.jp2')]
    return jp2s

def makeSymbolicPath(originalPath, symbolicPath):
    command = f'ln -s {originalPath} {symbolicPath}'
    process = subprocess.Popen(command.split(), stdout=subprocess.PIPE)
    output, error = process.communicate()
    return output, error

def createFolderSymbolicsLinks(productFolder, outputFolder):
    productName = productFolder.split("/")[-1]
    jp2s = getAllJP2(productFolder)

    if len(jp2s) == 15:
        safeProductPath = os.path.join(outputFolder, productName + ".SAFE")

        #if not os.path.exists(productPath): os.mkdir(productPath)
        if not os.path.exists(safeProductPath): os.mkdir(safeProductPath)

        granulePath = os.path.join(safeProductPath, "GRANULE")
        os.mkdir(granulePath)
        l2aPath = os.path.join(granulePath, "L2A")
        os.mkdir(l2aPath)
        imgdata = os.path.join(l2aPath, "IMG_DATA")
        os.mkdir(imgdata)
        qidata = os.path.join(l2aPath, "QI_DATA")
        os.mkdir(qidata)

        r10mPath = os.path.join(imgdata, "R10m")
        r20mPath = os.path.join(imgdata, "R20m")
        r60mPath = os.path.join(imgdata, "R60m")

        os.mkdir(r10mPath)
        os.mkdir(r20mPath)
        os.mkdir(r60mPath)

        for bandFile in jp2s:
            bandPath = os.path.join(productFolder, bandFile) 
            res = bandFile.split(".")[0].split("_")[-1]
            if res == "10m":
                symbolicPath = os.path.join(r10mPath, bandFile)
                output, error = makeSymbolicPath(bandPath, symbolicPath)
            elif res == "20m":
                symbolicPath = os.path.join(r20mPath, bandFile)
                output, error = makeSymbolicPath(bandPath, symbolicPath)
            elif res == "60m":
                symbolicPath = os.path.join(r60mPath, bandFile)
                output, error = makeSymbolicPath(bandPath, symbolicPath)

        return productName
    else:
        print(f"Not enough files in {productFolder}")

Thanks again @indrek-sunter for the amazing tool. It's working great.