commit c81627b5aeff59af51f1984dc6708bc3863f673b Author: Tercio da Silva Ferreira Date: Mon Jun 8 20:00:40 2026 -0300 1st commit diff --git a/LAGEF_UFF/LAGEF_UFF_Shoreline.py b/LAGEF_UFF/LAGEF_UFF_Shoreline.py new file mode 100644 index 0000000..1ada8f4 --- /dev/null +++ b/LAGEF_UFF/LAGEF_UFF_Shoreline.py @@ -0,0 +1,845 @@ +import ee +import geemap +import pandas as pd +import numpy as np +import matplotlib.pyplot as plt +import skimage.filters as filters +import random +import os + +#################################################################################### + +Map = geemap.Map() + +#################################################################################### MAIN FUNCTION +#################################################################################### +#################################################################################### +#################################################################################### + +def function_lc(ano_de_interesse, roi, path1, row1, porcentagem_nuvem_roi, caminho_excel_mares, nome_aba_excel, min_mare, max_mare,otsu_method,limiar_otsu): + + #"dicionário" + start_dateNuv = ano_de_interesse + roi = roi + porcentagem_nuvem_roi = porcentagem_nuvem_roi + file_path = caminho_excel_mares + sheet_name = nome_aba_excel + + # Definir o intervalo de datas para busca das imagens + end_dateNuv = start_dateNuv.advance(1, 'year') + + # Determinar a coleção do Landsat com base na data + landsat_collection = ee.ImageCollection( + ee.Algorithms.If( + start_dateNuv.difference(ee.Date('2013-01-01'), 'year').gte(0), + ee.ImageCollection('LANDSAT/LC08/C02/T1_L2'), # Objeto Landsat 8 + ee.ImageCollection('LANDSAT/LT05/C02/T1_L2') # Objeto Landsat 5 + ) + ).filterDate(start_dateNuv, end_dateNuv) \ + .filterBounds(roi) \ + .filter(ee.Filter.lt('CLOUD_COVER', 100)) + + # Aplicar o fator de escala e o offset à coleção + landsat_collection = landsat_collection##.map(apply_scale_factor) + + # Obter a primeira imagem da coleção + first_image = landsat_collection.first() + + # Obter o ID da imagem e imprimir + image_id = first_image.get('system:id').getInfo() + #print(f"ID da imagem utilizada: {image_id}") + + def cloud_coverage(image): + # Selecionar a banda de qualidade (QA_PIXEL) para identificar pixels de nuvens + qa = image.select('QA_PIXEL') + + # Criar uma máscara para pixels de nuvens (bits 3 e 5 no QA_PIXEL) + cloud_mask = qa.bitwiseAnd(1 << 3).Or(qa.bitwiseAnd(1 << 5)) + + # Calcular a área total da ROI + total_area = roi.area() + + # Calcular a área coberta por nuvens na ROI + cloud_area = cloud_mask.multiply(ee.Image.pixelArea()).reduceRegion( + reducer=ee.Reducer.sum(), + geometry=roi, + scale=30, + maxPixels=1e9 + ).get('QA_PIXEL') + + # Calcular a área total da imagem + image_area = image.geometry().area() + + # Calcular a área coberta por nuvens na imagem completa + image_cloud_area = cloud_mask.multiply(ee.Image.pixelArea()).reduceRegion( + reducer=ee.Reducer.sum(), + geometry=image.geometry(), + scale=30, + maxPixels=1e9 + ).get('QA_PIXEL') + + # Calcular a porcentagem de cobertura de nuvens + cloud_percentage_roi = ee.Number(cloud_area).divide(total_area).multiply(100) + cloud_percentage_image = ee.Number(image_cloud_area).divide(image_area).multiply(100) + + return image.set('cloud_coverage_roi', cloud_percentage_roi).set('cloud_coverage_image', cloud_percentage_image) + # Aplicar a função a cada imagem na coleção + landsat_with_cloud_coverage = landsat_collection.map(cloud_coverage) + + # Recuperar os IDs das imagens e as porcentagens de cobertura de nuvens + image_ids2 = landsat_with_cloud_coverage.aggregate_array('system:id').getInfo() + cloud_percentages_roi = landsat_with_cloud_coverage.aggregate_array('cloud_coverage_roi').getInfo() + cloud_percentages_image = landsat_with_cloud_coverage.aggregate_array('cloud_coverage_image').getInfo() + + # Definindo o intervalo de datas para busca das imagens + start_dateMar = start_dateNuv + end_dateMar = end_dateNuv + + # Definir o path e row específicos para a Baía de Guanabara + path = path1 + row = row1 + + # Carregar a coleção de imagens Landsat 8 + landsat_collectionMar = landsat_with_cloud_coverage \ + .filterDate(start_dateMar, end_dateMar) \ + .filter(ee.Filter.eq('WRS_PATH', path)) \ + .filter(ee.Filter.eq('WRS_ROW', row)) + + # Recuperar os IDs das imagens filtradas e as porcentagens de cobertura de nuvens na ROI + image_idsMar = landsat_collectionMar.aggregate_array('system:id').getInfo() + cloud_percentages_roiMar = landsat_collectionMar.aggregate_array('cloud_coverage_roi').getInfo() + + # Função para extrair a data dos IDs das imagens + def extract_date_from_id(image_id): + date_str = image_id.split('_')[-1] + return pd.to_datetime(date_str, format='%Y%m%d') + + # Criar um DataFrame com as datas das imagens e porcentagens de nuvens na ROI + image_dates_df = pd.DataFrame({ + 'image_id': image_idsMar, + 'image_date': [extract_date_from_id(image_id) for image_id in image_idsMar], + 'cloud_coverage_roi': cloud_percentages_roiMar + }) + + # Adicionar índice à coluna de data do DataFrame de imagens e garantir o tipo datetime + image_dates_df['image_date'] = pd.to_datetime(image_dates_df['image_date']) + image_dates_df.set_index('image_date', inplace=True) + + # Carregar a tabela de marés a partir da planilha específica + tides_df = pd.read_excel(file_path, sheet_name=sheet_name) + + # Converter a coluna 'Data' para datetime no DataFrame de marés e garantir o tipo correto + tides_df['Data'] = pd.to_datetime(tides_df['Data'], format='%d/%m/%Y') + + # Filtrar os valores de marés entre 0,51 e 0,96 e a hora de 9h ## USANDO 0.59 e 1.03 + filtered_tides_df = tides_df[ + (tides_df['valor'] >= min_mare) & + (tides_df['valor'] <= max_mare) & + (tides_df['Horat'] == 9) + ].copy() + + # Adicionar índice à coluna de data do DataFrame de marés e garantir o tipo datetime + filtered_tides_df['Data'] = pd.to_datetime(filtered_tides_df['Data']) + filtered_tides_df.set_index('Data', inplace=True) + + # Ordenar os DataFrames pelas datas (necessário para merge_asof) + image_dates_df.sort_index(inplace=True) + filtered_tides_df.sort_index(inplace=True) + + # Combinar os DataFrames pelas datas usando merge_asof + combined_df = pd.merge_asof( + image_dates_df, + filtered_tides_df, + left_index=True, + right_index=True, + direction='nearest', + tolerance=pd.Timedelta('1D') + ) + + # Filtrar imagens com menos de x% de cobertura de nuvens na ROI + filtered_combined_df = combined_df[combined_df['cloud_coverage_roi'] < porcentagem_nuvem_roi] # USANDO 0.01 + + # Obter os IDs das imagens correspondentes, removendo os NaNs resultantes da junção + matching_image_ids = filtered_combined_df.dropna(subset=['valor'])['image_id'].tolist() + + #print(matching_image_ids) + + # Função para aplicar máscara de nuvens + def mask_l8_sr(image): + qa_mask = image.select('QA_PIXEL').bitwiseAnd(int('11111', 2)).eq(0) #11111 + saturation_mask = image.select('QA_RADSAT').eq(0) + #optical_bands = image.select('SR_B.').multiply(0.0000275).add(-0.2) + #thermal_bands = image.select('ST_B.*').multiply(0.00341802).add(149.0) #.updateMask(qa_mask) + return image.updateMask(saturation_mask) \ + .updateMask(qa_mask) + #.addBands(optical_bands, None, True) \ + #.addBands(thermal_bands, None, True) \ + + # Carregar a coleção de imagens Landsat + landsat8 = landsat_collection + + # Definir o ID da imagem base manualmente ##estou testando a coleção de SR + base_image_id = matching_image_ids[0] + + # Selecionar a imagem base pelo ID + base_image = ee.Image(base_image_id) + + # Função para determinar as bandas de visualização com base na coleção + def get_visualization_bands(image): + # Verificar a coleção da imagem (Landsat 8 ou Landsat 5) + if 'LC08' in image.get('system:id').getInfo(): + # Definir as bandas para Landsat 8 + return ['SR_B4', 'SR_B3', 'SR_B2'] # Red, Green, Blue + elif 'LT05' in image.get('system:id').getInfo(): + # Definir as bandas para Landsat 5 + return ['SR_B3', 'SR_B2', 'SR_B1'] # Red, Green, Blue + else: + # Caso a coleção não seja reconhecida + return [] + + # Obter as bandas para visualização automaticamente + visualization_bands = get_visualization_bands(base_image) + + # Definir parâmetros de visualização + visualization = { + 'bands': visualization_bands, + 'min': 0, + 'max': 0.2 + } + + # Aplicar a máscara de nuvens na imagem base + combined_image = base_image + + # Período do mosaico de referência (base abaixo da imagem única) + start_date = start_dateNuv + end_date = end_dateNuv + + # Filtrar e mascarar a coleção de imagens no período de referência + filtered_collection = landsat8.filterDate(start_date, end_date).filterBounds(roi).map(mask_l8_sr) + + # Criar um mosaico mediano das imagens de referência + reference_mosaic = filtered_collection.median() + + #reference_mosaic = reference_mosaic.select(reference_mosaic.bandNames()).multiply(0.0000275).add(-0.2) + + # Função para preencher os pixels nublados da imagem base com o mosaico de referência + def fill_cloud_pixels(base, reference): + # Criar uma máscara para os pixels nublados + cloud_mask = base.mask().Not() + # Preencher os pixels nublados com os pixels do mosaico de referência + filled = base.unmask(reference) + return filled + + + # Preencher os pixels nublados da imagem base com o mosaico de referência + corrected_image = fill_cloud_pixels(combined_image, reference_mosaic) + + comp = combined_image.clip(roi) + + # Função para obter as bandas corretas dependendo da coleção de imagem (Landsat 5 ou Landsat 8) + def get_bands_for_mndwi(image): + # Verificar a coleção da imagem (Landsat 8 ou Landsat 5) + if 'LC08' in image.get('system:id').getInfo(): + # Landsat 8: B3 (Green), B6 (SWIR), B5 (NIR), B4 (Red), B2 (Blue) + return { + 'GREEN': image.select('SR_B3'), + 'SWIR': image.select('SR_B6'), + 'NIR': image.select('SR_B5'), + 'RED': image.select('SR_B4'), + 'BLUE': image.select('SR_B2') + } + elif 'LT05' in image.get('system:id').getInfo(): + # Landsat 5: B2 (Green), B5 (SWIR), B4 (NIR), B3 (Red), B1 (Blue) + return { + 'GREEN': image.select('SR_B2'), + 'SWIR': image.select('SR_B5'), + 'NIR': image.select('SR_B4'), + 'RED': image.select('SR_B3'), + 'BLUE': image.select('SR_B1') + } + else: + # Caso a coleção não seja reconhecida + return None + + # Selecionar as bandas corretas para a imagem base + bands = get_bands_for_mndwi(comp) + + # Verificar se as bandas foram corretamente identificadas + if bands: + # Calcular o MNDWI + mndwi = comp.expression( + '(GREEN - SWIR) / (GREEN + SWIR)', + bands + ).rename('mndwi') + + # Parâmetros de visualização para o MNDWI + mndwi_vis_params = { + 'min': -1, + 'max': 1, + 'palette': ['00FFFF', '0000FF'] + } + + # Adicionar o MNDWI ao mapa + #Map.add_ee_layer(mndwi, mndwi_vis_params, 'MNDWI', 1) + + else: + print('Coleção de imagem não reconhecida para MNDWI.') + #Map + + # Obter uma coleção de pixels da imagem MNDWI + mndwi_pixels = mndwi.sample(roi, scale=30).reduceColumns(ee.Reducer.toList(), ['mndwi']).get('list') + + # Converter a coleção de pixels em uma lista e, em seguida, em um array NumPy + mndwi_values = np.array(ee.List(mndwi_pixels).getInfo()) + + # selecao otsu + if otsu_method == "Otsu": + # Limiar único (duas classes) + otsu_threshold = filters.threshold_otsu(mndwi_values) + print("Otsu Threshold:", otsu_threshold) + + ## Imagem binária: mndwi > threshold => 1 (úmido); caso contrário, 0 (seco) + final_result_clip = mndwi.expression('mndwi > threshold ? 1 : 0', { + 'mndwi':mndwi, + 'threshold':otsu_threshold + }).rename('binary_mndwi').clip(roi) + + # Também pode salvar o threshold para referência + first_threshold = otsu_threshold + + # Criar imagem binária com base nesse limiar (igual acima) + binary_mndwi_first_threshold = final_result_clip.rename('binary_mndwi_first_threshold') + + else: + # Multi-threshold com 3 classes (água, lama, continente) + otsu_thresholds = filters.threshold_multiotsu(mndwi_values, classes=3) + print("Otsu Thresholds:", otsu_thresholds) + + binary_mndwi_classes = [] + for i in range(len(otsu_thresholds) + 1): + if i == 0: + binary_class = mndwi.expression('mndwi <= threshold ? 1 : 0', { + 'mndwi': mndwi, + 'threshold': otsu_thresholds[i] + }).rename(f'binary_class_{i}') # Água + elif i == len(otsu_thresholds): + binary_class = mndwi.expression('mndwi > threshold ? 1 : 0', { + 'mndwi': mndwi, + 'threshold': otsu_thresholds[i - 1] + }).rename(f'binary_class_{i}') # Continente + else: + binary_class = mndwi.expression('mndwi > threshold_min && mndwi <= threshold_max ? 1 : 0', { + 'mndwi': mndwi, + 'threshold_min': otsu_thresholds[i - 1], + 'threshold_max': otsu_thresholds[i] + }).rename(f'binary_class_{i}') # Lama + + binary_mndwi_classes.append(binary_class) + + # Combinar as classes em uma única imagem + final_result = ee.Image(binary_mndwi_classes[0]).multiply(0) + for i in range(len(binary_mndwi_classes)): + final_result = final_result.where(binary_mndwi_classes[i].eq(1), i) + + final_result_clip = final_result.clip(roi) + + # Primeiro limiar intermediário (água/solo exposto) + if limiar_otsu < len(otsu_thresholds): + first_threshold = otsu_thresholds[limiar_otsu] + else: + raise ValueError(f"limiar fora do intervado, existem apenas {len(otsu_thresholds)} limiares") + + # Criar imagem binária com base no primeiro limiar + binary_mndwi_first_threshold = mndwi.expression('mndwi > threshold ? 1 : 0', { + 'mndwi': mndwi, + 'threshold': first_threshold + }).rename('binary_mndwi_first_threshold').clip(roi) + + ### daqui para frente será para o tratamento visual dos dados + ## Selecionar a resolução que os resultados serão exportados mais tarde + # QUANTO MAIOR A RESOLUÇÃO MAIS SMOOTH O RESULTADO + expresm = 15 + + ##será necessário add um limiar (threshold) também a resolução em m acima para elimiar erros e ilhas, por exemplo + # em caso de um corpo hídrico maior, ou falhas maiores, próximas a linha de costa que se imagina deve setar o valor maior + waterbodysizem = 5000 ## para o RJ usar cerca de 5000 + islandsizem = 900 ## para o RJ usar cerca de 3000 + + ##agora sera feito um def para binarizar a água e terra aplicando as duas o filtro de corpos hidricos e resolução. + def removerfalhas(water_image, waterbodysizem, islandsizem, expresm): + water_image = water_image.int() + + #definir os próximos, a proximidade, com os parametros setados + pixland = ee.Number(waterbodysizem).divide(expresm).int() + pixwater = ee.Number(islandsizem).divide(expresm).int() + + #remover corpos hidricos no continente + landfill = water_image.addBands(water_image)\ + .reduceConnectedComponents(ee.Reducer.median(), 'binary_mndwi_first_threshold', pixland)\ + .unmask(99).eq(99).And(water_image.neq(0)) + + # remover ilhas e erros pequenos + waterfill = landfill.addBands(landfill)\ + .reduceConnectedComponents(ee.Reducer.median(), 'binary_mndwi_first_threshold_1', pixwater)\ + .unmask(99).eq(99).And(landfill.neq(1)) + + #limite entre terra e agua com os limites já feitos acima + return waterfill + + # binarizar e visualizar todos os dados feitos no bloco acima + limiteat = removerfalhas(binary_mndwi_first_threshold, waterbodysizem, islandsizem, expresm) + limitevis = {'min': 0, 'max': 1, 'palette': ['white', 'black']} + + #converter a linha de costa do raster para um vetor + vetor = limiteat.selfMask() \ + .reduceToVectors( + geometry=roi, + scale=expresm, + eightConnected=True, + maxPixels=1e20, + tileScale=16 + ) + + #adicionar o produto em vetor ao mapa e verificar se esta correto. + Map.add_ee_layer(vetor, {'color': 'blue'}, 'aguavetor') + Map + + # Polígono para linha + def extrair_linha_de_costa(vetor): + # Simplificar vetores + def feature(f): + coords = f.geometry().simplify(maxError=expresm).coordinates() + + # Buffer - rasterizar + # o polígono de fronteira + buffer = ee.Number(expresm).multiply(-1) + return f.setGeometry( + ee.Geometry.MultiLineString(coords).intersection(roi.buffer(buffer)) + ) + + vetores_processados = vetor.map(feature) + return vetores_processados + + vetor_linha_de_costa = extrair_linha_de_costa(vetor); + Map.add_ee_layer(vetor_linha_de_costa, {'color': 'red'},'Linha de costa') + + # Supondo que a variável 'imagem' seja a imagem do Landsat ou outro dataset com a data associada + imagem = comp # Substitua pelo ID correto + + # Obter a data da imagem (ano) + data_imagem = imagem.get("system:time_start").getInfo() + ano_imagem = ee.Date(data_imagem).format("YYYY").getInfo() # Extrai o ano da imagem + + # Calcular a área do ROI em metros quadrados e converter para km² + roi_area_m2 = roi.area().getInfo() # Área em metros quadrados + roi_area_km2 = roi_area_m2 / 1e6 # Converter para km² + #print(f"Área do ROI ({ano_imagem}): {roi_area_km2} km²") + + # Calcular a área do vetor (linha de costa) com um erro de margem de 1 metro + vetor_area_m2 = vetor.geometry().area(maxError=1).getInfo() # Área em metros quadrados + vetor_area_km2 = vetor_area_m2 / 1e6 # Converter para km² + #print(f"Área do vetor (linha de costa) ({ano_imagem}): {vetor_area_km2} km²") + + # Retornando o vetor e as áreas como um dicionário + return { + 'vetor': vetor, + 'vetor_lc': vetor_linha_de_costa, + 'area_vetor': f"Área do vetor (linha de costa) ({ano_imagem}): {vetor_area_km2} km²", + 'area_roi': f"Área do ROI ({ano_imagem}): {roi_area_km2} km²", + 'composite': comp, + 'mndwi': mndwi, + 'thresholds': otsu_threshold if otsu_method == "Otsu" else otsu_thresholds, + 'mndwi_values': mndwi_values, # array numpy + 'imagem_binarizada': binary_mndwi_first_threshold if otsu_method == "Otsu" else binary_mndwi_classes, + } + +#################################################################################### TIDE FUNCTION +#################################################################################### +#################################################################################### +#################################################################################### + +def estatisticas_mare(caminho_excel_mares, nome_aba_excel): + + """ + Carrega uma planilha de marés, calcula estatísticas descritivas e imprime os resultados. + + Parâmetros: + file_path (str): Caminho para o arquivo Excel - entre aspas simples. + sheet_name (str): Nome da aba da planilha que contém os dados - entre aspas simples. + """ + #"dicionário" + file_path = caminho_excel_mares + sheet_name = nome_aba_excel + + # Carregar a tabela de marés a partir da planilha especificada + tides_df = pd.read_excel(file_path, sheet_name=sheet_name) + + # Calcular as estatísticas descritivas para a coluna 'valor' + summary_stats = tides_df['valor'].describe(percentiles=[0.25, 0.5, 0.75]) + + # Renomear as colunas + summary_stats = summary_stats.rename({ + 'min': 'Min.', + '25%': '1st Qu.', + '50%': 'Median', + 'mean': 'Mean', + '75%': '3rd Qu.', + 'max': 'Max.' + }) + + # Selecionar e reordenar as colunas + summary_stats = summary_stats[['count', 'Min.', '1st Qu.', 'Median', 'Mean', '3rd Qu.', 'Max.']] + + # Imprimir as estatísticas descritivas + print(summary_stats) + +##################################################################################### RESULTS LINHAS loop +##################################################################################### +##################################################################################### +##################################################################################### + +def linha_de_costa_loop(ano_inicial, ano_final, function_lc, roi, path1, row1, porcentagem_nuvem_roi, caminho_excel_mares, nome_aba_excel, min_mare, max_mare, Map, otsu_method, limiar_otsu): + """ + Processa imagens para um intervalo de anos e gera resultados com cores aleatórias. + + Parâmetros: + start_year (int): Ano inicial para o processamento. + end_year (int): Ano final para o processamento (exclusivo). + processar_imagens (function): Função que processa imagens e retorna resultados. + roi (object): Região de interesse. + path1, row1 (int): Caminho e linha da imagem. + porcentagem_nuvem_roi (float): Porcentagem máxima de nuvem permitida na ROI. + file_path (str): Caminho do arquivo de entrada. + sheet_name (str): Nome da planilha no arquivo. + min_mare, max_mare (float): Limites mínimos e máximos da maré. + Map (object): Mapa interativo para adicionar camadas. + otsu_method (str): Método de Otsu (Multi_Otsu ou Otsu). + limiar_otsu (float): Valor de limiar pré-definido para Otsu, se aplicável. [0] = primeiro limiar + + Retorna: + dict: Dicionários contendo resultados por ano, áreas do vetor e áreas do ROI. + """ + + #"dicionário de argumentos" + start_year = ano_inicial + end_year = ano_final + file_path = caminho_excel_mares + sheet_name = nome_aba_excel + + # Dicionários para armazenar os vetores, áreas e as linhas de costa + resultados_por_ano = {} + areas_vetor = {} + areas_roi = {} + linhas_de_costa = {} # Dicionário para armazenar as linhas de costa por ano + + # Função para gerar uma cor aleatória no formato hexadecimal + def gerar_cor_aleatoria(): + return "#{:06x}".format(random.randint(0, 0xFFFFFF)) + + # Loop para processar imagens de start_year até end_year + for ano in range(start_year, end_year): + try: + # Define a data de início como o primeiro dia de janeiro do ano + data_inicio = ee.Date(f'{ano}-01-01') + + # Chama a função processar_imagens com todos os argumentos necessários + resultado = function_lc(data_inicio, roi, path1, row1, porcentagem_nuvem_roi, file_path, sheet_name, min_mare, max_mare, otsu_method, limiar_otsu) + + # Armazena o vetor e as áreas no dicionário + resultados_por_ano[ano] = resultado + areas_vetor[ano] = resultado['area_vetor'] + areas_roi[ano] = resultado['area_roi'] + + # Armazenar a linha de costa no dicionário + if 'vetor_lc' in resultado: + linhas_de_costa[ano] = resultado['vetor_lc'] # Adicionando a linha de costa ao dicionário + + # Gera uma cor aleatória para o ano + cor_aleatoria = gerar_cor_aleatoria() + + # Adiciona o vetor ao mapa com a cor gerada aleatoriamente + #if 'vetor' in resultado and isinstance(resultado['vetor'], (ee.FeatureCollection, ee.Feature, ee.Geometry)): + #Map.add_layer(resultado['vetor'], {'color': cor_aleatoria, 'width': 2}, f'Vetor {ano} ({cor_aleatoria})') + #else: + #print(f"Vetor inválido ou não encontrado para o ano {ano}") + + # Adiciona a linha de costa ao mapa + if ano in linhas_de_costa: + Map.add_layer(linhas_de_costa[ano], {'color': cor_aleatoria, 'width': 3}, f'Linha de Costa {ano} ({cor_aleatoria})') + + # Exibe as informações de área no console + print(f"Ano: {ano} - Área do vetor: {resultado['area_vetor']} ") + print(f"Ano: {ano} - Área do ROI: {resultado['area_roi']} ") + + except Exception as e: + # Se ocorrer um erro, imprime uma mensagem e pula para o próximo ano + print(f"Erro ao processar o ano {ano}: {e}") + continue # Pula para o próximo ano + + # Retorna os resultados incluindo as linhas de costa + return resultados_por_ano, areas_vetor, areas_roi, linhas_de_costa # Retorno com 'linhas_de_costa' + +#################################################################################### RESULTS area loop +#################################################################################### +#################################################################################### +#################################################################################### + +def area_linha_de_costa_loop(ano_inicial, ano_final, function_lc, roi, path1, row1, porcentagem_nuvem_roi, caminho_excel_mares, nome_aba_excel, min_mare, max_mare, Map): + """ + Processa imagens para um intervalo de anos e gera resultados com cores aleatórias. + + Parâmetros: + start_year (int): Ano inicial para o processamento. + end_year (int): Ano final para o processamento (exclusivo). + processar_imagens (function): Função que processa imagens e retorna resultados. + roi (object): Região de interesse. + path1, row1 (int): Caminho e linha da imagem. + porcentagem_nuvem_roi (float): Porcentagem máxima de nuvem permitida na ROI. + file_path (str): Caminho do arquivo de entrada. + sheet_name (str): Nome da planilha no arquivo. + min_mare, max_mare (float): Limites mínimos e máximos da maré. + Map (object): Mapa interativo para adicionar camadas. + + Retorna: + dict: Dicionários contendo resultados por ano, áreas do vetor e áreas do ROI. + """ + + #"dicionário de argumentos" + start_year = ano_inicial + end_year = ano_final + file_path = caminho_excel_mares + sheet_name = nome_aba_excel + + # Dicionários para armazenar os vetores, áreas e as linhas de costa + resultados_por_ano = {} + areas_vetor = {} + areas_roi = {} + linhas_de_costa = {} # Dicionário para armazenar as linhas de costa por ano + + # Função para gerar uma cor aleatória no formato hexadecimal + def gerar_cor_aleatoria(): + return "#{:06x}".format(random.randint(0, 0xFFFFFF)) + + # Loop para processar imagens de start_year até end_year + for ano in range(start_year, end_year): + try: + # Define a data de início como o primeiro dia de janeiro do ano + data_inicio = ee.Date(f'{ano}-01-01') + + # Chama a função processar_imagens com todos os argumentos necessários + resultado = function_lc(data_inicio, roi, path1, row1, porcentagem_nuvem_roi, file_path, sheet_name, min_mare, max_mare) + + # Armazena o vetor e as áreas no dicionário + resultados_por_ano[ano] = resultado + areas_vetor[ano] = resultado['area_vetor'] + areas_roi[ano] = resultado['area_roi'] + + # Armazenar a linha de costa no dicionário + if 'vetor_lc' in resultado: + linhas_de_costa[ano] = resultado['vetor_lc'] # Adicionando a linha de costa ao dicionário + + # Gera uma cor aleatória para o ano + cor_aleatoria = gerar_cor_aleatoria() + + # Adiciona o vetor ao mapa com a cor gerada aleatoriamente + if 'vetor' in resultado and isinstance(resultado['vetor'], (ee.FeatureCollection, ee.Feature, ee.Geometry)): + Map.add_layer(resultado['vetor'], {'color': cor_aleatoria, 'width': 2}, f'Vetor {ano} ({cor_aleatoria})') + else: + print(f"Vetor inválido ou não encontrado para o ano {ano}") + + # Adiciona a linha de costa ao mapa + #if ano in linhas_de_costa: + #Map.add_layer(linhas_de_costa[ano], {'color': cor_aleatoria, 'width': 3}, f'Linha de Costa {ano} ({cor_aleatoria})') + + # Exibe as informações de área no console + print(f"Ano: {ano} - Área do vetor: {resultado['area_vetor']} km²") + print(f"Ano: {ano} - Área do ROI: {resultado['area_roi']} km²") + + except Exception as e: + # Se ocorrer um erro, imprime uma mensagem e pula para o próximo ano + print(f"Erro ao processar o ano {ano}: {e}") + continue # Pula para o próximo ano + + # Retorna os resultados incluindo as linhas de costa + return resultados_por_ano, areas_vetor, areas_roi, linhas_de_costa # Retorno com 'linhas_de_costa' + +#################################################################################### VIZUALIZACAO do processamento +#################################################################################### +#################################################################################### + +def visualizar_composite(ano_de_interesse, roi, path1, row1, porcentagem_nuvem_roi, + caminho_excel_mares, nome_aba_excel, min_mare, max_mare, + otsu_method, limiar_otsu, Map): + """ + Visualiza os dados para um ano específico, incluindo RGB, MNDWI, binário e histograma. + + Parâmetros: + ano_de_interesse (int): Ano a ser visualizado. + roi (ee.Geometry): Região de interesse. + path1, row1 (int): Path e Row da cena Landsat. + porcentagem_nuvem_roi (float): Limite de nuvens. + caminho_excel_mares (str): Caminho para o Excel de marés. + nome_aba_excel (str): Aba do Excel. + min_mare, max_mare (float): Intervalo de maré permitido. + otsu_method (str): 'Otsu' ou 'Multi_Otsu'. + limiar_otsu (int): Limiar a ser utilizado. + Map (geemap.Map): Objeto de mapa interativo. + """ + import matplotlib.pyplot as plt + + # Executa a função principal + resultado = function_lc( + ano_de_interesse=ano_de_interesse, + roi=roi, + path1=path1, + row1=row1, + porcentagem_nuvem_roi=porcentagem_nuvem_roi, + caminho_excel_mares=caminho_excel_mares, + nome_aba_excel=nome_aba_excel, + min_mare=min_mare, + max_mare=max_mare, + otsu_method=otsu_method, + limiar_otsu=limiar_otsu + ) + + # Extrai os resultados + composite = resultado['composite'] + mndwi = resultado['mndwi'] + binarizada = resultado['imagem_binarizada'] + valor_otsu = resultado['thresholds'] + mndwi_values = resultado['mndwi_values'] # array numpy com os valores do MNDWI + + # Adiciona ao mapa RGB + vis_rgb = { + 'bands': ['SR_B4', 'SR_B3', 'SR_B2'], + 'min': 0, + 'max': 0.3, + 'gamma': 1.2 + } + Map.add_layer(composite.clip(roi), vis_rgb, f'RGB {ano_de_interesse.get("year").getInfo()}') + + # Adiciona MNDWI + Map.add_layer(mndwi.clip(roi), {'min': -1, 'max': 1, 'palette': ['purple', 'white', 'green']}, f'MNDWI {ano_de_interesse.get("year").getInfo()}') + + # Adiciona imagem binarizada + Map.add_layer(binarizada.clip(roi), {'min': 0, 'max': 2, 'palette': ['brown', 'yellow', 'blue']}, f'Binarizada {ano_de_interesse.get("year").getInfo()}') + + # Gera histograma com matplotlib a partir dos valores do MNDWI + plt.figure(figsize=(10, 5)) + plt.hist(mndwi_values, bins=50, color='gray', edgecolor='black') + plt.title(f'Histograma do MNDWI - Ano {ano_de_interesse.get("year").getInfo()}') + plt.xlabel('Valor MNDWI') + plt.ylabel('Contagem de Pixels') + + # Adiciona os limiares + if isinstance(valor_otsu, list): + for i, v in enumerate(valor_otsu): + plt.axvline(x=v, color='red', linestyle='--', label=f'Limiar {i+1} = {v:.2f}') + else: + plt.axvline(x=valor_otsu, color='red', linestyle='--', label=f'Limiar = {valor_otsu:.2f}') + + plt.legend() + plt.grid(True) + plt.show() + +#################################################################################### EXPORTS Areas e/ou Linhas +#################################################################################### +#################################################################################### +#################################################################################### + +def exportar_resultados(resultados_lc, caminho_saida, exportar_linhas=True, exportar_vetores=True): + """ + Função para exportar os resultados (vetores ou linhas de costa) para o Google Drive + e criar uma tabela de áreas em formato Excel. + + Parâmetros: + resultados_teste (tuple): Tupla com os resultados do processamento, contendo os vetores e áreas por ano. + output_path (str): Caminho para a pasta de saída no Google Drive. + exportar_linhas (bool): Se True, exporta as linhas de costa. Default é True. + exportar_vetores (bool): Se True, exporta os vetores de área. Default é True. + + Retorna: + list: Lista de tarefas de exportação para execução no Google Earth Engine. + """ + # "dicionário de argumentos" + resultados_teste = resultados_lc + output_path = caminho_saida + + # Inicializa uma lista para acumular os dados de área + tabela_acumulada = [] + + # Lista para armazenar as tarefas de exportação + export_tasks = [] + + # Extrai os resultados dos anos (considerando que resultados_teste é uma tupla com a estrutura correta) + resultados_por_ano, _, _, _ = resultados_teste # Desempacotando a tupla + + # Percorrer os resultados do teste por ano + for ano, resultado in resultados_por_ano.items(): + try: + # Verifica se o vetor está presente para o ano + area_vetor = resultado['area_vetor'] + area_roi = resultado['area_roi'] + + # Acumula os dados da tabela para o ano + tabela_acumulada.append({ + 'Ano': ano, + 'Área do vetor (km²)': area_vetor, + 'Área do ROI (km²)': area_roi + }) + + # Exportar o vetor como SHP (caso o usuário tenha escolhido exportar vetores) + if exportar_vetores: + vetor = resultado['vetor'] + export_vetor = ee.FeatureCollection(vetor) + export_task_vetor = ee.batch.Export.table.toDrive( + collection=export_vetor, + description=f'vetor_{ano}_linha_de_costa', + fileFormat='SHP', + folder=output_path # Usando o caminho definido pelo usuário + ) + export_task_vetor.start() # Inicia a tarefa de exportação + export_tasks.append(export_task_vetor) + + # Exportar a linha de costa como SHP (caso o usuário tenha escolhido exportar linhas) + if exportar_linhas: + vetor_lc = resultado['vetor_lc'] + export_linha = ee.FeatureCollection(vetor_lc) + export_task_linha = ee.batch.Export.table.toDrive( + collection=export_linha, + description=f'linha_de_costa_{ano}', + fileFormat='SHP', + folder=output_path # Usando o caminho definido pelo usuário + ) + export_task_linha.start() # Inicia a tarefa de exportação + export_tasks.append(export_task_linha) + + except Exception as e: + print(f"Erro ao processar o ano {ano}: {e}") + + # Criar DataFrame com os dados acumulados + df_tabela = pd.DataFrame(tabela_acumulada) + + # Exporta a tabela com as informações de área como arquivo Excel + tabela_path = f"{output_path}/tabela_areas_total.xlsx" + df_tabela.to_excel(tabela_path, index=False) + + # Retorna as tarefas de exportação para execução no Google Earth Engine + return export_tasks + +#################################################################################### + +# Em caso de problema ou dúvida procurar por Pablo Simões no contato abaixo: + +# pablosergio.simoes@gmail.com / pablosimoes@id.uff.br + + + + + + + + + + + diff --git a/LAGEF_UFF/__init__.py b/LAGEF_UFF/__init__.py new file mode 100644 index 0000000..fb4175c --- /dev/null +++ b/LAGEF_UFF/__init__.py @@ -0,0 +1,36 @@ +import ee + +def autenticar_gee(project: str): + """ + Autentica e inicializa o Google Earth Engine (GEE) com o projeto fornecido. + + Args: + project (str): Nome do projeto no GEE. + + Raises: + Exception: Caso a autenticação falhe. + """ + try: + ee.Authenticate() + ee.Initialize(project=project) + print(f"Autenticação bem-sucedida com o projeto: {project}") + except Exception as e: + raise Exception(f"Erro na autenticação ou inicialização do GEE: {e}") + +# Solicita que o usuário insira o nome do projeto no momento da importação +try: + project_name = input("Insira o nome do seu projeto no Google Earth Engine: ") + autenticar_gee(project_name) +except Exception as e: + raise ImportError(f"Erro ao autenticar o Google Earth Engine: {e}") + +# Importa as funções da biblioteca +from .LAGEF_UFF_Shoreline import ( + function_lc, + estatisticas_mare, + area_linha_de_costa_loop, + linha_de_costa_loop, + exportar_resultados, + visualizar_composite +) + diff --git a/LAGEF_UFF_Shoreline.egg-info/PKG-INFO b/LAGEF_UFF_Shoreline.egg-info/PKG-INFO new file mode 100644 index 0000000..da824f1 --- /dev/null +++ b/LAGEF_UFF_Shoreline.egg-info/PKG-INFO @@ -0,0 +1,31 @@ +Metadata-Version: 2.4 +Name: LAGEF-UFF-Shoreline +Version: 0.1.0 +Summary: Scripts para análise de linha de costa - Lagef UFF - projeto IVC +Author: Pablo Simoes +Author-email: ['pablosergio.simoes@gmail.com', 'pablosimoes@id.uff.br'] +License: MIT License +Keywords: lagef uff,linha de costa,shoreline,google earth engine +Description-Content-Type: text/markdown +License-File: LICENCE +Requires-Dist: pandas +Requires-Dist: geemap +Requires-Dist: numpy +Requires-Dist: earthengine-api +Requires-Dist: scikit-image +Requires-Dist: matplotlib +Dynamic: author +Dynamic: author-email +Dynamic: description +Dynamic: description-content-type +Dynamic: keywords +Dynamic: license +Dynamic: license-file +Dynamic: requires-dist +Dynamic: summary + +## Repositorio nao oficial +### Linha de costa Lagef - UFF - Projeto IVC - Pablo Simoes + +# Repositorio teste para o Projeto IVC - LAGEF - UFF + diff --git a/LAGEF_UFF_Shoreline.egg-info/SOURCES.txt b/LAGEF_UFF_Shoreline.egg-info/SOURCES.txt new file mode 100644 index 0000000..476a00a --- /dev/null +++ b/LAGEF_UFF_Shoreline.egg-info/SOURCES.txt @@ -0,0 +1,10 @@ +LICENCE +README.md +setup.py +LAGEF_UFF/LAGEF_UFF_Shoreline.py +LAGEF_UFF/__init__.py +LAGEF_UFF_Shoreline.egg-info/PKG-INFO +LAGEF_UFF_Shoreline.egg-info/SOURCES.txt +LAGEF_UFF_Shoreline.egg-info/dependency_links.txt +LAGEF_UFF_Shoreline.egg-info/requires.txt +LAGEF_UFF_Shoreline.egg-info/top_level.txt \ No newline at end of file diff --git a/LAGEF_UFF_Shoreline.egg-info/dependency_links.txt b/LAGEF_UFF_Shoreline.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/LAGEF_UFF_Shoreline.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/LAGEF_UFF_Shoreline.egg-info/requires.txt b/LAGEF_UFF_Shoreline.egg-info/requires.txt new file mode 100644 index 0000000..1f4030f --- /dev/null +++ b/LAGEF_UFF_Shoreline.egg-info/requires.txt @@ -0,0 +1,6 @@ +pandas +geemap +numpy +earthengine-api +scikit-image +matplotlib diff --git a/LAGEF_UFF_Shoreline.egg-info/top_level.txt b/LAGEF_UFF_Shoreline.egg-info/top_level.txt new file mode 100644 index 0000000..8caae25 --- /dev/null +++ b/LAGEF_UFF_Shoreline.egg-info/top_level.txt @@ -0,0 +1 @@ +LAGEF_UFF diff --git a/LICENCE b/LICENCE new file mode 100644 index 0000000..0181fe8 --- /dev/null +++ b/LICENCE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2024 Pablo Sergio Marques Simoes - Projeto IVC - LAGEF UFF + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/PKG-INFO b/PKG-INFO new file mode 100644 index 0000000..da824f1 --- /dev/null +++ b/PKG-INFO @@ -0,0 +1,31 @@ +Metadata-Version: 2.4 +Name: LAGEF-UFF-Shoreline +Version: 0.1.0 +Summary: Scripts para análise de linha de costa - Lagef UFF - projeto IVC +Author: Pablo Simoes +Author-email: ['pablosergio.simoes@gmail.com', 'pablosimoes@id.uff.br'] +License: MIT License +Keywords: lagef uff,linha de costa,shoreline,google earth engine +Description-Content-Type: text/markdown +License-File: LICENCE +Requires-Dist: pandas +Requires-Dist: geemap +Requires-Dist: numpy +Requires-Dist: earthengine-api +Requires-Dist: scikit-image +Requires-Dist: matplotlib +Dynamic: author +Dynamic: author-email +Dynamic: description +Dynamic: description-content-type +Dynamic: keywords +Dynamic: license +Dynamic: license-file +Dynamic: requires-dist +Dynamic: summary + +## Repositorio nao oficial +### Linha de costa Lagef - UFF - Projeto IVC - Pablo Simoes + +# Repositorio teste para o Projeto IVC - LAGEF - UFF + diff --git a/README.md b/README.md new file mode 100644 index 0000000..7b5557a --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +## Repositorio nao oficial +### Linha de costa Lagef - UFF - Projeto IVC - Pablo Simoes + +# Repositorio teste para o Projeto IVC - LAGEF - UFF + diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..8bfd5a1 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,4 @@ +[egg_info] +tag_build = +tag_date = 0 + diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..f712019 --- /dev/null +++ b/setup.py @@ -0,0 +1,23 @@ +from setuptools import setup + +with open('README.md','r') as arq: + readme = arq.read() + +setup(name='LAGEF-UFF-Shoreline', + version='0.1.0', + license='MIT License', + author='Pablo Simoes', + long_description=readme, + long_description_content_type="text/markdown", + author_email=['pablosergio.simoes@gmail.com','pablosimoes@id.uff.br'], + keywords=['lagef uff','linha de costa','shoreline','google earth engine'], + description=u'Scripts para análise de linha de costa - Lagef UFF - projeto IVC', + packages=['LAGEF_UFF'], + install_requires=['pandas','geemap','numpy','earthengine-api','scikit-image','matplotlib'],) + + + + + + +