{"id":10028,"date":"2025-10-14T09:00:42","date_gmt":"2025-10-14T12:00:42","guid":{"rendered":"https:\/\/www.fernandoquadro.com.br\/html\/?p=10028"},"modified":"2025-10-14T10:16:28","modified_gmt":"2025-10-14T13:16:28","slug":"geoserver-ia-geracao-automatica-de-camadas-de-heatmap","status":"publish","type":"post","link":"https:\/\/www.fernandoquadro.com.br\/html\/2025\/10\/14\/geoserver-ia-geracao-automatica-de-camadas-de-heatmap\/","title":{"rendered":"GeoServer + IA: gera\u00e7\u00e3o autom\u00e1tica de camadas de heatmap"},"content":{"rendered":"<p>Os <strong>mapas de calor (heatmaps)<\/strong> s\u00e3o uma das formas mais intuitivas de<strong> visualizar densidade de ocorr\u00eancias geogr\u00e1ficas<\/strong>, seja para representar crimes, atendimentos de sa\u00fade, pontos de coleta de res\u00edduos ou eventos clim\u00e1ticos.<\/p>\n<p>No GeoServer, podemos gerar mapas de calor usando o WMS Heatmap Rendering Transform, mas configurar isso manualmente para dezenas de camadas pode ser trabalhoso.<\/p>\n<p>Neste post, vamos mostrar como automatizar esse processo com Python + IA, criando um pipeline que:<\/p>\n<ul>\n<li>Analisa automaticamente seus dados espaciais;<\/li>\n<li>Gera os par\u00e2metros ideais do heatmap (raio, cores, intensidade);<\/li>\n<li>Publica o estilo e a camada automaticamente no GeoServer;<\/li>\n<li>Pode ser aplicado a qualquer dataset de pontos no PostGIS.<\/li>\n<\/ul>\n<p><strong>1. O conceito de heatmap no GeoServer<\/strong><\/p>\n<p>O GeoServer suporta a gera\u00e7\u00e3o de heatmaps a partir de camadas de pontos usando o processo de renderiza\u00e7\u00e3o \u201cvec:Heatmap\u201d dentro de um estilo SLD.<\/p>\n<p>Exemplo b\u00e1sico de configura\u00e7\u00e3o manual:<\/p>\n<pre>&lt;RasterSymbolizer&gt;\r\n  &lt;Geometry&gt;\r\n    &lt;ogc:PropertyName&gt;geom&lt;\/ogc:PropertyName&gt;\r\n  &lt;\/Geometry&gt;\r\n  &lt;Opacity&gt;0.6&lt;\/Opacity&gt;\r\n  &lt;ColorMap type=&quot;ramp&quot; extended=&quot;true&quot;&gt;\r\n    &lt;ColorMapEntry color=&quot;#0000FF&quot; quantity=&quot;0&quot; opacity=&quot;0&quot;\/&gt;\r\n    &lt;ColorMapEntry color=&quot;#00FF00&quot; quantity=&quot;0.5&quot; opacity=&quot;0.7&quot;\/&gt;\r\n    &lt;ColorMapEntry color=&quot;#FF0000&quot; quantity=&quot;1&quot; opacity=&quot;1&quot;\/&gt;\r\n  &lt;\/ColorMap&gt;\r\n&lt;\/RasterSymbolizer&gt;\r\n<\/pre>\n<p>O problema \u00e9 que definir manualmente raio, opacidade e escala de cores exige tentativas e erros. \u00c9 a\u00ed que voc\u00ea pode utilizar a IA para automatizar essa etapa.<\/p>\n<p><strong>2. Onde entra a IA<\/strong><\/p>\n<p>A IA pode atuar para:<\/p>\n<ol>\n<li>\n      <strong>Analisar a densidade e distribui\u00e7\u00e3o dos pontos<\/strong><br \/>\n      <span>(via amostra SQL do PostGIS);<\/span>\n    <\/li>\n<li>\n      <strong>Sugerir automaticamente<\/strong>:<\/p>\n<ul>\n<li>Raio ideal para suaviza\u00e7\u00e3o do heatmap;<\/li>\n<li>Paleta de cores coerente com o contexto <em>(ex.: seguran\u00e7a, sa\u00fade, meio ambiente)<\/em>;<\/li>\n<li>Limites de intensidade <em>(quantidade m\u00ednima\/m\u00e1xima de ocorr\u00eancias)<\/em>;<\/li>\n<\/ul>\n<\/li>\n<li>\n      <strong>Gerar o SLD completo<\/strong> com os par\u00e2metros otimizados.\n    <\/li>\n<\/ol>\n<p><strong>3. PostGIS + Python + IA + GeoServer<\/strong><\/p>\n<p>A seguir, um exemplo completo de automa\u00e7\u00e3o, do banco ao GeoServer que:<\/p>\n<ul>\n<li>Conecta-se ao banco PostGIS e coleta estat\u00edsticas da camada (contagem e extens\u00e3o).<\/li>\n<li>Envia essas informa\u00e7\u00f5es \u00e0 IA, que gera um SLD completo com o transform \u201cvec:Heatmap\u201d.<\/li>\n<li>Publica automaticamente o estilo no GeoServer via REST API.<\/li>\n<li>O resultado pode ser aplicado imediatamente na camada eventos_ocorrencias.<\/li>\n<\/ul>\n<pre>\r\nimport psycopg2\r\nimport openai\r\nimport requests\r\n\r\n# Configura\u00e7\u00f5es\r\nDB_NAME = \"gisdb\"\r\nDB_USER = \"gis\"\r\nDB_PASS = \"123\"\r\nDB_HOST = \"localhost\"\r\n\r\nGEOSERVER_URL = \"http:\/\/localhost:8080\/geoserver\/rest\/styles\"\r\nGEOSERVER_USER = \"admin\"\r\nGEOSERVER_PASS = \"geoserver\"\r\n\r\nLAYER_NAME = \"eventos_ocorrencias\"\r\nSTYLE_NAME = \"heatmap_eventos\"\r\n\r\n# 1. Amostrar dados para an\u00e1lise\r\nconn = psycopg2.connect(f\"dbname={DB_NAME} user={DB_USER} password={DB_PASS} host={DB_HOST}\")\r\ncur = conn.cursor()\r\ncur.execute(f\"SELECT COUNT(*), ST_Extent(geom) FROM {LAYER_NAME};\")\r\ntotal, bbox = cur.fetchone()\r\n\r\n# 2. Gerar estilo Heatmap com IA\r\nprompt = f\"\"\"\r\nCrie um estilo SLD para gerar um heatmap no GeoServer.\r\nUse o transform 'vec:Heatmap' com par\u00e2metros otimizados.\r\nContexto:\r\n- Camada: {LAYER_NAME}\r\n- Total de pontos: {total}\r\n- Extens\u00e3o espacial: {bbox}\r\n- O mapa representa ocorr\u00eancias de eventos.\r\nA paleta de cores deve ir de azul (baixa densidade) a vermelho (alta densidade).\r\n\"\"\"\r\n\r\nresposta = openai.ChatCompletion.create(\r\n    model=\"gpt-4o-mini\",\r\n    messages=[{\"role\": \"user\", \"content\": prompt}]\r\n)\r\n\r\nsld_xml = resposta.choices[0].message.content\r\n\r\n# 3. Publicar estilo no GeoServer\r\nheaders = {\"Content-type\": \"application\/vnd.ogc.sld+xml\"}\r\nr = requests.post(\r\n    f\"{GEOSERVER_URL}?name={STYLE_NAME}\",\r\n    data=sld_xml.encode(\"utf-8\"),\r\n    headers=headers,\r\n    auth=(GEOSERVER_USER, GEOSERVER_PASS)\r\n)\r\n\r\nif r.status_code in [200, 201]:\r\n    print(f\"Estilo '{STYLE_NAME}' publicado com sucesso!\")\r\nelse:\r\n    print(\"Erro ao publicar estilo:\", r.status_code, r.text)\r\n\r\n<\/pre>\n<p>A sa\u00edda gerada pelo script ser\u00e1:<\/p>\n<pre>&lt;StyledLayerDescriptor version=&quot;1.0.0&quot;&gt;\r\n  &lt;NamedLayer&gt;\r\n    &lt;Name&gt;eventos_ocorrencias&lt;\/Name&gt;\r\n    &lt;UserStyle&gt;\r\n      &lt;Title&gt;Heatmap de Ocorr\u00eancias&lt;\/Title&gt;\r\n      &lt;FeatureTypeStyle&gt;\r\n        &lt;Transformation&gt;\r\n          &lt;ogc:Function name=&quot;vec:Heatmap&quot;&gt;\r\n            &lt;ogc:Function name=&quot;parameter&quot;&gt;\r\n              &lt;ogc:Literal&gt;weightAttr&lt;\/ogc:Literal&gt;\r\n              &lt;ogc:Literal&gt;&lt;\/ogc:Literal&gt;\r\n            &lt;\/ogc:Function&gt;\r\n            &lt;ogc:Function name=&quot;parameter&quot;&gt;\r\n              &lt;ogc:Literal&gt;radiusPixels&lt;\/ogc:Literal&gt;\r\n              &lt;ogc:Literal&gt;20&lt;\/ogc:Literal&gt;\r\n            &lt;\/ogc:Function&gt;\r\n          &lt;\/ogc:Function&gt;\r\n        &lt;\/Transformation&gt;\r\n        &lt;Rule&gt;\r\n          &lt;RasterSymbolizer&gt;\r\n            &lt;Opacity&gt;0.7&lt;\/Opacity&gt;\r\n            &lt;ColorMap type=&quot;ramp&quot;&gt;\r\n              &lt;ColorMapEntry color=&quot;#0000FF&quot; quantity=&quot;0&quot; opacity=&quot;0&quot;\/&gt;\r\n              &lt;ColorMapEntry color=&quot;#00FF00&quot; quantity=&quot;0.5&quot; opacity=&quot;0.7&quot;\/&gt;\r\n              &lt;ColorMapEntry color=&quot;#FF0000&quot; quantity=&quot;1&quot; opacity=&quot;1&quot;\/&gt;\r\n            &lt;\/ColorMap&gt;\r\n          &lt;\/RasterSymbolizer&gt;\r\n        &lt;\/Rule&gt;\r\n      &lt;\/FeatureTypeStyle&gt;\r\n    &lt;\/UserStyle&gt;\r\n  &lt;\/NamedLayer&gt;\r\n&lt;\/StyledLayerDescriptor&gt;\r\n<\/pre>\n<p>A IA gera n\u00e3o s\u00f3 as cores, mas tamb\u00e9m par\u00e2metros adaptados ao tamanho da amostra (por exemplo, ajustando o raio se a camada tiver muitos ou poucos pontos).<\/p>\n<p>Voc\u00ea pode evoluir esse fluxo para:<\/p>\n<ul>\n<li>Rodar diariamente e gerar heatmaps atualizados com novos dados;<\/li>\n<li>Integrar ao GeoNode, atualizando automaticamente o estilo da camada;<\/li>\n<li>Usar IA para escolher paletas tem\u00e1ticas (ex.: \u201cvermelho\u2013amarelo\u201d para calor humano, \u201cverde\u2013azul\u201d para vegeta\u00e7\u00e3o).<\/li>\n<\/ul>\n<p>\ud83d\udca1 Dica: para heatmaps temporais, combine com filtros SQL por data e gere um estilo din\u00e2mico para cada per\u00edodo (ex.: \u201cocorr\u00eancias_2025_01.sld\u201d).<\/p>\n<p><strong>4. Conclus\u00e3o<\/strong><\/p>\n<p>A combina\u00e7\u00e3o de PostGIS + IA + GeoServer permite criar pipelines geoespaciais realmente inteligentes capazes de analisar, gerar e publicar visualiza\u00e7\u00f5es complexas de forma autom\u00e1tica.<\/p>\n<p>Esse tipo de automa\u00e7\u00e3o \u00e9 especialmente \u00fatil em projetos de monitoramento ambiental, urbano e operacional, onde o volume de dados cresce rapidamente. Veja alguns benef\u00edcios:<\/p>\n<ul>\n<li>Heatmaps autom\u00e1ticos e personalizados sem ajustes manuais.<\/li>\n<li>IA adaptando par\u00e2metros de renderiza\u00e7\u00e3o conforme o dataset.<\/li>\n<li>Integra\u00e7\u00e3o total com GeoServer via REST API.<\/li>\n<li>Atualiza\u00e7\u00e3o cont\u00ednua, ideal para dashboards geoespaciais em tempo real.<\/li>\n<\/ul>\n<p>Gostou desse post? Achou ele \u00fatil? Ent\u00e3o que tal deixar um coment\u00e1rio ?<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Os mapas de calor (heatmaps) s\u00e3o uma das formas mais intuitivas de visualizar densidade de ocorr\u00eancias geogr\u00e1ficas, seja para representar crimes, atendimentos de sa\u00fade, pontos de coleta de res\u00edduos ou eventos clim\u00e1ticos. No GeoServer, podemos gerar mapas de calor usando&#8230; <a class=\"more-link\" href=\"https:\/\/www.fernandoquadro.com.br\/html\/2025\/10\/14\/geoserver-ia-geracao-automatica-de-camadas-de-heatmap\/\">Continue Reading &rarr;<\/a><\/p>\n","protected":false},"author":275,"featured_media":10033,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[24],"tags":[208,343],"class_list":["post-10028","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-gis","tag-geoserver","tag-ia"],"_links":{"self":[{"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/posts\/10028","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/users\/275"}],"replies":[{"embeddable":true,"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/comments?post=10028"}],"version-history":[{"count":5,"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/posts\/10028\/revisions"}],"predecessor-version":[{"id":10046,"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/posts\/10028\/revisions\/10046"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/media\/10033"}],"wp:attachment":[{"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/media?parent=10028"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/categories?post=10028"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/tags?post=10028"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}