Blog Geo.NET Geoprocessamento, SIG e Sensoriamento Remoto

4ago/101

Construindo funcionalidades para o WKT Raster

No post anterior, falamos um pouquinho sobre como o WKT Raster funciona. Hoje gostaria de mostrar um pouquinho sobre as maquinações que ando desenvolvendo para o PostGIS e WKT Raster.

Em tese, se o raster está armazenado no banco e conseguimos determinar o valor de cada pixel, poderíamos usar a SQL para realizar álgebra de mapas? A resposta é sim, podemos. É claro, já existem softwares especializados em realizar álgebra de mapas, como o IDRISI, ENVI, SPRING, ArcGIS (com Spatial Analyst), o módulo Sextante do gvSIG, WhiteBox, entre outros.

A vantagem de fazermos isto no PostGIS é que podemos aproveitar de algumas funcionalidades do banco de dados para realizar atualizações automáticas (funciona, mas a perfomance não deve ser das melhores), controlar melhor o acesso aos rasters - centralizando tudo em uma única localização, backup, etc.

Existem diversas funções para análise espacial de rasters, incluindo as matemáticas, lógicas, entre outras. Hoje irei mostrar apenas algumas matemáticas, que são bem simples. O módulo WKT Raster já planeja construir em C (linguagem nativa do PostgreSQL) algumas funções para análise espacial, mas enquanto isto não acontece, vamos levando com estas aqui.

Importante: estas funções só operam com rasters de uma única banda. Todas as operações são realizadas na banda 1. Nenhuma operação é realizada na banda 2 ou 3 - se bem que o suporte para tal é simples de ser construído.

Cuidado ao utilizar estas funções. Caso você sobreescreva seu raster, não o conseguirá de volta - caso precise.

ST_Plus

Esta função adiciona um valor double precision ao nosso raster de interesse. Se o pixel tem valor 1 e nosso argumento é 1, o resultado daquele pixel será 2. Esta função tem como entrada um raster e um valor numérico. O retorno da função é um objeto raster completo.

CREATE OR REPLACE FUNCTION ST_Plus(p_grid raster, z double precision)
	RETURNS raster AS
$$
DECLARE
	w integer;
	h integer;
	z1 integer;

	grid raster;
BEGIN

	SELECT
		ST_Width(p_grid),
		ST_Height(p_grid)
	 into w,h;

	-- realizar cópia do raster original
	grid := p_grid;

	for i in 1..h loop
		for j in 1..w loop

			-- selecting cell value
			z1 := ST_Value(p_grid,i,j);
			grid := st_setvalue(grid,1,i,j,z1 + z);

		end loop;
	end loop;

	return grid;
END
$$
language 'plpgsql';

A função é bem simples. Ela copia o raster original em memória e adiciona o valor à cada pixel. Sem segredos. Como usá-la? Recomendo primeiramente, duplicar sua coluna do tipo raster, pois a função de adição de colunas raster é bastante longa e com parâmetros meio obscuros. Procure o arquivo SQL gerado pelo gdal2wktraster e ache a linha que adiciona a coluna. Modifique o nome da coluna e execute este comando novamente. Depois disso popule a coluna com os novos valores.

SELECT AddRasterColumn('public','teste_raster','grid_stplus',-1, ARRAY['16BUI'], false,
       true, null, 0.000833, -0.000833, 9, 9,
           ST_Envelope(
               ST_SetSRID('POLYGON((-49.500416 -18.000416,-49.500416 -19.000416,-48.000416 -18.000416,-48.000416 -19.000416,-49.500416 -18.000416))'::geometry, -1)));

UPDATE teste_raster SET grid_stplus = ST_Plus('nome_da_coluna_raster_original',10);

Faça um teste com ST_Value para identificar se tudo correu bem. Neste teste, somamos 10 unidades ao valor de cada pixel da coluna original raster. Por que estamos criando uma coluna extra para armazenar nosso novo raster? Se alterarmos o raster original, não conseguiremos ele de volta, portanto, cuidado ao utilizar as funções.

ST_Minus

De forma similar à ST_Plus, ST_Minus vai subtrair determinado valor de cada pixel de nosso raster e nos trará como resultado o raster modificado.

CREATE OR REPLACE FUNCTION ST_Minus(p_grid raster, z double precision)
	RETURNS raster AS
$$
DECLARE
	w integer;
	h integer;
	z1 integer;

	grid raster;
BEGIN

	SELECT
		ST_Width(p_grid),
		ST_Height(p_grid)
	 into w,h;

	-- realizar cópia do raster original
	grid := p_grid;

	for i in 1..h loop
		for j in 1..w loop

			-- selecting cell value
			z1 := ST_Value(p_grid,i,j);
			grid := st_setvalue(grid,1,i,j,z1 - z);

		end loop;
	end loop;

	return grid;
