enomis-dev / YouTube

Youtube tutorials of my channel pyinsights
1 stars 0 forks source link

question about Lesson 5 #1

Open Lecaethomas opened 1 month ago

Lecaethomas commented 1 month ago

Hi, First of all, thanks a lot for your hard work to make geospatial insights available for all, your tutorials are great. I took the lesson 5: Semantic segmentation with geospatial data, the notebook works fine and now that I have satisfying results I'd like to export the predicted mask as a tif file. This is my code but it seems I didn't understand something as the exported .tif is never well geolocated (using your example data, the mask end up in Columbia).. Could you provide me some more light please?

width = predicted_masks.shape[2]
height = predicted_masks.shape[1]
transform = Affine(0.60, 0.00, 440055.00, 0.00, -0.60, 4303429.20)
crs = 'EPSG:26918'  # Coordinate reference system (modify as needed)

# Function to save the predicted mask as a .tif file
def save_mask_as_tif(mask, filename, transform, crs):
    with rasterio.open(
        filename,
        'w',
        driver='GTiff',
        height=mask.shape[0],
        width=mask.shape[1],
        count=1,
        dtype=mask.dtype,
        crs=crs,
        transform=transform
    ) as dst:
        dst.write(mask, 1)

# Convert predicted_masks to numpy and save as .tif
predicted_mask_numpy = predicted_masks.cpu().numpy().astype('uint8')  # Assuming masks are in binary format

# Save the first predicted mask as a sample
save_mask_as_tif(predicted_mask_numpy[0], 'predicted_mask.tif', transform, crs)

By advance, thanks Thomas

enomis-dev commented 1 month ago

Hi @Lecaethomas thanks for your support, looking to your code it looks good. It could be that your mask has different affine or crs with respect to your input raster, I was wondering if you can share with me the input raster as well as the predicted mask, thank you.

Lecaethomas commented 1 month ago

Hi, sorry for the lack of context, I used your code and your input for a first try (NAIP imagery and Chesapeake landcover layer). The transform I use is the one returned by rasterio based on the input, and the crs too. These are the reasons why I was wondering if I didn't lose the georeference somehow during the process. I never tried deep learning before, so I don't know what can happen to the georeferencing during the process image

enomis-dev commented 1 month ago

Hi! No worries the 2 snippets of code you shared with me, look correct. I'll try to replicate locally. In case the files are not too big, could you share here please?

Lecaethomas commented 1 month ago

Thanks a lot for your help! I pushed my code here, it would be easier for you to reproduce. (be careful, I left the number of samples as if I was on kaggle)

enomis-dev commented 1 month ago

I'll check better during the weekend but at first sight you're copying the affine of the original naip big tile to the predicted mask. The fact is that the mask is calculated on a crop of the original image and the affine therefore changes. The whole concept of the training was to have a testing and validation sets from some original big tiles by subcropping it in order to do data augumentation.

If you would like to check the model and have a well geolocated tiff file you could:

I'll try to elaborate more in the next days, thanks for your question

enomis-dev commented 1 month ago

Hi! Here a code you could use to do the prediction on a input .tif In case the input .tif is too big as in this case you can read a crop.

# define path to one of the naip tile
path_tile = "/tmp/naip_val/m_3807512_sw_18_060_20180815.tif"

# print original raster shape
with rasterio.open(path_tile) as src:
    print("Original shape:", src.shape)

# input window in pixels
window = rasterio.windows.Window(500, 500, 1000, 1000)
# let's open a crop of the .Tif file
with rasterio.open(path_tile) as src:
    # Read the data within the window
    data = src.read(window=window)
    print("Original affine:", src.transform)

    # Optionally, get the transform for the window
    transform = src.window_transform(window)
    print("Windows affine:", transform)

    # Get the metadata of the input file
    metadata = src.meta.copy()

    print("Crop shape:", data.shape)

Prediction:

# Convert the NumPy array to a PyTorch tensor and reshape, we ignore band 4 that is the transperency
tensor_data = torch.tensor(data[0:3]).unsqueeze(0).float()  # tensor_data.shape will be (1, 3, 500, 500)
print("Tensor shape for prediction:",tensor_data.shape)

# Convert logits to predicted class labels
pred = model(tensor_data)
mask = torch.argmax(pred, dim=1)
print("Mask shape:", data.shape)

Save cropped tif

# Write the cropped data to a new .Tif file
output_tif_path = "crop.tif"

metadata.update({
    'height': window.height,
    'width': window.width,
    'transform': transform
})

with rasterio.open(output_tif_path, 'w', **metadata) as dst:
    dst.write(data)

Save cropped mask

# Write the mask data a new .Tif file
output_tif_path = "mask.tif"

metadata.update({
    'count': 1,           # Update the number of bands
    'height': window.height,
    'width': window.width,
    'transform': transform
})

with rasterio.open(output_tif_path, 'w', **metadata) as dst_mask:

    dst_mask.write(mask.cpu().numpy().astype(np.uint8))

Yo will be able to open them in QGIS for instance with the good geolocation:

image

Lecaethomas commented 1 month ago

Thanks a lot to have taken the time to test it! I'll try that during the week :)