Alejandro C. Frery, Talita Perciano
Abstract
These notes are introductory to both R and to image processing. R is a FLOSS (Free-Libre Open Source Software) platform and a high-level matrix-oriented programming language and, therefore, it is well suited for implementing many basic operations required for image processing.
Resumo
Este texto apresenta algumas noções básicas de processamento digital de imagens empregando R. R é uma plataforma FLOSS (Free-Libre Open Source Software) e uma linguagem de programação de alto nível orientada a processamento matricial e, com isso, apta a lidar de forma natural com muitas operações básicas e transformações de imagens.
1.1. Introdução: imagens e R
Neste seção veremos alguns comandos básicos da plataforma R, bem como as definições e a notação que iremos empregar no restante do texto. No seção 1.2 apresentaremos as principais definições e notações a serem em-pregadas no resto do texto. No seção 1.3 comentamos as características mais salientes dos principais formatos pictóricos de imagens, e mostramos como li-dar com eles (ler e gravar) em R. O seção 1.4 apresenta algumas das principais transformações locais, com ênfase nas operações de melhoria de contraste. O seção 1.5, que conclui estas notas, apresenta os conceitos básicos das filtra-gens linear (convolução no domínio do espaço e da frequência) e não linear (fitros da mediana e Nagao-Matsuyama).
1.1.1. Processamento de Imagens
O campo de processamento digital de imagens refere-se a processar ima-gens digitais por meio de um computador. Uma imagem pode ser definida
como uma função bidimensional, f(x, y), ondexeysão coordenadas
espaci-ais, e a amplitude de f em qualquer par de coordenadas(x, y)é chamada de
intensidade ou nível de cinza da imagem naquele ponto. Quandox,y, e os
valores de intensidade de f são todos finitos, quantidades discretas,
chama-mos a imagem de imagem digital. Note que uma imagem digital é composta de um número finito de elementos, onde cada um possui uma posição particular e um valor escalar ou vetorial. As imagens coloridas frequentemente possuem
valores vetoriales de dimensão3, enquanto as imagens em tons de cinza re-querem apenas um escalar em cada posição. O termo mais amplamente usado na área para denominar estes elementos é pixel. No seção 1.2 serão vistas, mais formalmente, as definições e notações envolvidas.
O processamento digital de imagens é um campo de estudo bastante vasto e, na verdade, não há um acordo geral entre autores e pesquisadores sobre onde este campo termina e outras áreas relacionadas, como análise de ima-gens e visão computacional, começam. Porém, um paradigma bastante utili-zado é considerar três níveis de processos computadoriutili-zados: processamento de baixo, médio e alto nível. Os primeiros envolvem operações primitivas como preprocessamento para reduzir ruído e melhoramento de contraste, onde o foco está nos valores e operações sobre os mesmos. Processos de nível mé-dio envolvem tarefas como segmentação (particionar uma imagem em regiões ou objetos), descrição destes objetos para reduzí-los a uma forma adequada para o processamento pelo computador, e classificação de objetos individuais; neste nível já há um certo grau de preocupação com a semântica das informa-ções contidas na imagem. Por fim, processos de alto nível envolvem buscar o significado de conjuntos de objetos reconhecidos e realizar funções congnitivas frequentemente associadas à visão natural.
Historicamente, uma das primeiras aplicações de imagens digitais foi na indústria de jornais, quando figuras foram, pela primeira vez, enviadas por um cabo submarino entre Londres e Nova Iorque. A introdução deste tipo de cabo, no início dos anos 20, reduziu o tempo necessário para transportar uma ima-gem através do Atlântico de mais de uma semana para menos de três horas. Equipamentos especializados de impressão codificavam as imagens para a transmissão e reconstruíam as mesmas no fim da recepção. Os primeiros ca-bos eram capazes de codificar imagens em cinco níveis de cinza distintos. Esta capacidade foi aumentada para 15 níveis em 1929.
A história do processamento digital de imagens está intimamente relacio-nada à história do desenvolvimento do computador digital. De fato, os primei-ros computadores podeprimei-rosos o suficiente para carregar tarefas significativas de processamento de imagens surgiram no início dos anos 60. Desde então, começaram a surgir tarefas consideradas realmente de processamento digital de imagens:
• Em 1964, no JPL – Jet Propulsion Laboratory, Califórnia, imagens da
lua foram processadas por um computador para corrigir diversos tipos de distorções.
• No início dos anos 70, técnicas de processamento digital de imagens
começaram a ser usadas em imageamento médico e na astronomia. A invenção da Tomografia Computadorizada pode ser citada como um dos eventos mais importantes na aplicação de processamento de imagens do diagnóstico médico.
Desde esta época até os dias atuais o campo de processamento de ima-gens cresceu vigorosamente. Além de aplicações na medicina e no programa
espacial, técnicas de processamento de imagens são atualmente usadas em um vasto campo de aplicações como na biologia, geografia, arqueologia, fí-sica e temas relacionados, medicina nuclear, defesa, entre outros. Além disso, existe uma outra grande área de aplicação de técnicas de processamento di-gital de imagens que é solucionar problemas relacionados à percepção pelo computador. Problemas como reconhecimento automático de caracteres, vi-são de máquina industrial para inspeção de produtos, processamento de im-pressões digitais e processamento de imagens de satélite são alguns exemplos de aplicações nesta área. Consulte [Gonzalez and Woods 2007] para leitura adicional.
Neste curso serão apresentadas algumas das operações mais comuns uti-lizadas para o processamento digital de imagens e como estas operações são feitas usando a plataforma R.
1.1.2. A plataforma R
A plataforma R é Free/Libre and Open Source Software (FLOSS). Seu código-fonte está disponível para qualquer pessoa e pode ser alterado para adequá-lo a necessidades específicas, sem ter que pagar. Portanto, FLOSS é de fato gratuito, mas usar este termo somente para designar softwares sem custo é contar a metade da história.
O software gratuito (freeware), por si só, é um software que pode ser usado sem precisar pagar. Porém, não necessariamente se tem acesso ao seu código-fonte e, portanto, nem sempre pode ser alterado ou simplesmente estudado, e frequentemente só pode ser usado da forma como ele foi disponi-bilizado.
R é uma linguagem e um ambiente para computação estatística e para pre-paração de gráficos de alta qualidade. É um projeto GNU similar à linguagem e ambiente S-PLUS [Chambers 2008] e, ainda que haja diferenças significativas entre eles, grande parte do código desenvolvido para um funciona no outro.
R oferece uma grande variedade de técnicas estatísticas (modelos linea-res e não-linealinea-res, testes estatísticos clássicos, modelos de séries temporais, classificação e agrupamento, entre outros) e gráficas, e é altamente extensível. R é uma coleção integrada de facilidades de software para manipulação de dados, realização de cálculos e preparação de gráficos, que inclui
• tratamento efetivo de dados e facilidades de armazenamento;
• operadores para cálculos em matrizes multidimensionais;
• ferramentas de diversos níveis de sofisticação para análises de dados; • facilidades gráficas para análise de dados;
• uma linguagem de programação bem definida, simples e eficaz que
in-clui expressões condicionais, laços, funções recursivas definidas pelo usuário e recursos de entrada e saída.
Antes de começar a usar R, recordemos que estão disponíveis emhttp:
exe-cutáveis já compilados para diversos sistemas operacionais. Nesse sítio encon-tram-se também disponíveis textos e tutoriais. A versão que utilizaremos para o desenvolvimento destas notas é a 2.8.1 para Linux, disponibilizada em de-zembro de 2008.
Em Ubuntu e outros derivados de Debian, basta dar o seguinte comando para instalar a plataforma:
$ sudo apt-get install r-base
A instalação de bibliotecas deve ser feita como super-usuário. Para entrar no R em Linux, digite “R” na linha de comando
$ R
Para pedir ajuda, já dentro de R, digite:
> ?data
> help . s t a r t ( )
Se desejarmos indicar o navegador a ser utilizado (que deverá ter capa-cidade para processar Java), por exemplo Mozilla, poderemos fazê-lo da se-guinte forma: > help . s t a r t ( browser= " m o z i l l a " ) Para sair do R: > q ( ) 1.1.2.1. Primeiros passos
R pode ser usado como uma calculadora de grande capacidade. Vamos à seguinte sessão 1 $ R 2 > 2 3 [1] 2 4 > 2+2 5 [1] 4 6 > sqrt(2) 7 [1] 1.414214 8 > exp(sqrt(2)) 9 [1] 4.11325 10 > sin(exp(sqrt(2))) 11 [1] -0.8258217
12 > sinh(exp(sqrt(2))) 13 [1] 30.56439
14 > sinh(exp(sqrt(2 - 1i*2))) 15 [1] -20.96102-6.575177i 16 > q()
17 Save workspace image? [y/n/c]: n
Iniciamos uma sessão (em Linux) chamando, a partir de qualquer caminho, o sistema R (linha 1). Entre as linhas 1 e 2, teremos uma saída com informa-ções da versão do R, sua data de lançamento e outros dados (aqui omitidos). A linha 2 passa ao R uma entrada constante e R a imprime (linha 3); a saída de
dados numéricos é precedida pelo indicador da linha, neste caso[1], já que
R supõe que pode haver mais de uma linha de dados; este tipo de marcador pode ser alterado. Na linha 4 pedimos ao R que calcule2+ 2, e o resultado é impresso na linha 5. Nas linhas 6, 8, 10 e 12 solicitamos a realização de outros cálculos, e seus respectivos resultados são exibidos nas linhas 7, 9, 11 e 13.
R trabalha com números complexos; a unidade complexa√−1é denotada na
entrada por1i, e as linhas 14 e 15 mostram uma operação com complexos e
seu resultado, respectivamente. Ao terminar uma sessão (linha 16) R nos per-guntará se desejamos guardar as variáveis e funções definidas (linha 17) para uso futuro; se assim o fizermos, salvaremos também os comandos que foram emitidos na sessão. Se desejamos exportar os comandos para um arquivo de
texto, podemos fazê-lo comsavehistory(file = "arquivo.txt"), para
depois recuperá-los comloadhistory(file = "arquivo.txt").
Para ter uma idéia da capacidade gráfica do R podemos usar os seguintes comandos, que ativarão as demonstrações incluídas na distribuição básica:
1 > demo("graphics") 2 > demo("image") 3 > demo("persp") 4 > demo("recursion")
A linha 1 ativa a demonstração de algumas capacidades gráficas do R, in-cluindo o uso de cores. A linha 2 ativa a demonstração dos recursos de uso de imagens para visualização de dados multidimensionais. A linha 3 mostra alguns recursos do R para visualização de funções multidimensionais em pers-pectiva. A linha 4 mostra como R implementa um método adaptativo para cal-cular integrais numéricas.
1.1.2.2. Bibliotecas
O sistema R utiliza diversas bibliotecas de funções e conjuntos de dados
adicionais, que são carregadas com a auxílio da funçãolibrary(), tal como
1 > library(cluster)
Essa função carrega bibliotecas já instaladas localmente. O comando
1 > install.packages()
abre interfaces para instalar novas bibliotecas; mais sobre esse assunto na página 9 deste texto.
No sitehttp://cran.r-project.orgestão disponíveis as bibliotecas
oficiais, que cobrem uma ampla gama de aplicações.
1.1.2.3. Leitura e Importação de Dados
Com a instalação completa do R ficam disponíveis vários conjuntos de da-dos, e para lê-los basta utilizar a funçãodata():
1 > data(iris)
Dados podem ser importados no sistema a partir de várias fontes, como
ar-quivos ASCII (extensãotxtoucsv), bancos de dados e planilhas. Dois tipos
de importação bastante utilizados são as de arquivos de tipotxtecsv. Para
importar arquivos ASCII, R oferece duas funções interessantes:read.table()
eread.csv(ver exemplo a seguir).
1 > read.table("dados.txt")
2 > read.csv("dados.csv", sep=";")
Para ver as variáveis que estão na memória:
1 > ls() 2 > iris
3 > summary(iris)
4 Sepal.Length Sepal.Width Petal.Length Petal.Width 5 Min. :4.300 Min. :2.000 Min. :1.000 Min. :0.100 6 1st Qu.:5.100 1st Qu.:2.800 1st Qu.:1.600 1st Qu.:0.300 7 Median :5.800 Median :3.000 Median :4.350 Median :1.300 8 Mean :5.843 Mean :3.057 Mean :3.758 Mean :1.199 9 3rd Qu.:6.400 3rd Qu.:3.300 3rd Qu.:5.100 3rd Qu.:1.800 10 Max. :7.900 Max. :4.400 Max. :6.900 Max. :2.500 11 Species
12 setosa :50 13 versicolor:50 14 virginica :50
Na listagem acima vemos a saída da funçãols(), que é o conjunto de
de conjuntos de dados; no nosso caso, a saída é um conjunto de estatísticas de resumo (valores mínimo e máximo, primeiro, segundo e terceiro quartis, e média) de cada variável.
1.1.2.4. Amostras Univariadas
A plataforma R oferece diversas funções para o cálculo de estatísticas des-critivas, como a média, a mediana, estatísticas de ordem, medidas de disper-são, assimetria e curtose. Para ilustrar o uso destas funções será utilizado o
conjunto de dadosiris, disponível no R. Este conjunto de dados consiste em
151 linhas com seis colunas cada uma. A primeira linha, de tipo texto, des-creve o conteúdo de cada coluna. As cinco primeiras colunas correspondem a medidas realizadas sobre flores, e a última, que é de tipo texto, categoriza em uma de três espécies cada flor medida. As duas primeiras linhas (numéricas) e todas as colunas do conjunto de dados podem ser visualizadas da seguinte forma:
1 > iris[1:2,]
2 Sepal.Length Sepal.Width Petal.Length Petal.Width Species
3 1 5.1 3.5 1.4 0.2 setosa
4 2 4.9 3.0 1.4 0.2 setosa
A primeira coluna está rotuladaSepal.Length; para ver os valores basta
emitir o seguinte comando:
1 > iris$Sepal.Length 2 [1] 5.1 4.9 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9 5.4 4.8 3 [13] 4.8 4.3 5.8 5.7 5.4 5.1 5.7 5.1 5.4 5.1 4.6 5.1 4 [25] 4.8 5.0 5.0 5.2 5.2 4.7 4.8 5.4 5.2 5.5 4.9 5.0 5 [37] 5.5 4.9 4.4 5.1 5.0 4.5 4.4 5.0 5.1 4.8 5.1 4.6 6 [49] 5.3 5.0 7.0 6.4 6.9 5.5 6.5 5.7 6.3 4.9 6.6 5.2 7 [61] 5.0 5.9 6.0 6.1 5.6 6.7 5.6 5.8 6.2 5.6 5.9 6.1 8 [73] 6.3 6.1 6.4 6.6 6.8 6.7 6.0 5.7 5.5 5.5 5.8 6.0 9 [85] 5.4 6.0 6.7 6.3 5.6 5.5 5.5 6.1 5.8 5.0 5.6 5.7 10 [97] 5.7 6.2 5.1 5.7 6.3 5.8 7.1 6.3 6.5 7.6 4.9 7.3 11 [109] 6.7 7.2 6.5 6.4 6.8 5.7 5.8 6.4 6.5 7.7 7.7 6.0 12 [121] 6.9 5.6 7.7 6.3 6.7 7.2 6.2 6.1 6.4 7.2 7.4 7.9 13 [133] 6.4 6.3 6.1 7.7 6.3 6.4 6.0 6.9 6.7 6.9 5.8 6.8 14 [145] 6.7 6.7 6.3 6.5 6.2 5.9
Se queremos ter acesso às variáveis diretamente, sem necessidade de fazer referência ao conjunto de dados (iris), podemos colocar as variáveis na lista de objetos definidos com o comando
1 > attach(iris)
Para calcular a média amostral da variávelSepal.Lengthbasta fazer
1 > mean(Sepal.Length) 2 [1] 5.843333
A mediana amostral é obtida com
1 > median(Sepal.Length) 2 [1] 5.8
Para calcular os quartis fazemos
1 > quantile(Sepal.Length) 2 0% 25% 50% 75% 100% 3 4.3 5.1 5.8 6.4 7.9
A funçãoquantile()admite como argumento opcional um vetor de
valo-res no intervalo[0, 1], retornando os percentis da amostra nesses pontos. Se, por exemplo, queremos calcular os decis deveríamos entrar com o comando
quantile(iris$Sepal.Length, v), ondevé o vetor que contém os va-lores(i/10)1≤i≤9. Podemos fazê-lo manualmente, ou utilizar uma função do R
para gerar este vetor auxiliar.
1 > quantile(Sepal.Length, seq(.1,.9,.1)) 2 10% 20% 30% 40% 50% 60% 70% 80% 90% 3 4.80 5.00 5.27 5.60 5.80 6.10 6.30 6.52 6.90
Já que usaremos este vetor várias vezes, é conveniente guardá-lo em uma variável de nome mais curto e manejável com o comando
1 > l_s <- Sepal.Length
As últimas versões do R admitem “=” como comando de atribuição, em vez
do mais exótico (porém mais utilizado, até agora) “<-”.
R também oferece funções para calcular medidas de dispersão como vari-ância (var), desvio padrão (sd, por standard deviation) e mediana do desvio absoluto (mad, por median absolute deviation), tal como é mostrado a seguir.
1 > var(l_s) 2 [1] 0.6856935 3 > sd(l_s) 4 [1] 0.8280661 5 > mad(l_s) 6 [1] 1.03782
1 > max(l_s) 2 [1] 7.9 3 > min(l_s) 4 [1] 4.3 5 > length(l_s) 6 [1] 150
Para calcular estatísticas de ordem superior, como assimetria e curtose,
é necessário carregar o pacotee1071, que provê as funçõesskewness()e
kurtosis(). 1 > install.packages("e1071") 2 > library(e1071) 3 > skewness(l_s) 4 [1] 0.3086407 5 > kurtosis(l_s) 6 [1] -0.6058125
A linha 1 é necessária para baixar uma biblioteca que não está disponível lo-calmente. R usará a conexão a Internet para obtê-la. Se o comando é dado para uma biblioteca já instalada, R verificará se há uma versão mais atual e, se houver, a instalará.
R permite construir gráficos com facilidade. Por exemplo, para construir um
boxploté necessário apenas emitir o comando
1 > boxplot(iris[,-5], horizontal=TRUE, notch=TRUE, 2 main="Exemplo de Boxplot")
Ao informar como entradairis[,-5]estamos pedindo para considerar todas
as linhas e para omitir a quinta coluna, que não é de valores mas sim de rótulos. O resultado deste comando é mostrado na Figura 1.1.
De fato, para gerar o arquivo que armazena o gráfico mostrado na Fi-gura 1.1 é necessário ativar o dispositivo de saída, fazer o gráfico e desativar o dispositivo. A sequência de instruções é
1 > postscript("box_plot")
2 > boxplot(iris[,-5], horizontal=TRUE, notch=TRUE, 3 main="Exemplo de Boxplot")
4 > dev.off()
Embora seja possível fazer uma simples captura da janela, este procedimento irá gerar um conjunto de dados matriciais. Procedendo tal como explicado acima, o gráfico será armazenado em formato vetorial e, com isso, a sua qua-lidade visual estará garantida seja qual for a ampliação a que for submetido.
Sepal.Length Sepal.Width Petal.Length Petal.Width 0 2 4 6 8 Exemplo de Boxplot
Figura 1.1. Exemplo de Boxplot.
Outro gráfico importante é o histograma, que pode ser construído com o seguinte comando:
1 > library(MASS)
2 > hist.scott(Sepal.Length, prob=TRUE, main="Histograma", 3 xlab="Comprimento da Sepala", ylab="Proporcoes")
e seu resultado pode ser visto na Figura 1.2. O histograma será definido com cuidado na equação (1) (página 19). R oferece uma grande variedade de parâ-metros para controlar o aspecto com que os histogramas em particular, e todos os gráficos em geral, são produzidos e exibidos. Para produzir este histograma
utilizamos uma função otimizada,hist.scott, disponível no pacoteMASS.
Uma forma entre gráfica e alfanumérica é o diagrama de galhos e folhas (stem-and-leaf plot):
1 > stem(Petal.Length)
2 The decimal point is at the | 3
4 1 | 012233333334444444444444 5 1 | 55555555555556666666777799
Histograma Comprimento da Sépala Proporções 4 5 6 7 8 0.0 0.1 0.2 0.3 0.4
Figura 1.2. Histograma dos comprimentos de sépalas.
7 2 | 8 3 | 033 9 3 | 55678999 10 4 | 000001112222334444 11 4 | 5555555566677777888899999 12 5 | 000011111111223344 13 5 | 55566666677788899 14 6 | 0011134 15 6 | 6779 1.1.2.5. Amostras Multivariadas
R trata com facilidade dados multivariados, isto é, onde para cada indiví-duo temos um vetor de observações. A notação que utilizaremos para deno-tar um conjunto de nvetores k-dimensionais éyyy= (yyy1, . . . , yyyn), com yyyi∈R
k.
Quandok= 3temos a forma natural de armazenar informações de cor, mas
há sensores capazes de captar centenas de componentes. O sensor AVIRIS, por exemplo, registra as centas em cerca de duzentas-e-cinquenta componen-tes [Curran and Dungan 1990].
Este tipo de dados aparece naturalmente em estudos onde se mede mais de um atributo para cada indivíduo como, por exemplo, em antropometria onde se registram o peso, a estatura, a idade e diversas medidas corporais de cada pessoa. Este tipo de análise está recebendo atualmente muita atenção, já que é um passo importante na cadeia de operações conhecida como KDD –
Kno-wledge Discovery in Databases. Em particular, os dadosiristêm dimensão quatro (k= 4); vistos em conjunto, sua dimensão é cento-e-cinquenta (n= 150), mas agrupados em três categorias de cinquenta observações cada.
Para obter uma visão geral de um conjunto de dados deste tipo podemos emitir o seguinte comando
1 > summary(iris)
2 Sepal.Length Sepal.Width Petal.Length 3 Min. :4.300 Min. :2.000 Min. :1.000 4 1st Qu.:5.100 1st Qu.:2.800 1st Qu.:1.600 5 Median :5.800 Median :3.000 Median :4.350 6 Mean :5.843 Mean :3.057 Mean :3.758 7 3rd Qu.:6.400 3rd Qu.:3.300 3rd Qu.:5.100 8 Max. :7.900 Max. :4.400 Max. :6.900
9 Petal.Width Species 10 Min. :0.100 setosa :50 11 1st Qu.:0.300 versicolor:50 12 Median :1.300 virginica :50 13 Mean :1.199 14 3rd Qu.:1.800 15 Max. :2.500
O comandosummaryfornece resumos de cada uma das variáveis, mas não
informa nada a respeito da relação entre elas.
A matriz de covariância descreve relações entre variáveis, assim como sua variância:
1 > var(iris[1:150, 1:4])
2 Sepal.Length Sepal.Width Petal.Length 3 Sepal.Length 0.68569351 -0.04243400 1.2743154 4 Sepal.Width -0.04243400 0.18997942 -0.3296564 5 Petal.Length 1.27431544 -0.32965638 3.1162779 6 Petal.Width 0.51627069 -0.12163937 1.2956094 7 Petal.Width 8 Sepal.Length 0.5162707 9 Sepal.Width -0.1216394 10 Petal.Length 1.2956094 11 Petal.Width 0.5810063
rótulos. Analogamente, é possível obter a matriz de correlações:
1 > cor(iris[1:150, 1:4])
2 Sepal.Length Sepal.Width Petal.Length 3 Sepal.Length 1.0000000 -0.1175698 0.8717538 4 Sepal.Width -0.1175698 1.0000000 -0.4284401 5 Petal.Length 0.8717538 -0.4284401 1.0000000 6 Petal.Width 0.8179411 -0.3661259 0.9628654 7 Petal.Width 8 Sepal.Length 0.8179411 9 Sepal.Width -0.3661259 10 Petal.Length 0.9628654 11 Petal.Width 1.0000000
Um gráfico muito interessante para se ver simultaneamente o comporta-mento de todos os pares de variáveis de um conjunto multivariado é o diagrama de pares, que é obtido com
1 > pairs(iris[,-5], main="Conjunto Iris", pch=21, 2 bg=c("red","green3","blue")[unclass(Species)])
e é mostrado na Figura 1.3. A funçãounclasstransforma classes em atributos
numéricos, que por sua vez são utilizados como índices para as cores.
A funçãostars()também é muito utilizada:
1 > stars(iris, full=TRUE, draw.segments=TRUE, 2 key.loc=c(27,1))
O resultado é mostrado na Figura 1.4.
As variações possíveis para estes gráficos são, também, muitas. Uma das mais importantes consiste no uso de de “fatores”. Em R, um “fator” é uma va-riável categórica que indica a pertinência de uma observação a uma classe. No exemplo dos dados de flores, podemos atribuir a cada vetor de tamanho
4de valores (largura e comprimento da sépala, largura e comprimento da
pé-tala) a variável categórica “espécie”. Essa representação irá facilitar muito a visualização e a análise dos dados, tal como ilustrado no código que segue.
O seguinte exemplo requer o uso da bibliotecalattice, uma das mais
poderosas ferramentas de visualização e análise de de dados multivariados em R [Murrell 2006, Sarkar 2008].
1 > library(lattice)
2 > splom(~iris[,1:4] | Species, data = iris, pscales = 0, 3 + varnames = c("Sepal\nLength", "Sepal\nWidth",
4 + "Petal\nLength, "Petal\nWidth"))
Sepal.Length 2.0 2.5 3.0 3.5 4.0 0.5 1.0 1.5 2.0 2.5 4.5 5.5 6.5 7.5 2.0 2.5 3.0 3.5 4.0 Sepal.Width Petal.Length 1 2 3 4 5 6 7 4.5 5.0 5.5 6.0 6.5 7.0 7.5 8.0 0.5 1.0 1.5 2.0 2.5 1 2 3 4 5 6 7 Petal.Width Conjunto Iris
Figura 1.3. Diagrama de pares para os dados iris.
No código acima, a linha 1 carrega a bibliotecalattice. A linha 2 esti-pula a criação de um gráfico de acordo com uma fórmula: as quatro primeiras colunas do conjunto iris, onde estão os valores, em função do fator espécie.
O trechopscales = 0desta linha elimina o uso de marcas numéricas nos
eixos para facilitar a visualização mais qualitativa do que quantitativa das rela-ções entre as variáveis. As linhas 3 e 4 apenas especificam a forma em qual os rótulos das variáveis serão mostrados.
Na figura 1.5 podemos notar como as variáveis que descrevem medidas de pétalas variam de forma diferente em função da espécie: quando se trata de Virginica, ambas adotam valores relativamente grandes, quando é Setosa os valores são pequenos, e quando a espécie é Versicolor observa-se uma variação intermediária. Essa, bem como muitas outras relações interessantes, são evidenciadas pelo fato da figura 1.5 exibir os dados de forma sincronizada, isto é, fazendo coincidir os eixos de cada uma das três caixas que o compõem. Uma biblioteca mínima a respeito de R é formada pelos seguintes livros: [Chambers 2008, Chambers et al. 1983, Crawley 2005, Crawley 2007, Dalgaard 2002, Davison and Hinkley 1997, Everitt and Hothorn 2006, Maindonald and Braun 2003, Murrell 2006, Paradis 2005, Sarkar 2008, Spector 2008, Venables and Ripley 2000, Venables and Ripley 2002, Venables and Smith 2001, Verzani 2004]. Em parti-cular, o texto de [Velho et al. 2008] apresenta uma abordagem similar à destas
Sepal.Length Sepal.Width
Petal.Length Petal.Width Species
Figura 1.4. Diagrama de estrelas a partir do conjunto de dados iris.
notas e todos os exemplos dos Capítulos 3 e 10 foram implementados em R. Três recursos na Web são essenciais:
• O sítio oficial de R:http://www.r-project.org
• A lista de discussão R-help (em Inglês): https://stat.ethz.ch/
mailman/listinfo/r-help
• A lista de discussão RSTAT (em Português):http://br.groups.yahoo.
com/group/R_STAT
1.2. Imagens: definições e notação
O conjunto dos números reais será denotadoR, o dos números complexos
C, o dos números inteirosZe o dos números naturais (incluindo o zero)N. O
número de elementos do conjuntoAserá denotado#A. O indicador do conjunto
Aserá denotado como1A, isto é,
1A(x) =
1 se x∈ A
0 se x∈ A./
processa-Figura 1.5. Diagrama de pontos por classe dos dados iris.
mento de imagens, são os livros de [Mascarenhas and Velasco 1989], o de [Jain 1989], o de [Banon 2000] e o já mencionado [Velho et al. 2008].
Uma imagem, no contexto destas notas, sempre será uma função definida sobre uma grade finita euclidiana regular bidimensional sobre um subconjunto dos vetores reaisp-dimensionais, isto é, o conjuntoS= [0, m −1]×[0,n−1] ⊂Z
2
denotará o suporte das imagens; note que[0, m − 1] ⊂N0, ondeN0 denota o conjunto dos naturais incluindo o zero e[0, n−1] ⊂N0são intervalos de inteiros,
logo,Sé uma região conexa. Uma imagem é um objeto da forma f : S→ K,
ondeK⊂R
p ou aindaK⊂
C
p. Dependendo da plataforma computacional
empregada, m≥ 1 e n≥ 1 denotarão, respectivamente, o número de linhas
bidimensionais pelas linhas na primeira variável e pelas colunas na segunda (diferentemente de, por exemplo, as plataformas IDL e ENVI), diremos que a
imagem fpossuimlinhas encolunas.
Desta forma ficam excluídas desta discussão as imagens tomográficas, por serem elas funções definidas sobre grades tridimensionais, bem como os mo-delos de imagens de certas máquinas morfológicas, por eles empregarem gra-des exagonais. Também não iremos considerar o tempo, isto é, vídeo.
No que segue descreveremos dois elementos importantes ao se tratar de imagens: a estrutura espacial, caracterizada pelo conceito de “vizinhança”, e o conjunto dos valores possíveis em cada posição da imagem, isto é, o seu contradomínio.
1.2.1. Vizinhanças
Algumas das mais importantes operações com imagens dependem não
apenas do valor observado na coordenada s∈ S, mas também dos valores
observados em uma região próxima dessa coordenada. Torna-se, portanto, importante definir com precisão o conceito de “proximidade”.
Dada a natureza discreta do suporte S, há várias maneiras de definir a
vizinhança da posiçãos∈ S, que será denotada∂s e que, por definição, não
inclui a própria coordenadas. Um caso extremo é o da vizinhança vazia, isto é,∂s= /0; no outro extremo, cada coordenada pode ter como vizinhos todos os
outros pontos, ou seja,∂s= S \ {s}.
É comum ouvir dizer “usaremos os quatro vizinhos mais próximos”; isso é intuitivo mas, não resolve corretamente a definição de vizinhança em bordas e esquinas da imagem. Para tomar conta de todas as situações possíveis podemos usar o conceito de distância, por exemplo
∂s= {t ∈ S \ {s} : d(s,t) ≤ k},
onded(s,t)é alguma distância entre as coordenadass,t ∈ S. As distâncias mais frequentes são a de Manhattan (ouL1), a euclidiana (ouL2) e a de Kolmogorov
(ouL∞) dadas, respectivamente, por
d1(s,t) = |s1−t1| + |s2−t2|,
d2(s,t) =
q
(s1−t1)2+ (s2−t2)2, e
d∞(s,t) = max{|s1−t1|,|s2−t2|}.
Na relações acima denotamoss= (s1, s2)et= (t1,t2).
1.2.2. Contradomínios
Tal como comentado no início do seção 1.2, uma imagem é uma função
que a cada coordenada do suportes∈ Satribui um valor emR
pou ainda em
C
p, comp≥ 1inteiro. DenotaremosKo contradomínio da imagem f. A forma
em que os valores do contradomínio são efetivamente armazenados em um computador digital é denominada “quantização”.
O contradomínio mais simples é o binário, onde temos K= {0,1}. A vi-sualização de uma imagem binária pode ser feita de diversas maneiras, por
exemplo atribuindo a cada valor0a cor preta e a cada valor 1a cor branca.
Fica assim claro que a visualização de uma imagem está apenas associada ao seu contradomínio, mas não está necessariamente determinada por ele.
Um outro contradomínio frequentemente encontrado nas aplicações é o formado pelos primeiros256inteiros, começando no0, isto é,K= {0,1,...,255}. Esse é conhecido como “formato byte”.
Ainda nos contradomínios unidimensionais, é frequente encontrar inteiros com e sem sinal, inteiros longos (com e sem sinal), palavras em ponto flutuante e em precisão estendida.
Quando se trata de contradomínios multidimensionais, o mais frequente
é que sejam usadaspcópias do mesmo contradomínio unidimensional para
definir o espaço de valores da imagem, isto é, teremos imagens binárias p
-dimensionais, imagens bytep-dimensionais e assim por diante. Cada uma das
dimensões irá medir, tipicamente, diferentes propriedades da cena, isto é, do mundo real. Um exemplo disso é o das imagens de sensoriamento remoto obtidas pelos sensores do Satélite Sino-Brasileiro de Recursos Terrestres –
CBERS (verhttp://www.cbers.inpe.br). A sua câmera imageadora de
alta resolução – CCD produz imagens nas seguintes bandas espectrais:
• 0, 51− 0,73µm (pancromática) • 0, 45− 0,52µm (azul)
• 0, 52− 0,59µm (verde) • 0, 63− 0,69µm (vermelho)
• 0, 77− 0,89µm (infravermelho próximo).
Cada uma dessas bandas é registrada com quantização de8bits, isto é, em
formato byte.
Imagens com contradomínio complexo são bem mais específicas. Elas aparecem quando o mecanismo de imageamento registra não apenas a in-tensidade do sinal mas também a fase relativa do mesmo. Exemplos de apli-cações onde aparecem imagens complexas são as imagens de elastografia [Silva et al. 2006] (com valores emC) e as de polarimetria por radar de aber-tura sintética [Frery et al. 2007] (com valores emC
p). A quantização mais
fre-quente para as imagens em formato complexo é a de precisão simples tanto para a parte real quanto para a parte imaginária de cada banda.
Uma ferramenta importante para fazer uma descrição sucinta dos valores adotados por uma imagem é o histograma. Este objeto é uma contagem dos valores observados em certos intervalos determinados pelo usuário.
Seja f : S→ K ⊂Ruma imagem eI= {I0, I1, . . . , Iq}uma partição finita do contradomínio em intervalos, isto é, os elementos deI satisfazem:
1. cadaIié um intervalo (não necessariamente não degenerado),
3. a união deles é exatamente o contradomínio:S0≤i≤qIi= K.
De posse de uma partiçãoI do contradomínio, o histograma da imagem
f é definido como o vetor deq+ 1componentes naturais, onde a componente
ié o número de elementos emSonde a imagem adota um valor na partiçãoIi,
isto é, o histograma da imagemfem relação à partiçãoI é a funçãoHI( f ) =
(H0, H1, . . . , Hq)onde
Hi= #{s ∈ S : f (s) ∈ Ii}. (1)
Freqüentemente empregaremos o histograma de proporções da imagem fem
relação à partiçãoI, que é definido comohI( f ) = HI( f )/#S = (h0, h1, . . . , hq),
isto é, é o histograma de f em relação à partiçãoI com cada componente
dividida pelo número de elementos deS.
1.3. Formatos de imagens e leitura de dados
Há duas grandes classes de informações visuais que podem ser armaze-nadas em um computador digital: as imagens vetoriais e as matriciais. As primeiras são formadas pela descrição, em alguma linguagem conveniente, dos elementos geométricos que compõem a imagem. Elas são a forma ideal para mostrar, em qualquer escala que for necessária, informações que podem ser descritas pela junção de formas geométricas relativamente simples; são exemplos desse tipo de informação as figuras 1.1 (segmentos, circunferências e texto), 1.2 (segmentos e texto), e 1.3 (segmentos, circunferências, cores e texto). O segundo tipo de informações visuais que podemos armazenar é o das imagens matriciais. Nestas últimas, o elemento básico é um valor associ-ado a uma posição. As imagens matriciais são o objeto destas notas e serão detalhadas no que segue deste seção.
No contexto de imagens digitais, um formato de imagem é uma forma pa-drão de organizar e armazenar dados de imagem. O formato define como os dados são arranjados e o tipo de compressão –se existir algum– que é usado. De maneira informal, formatos de imagens, também chamados de “gráficos raster” ou “arquivos bitmap” (mapa de bits), contêm uma represen-tação de um gráfico armazenada como pixels a uma resolução fixa. Um exem-plo é uma imagem fotográfica digital ou imagem escaneada. Alguns dos for-matos de imagens mais comuns são GIF, JPEG, PNG, TIFF e BMP. O livro de [Murray and Ryper 1994] continua sendo uma referência excelente tanto pela sua abrangência quanto pela profundidade com que disseca os principais formatos gráficos.
Os formatos de imagens podem ser divididos em duas classes: binário e vários tons. Uma imagem binária possui apenas duas tonalidades, enquanto que uma imagem em vários tons possui toda a gama de tons de cinza entre o branco e o preto. A tabela 1.1 mostra alguns formatos de imagens conhecidos dividos nestas duas classes.
Dentre as diversas maneiras de descrever cores (ver [Velho et al. 2008]), faremos referência apenas ao espaço RGB. Cada cor no espaço RGB é des-crita em uma base aditiva formada pelas cores primárias vermelho (R – Red ),
Binário Tom contínuo
CCITT Grupo 3 JPEG
CCITT Grupo 4 JPEG-LS
JBIG (ou JBIG1) JPEG-2000
JBIG2 BMP
TIFF GIF
PDF PNG TIFF
Tabela 1.1. Formatos de imagens
verde (G – Green) e azul (B – Blue).
Os formatos descritos a seguir são conhecidos genericamente como “for-matos pictóricos”, por estarem intimamente relacionados ao armazenamento e à distribuição de fotografias.
1.3.1. TIFF
O TIFF (Tagged Image File Format) é um formato flexível que normalmente salva 8 bits ou 16 bits por cor (vermelho, verde, azul) para um total de 24 bits e 48 bits, respectivamente, usando TIFF ou TIF como extensão. Este formato su-porta uma variedade de padrões de compressão de imagens, incluindo JPEG, JPEG-LS e JPEG-2000. Nenhum leitor simples lê todo tipo de arquivo TIFF, e por causa disso é frequentemente referenciado como uma família de formatos mais do que um único formato. Os dados em arquivos TIFF podem estar com-primidos com perdas e sem perdas (alguns oferecem compressão sem perda relativamente de boa qualidade para imagens binárias). Algumas câmeras di-gitais podem salvar no formato TIFF, usando o algoritmo de compressão LZW (Lempel-Ziv-Welch, ver [Nelson 1989]) para armazenamento sem perdas. O formato de imagem TIFF não é amplamente suportado por navegadores Web, porém ainda é amplamente aceito como um padrão de arquivo para fotografia no comércio de impressão. Por fim, este formato suporta espaços de cores es-pecíficos para certos dispositivos de impressão, com o CMYK definido por um conjunto particular de tintas para impressão: os pigmentos cian (C), magenta (M), amarelo (Y – Yellow ) e preto (K – blacK ) que formam um espaço de cores subtrativas.
1.3.2. JPEG
Arquivos JPEG (Joint Photographic Experts Group) armazenam dados (na maioria dos casos) em um formato com perdas. Praticamente todas as câme-ras digitais podem salvar imagem no formato JPEG, que suporta 8 bits por cor para um total de 24 bits, produzindo arquivos relativamente pequenos. Quando não é muito grande, a compressão não denigre visivelmente a
qua-lidade da imagem, mas arquivos JPEG podem sofrem de degradações percep-tíveis quando editados e salvos repetidamente. Imagens fotográficas podem ser melhor armazenadas em um formato sem perdas diferente do JPEG se as mesmas tiverem que ser re-editadas futuramente, ou se pequenos artefa-tos forem inaceitáveis na imagem. O formato JPEG também é usado como o algoritmo de compressão de imagem em muitos arquivos PDF.
1.3.3. PNG
O formato de imagem PNG (Portable Network Graphics) foi criado como o sucessor livre e em código aberto do GIF. Este formato suporta truecolor (16 milhões de cores) enquanto que o GIF suporta apenas 256 cores. O arquivo PNG destaca-se quando a imagem possui grandes áreas uniformemente colo-ridas. O formato PNG sem perdas é mais apropriado para edição de figuras e os formatos com perdas, como o JPEG, são melhores para distribuição final de imagens fotográficas, pois arquivos JPEG são menores do que arquivos PNG. Muitos navegadores Web antigos não suportam o formato PNG, porém todos os navegadores atuais suportam as variantes mais comuns do formato PNG, incluindo transparência em 8 bits.
1.3.4. BMP
O formato de imagem BMP (Windows Bitmap) suporta arquivos gráficos dentro do sistema operacional Microsoft Windows. Tipicamente, os dados de arquivos BMP não são comprimidos e, portanto, ocupam muito espaço. A grande vantagem deste formato é sua simplicidade e grande aceitação.
1.3.5. Leitura de formatos pictóricos no R
R possui algumas funções úteis para a leitura e o gravação dos quatro for-matos de imagens discutidos anteriormente. O trecho de código abaixo apre-senta o uso de funções para leitura.
1 > # Leitura 2 > imagem <- read.jpeg("imagem.jpg") 3 > plot.imagematrix(imagem) 4 > library(SoPhy) 5 > imagem <- read.picture("imagem.tiff") 6 > plotRGB(imagem) 7 > library(pixmap) 8 9 > # Funcao read.image
10 read.image <- function(file, imdir="/usr/X11R6/bin/",...){ 11 if(!require(pixmap))
12 stop("library pixmap required and not found\n") 13 newfile <- tempfile()
14 cmd <- paste(sep="",imdir,"convert ", ... ," ",file, 15 + " pnm:",newfile)
16
17 retval <- system(cmd) 18 if(retval != 0) {
19 errmsg <- paste("system command",cmd, 20 + "failed with error code",retval,"\n") 21 stop(errmsg) 22 } 23 p1 <- read.pnm(newfile) 24 unlink(newfile) 25 p1 26 } 27 28 > imagem <- read.image("imagem.bmp")
29 > imagem <- getChannels(imagem, colors = "all") 30 > imagem <- imagemmatrix(imagem,type="rgb") 31 > plot(imagem)
32 > imagem <- read.image("imagem.png")
33 > imagem <- getChannels(imagem, colors = "all") 34 > imagem <- imagemmatrix(imagem,type="rgb") 35 > plot(imagem)
No código acima, a linha 2 mostra como ler uma imagem no formato JPEG. Para leitura de imagens no formato TIFF é necessário o uso da biblioteca
SoPhy que fornece a funçãoread.picture, como mostrado nas linhas 4 e 5. O R não fornece uma forma direta para ler imagens nos formatos BMP e PNG, porém pode ser usada uma função disponível no programa
ImageMa-gick (http://www.imagemagick.org) chamadaread.image, juntamente
com a bibliotecapixmap. Esta função está presente no código acima a partir
da linha 9. Na linha 11 a função verifica a existência do pacotepixmap. Na
linha 13 é criado o nome de um arquivo temporário. O comandopasteusado
na linha 14 cria, através de concatenações de strings um comando para ser executado pelo sistema. Este comando é usado para converter para pnm a imagem passada como parâmetro pela chamada da função. Na linha 17 o
co-mandosystemfaz uma chamada para o sistema executar o comando contido
na strig cmd. Após a conversão da imagem, o comandoread.pnmé usado
para ler a imagem, como visto na linha 23. Por fim, na linha 24 é usado o
comandounlinkpara apagar o arquivo temporário criado anteriormente. As
linhas de 28 até 35 mostram como usar a funçãoread.imagepara ler
ima-gens nos dois formatos.
O trecho de código abaixo apresenta o uso de funções para gravação.
1 > # Gravacao
2 > png(filename = "imagem.png", width = 480, height = 480) 3 > plot(imagem)
5 6 > jpeg(filename="imagem.jpg",width=480,height=480, 7 + quality=80) 8 > plot(imagem) 9 > dev.off() 10 11 > imagem 12 size: 458 x 372 13 type: rgb 14 > imagem <- array(imagem,dim=c(458,372,3)) 15 > imagem <- imagem*255 16 > write.picture(imagem,"imagem.tiff") 17 18 > bitmap("imagem.bmp",’bmp256’) 19 > plot(imagem) 20 > dev.off()
No código acima as linhas 2, 7, 16 e 18 mostram como salvar imagens
nos formatos PNG, JPEG, TIFF e BMP, respectivamente. O comando png
recebe como parâmetros o nome da imagem, a altura e a largura da imagem. O
comandojpegtambém recebe como parâmetros o nome da imagem, a altura
e a largura da mesma, bem como a qualidade desejada para a gravação da
imagem. Para o comandobitmapbasta fornecer o nome da imagem e o tipo
(outros tipos aceitos podem ser vistos através do comandohelp(bitmap).
1.4. Operações pontuais
As operações mais simples que podem ser realizadas sobre uma ima-gem são as conhecidas como operações pontuais. Estas operações estão definidas de forma tal que cada valor na imagem de saída depende apenas do valor correspondente na imagem de entrada, isto é, são caracterizadas para imagens f, g : S → Kpor operadoresΨ= (Ψs)s∈Sda formag=Ψ( f )onde
g(s) = (Ψs( f (s)))s∈S. Em outras palavras, o valor da nova imagem na
coorde-nadas, denotadog(s)dependerá apenas do valor da imagem de entrada na
mesma coordenada (f(s)) e do operador definido para ela (Ψs).
O operador pontual mais simples que podemos definir é a identidade, isto é,Ψs( f (s)) = f (s)para todos∈ S; com issog(s) = f (s)para todos∈ S.
As operações pontuais tal como definidas acima são muito gerais, permi-tindo mudar a regra de transformação conforme muda a coordenada, isto é, é possível definir operadoresΨ= (Ψs)s∈Stais queΨs( f (s)) 6=Ψt( f (t))ses6= t
mesmo se f(s) = f (t). Embora esta generalidade seja desejável, na grande
maioria das situações práticas é suficiente trabalhar com a mesma operação
em cada coordenada, isto é, fazendoΨs=Ψtpara todas as coordenadas. Se
este for o caso a operação pontual ficará definida pelo operadorΨsem neces-sidade de especificá-lo para cada elementos∈ S. Este tipo de transformações
é conhecido como invariante por translação.
As transformações pontuais podem, em geral, ser especificadas através de tabelas de visualização, conhecidas como LUTs (Look-Up Tables), especial-mente quando o contradomínio das imagens é finito. No que segue será dada especial ênfase às imagens no formato byte, isto é, às imagens f, g : S → K = [0, 255] ⊂N. Para este tipo de imagem qualquer tansformação pontual invari-ante por translação pode ser especificada (e convenientemente implementada)
por uma LUT de255entradas ou, mais economicamente, por um vetor de255
entradas onde cada uma é um valor emK. Com efeito, a transformação Ψ
ficará especificada pelo vetor(v(0), . . . , v (255))fazendov(i) =Ψ(i)e a transfor-mação será aplicada fazendog(s) = v( f (s))para cada coordenada. A não ser que seja especificada outra coisa, quando se trata de uma imagem colorida, a operação é aplicada em cada uma das três bandas.
1.4.1. Negativo digital
Neste contexto, a transformação identidade é, então, especificada pelo ve-torv(i) = i, enquantov(i) = 255 − iespecifica o negativo digital. O código que segue calcula o negativo de uma imagem.
1 > library(rimage) 2 > load("imagem.Rdata") 3 > imagem 4 size: 458 x 372 5 type: rgb 6 > negativo <- 1 - imagem 7 > plot.imagematrix(negativo)
No código acima a linha 1 carrega a bibliotecarimagee a linha 2 lê uma
matriz com os valores de uma imagem no R. Esta imagem será usada daqui em diante para ilustrar as operações apresentadas nestas notas. Na linha 6 é realizada a transformação de negativo digital da imagem para todas as bandas; note que ao invés de subtrair o valor de255ele é subtraído de1, isso se deve à conversão interna que a plataforma faz dos valores, padronizando-os para o intervalo[0, 1].
Utiliza-se a funçãoplot.imagemmatrixpara visualizar a imagem
trans-formada. A Figura 1.6 mostra a imagem original (“Moreno Bom”, acrílico sobre
tela, 2008, de Enilson Costahttp://enilson.costa.googlepages.com;
direitos cedidos pelo autor) e seu negativo digital.
Às vezes é conveniente definir transformações pontuaisΨsupondo as
ima-gens com contradomínio real. A versão discreta desta transformação consiste
em truncar e arredondar os valores transformados, isto é, em fazer g(s) =
⌊min{max{0,Ψ( f (s)},255} + 1/2⌋, onde ⌊x⌋ = max{t ∈Z: t≤ x}denota o arre-dondamento para abaixo do valorx∈R.
(a) Imagem original (b) Negativo digital
Figura 1.6. Ilustração da transformação de negativo digital.
1.4.2. Mudança de brilho e de constraste
Para quaisquer números reaisα eβ as operações pontuais “mudança de
escala porα” e “acréscimo do valorβ” são definidas, respectivamente, como
Sα( f ) =αf eTβ( f ) = f +β, sendo a primeira o produto de escalares em cada coordenada e a segunda a soma de escalares em cada coordenada. A trans-formaçãoΨserá dita “transformação linear” se Ψ(αf+β) =αΨ( f ) +β para
todos reaisα eβ e toda imagem f. As transformações lineares podem ser
vi-sualizadas como retas no espaço( f (s), g(s)). A transformação será dita
“trans-formação linear por partes” se existe uma partição de K tal que para cada
elemento da partição a transformação é linear. Um exemplo de transformação linear por partes para imagens reais ég(s) =| f (s)|. O código a seguir mostra
como realizar as operações de mudança de escala porαe acréscimo do valor
β.
1 > alpha <- 0.3 2 > beta <- 0.5
3 > imagem1 <- imagem*alpha 4 > imagem2 <- imagem + beta 5 > imagem3 <- imagem*alpha + beta 6 > plot.imagematrix(imagem1) 7 > plot.imagematrix(imagem2) 8 > plot.imagematrix(imagem3)
No código acima as linhas 1 e 2 definem os valores deαeβ. As linhas 3, 4 e 5 realizam, respectivamente, as transformações de escala, de acréscimo de valor e as duas operações simultaneamente. A Figura 1.7 mostra o resultado das operações de mudança de escala e acréscimo de valor.
Como pode ser observado na figura, estas operações redundam em mu-danças de brilho e contraste em uma imagem, sendo que a determinação de
αe deβ fica por conta do usuário, e nem sempre é fácil achar um par de
va-lores capaz de produzir um resultado próximo do ideal. Para isso é necessário definir alguma métrica que guie a procura desses valores como, por exemplo, variância (que é uma medida de contraste) ou entropia (que é uma medida de informação.
1.4.3. Equalização do histograma
Uma operação pontual para melhoria do contraste que não depende de especificações do usuário, e que faz parte do repertório básico de transforma-ções de imagens, é a equalização do histograma. Intuitivamente, uma imagem com uma boa gradação de tons de cinza deverá ter aproximadamente a mesma quantidade de posições com cada valor possível deK. No outro extremo, tería-mos uma imagem com um único valor, isto é, sem nenhuma informação visual. Essa imagem com boa gradação de tons de cinza teria, em princípio, um histo-grama aproximadamente uniforme. . . e histohisto-gramas uniformes são típicos de eventos oriundos de variáveis aleatórias com distribuição uniforme.
Precisaremos de um par de definições e de um resultado importante de probabilidade para justificar o funcionamento da técnica de equalização do his-tograma.
Definição 1.4.1 (Distribuição uniforme em(0, 1)) A variável aleatória X se-gue a distribuição uniforme no intervalo(0, 1)se a sua função de distribuição acumulada é F(t) = 0 set≤ 0, t se0< t < 1, 1 set≥ 1. (2)
A distribuição uniforme é central em probabilidade e em estatística compu-tacional. Ela é a base dos algoritmos para geração de ocorrências de va-riáveis aleatórias com qualquer tipo de distribuição [Bustos and Frery 1992, Frery and Cribari-Neto 2005, Vieira et al. 2008], e pode ser generalizada para outros suportes distintos do intervalo(0, 1), inclusive para conjuntos discretos finitos.
Teorema 1.4.1 (Inversão) Seja a variável aleatória contínuaY, cuja distribui-ção é caracterizada pela fundistribui-ção de distribuidistribui-ção acumuladaFY. A variável
alea-tóriaU= FY(Y )possui distribuição uniforme em(0, 1).
Este teorema, cuja prova pode ser vista em [Bustos and Frery 1992], fornece o suporte teórico para a transformação que estamos procurando.
Com efeito, se o que queremos é uma imagem com um histograma o mais uniforme possível, podemos modelar os valores observados como sendo even-tos, isto é, ocorrências da variável aleatóriaY. Já que não conhecemosFY, a
função de distribuição acumulada que caracteriza a distribuição deY, podemos estimá-la. Para tanto, podemos lançar mão da função empírica.
Definição 1.4.2 (Função empírica) Sejamx1, . . . , xnocorrências das variáveis
aleatóriasX1, . . . , Xntodas com a mesma distribuição caracterizada pela função
de distribuição acumuladaF. A função empírica, dada por
b F(t) =1
n#{i : xi≤ t},
é um estimador deF.
As propriedades da função empírica bem como a sua relação com inferência robusta podem ser vistas no já clássico livro de [Huber 1981].
A definição 1.4.2 fornece meios para estimarF, que segundo o teorema 1.4.1 é a transformação que precisamos para obter a distribuição que desejamos e que foi estipulada na definição 1.4.1. Temos todos os ingredientes para resolver o nosso problema:
1. Calcular a função empírica da imagemf= (x1, . . . , xn), isto é, obterFb( f ).
2. Obter a imagem com o histograma equalizadog : S→ [0,1]aplicando
pontualmenteFba f, isto é,g(s) = bF( f (s)).
Em se tratando de imagens coloridas, esta transformação pode ser aplicada
banda a banda independentemente. Pelo fato deFbser apenas um estimador
deF, e pela natureza discreta dos dados, dificilmente a imagem transformadag
terá um histograma perfeitamente distribuído; de qualquer maneira, o resultado de aplicar esta transformação costuma ser notável.
O código abaixo mostra como realizar a operação de equalização no R.
1 > library(rimage) 2 > banda1 <- imagematrix(imagem[,,1],noclipping=T) 3 > banda2 <- imagematrix(imagem[,,2],noclipping=T) 4 > banda3 <- imagematrix(imagem[,,3],noclipping=T) 5 > banda1_equalizada <- equalize(banda1) 6 > banda2_equalizada <- equalize(banda2) 7 > banda3_equalizada <- equalize(banda3) 8 > imagem_equalizada <- array(dim=dim(imagem)) 9 > imagem_equalizada[,,1] <- banda1_equalizada 10 > imagem_equalizada[,,2] <- banda2_equalizada 11 > imagem_equalizada[,,3] <- banda3_equalizada 12 > imagem_equalizada <- imagematrix(imagem_equalizada) 13 > library(MASS) 14 > par(mfrow=c(2,2))
15 > plot.imagematrix(imagem) 16 > hist.scott(imagem,main="",xlab="Intensidades", 17 + ylab="Densidade") 18 > plot.imagematrix(imagem_equalizada) 19 > hist.scott(imagem_equalizada,main="",xlab="Intensidades" 20 + ,ylab="Densidade")
A biblioteca rimage fornece a função equalize que equaliza o
histo-grama de uma imagem. Neste caso a equalização é feita em cada uma das bandas da imagem (ver linhas 5 a 7) e depois é feita a composição das bandas
equalizadas para formar a imagem final (ver linhas 8 a 12). O comandopar
usado na linha 14 divide a janela gráfica do R em quatro regiões (duas lihas e duas colunas). Na primeira região é apresentada a imagem original (linha 15), na segunda o histograma desta imagem (linha 16), na terceira (linha 18) e na quarta (linha 19) a imagem equalizada e seu histograma respectivamente. No
comandohist.scottsão usados os parâmetrosxlabeylabque
especi-ficam os rótulos para os eixos x e y do gráfico respectivamente. A Figura 1.8 apresenta o resultado do código acima. Nela percebemos uma característica desta operação: as cores são alteradas (posto que a transformação é aplicada em cada banda, independentemente das outras) e eventuais ruídos são ampli-ficados.
A operação de binarização, também conhecida como limiarização em rela-ção ao valora, é uma operação linear por partes definida comog(s) =1
[a,∞)( f (s)).
Esta operação pode ser generalizada parakvalores comk−1limiares. Quando
aplicada a imagens coloridas, ela é conhecida como “posterização”. O código a seguir mostra como realizar a operação de binarização no R.
1 > banda1 <- imagematrix(imagem[,,1],type="grey") 2 > limiar <- 0.5 3 > ind1 <- which(banda1<limiar) 4 > ind2 <- which(banda1>=limiar) 5 > binaria <- banda1 6 > binaria[ind1] <- 0 7 > binaria[ind2] <- 1 8 > plot.imagematrix(binaria)
No código acima a linha 1 extrai uma das bandas da imagem colorida ori-ginal e a linha 2 define o limiar que será aplicado a imagem. Em seguida, as linhas 3 e 4 buscam os pixels na imagem que possuem valores menores do que o limiar e maiores ou iguais ao mesmo, respectivamente. As linhas 6 e 7 aplicam o limiar a imagem. A Figura 1.9 mostra o resultado da binarização.
De forma semelhante podemos fazer uma posterização na imagem co-lorida. Observe o código em R que segue.
2 > limiar2 <- 0.6
3 > ind1 <- which(imagem<limiar1)
4 > ind2 <- which(imagem>=limiar1 && imagem<limiar2) 5 > ind3 <- which(imagem>=limiar2) 6 > posterizada <- imagem 7 > posterizada[ind1] <- 0 8 > posterizada[ind2] <- 0.45 9 > posterizada[ind3] <- 1 10 > plot.imagematrix(posterizada)
A Figura 1.10 apresenta o resultado da posterização feita usando o código acima.
Lembramos que nos exemplos acima os limiares estão no intervalo [0, 1]
por causa da padronização interna que a biblioteca faz nos dados.
1.5. Filtragem linear e não linear
Diferentemente das operações pontuais, as operações de filtragem são
lo-cais, isto é, se gé o resultado de filtrar f, então o valor g(s) irá depender
tanto de f(s)quanto dos valores adotados por f na vizinhança des, isto é
g(s) =ϒ( f (s), f (t) : t ∈∂s). Evidentemente, as operações pontuais são opera-ções locais definidas sobre a vizinhança vazia. As operaopera-ções de filtragem, em geral, são mais poderosas do que as operações pontuais.
Existem inúmeras classificações para as operações de filtragem ou, mais simplesmente, para os filtros de imagens. Dentre as mais importantes podem ser mencionadas as seguintes:
• Filtragem linear (para todos∈ Sos operadoresϒs satisfazemϒs(α1f+
α2g) =α1ϒs( f ) +α2ϒs(g)para todo par de escalaresα1,α2e todo par de
imagens f, g) vs. filtragem não linear.
• Filtragem por mudança de domínio, quando se emprega uma
represen-tação da imagem diferente da original como, por exemplo, no domínio de Fourier, Wavelet etc. (ver, por exemplo, [Jain 1989]).
• Filtragem estatística, quando o substrato teórico para construir o filtro
decorre das propriedades estocásticas dos dados observados.
1.5.1. Filtros lineares
Uma propriedade interessante dos filtros lineares invariantes por translação é que os mesmos ficam unicamente definidos por uma “máscara”. A másca-ra de ladoℓ(ímpar) que define todo filtro linear invariante por translação é o conjunto de valores reaismmm= (mi j)com−(ℓ − 1)/2 ≤ i, j ≤ (ℓ − 1)/2tal que
g(x, y) =
∑
i, jf(x + i, y + j)mi j, (3)
para toda coordenada(x, y) na grade que esteja convenientemente distante
sua aplicação é denotada porg= f ∗ mmm[Gomes and Velho 1994]. Embora a máscara tenha sido definida com suporte quadrado, qualquer tipo de suporte pode ser acomodado em um quadrado suficientemente grande preenchendo com zeros onde corresponder.
A filtragem por convolução é muito usada na prática devido à sua conexão com a filtragem no domínio de Fourier e pelo custo computacional relativa-mente baixo que ela demanda, já que estas operações consistem em realizar médias ponderadas dos dados de entrada (no domínio da imagem) ou, equiva-lentemente, produtos ponto a ponto no domínio de Fourier.
Sempre que desejável e possível, será utilizada uma notação compacta omitindo a coordenada, isto é, se a imagemgé o resultado da operação pontual ϒsobre cada valor f(s), então ao invés de escreverg= (g(s))s∈S= (ϒ( f (s)))s∈S será escritog=ϒ( f ).
1.5.1.1. Filtro gaussiano
O filtro gaussiano é um filtro linear que é normalmente usado para suavizar imagens, removendo detalhes e ruído. Este filtro é bastante similar ao filtro da média neste sentido, porém usa uma máscara diferente que representa o formato de uma distribuição gaussiana. A densidade que caracteriza a distri-buição gaussiana bidimensional de média nula possui a forma:
G(x, y) = 1 2πσ2exp n −x 2+ y2 2σ2 o , (4) comσ> 0e(x, y) ∈R 2.
Para construir uma máscara de convolução para este filtro, basta produzir uma aproximação discreta para a função gaussiana. Uma máscara gaussiana bidimensional é definida pelo seu tamanho e desvio padrão. No código em
R abaixo, são construídas três máscaras gaussianas de tamanho11× 11
va-riando o valor deσ. Estas máscaras são aplicadas a uma imagem à qual foi
adicionado ruído gaussiano e, para tanto, faremos uso da bibliotecabiOps. A partir da linha 1 definimos as funções que auxiliam na construção das
máscaras gaussianas: meshgrid (que define os valores da grade sobre a
qual a máscara é montada), egaussian_mask(que efetivamente calcula os
valores da máscara, começando na linha 7). As linhas 16 e 17 padronizam a matriz de convolução de tal forma que a soma dos seus elementos seja unitária. Isto é feito para manter constante o brilho médio da imagem após a filtragem.
1 > meshgrid <- function(x,y){ 2 ignore.arg2 <- function(x,y) {x} 3 list(x=t(outer(x,y,FUN=ignore.arg2)),y=outer(y,x, 4 + FUN=ignore.arg2)) 5 } 6
7 > gaussian_mask <- function(tamanho,sigma){ 8 tam <- (tamanho-1)/2 9 std <- sigma 10 mesh <- meshgrid(-tam:tam,-tam:tam) 11 x <- mesh$x 12 y <- mesh$y 13 arg <- -(x*x + y*y)/(2*std*std) 14 h <- exp(arg) 15 sumh <- sum(h) 16 if (sumh != 0) 17 h <- h/sumh 18 }
A listagem a seguir calcula três matrizes de convolução gaussiana de
tama-nho5× 5com diferentes valores do parâmetroσ. As máscaras assim criadas
são mostradas nas equações (5), (6) e (7).
1 > mascara1 = gaussian_mask(5, 1) 2 > mascara2 = gaussian_mask(5, 2) 3 > mascara10 = gaussian_mask(5, 10) m1 = 0.003 0.013 0.022 0.013 0.003 0.013 0.060 0.098 0.060 0.013 0.022 0.098 0.162 0.098 0.022 0.013 0.060 0.098 0.060 0.013 0.003 0.013 0.022 0.013 0.003 , (5) m2 = 0.023 0.034 0.038 0.034 0.023 0.034 0.049 0.056 0.049 0.034 0.038 0.056 0.063 0.056 0.038 0.034 0.049 0.056 0.049 0.034 0.023 0.034 0.038 0.034 0.023 , (6) m10 = 0.039 0.040 0.040 0.040 0.039 0.040 0.040 0.041 0.040 0.040 0.040 0.041 0.041 0.041 0.040 0.040 0.040 0.041 0.040 0.040 0.039 0.040 0.040 0.040 0.039 . (7)
Nas equações (5), (6) e (7) constatamos que quanto maior o valor do
espa-lhamento,σ, menor será a diferença entre os valores nas máscaras. A razão
entre os valores máximo e mínimo na máscara comσ= 1é0.162/0.003 ≈ 55,
enquanto que na máscara comσ = 10é 0.041/0.039 ≈ 1. Assim sendo, na
pixel periférico, enquanto na segunda máscara todos os pixels terão aproxima-damente a mesma influência no resultado final aumentando, assim, o efeito do borramento. Esse efeito fica manifesto nos exemplos a seguir.
A filtragem por convolução pode ser feita utilizando a funçãoimgConvolve
do pacotebiOps, tal como mostrado a seguir.
1 > sertanejo = readJpeg("sertanejo.jpg")
2 > sertanejo_gauss = imgGaussianNoise(sertanejo, 0, 1000) 3 > filtrada1 = imgConvolve(sertanejo_gauss, mascara1) 4 > filtrada10 = imgConvolve(sertanejo_gauss, mascara10)
A linha 2 acima soma eventos de variáveis aleatórias gaussianas de média
nula e variância1000a cada valor de cada banda em cada coordenada da
ima-gem original (mostrada na Figura 1.11(a)). O resultado dessa contaminação é mostrado na Figura 1.11(b) A linha 3 e a seguinte calculam as imagens filtradas
por convolução com as máscaras definidas acima comσ= 1e comσ= 10.
A Figura 1.11 apresenta o resultado da filtragem usando duas das três más-caras produzidas pelo código. Nessa imagem percebemos que a convolução por uma máscara gaussiana reduz efetivamente o ruído, mas quanto mais in-tensa essa redução maior será o borramento introduzido na imagem.
1.5.1.2. Filtro laplaciano
O filtro laplaciano é um filtro passa-altas caracterizado por uma máscara
de tamanhoℓ × ℓque aproxima no domínio discreto a operação de derivação.
O valor central da máscara costuma ser positivo e cercado de valores nega-tivos nas direções norte-sul e leste-oeste e, geralmente, a soma dos pesos é zero. Com a aplicação deste filtro há um aumento de contraste na imagem filtrada, o que introduz, muitas vezes, bordas artificiais que podem confundir o observador. A Figura 1.12 mostra um exemplo de aplicação do filtro laplaciano.
NoReste filtro é implementado pela funçãolaplaciancomo mostrado
no código abaixo. 1 > library(rimage) 2 > imagem 3 size: 458 x 372 4 type: rgb 5 > plot.imagematrix(imagem) 6 > laplaciano <- normalize(laplacian(imagem)) 7 > plot.imagematrix(laplaciano)
O filtro laplaciano, por ser um filtro que possue a propriedade de detectar bordas, pode ser utilizado para ajudar na segmentação de imagens baseada
em bordas, que busca separar áreas homogêneas (segmentos) pela identifica-ção das fronteiras entre elas.
1.5.2. Filtros não lineares
Esta família de filtros é maior do que a dos filtros lineares. No que segue veremos apenas dois membros dela: a mediana (que é um caso simples de filtro morfológico) e o filtro de Nagao-Matsuyama, que é um caso particular de filtro adaptativo. Para mais sobre morfologia matemática recomendamos os textos [Banon 2000, Banon and Barrera 1994].
1.5.2.1. Filtro da mediana
Alguns filtros, como o da média por exemplo, possuem limitações ao re-mover ruídos em uma imagem visto que os mesmos não preservam bordas e detalhes finos da imagem. Para contornar este problema, uma técnica al-ternativa é o filtro da mediana, que é um filtro não convolucional e não linear cujo efeito é similar ao dos filtros passa-baixas. Este filtro calcula o novo nível de cinza como o mediano daqueles observados no domínio da máscara. A mediana de uma máscarammmde ladoℓé dada por
med(mmm) =
m(ℓ2+1)/2:ℓ2, seℓ2for ímpar;
(mℓ2/2:ℓ2+ mℓ2/2+1:ℓ2)/2, caso contrário,
ondemmm= (m1:ℓ2, . . . , mℓ2:ℓ2)é o vetormmmordenado de menor para maior.
Com a aplicação deste filtro é possível eliminar, através de uma computa-ção simples e rápida, informações indesejáveis que corrompem a qualidade da imagem e, ao mesmo tempo, preservar as bordas na imagem. Devido a essa habilidade, o filtro da mediana é freqüentemente escolhido para suavizar ima-gens que apresentam ruídos conhecidos como “sal-e-pimenta”. O efeito visual do ruído “sal-e-pimenta”, ou Speckle, proporciona uma textura granulosa que pode dificultar a interpretação das imagens [Sinha and Hong 1990].
Uma desvantagem deste filtro é a de ser menos eficiente do que o da mé-dia para combater o ruído gaussiano aditivo (sinal de ruído com distribuição gaussiana).
NoR, o pacotebiOpsfornece a funçãoimgBlockMedianFilterque
im-plementa este filtro tendo como parâmetros a imagem a ser filtrada e o tama-nho da máscara a ser utilizada. O código abaixo mostra como usar esta função para filtrar a imagem que estamos utilizando com ruído “sal-e-pimenta”.
1 > library(biOps) 2 > imagem_ruido <- imgSaltPepperNoise(imagem,10) 3 > imagem_ruido 4 size: 458 x 372 5 type: rgb 6 > plot.imagematrix(imagem_ruido)