END
$$
language 'plpgsql';

Recomendo testar da mesma maneira que a função anterior. O uso é o mesmo - modificando o nome da função.

ST_Plus

Esta função realiza a multiplicação do valor do pixel. Simples e direta.

CREATE OR REPLACE FUNCTION ST_Times(p_grid raster, z double precision)
	RETURNS raster AS
$$
DECLARE
	w integer;
	h integer;
	z1 integer;

	grid raster;
BEGIN

	SELECT
		ST_Width(p_grid),
		ST_Height(p_grid)
	 into w,h;

	-- realizar cópia do raster original
	grid := p_grid;

	for i in 1..h loop
		for j in 1..w loop

			-- selecting cell value
			z1 := ST_Value(p_grid,i,j);
			grid := st_setvalue(grid,1,i,j,z1 * z);

		end loop;
	end loop;

	return grid;
END
$$
language 'plpgsql';

Use-a do mesmo jeito que as anteriores.

ST_Divide

CREATE OR REPLACE FUNCTION ST_Divide(p_grid raster, z double precision)
	RETURNS raster AS
$$
DECLARE
	w integer;
	h integer;
	z1 integer;

	grid raster;
BEGIN
	if (z = 0) then
		return p_grid;
	end if;

	SELECT
		ST_Width(p_grid),
		ST_Height(p_grid)
	 into w,h;

	-- realizar cópia do raster original
	grid := p_grid;

	for i in 1..h loop
		for j in 1..w loop

			-- selecting cell value
			z1 := ST_Value(p_grid,i,j);
			grid := st_setvalue(grid,1,i,j,z1 / z);

		end loop;
	end loop;

	return grid;
END
$$
language 'plpgsql';

ST_Power

Esta função eleva o valor da célula ao valor passado como parâmetro na função. Se temos uma célula de valor 2, e passamos 2 como parâmetro, teremos o 4 como resultado (2^2);

CREATE OR REPLACE FUNCTION ST_Power(p_grid raster, z double precision)
	RETURNS raster AS
$$
DECLARE
	w integer;
	h integer;
	z1 integer;

	grid raster;
BEGIN

	SELECT
		ST_Width(p_grid),
		ST_Height(p_grid)
	 into w,h;

	-- realizar cópia do raster original
	grid := p_grid;

	for i in 1..h loop
		for j in 1..w loop

			-- selecting cell value
			if z = 0 then
				grid := st_setvalue(grid,1,i,j,1);
			else
				z1 := st_value(p_grid,i,j);
				grid := st_setvalue(grid,1,i,j,z1 ^ z);
			end if;

		end loop;
	end loop;

	return grid;
END
$$
language 'plpgsql';

E assim podemos construir funções que alterem nossos rasters originais. São funções simples, praticamente demonstrativas. Na sequência demonstraremos algumas funções mais interessantes, como declividade, cálculo de fluxo de direção, identificação de depressões, eliminação de depressões, entre outras.

Um abraço,

George R. C. Silva

Compartilhe:
31jul/104

PostGIS WKT Raster

Buenas pessoal,

Como estão as coisas? Hoje vamos conversar um pouquinho sobre o WKT Raster.

O WKT Raster é um projeto para implementar suporte aos famosos grids, rasters, imagens ao PostGIS. WKT vem de Well Known Text (algo como "texto bem conhecido").

O projeto já tem código compilado e funcionando e tomei a semana para testá-lo de acordo. A implementação veio da especificação desenvolvida por Pierre Racine. O projeto tem como objetivo integrar-se perfeitamente ao engine do PostGIS já existente, sendo possível executar operações espaciais / álgebra de mapas, carregar rasters multi-bandas, entre outras coisas deliciosas.

Este projeto é muito interessante, pois podemos armazenar os rasters dentro do banco de dados, garantindo ou excluindo acesso à quem realmente precisa, ao invés de ficarmos com milhares de cópias por aí (imagine um escritório com 20 analistas GIS - qual é quantidade de informações duplicadas), sem saber ao certo qual é a mais atual ou com melhor qualidade - enfim, nos garante todas as vantagens do armazenamento centralizado em banco de dados. Não necessariamente precisamos armazenar os dados no PostgreSQL, podemos deixá-los em HD e adicionar somente os metadados e acessá-los da mesma forma, caso você esteja preocupado com disco ;) . Em suma, é demais!

Vamos comentar com instalar essa belezinha no seu PostgreSQL - em Windows XP. Linux users, sorry.

Pré-requisitos

Sempre existem né?

  • PostgreSQL/PostGIS instalado. O PostGIS deve 1.4 ou maior, determinando também a versão do PostgreSQL: 8.3 ou maior;
  • Python;
  • GDAL/python;
  • WKT Raster;

Instalação

1) Instale o Python, 2.5 ou 2.6. Estou usando o 2.5, que foi instalado junto com o ArcGIS. Portanto, se você tem esta instação específica, não se preocupe. Esta instalação é bem simples. Dois cliques, pá pum, está instalado.

2) Instale os GDAL bindings. Para fazer isso é só descompactar a pasta zipada e colocá-la no diretório que mais lhe agradar. Coloquei a minha pasta (gdalwin32-1.6) no diretório C:\.

2.1) Vá em Painel de Controle > Sistema > Avançado > Variáveis de Ambiente. Procure a variável PATH. Ela é composta de vários diretórios separados por um ponto-e-vírgula, correto? Adicione o diretório C:\gdalwin32-1.6\bin nesta listinha e adicione um ; no final. Claro, se você pos a pasta do gdal em outro diretório, faça as alterações pertinentes.

2.2 ) Ainda em variáveis de ambiente, adicione uma nova variável, chamada GDAL_DATA e adicione o caminho C:\gdalwin32-1.6\data como caminho. Como esta variável de ambiente é usada somente pelo GDAL, não se preocupe em colocar o ;. Mas se colocar também não faz mal. Dê OK para salvar as variáveis de ambiente. Os bindings do GDAL para Python já estão instalados. Você pode acessá-los e utilizar o GDAL para um monte de coisas, como converter coordenadas de rasters, reprojetá-los, etc. tudo usando uma linha de comando.

3) Descompacte o pacote do WKT Raster.

3.1) Copie o arquivo rtpostgis.dll para a pasta lib do PostgreSQL. Geralmente é algo como C:\Program Files\PostgreSQL\8.x\lib;

3.2) Copie os arquivos gdal2wktraster.py e libgdal.dll para a pasta bin da sua instalação do PostgreSQL. Fácil né?

3.3) Vamos instalar os comandos e funções do Wkt Raster no nosso banco agora. Abra o PgAdmin3 ou o console sql do Postgres e conecte-se ao banco de dados alvo. Feito isso, rode os comandos que se encontram na pasta share\contrib\ do pacote WktRaster. Feito isso, teste se o WKT Raster está funcionando apropriadamente usando o comando SQL:

SELECT postgis_raster_lib_build_date(),postgis_raster_lib_version();

Caso o comando tenha sucesso, tudo foi instalado com sucesso.

A instalação termina aqui. Mas como carregar um raster para dentro de nosso banco de dados? Podemos utilizar a ferramenta em Python desenvolvida para este propósito, o script gdal2wktraster.py

Carregar um raster para o banco de dados

Esta ferramenta é uma aplicação em linha de comando, bastante fácil de utilizar. O resultado dela é um script .sql que você pode rodar pelo console sql ou pelo PgAdmin3.

Abra um console DOS e digite:

python "CaminhoParaOArquivo\gdal2wktraster.py" --help

Isto lhe deve dar todas as opções da ferramenta.

Algumas:

  • -t nome da tabela à ser criada no PostGIS, e.g. -t teste_raster;
  • -o nome do arquivo de saída, e.g. -o srtm.sql;
  • -k especifica o tamanho tile. Esta opção é muito importante, pois divide seu raster original em diversos registros cada um com este tamanho, em pixels. e.g. -k 90x90; Caso você não utilize esta opção, seu raster original ocupará apenas um único registro da tabela. Se você utilizá-la, você diz ao PostGIS: pegue este raster, fatie-o em pedaços de tal tamanho e insira-os nesta tabela!
  • -f especifica o nome da coluna do tipo raster. e.g. -f grid;
  • -r esta é a opção mais importante de todas, com ela especificamos o arquivo original à ser carregado. e.g. -r "CaminhoDoArquivoRaster\arquivo.tif";

Exemplo de um comando completo

C:\Python25\python.exe "C:\Program Files\PostgreSQL\8.3\bin\gdal2wktraster.py" - r "C:\srtm.tif" -k 90x90 -f grid -t srtm -o srtm.sql

Esta ferramenta é bem fácil de utilizar e gera um SQL limpinho, só faltando rodá-lo dentro do banco de dados.

Estou desenvolvendo algumas ferramentinhas de análise espacial, em especial ferramentas para extração automática de feições - algumas já estão prontas, outras ainda no forno, mas logo logo falo sobre elas! Esta é a página oficial do WKT Raster.

O que acharam?

Abraços!

George R. C. Silva

Compartilhe:
   
Get Adobe Flash playerPlugin by wpburn.com wordpress themes