CHAPTER ONE - quatinetwork.files.wordpress.com · cifra pode ser conhecida, mas não a chave; assim...

31
/ EDOA / 1 CHAPTER ONE Aula 16 CHAPTER TWO Criptografia O envio e o recebimento de informações sigilosas é uma necessidade antiga, que existe há centenas de anos. Com o surgimento da Internet e de sua consequente facilidade de transmitir dados, a criptografia tornou-se uma ferramenta fundamental para permitir que apenas o emissor e o receptor tenham acesso seguro à informação trabalhada. O termo criptografia surgiu da fusão das palavras gregas "kryptós" e "gráphein", que significam "oculto" e "escrever", respectivamente. Trata-se de um conjunto de conceitos e técnicas que visa codificar uma informação de forma que somente o emissor e o receptor possam acessá-la, evitando que um intruso consiga interpretá-la. Para isso, uma série de técnicas são usadas. Na computação, as técnicas mais conhecidas envolvem o conceito de chaves, as chamadas chaves criptográficas. Trata-se de um conjunto de bits baseado em um determinado algoritmo capaz de codificar e de decodificar informações. Se o receptor da mensagem usar uma chave incompatível com a chave do emissor, não conseguirá extrair a informação. O primeiro lugar natural a pensar no uso de criptografia é nos cenários de guerra, para comunicar estratégias de movimentação a tropas distantes, espionagem, etc. Se o inimigo intercepta essa comunicação, principalmente sem o primeiro saber, ganha a guerra. Por isso quem primeiro estudou técnicas de criptografia foram os militares, governos e instituições de

Transcript of CHAPTER ONE - quatinetwork.files.wordpress.com · cifra pode ser conhecida, mas não a chave; assim...

/ EDOA / 1

CHAPTER ONE

Aula 16

CHAPTER TWO

CriptografiaO envio e o recebimento de informações sigilosas é uma necessidade antiga, que existe há centenas de anos. Com o surgimento da Internet e de sua consequente facilidade de transmitir dados, a criptografia tornou-se uma ferramenta fundamental para permitir que apenas o emissor e o receptor tenham acesso seguro à informação trabalhada.

O termo criptografia surgiu da fusão das palavras gregas "kryptós" e "gráphein", que significam "oculto" e "escrever", respectivamente. Trata-se de um conjunto de conceitos e técnicas que visa codificar uma informação de forma que somente o emissor e o receptor possam acessá-la, evitando que um intruso consiga interpretá-la. Para isso, uma série de técnicas são usadas.

Na computação, as técnicas mais conhecidas envolvem o conceito de chaves, as chamadas chaves criptográficas. Trata-se de um conjunto de bits baseado em um determinado algoritmo capaz de codificar e de decodificar informações. Se o receptor da mensagem usar uma chave incompatível com a chave do emissor, não conseguirá extrair a informação.

O primeiro lugar natural a pensar no uso de criptografia é nos cenários de guerra, para comunicar estratégias de movimentação a tropas distantes, espionagem, etc. Se o inimigo intercepta essa comunicação, principalmente sem o primeiro saber, ganha a guerra. Por isso quem primeiro estudou técnicas de criptografia foram os militares, governos e instituições de

/ EDOA / 2

pesquisas secretas. Focavam em duas coisas: como criptografar melhor e como descriptografar as mensagens do inimigo (criptoanálise).

Os primeiros métodos criptográficos existentes usavam apenas um algoritmo de codificação. Assim, bastava que o receptor da informação conhecesse esse algoritmo para poder extraí-la. No entanto, se um intruso tivesse posse desse algoritmo, também poderia efetuar um processo de decifragem, caso capturasse os dados criptografados.

Criptografia só pode ser considerada como tal se 4 princípios básicos forem seguidos e oferecidos: confidencialidade, autenticação, integridade da informação e não repudiabilidades.

• confidencialidade da mensagem: só o destinatário autorizado deve ser capaz de extrair o conteúdo da mensagem da sua forma cifrada. Além disso, a obtenção de informação sobre o conteúdo da mensagem (como uma distribuição estatística de certos caracteres) não deve ser possível, uma vez que, se o for, torna mais fácil a análise criptográfica.

• integridade da mensagem: o destinatário deverá ser capaz de determinar se a mensagem foi alterada durante a transmissão.

• autenticação do remetente: o destinatário deverá ser capaz de identificar o remetente e verificar que foi mesmo ele quem enviou a mensagem.

• não-repúdio ou irretratabilidade do emissor: não deverá ser possível ao emissor negar a autoria da mensagem.

Nem todos os sistemas ou algoritmos criptográficos são utilizados para atingir todos os objetivos listados acima. Normalmente, existem algoritmos específicos para cada uma destas funções. Mesmo em sistemas criptográficos bem concebidos, bem implementados e usados adequadamente, alguns dos objetivos acima não são práticos (ou mesmo desejáveis) em algumas circunstâncias. Por exemplo, o remetente de uma mensagem pode querer permanecer anônimo, ou o sistema pode destinar-se a um ambiente com recursos computacionais limitados.

Cifras e códigos

Há duas maneiras básicas de se criptografar mensagens: através de códigos ou através de cifras. A primeira delas procura esconder o conteúdo da mensagem através de códigos predefinidos entre as partes envolvidas na troca de mensagens. Imagine o exemplo onde em uma guerra, um batalhão tem duas opções de ação contra o inimigo: atacar pelo lado direito do inimigo ou não atacar. A decisão depende da avaliação de um general posicionado em um local distante da posição de ataque deste batalhão. É acertado que se for enviado uma mensagem com a palavra "calhau", o

/ EDOA / 3

exército deverá atacar pela direita; se for enviada uma mensagem com a palavra "araçagy", não deve haver ataque. Com isso, mesmo que a mensagem caia em mãos inimigas, nada terá significado coerente. O problema deste tipo de solução é que com o uso constante dos códigos, eles são facilmente decifrados. Outro problema é que só é possível o envio de mensagens predefinidas. Por exemplo: não há como o general mandar seu exército atacar pela esquerda.

O outro método usado para criptografar mensagens é a cifra, técnica na qual o conteúdo da mensagem é cifrado através da mistura e/ou substituição das letras da mensagem original. A mensagem é decifrada fazendo-se o processo inverso ao ciframento.

Na linguagem não-técnica, um código secreto é o mesmo que uma cifra. Porém, na linguagem especializada os dois conceitos são distintos. Um código funciona manipulando o significado, normalmente pela substituição simples de palavras ou frases. Uma cifra, ao contrário, trabalha na representação da mensagem (letras, grupos de letras ou, atualmente, bits).

Por exemplo, um código seria substituir a frase "Atacar imediatamente" por "Mickey Mouse". Uma cifra seria substituir essa frase por "sysvst ozrfosyszrmyr". No Dia D, por exemplo, as praias de desembarque não eram conhecidas pelo seu nome próprio, mas pelos seus códigos (Omaha, Juno, etc.).

Basicamente, códigos não envolvem chave criptográfica, apenas tabelas de substituição ou mecanismos semelhantes. Códigos podem ser então encarados como cifras cuja a chave é o próprio conhecimento do mecanismo de funcionamento da cifra.

A cifra é um ou mais algoritmos que cifram e decifram um texto. A operação do algoritmo costuma ter como parâmetro uma chave criptográfica. Tal parâmetro costuma ser secreto (conhecido somente pelos comunicantes). A cifra pode ser conhecida, mas não a chave; assim como se entende o mecanismo de uma fechadura comum, mas não se pode abrir a porta sem uma chave real.

A principal vantagem das cifras em relação aos códigos é a não limitação das possíveis mensagens a serem enviadas, além de ser tornarem mais difíceis de serem decifradas.

As cifras são implementadas através de algoritmos associados a chaves, longas seqüências de números e/ou letras que determinarão o formato do texto cifrado.

Os principais tipos de cifras são:

• Cifras de Transposição: método pelo qual o conteúdo da

/ EDOA / 4

mensagem é o mesmo, porém com as letras postas em ordem diferente. Por exemplo, pode-se cifrar a palavra "CARRO" e escrevê-la "ORARC";

• Cifras de Substituição: neste tipo de cifra, troca-se cada letra ou grupo de letras da mensagem de acordo com uma tabela de substituição. As cifras de substituições podem ser subdivididas em:

• Cifra de substituição simples, monoalfabética ou Cifra de César: é o tipo de cifra na qual cada letra da mensagem é substituída por outra, de acordo com uma tabela baseada geralmente num deslocamento da letra original dentro do alfabeto. Ela é também chamada Cifra de César devido ao seu uso pelo imperador romano quando do envio de mensagens secretas. César quando queria enviar mensagens secretas a determinadas pessoas, substituía cada letra "A" de sua mensagem original pela letra "D", o "B" pelo "E", etc., ou seja, cada letra pela que estava três posições a frente no alfabeto.

• Cifra de substituição polialfabética: consiste em utilizar várias cifras de substituição simples, em que as letras da mensagem são rodadas seguidamente, porém com valores diferentes.

• Cifra de substituição de polígramos: utiliza um grupo de caracteres ao invés de um único caractere individual para a substituição da mensagem. Por exemplo, "ABA" pode corresponder a "MÃE" e "ABB" corresponder a "JKI".

• Cifra de substituição por deslocamento: ao contrário da cifra de César, não usa um valor fixo para a substituição de todas as letras. Cada letra tem um valor associado para a rotação através de um critério. Por exemplo, cifrar a palavra "CARRO" utilizando o critério de rotação "023", seria substituir "C" pela letra que está 0(zero) posições a frente no alfabeto, o "A" pela letra que está 2 (duas) posições a frente, e assim por diante, repetindo-se o critério se necessário.

Chaves

Uma chave criptográfica é um valor secreto que modifica um algoritmo de encriptação. A fechadura da porta da frente da sua casa tem uma série de pinos. Cada um desses pinos possui múltiplas posições possíveis. Quando alguém põe a chave na fechadura, cada um dos pinos é movido para uma posição específica. Se as posições ditadas pela chave são as que a fechadura precisa para ser aberta, ela abre, caso contrário, não.

Com o uso de chaves, um emissor pode usar o mesmo algoritmo (o mesmo

/ EDOA / 5

método) para vários receptores. Basta que cada um receba uma chave diferente. Além disso, caso um receptor perca ou exponha determinada chave, é possível trocá-la, mantendo-se o mesmo algoritmo.

As chaves podem ser conjuntos de vários bits (de 64 bits, de 128 bits, etc.). Esses valores expressam o tamanho de uma determinada chave. Quanto mais bits forem utilizados, mais segura será a criptografia.

Chaves simétricas e assimétricas

Há dois tipos de chaves criptográficas: chaves simétricas e chaves assimétricas.

Chave simétrica

Esse é um tipo de chave mais simples, onde o emissor e o receptor fazem uso da mesma chave, isto é, uma única chave é usada na codificação e na decodificação da informação. A Chave Simétrica é uma seqüencia de bits e é ela que define o nível de segurança da comunicação. Ela deve ser sempre secreta. Chama-se simétrica porque todos os interessados em se comunicar devem ter uma cópia da mesma chave.

Como exemplo de seu funcionamento, se a Paula quer enviar uma mensagem secreta para Tatiana, ela deve fazer isso:

Mensagem + ChaveSimétrica = MensagemCriptografada

/ EDOA / 6

Então MensagemCriptografada é enviada para Tatiana por uma rede aberta, que para lê-la terá que fazer o seguinte:

MensagemCriptografada + ChaveSimétrica = Mensagem

Uma analogia a essas equações seria como se ambas trocassem caixas que abrem e fecham com uma chave (a chave simétrica), que contém cartas secretas. Para a Tatiana abrir a caixa da Paula, terá que usar uma cópia da chave que a última usou para fecha-la.

O que representamos pela soma (+) é na verdade o algoritmo de cifragem (ou o mecanismo da fechadura) que criptografa e descriptografa a mensagem. Hoje em dia, esses algoritmos tem geralmente seu código fonte aberto, e isso ajudou-os a se tornarem mais seguros ainda, pois foram limpos e revisados ao longo dos anos por muitas pessoas ao redor do mundo.

Existem vários algoritmos que usam chaves simétricas, como o DES, o IDEA, e o RC:

• DES (Data Encryption Standard): criado pela IBM em 1977, faz uso de chaves de 56 bits. Isso corresponde a 72 quatrilhões de combinações. É um valor absurdamente alto, mas não para um computador potente. Em 1997, esse algoritmo foi quebrado por técnicas de "força bruta" (tentativa e erro) em um desafio promovido na internet;

• IDEA (International Data Encryption Algorithm): criado em 1991 por James Massey e Xuejia Lai, o IDEA é um algoritmo que faz uso de chaves de 128 bits e que tem uma estrutura semelhante ao DES. Sua implementação em software é mais fácil do que a implementação deste último;

• RC (Ron's Code ou Rivest Cipher): criado por Ron Rivest na empresa RSA Data Security, esse algoritmo é muito utilizado em e-mails e faz uso de chaves que vão de 8 a 1024 bits. Possui várias versões: RC2, RC4, RC5 e RC6. Essencialmente, cada versão difere da outra por trabalhar com chaves maiores.

• AES (Advanced Encryption Standard) - que é baseado no DES;

• 3DES: Baseia-se na utilização três vezes seguidas do DES com chaves diferentes.

O uso de chaves simétricas tem algumas desvantagens, fazendo com que sua utilização não seja adequada em situações onde a informação é muito valiosa. O maior problema da criptografia de chave simétrica é como o remetente envia a chave secreta ao destinatário através de uma rede aberta (e teoricamente insegura). Se um intruso descobri-la, poderá ler todas as mensagens trocadas. Mais ainda, comprometerá a comunicação entre todo o

/ EDOA / 7

conjunto de pessoas que confiavam nessa chave. Para começar, é necessário usar uma grande quantidade de chaves caso muitas pessoas ou entidades estejam envolvidas. Ainda, há o fato de que tanto o emissor quanto o receptor precisam conhecer a mesma chave.

Chave assimétrica

Em 1976, Whitfield Diffie e Martin Hellman propuseram os conceitos da criptografia de chave pública também conhecida por criptografia por par de chaves ou de chave assimétrica. Eles descobriram fórmulas matemáticas que permitem que cada usuário tenha um par de chaves de criptografia matematicamente relacionadas, uma privada e outra pública, sendo a última, como o próprio nome diz, publicamente disponível para qualquer pessoa. Essas fórmulas têm a característica de o que for criptografado com uma chave, só pode ser descriptografado com seu par.

Então, no nosso exemplo, Paula agora enviaria uma mensagem para Tatiana da seguinte maneira:

Mensagem + ChavePública(Tatiana) = MensagemCriptografada

E Tatiana leria a mensagem assim:

MensagemCriptografada + ChavePrivada(Tatiana) = Mensagem

E Tatiana responderia para Paula da mesma forma:

Resposta + ChavePública(Paula) = RespostaCriptografada

/ EDOA / 8

Ou seja, uma mensagem criptografada com a chave pública de uma, só pode ser descriptografada com a chave privada da mesma, então a primeira pode ser livremente disponibilizada na Internet. E se a chave privada da Paula for roubada, somente as mensagens para a Paula estariam comprometidas.

O cifrador de chave pública tido como mais confiável é o RSA (iniciais de Rivest, Shamir e Adleman, seus criadores).

Criptografia assimétrica permitiu ainda outras inovações revolucionárias: se Tatiana quer publicar um documento e garantir sua autenticidade, pode fazer:

Documento + ChavePrivada(Tatiana) = DocumentoCriptografado

Se um leitor conseguir descriptografar este documento com a chave pública da Tatiana significa que ele foi criptografado com a chave privada da Tatiana, que somente ela tem a posse, o que significa que somente a Tatiana poderia te-lo publicado. Nasce assim a assinatura digital.

Entre os algoritmos que usam chaves assimétricas, o mais conhecido é o RSA (Rivest, Shamir and Adleman). Criado em 1977 por Ron Rivest, Adi Shamir e Len Adleman nos laboratórios do MIT (Massachusetts Institute of Technology), é um dos algoritmos de chave assimétrica mais usados. Nele, números primos são utilizados da seguinte forma: dois números primos são multiplicados para se obter um terceiro valor. Porém, descobrir os dois primeiros números a partir do terceiro (ou seja, fazer uma fatoração) é muito trabalhoso. Se dois números primos grandes (realmente grandes) forem usados na multiplicação, será necessário usar muito processamento para descobrí-los, tornando essa tarefa praticamente inviável. Basicamente, a chave privada no RSA são os números multiplicados e a chave pública é o valor obtido.

Outros algoritmos:

• DSA (Digital Signature Algorithm);

• Schnorr (praticamente usado apenas em assinaturas digitais);

• Diffie-Hellman.

• Curvas elípticas

• El Gamal

Considerações finais

• Nenhum algoritmo é ideal para todas as situações. Porém, os seguintes princípios gerais se aplicam:

/ EDOA / 9

• A criptografia segura geralmente consome mais recursos da CPU que criptografia menos segura.

• As chaves extensas geralmente produzem uma criptografia mais segura que as chaves mais curtas.

• A criptografia assimétrica é mais segura que a criptografia simétrica, que usa o mesmo comprimento de chave mas é relativamente mais lenta.

• Codificações em bloco com chaves extensas são mais seguras que codificações em fluxo.

• Senhas longas e complexas são mais seguras que senhas curtas.

• Se você estiver criptografando muitos dados, deve criptografá-los usando uma chave simétrica e criptografar a chave simétrica com uma chave assimétrica.

• Dados criptografados não podem ser compactados, mas dados compactados podem ser criptografados. Se você usar compactação, deverá compactar os dados antes de criptografá-los.

CHAPTER THREE

Compiladores e interpretadoresUm compilador é um programa de sistema que traduz um programa descrito em uma linguagem de alto nível para um programa equivalente em código de máquina para um processador. Em geral, um compilador não produz diretamente o código de máquina mas sim um programa em linguagem simbólica (assembly) semanticamente equivalente ao programa em linguagem de alto nível. O programa em linguagem simbólica é então traduzido para o programa em linguagem de máquina através de montadores.

Para desempenhar suas tarefas, um compilador deve executar dois tipos de atividade. A primeira atividade é a análise do código fonte, onde a estrutura e significado do programa de alto nível são reconhecidos. A segunda atividade é a síntese do programa equivalente em linguagem simbólica. Embora conceitualmente seja possível executar toda a análise e apenas então iniciar a síntese, em geral estas duas atividades ocorrem praticamente em paralelo.

/ EDOA / 10

Para apresentar um exemplo das atividades que um compilador deve desempenhar, considere o seguinte trecho de um programa em C:

Para o compilador, este segmento nada mais é do que uma seqüência de caracteres em um arquivo texto. O primeiro passo da análise é reconhecer que agrupamentos de caracteres têm significado para o programa -- por exemplo, saber que int é uma palavra-chave da linguagem e que a e b serão elementos individuais neste programa. Posteriormente, o compilador deve reconhecer que a seqüência int a corresponde a uma declaração de uma variável inteira cujo identificador recebeu o nome a.

As regras de formação de elementos e frases válidas de uma linguagem são expressos na gramática da linguagem. O processo de reconhecer os comandos de uma gramática é conhecido como reconhecimento de sentenças.

A aplicação do conceito de reconhecimento de sentenças para agrupar as seqüências de caracteres em ``palavras'' é a análise léxica. Os elementos reconhecidos nessa primeira etapa da compilação são denominados itens léxicos ou tokens. Para o exemplo acima, a seguinte lista de tokens seria reconhecida pelo compilador:

No. token Valor token No. token Valor token

1 int 14 20

2 a 15 ;

3 , 16 valor

4 b 17 =

5 , 18 a

6 valor 19 *

7 ; 20 (

8 a 21 b

9 = 22 +

10 10 23 20

11 ; 24 )

12 b 25 ;

13 =    

/ EDOA / 11

Para desempenhar a análise léxica, o compilador deve ter conhecimento de quais são os tokens válidos da linguagem, assim como suas palavras chaves e regras para formação de identificadores. Por exemplo, a declaração

int 1var;

deve resultar em erro nessa etapa da análise, pois 1var não é uma constante ou identificador válido. Se um programa contendo esta declaração fosse compilado usando o compilador gcc, por exemplo, a esta linha seria associado o erro ``nondigits in number and not hexadecimal'', mostrando que o compilador esperava que 1var fosse um número, já que inicia com um algarismo. A análise léxica será estudada na Seção 3.2.

Resumindo, sobre o analisador léxico:

• É a interface entre o programa fonte e o compilador

• Funções básicas:

• Ler o programa fonte

• Agrupar caracteres em itens léxicos (tokens)

• Identificadores

• Palavras Reservadas

• Constantes (numéricas e literais)

• Símbolos especiais (simples, duplos, ...)

• Ignorar elementos sem valor sintático

• Espaços em brancos, comentários e caracteres de controle

• Detectar e diagnosticar erros léxicos

• Símbolos inválidos, elementos mal formados

O segundo passo da análise desempenhado pelo compilador é a análise sintática, onde a estrutura do programa é analisada a partir do agrupamento de tokens. Nesta etapa, o compilador deverá reconhecer que a seqüência de tokens obtida do segmento de código apresentado no início da seção corresponde a quatro comandos, sendo o primeiro deles um comando de declaração de variáveis e os três restantes de atribuição. Adicionalmente, deverá reconhecer que o último dos comandos de atribuição contém subexpressões que deverão ser avaliadas para completar a atribuição na execução do programa.

/ EDOA / 12

Para que este passo possa ser realizado pelo compilador, ele deve ter conhecimento de como são formados os comandos válidos da linguagem. Por exemplo, um comando de declaração de variáveis como

int int x;

deve resultar em erro nesta etapa -- o compilador gcc indicaria o erro com uma mensagem ``two or more data types in declaration of `x' ''.

Após realizada a análise, na fase de síntese o compilador deverá gerar o código em linguagem simbólica equivalente ao código analisado. Por exemplo, para um compilador C gerando código para a linguagem simbólica de um processador 68000, os seguintes mapeamentos poderiam estar preparados:

C Assembly 68K

int V V DS.W 1

L + R   MOVE.W L,D1

    ADD.W R,D1

    MOVE.W D1,VTMP

L * R   MOVE.W L,D1

    MULS.W R,D1

    MOVE.W D1,VTMP

L = R   MOVE.W R,D1

    MOVE.W D1,L

onde L e R seriam substituídos pelo compilador pelas variáveis usadas internamente na síntese do programa.

Na verdade, compiladores não trabalham diretamente com o código de um processador específico. Normalmente o código gerado nessa fase é expresso em alguma linguagem intermediária, próxima do assembly mas independente de processador, que depois pode ser mapeada para diversos processadores distintos.

/ EDOA / 13

Geração de código intermediário:

while i < 100 do i := j + i;

/ EDOA / 14

Estrutura de um compilador

A interação entre os algoritmos, usados nas fases de um compilador, e as estruturas de dados, que dão suporte a essas fases, é bastante forte.

O escritor do compilador tenta implementar esses algoritmos de forma tão eficiente quanto possível, sem incorrer em muita complexidade adicional.

Idealmente, um compilador deveria ser capaz de compilar um programa em tempo proporcional ao tamanho do programa, ou seja, em tempo O(n), em que n mede o tamanho do programa (usualmente, o número de caracteres).

Marcas

Quando um sistema de varredura armazena caracteres em uma marca, ele, em geral, representa a marca simbolicamente, ou seja, como um valor de um tipo de dado enumerado que representa o conjunto de marcas da linguagem-fonte.

Por vezes, é também necessário preservar a cadeia de caracteres ou outras informações derivadas dela, como, por exemplo, o nome associado a uma marca identificadora ou o valor de uma marca numérica.

Na maioria das linguagens, o sistema de varredura precisa apenas gerar uma

/ EDOA / 15

marca por vez.

Nesse caso, uma única variável global pode ser usada para preservar a informação da marca.

Em outros casos (mais notavelmente em Fortran), pode ser necessária uma matriz de marcas.

A árvore sintática

Se o analisador sintático gera uma árvore sintática, ela é normalmente construída como uma estrutura padrão baseada em ponteiros, que é alocada dinamicamente à medida que a análise sintática ocorre.

A árvore toda pode ser armazenada como uma única variável que aponta para o nó-raiz.

Cada nó na estrutura é um registro cujos campos representam a informação coletada pelo analisador sintático e, posteriormente, pelo analisador semântico.

Por exemplo, o tipo de dados de uma expressão pode ser um campo no nó da árvore sintática para aquela expressão.

Por vezes, para economizar espaço, esses campos são também alocados dinamicamente, ou então armazenados em outras estruturas de dados, como a tabela de símbolos, que permitem a alocação e a liberação seletivas.

Cada nó da árvore sintática pode requerer o armazenamento de diferentes atributos, dependendo do tipo de estrutura da linguagem representada (por exemplo, um nó de expressão tem requisitos diferentes de um nó de declaração).

Nesse caso, cada nó na árvore sintática pode ser representado por um registro variante, com cada tipo de nó contendo apenas as informações necessárias para cada caso.

A tabela de símbolos

Essa estrutura de dados guarda informações de identificadores: funções, variáveis, constantes e tipos de dados.

A tabela de símbolos interage com quase todas as fases do compilador: varredura, análise sintática e análise semântica.

O analisador semântico adiciona tipos de dados e outras informações; e as fases de otimização e geração de código utilizam a informação da tabela de símbolos para efetuar escolhas apropriadas para o código-objeto.

/ EDOA / 16

Corno a tabela de símbolos é acessada, com bastante freqüência, a inserção, a eliminação e o acesso precisam ser eficientes, preferivelmente de tempo constante. Uma estrutura de dados padrão para isso é a tabela de hashing, embora diversas estruturas de árvores possam ser utilizadas. Por vezes, diversas tabelas são utilizadas e mantidas em uma lista ou pilha.

A tabela de literais

Inserção eficiente e acesso rápido são também essenciais para a tabela de literais, que armazena constantes e cadeias de caracteres usados em um programa.

Entretanto, uma tabela de literais não precisa permitir eliminações, pois seus dados se aplicam globalmente ao programa, e uma constante ou cadeia de caracteres aparece apenas uma vez nessa tabela.

A tabela de literais é importante para reduzir o tamanho de um programa na memória, pois permite o reaproveitamento das constantes e das cadeias de caracteres.

Ela também é usada pelo gerador de código para construir endereços simbólicos para literais e para fornecer definições de dados ao arquivo de código-fonte.

Códido intermediário

Dependendo do tipo de código intermediário (por exemplo, código de três endereços e P-código) e das otimizações efetuadas, esse código pode ser armazenado como uma matriz de cadeias de caracteres, um arquivo-texto temporário ou uma lista ligada de estruturas.

Arquivos temporários

Antigamente, os computadores não possuíam memória suficiente para que um programa inteiro fosse mantido na memória durante a compilação.

Esse problema era resolvido com arquivos temporários que preservavam os resultados dos passos intermediários de tradução ou pela compilação "sob demanda", ou seja, pelo armazenamento apenas de informação das partes anteriores do programa-fonte que possibilitavam a continuação da tradução.

Restrições de memória são agora um problema muito menor, e é possível manter na memória uma unidade completa de compilação, especialmente se a linguagem contar com compilação separada.

Ainda assim, os compiladores ocasionalmente consideram útil gerar arquivos intermediários durante alguns dos passos de processamento.

/ EDOA / 17

CHAPTER FOUR

Compressão de dadosÉ impossível pensarmos nos dias de hoje num mundo computacional sem pensarmos nas formas de armazenamento de dados. Isto implica articularmos todos os aspectos do armazenamento. Desde como gravaremos fisicamente, como transmitiremos estes dados de formas mais eficientes até em formas de compactação destes dados.

A compactação consiste basicamente numa forma de armazenamento reduzido de um conjunto de dados.

A compressão de dados é o ato de reduzir o espaço ocupado por dados num determinado dispositivo. Essa operação é realizada através de diversos algoritmos de compressão, reduzindo a quantidade de bytes para representar um dado, sendo esse dado uma imagem, um texto, ou um arquivo (ficheiro) qualquer.

Comprimir dados destina-se também a retirar a redundância, baseando-se que muitos dados contêm informações redundantes que podem ou precisam ser eliminadas de alguma forma. Essa forma é através de uma regra, chamada de código ou protocolo, que, quando seguida, elimina os bits redundantes de informações, de modo a diminuir seu tamanho nos ficheiros. Por exemplo, a sequência "AAAAAA" que ocupa 6 bytes, poderia ser representada pela sequência "6A", que ocupa 2 bytes, economizando 67% de espaço.

Além da eliminação da redundância, os dados são comprimidos pelos mais diversos motivos. Entre os mais conhecidos estão economizar espaço em dispositivos de armazenamento, como discos rígidos, ou ganhar desempenho (diminuir tempo) em transmissões.

Embora possam parecer sinônimos, compressão e compactação de dados são processos distintos. A compressão, como visto, reduz a quantidade de bits para representar algum dado, enquanto a compactação tem a função de unir dados que não estejam unidos. Um exemplo clássico de compactação de dados é a desfragmentação de discos.

Existem diversas formas de se classificar os métodos de compressão de dados. O mais conhecido é pela ocorrência ou não de perda de dados durante o processo. Entretanto diversas outras formas de classificação são úteis para se avaliar e comparar os métodos de compressão de dados, e sua aplicação em problemas específicos.

/ EDOA / 18

Com perdas e sem perdas

Esta é a forma mais conhecida de se classificar os métodos de compressão de dados.

Diz-se que um método de compressão é sem perdas (em inglês, lossless) se os dados obtidos após a compressão são idênticos aos dados originais, ou os dados que se desejou comprimir. Esses métodos são úteis para dados que são obtidos diretamente por meios digitais, como textos, programas de computador, planilhas eletrônicas, etc., onde uma pequena perda de dados acarreta o não funcionamento ou torna os dados incompreensíveis. Um texto com letras trocadas, uma planilha com valores faltantes ou inexatos, ou um programa de computador com comandos inválidos são coisas que não desejamos e que podem causar transtornos. Algumas imagens e sons precisam ser reproduzidos de forma exata, como imagens e gravações para perícias, impressões digitais, etc.

Por outro lado, algumas situações permitem que perdas de dados poucos significativos ocorram. Em geral quando digitalizamos informações que normalmente existem de forma analógica, como fotografias, sons e filmes, podemos considerar algumas perdas que não seriam percebidas pelo olho ou ouvido humano. Sons de frequências muito altas ou muito baixas que os humanos não ouvem, detalhes muito sutis como a diferença de cor entre duas folhas de uma árvore, movimentos muito rápidos que não conseguimos acompanhar num filme, todos estes detalhes podem ser omitidos sem que as pessoas percebam que eles não estão lá. Nesses casos, podemos comprimir os dados simplesmente por omitir tais detalhes. Assim, os dados obtidos após a compressão não são idênticos aos originais, pois "perderam" as informações irrelevantes, e dizemos então que é um método de compressão com perdas (em inglês, lossy).

Um método de compressão de dados é dito com perda (em inglês loss data compression) quando a informação obtida após a descompressão é diferente da original (antes da compressão), mas suficientemente "parecida" para que seja de alguma forma útil.

Métodos

Tecnicamente, reduzir o tamanho do texto removendo todas as vogais também pode ser considerado compressão com perda de dados. O texto geralmente ainda é legível pelo contexto dado pelas consoantes. Pesquisadores também usaram compressão com perda de dados em texto por ou usar um dicionário para substituir palavras pequenas por grandes, ou técnicas geradoras de texto [1], embora esses possam cair na categoria

/ EDOA / 19

relacionada de Conversão com perda de dados.

Simetria

Quando falamos de métodos simétricos ou assimétricos de compressão de dados, estamos falando na verdade nas diferenças de complexidade entre a compressão e a descompressão. Quando a compressão e a descompressão são feitas executando-se métodos ou algoritmos idênticos ou bem semelhantes, dizemos que o método de compressão é simétrico. Bons exemplos são os algoritmos de codificação aritmética, ou o método LZW, baseado em dicionários. Neles o algoritmo de compressão e de descompressão são praticamente idênticos, e tem a mesma complexidade.

Quando o método de compressão é mais complexo que o de descompressão (ou em casos raros, o de descompressão é mais complexo que o de compressão), dizemos que o método de compressão é assimétrico. Este tipo de método é útil quando vamos comprimir apenas uma vez, mas descomprimir várias vezes (músicas em formato MP3 são um bom exemplo disso). Nesse caso temos todo o tempo do mundo para comprimir, mas a descompressão tem de ser feita em tempo real. Algoritmos como o DEFLATE, usados em programas comuns de compressão de dados são tipicamente assimétricos.

Adaptabilidade

A compressão de dados pode ser baseada em métodos rígidos, cujas regras não variam de acordo com os dados, nem a medida que os dados são lidos. São os métodos não adaptativos. Por outro lado, diversos métodos conseguem ir se adaptando aos dados a medida que estes são processados. Nesse caso o método é adaptativo. Métodos baseados em dicionário como as famílias LZ77 e LZ78 são naturalmente adaptativos já que é inviável que os programas de compressão carreguem dicionários de dados padronizados, ou que os dicionários sejam enviados junto com os arquivos. Métodos de aproximação de entropia, como a codificação de Huffman ou a codificação aritmética podem ser tanto adaptativos, inferindo as probabilidades a medida que os dados são lidos, como não adaptativos, usando probabilidades fixas ou determinadas por uma leitura prévia dos dados. Codificações fixas, como os códigos de Golomb, são naturalmente não adaptativos.

De fluxo e de bloco

Tradicionalmente os métodos de compressão de dados tratam os dados como um fluxo contínuo de dados, em geral visando à transmissão dos dados ou seu armazenamento seqüencial. Entretanto métodos mais recentes se aproveitam do fato de que dados próximos uns dos outros podem ser agrupados e processados em conjunto, de forma a aumentar a compressão.

/ EDOA / 20

Esses métodos são classificados como métodos de compressão de bloco (block compression em inglês), como, por exemplo, o método de Burrows-Wheeler. Os métodos tradicionais são conhecidos como métodos de compressão de fluxo (stream compression em inglês).

Classificação quanto à operação

Os métodos de compressão são também classificados pela forma como operam, e pelo objetivo que buscam atingir. Nesta forma de classificação podemos citar:

métodos estatísticos ou métodos de aproximação de entropia: São métodos que usam as probabilidades de ocorrência dos símbolos no fluxo de dados e alteram a representação de cada símbolo ou grupo de símbolos. Desta forma eles visam reduzir o número de bits usados para representar cada símbolo ou grupo de símbolos, e assim aproximar o tamanho médio dos símbolos ao valor da entropia dos dados. São os métodos que se baseiam diretamente na teoria da informação como a codificação de Huffman ou a codificação aritmética.

métodos baseados em dicionários, ou métodos de redução de redundância: São os métodos que usam dicionários ou outras estruturas similares de forma a eliminar repetições de símbolos (frases) redundantes ou repetidas. Métodos como LZ77 e LZ78 fazem parte desse grupo. Os programas mais usados de compressão sem perdas em geral associam uma técnica baseada em dicionário com uma técnica estatística.

Transformações são métodos que por si só não comprimem os dados, mas são capazes de transformar dados que não seriam comprimidos ou seriam pouco comprimidos pelos métodos normais, em dados que podem ser mais facilmente comprimidos. São em geral usados para compressão com perdas de forma a eliminar a correlação entre os dados adjacentes e assim identificar quais dados podem ser eliminados sem prejuízo do resultado final. Um exemplo é a Transformada discreta de cosseno, usado pelos padrões JPEG e MPEG. Uma exceção é o método de Burrows-Wheeler, usado na compressão sem perda de dados.

Codecs

CoDec é o acrônimo de Codificador/Decodificador, dispositivo de hardware ou software que codifica/decodifica sinais.

Existem dois tipos de codecs:

/ EDOA / 21

• Sem perdas (lossless, em inglês)

• Com perdas (lossy, em inglês)

Codecs sem Perdas

Os codecs sem perdas são codecs que codificam som ou imagem para comprimir o arquivo sem alterar o som ou imagem originais. Se o arquivo for descomprimido, o novo arquivo será idêntico ao original. Esse tipo de codec normalmente gera arquivos codificados que são entre 2 a 3 vezes menores que os arquivos originais. São muito utilizados em rádios e emissoras de televisão para manter a qualidade do som ou imagem.

Exemplos desse tipo de codec são o flac, shorten, wavpack e monkey's audio, para som.

Para vídeo, HuffYUV, MSU[1], MJPEG,H.264 e FFmpeg Video 1.

Para imagens, temos os formatos PNG e TIFF.

Codecs com Perdas

Os codecs com perdas são codecs que codificam som ou imagem, gerando uma certa perda de qualidade com a finalidade de alcançar maiores taxas de compressão. Essa perda de qualidade é balanceada com a taxa de compressão para que não sejam criados artefatos perceptíveis.

Por exemplo, se um instrumento muito baixo toca ao mesmo tempo que outro instrumento mais alto, o primeiro é suprimido, já que dificilmente será ouvido. Nesse caso, somente um ouvido bem treinado pode identificar que o instrumento foi suprimido.

Os codecs com perdas foram criados para comprimir os arquivos de som ou imagem a taxas de compressão muito altas. Por exemplo, o Vorbis e o Mp3 são codecs para som que facilmente comprimem o arquivo de som em 10 a 12 vezes o tamanho original, sem gerar artefatos significativos.

Exemplos de codecs com perdas são o Ogg Vorbis, MP3, AC3 e WMA, para som. Para vídeo, temos o Xvid, DivX, RMVB, WMV, Theora e Sorenson. E para imagens temos o JPEG, JPEG 2000 e GIF.

Taxa de Bits

A taxa de bits ou bitrate, em inglês, é uma das medidas da qualidade de um arquivo comprimido. A taxa de bits representa o tamanho final desejado para o arquivo e, normalmente, é apresentada como Kbit/s.

1 Kbit/s significa que a cada segundo, o codec tem 1000 bits do arquivo final para utilizar, ou seja, se um arquivo de som tem 8 segundos e é

/ EDOA / 22

comprimido a uma taxa de 1 Kbit/s, o arquivo final terá 8 Kbits ou 1 Kbyte. Conclui-se, então, que quanto maior for a taxa de bits, melhor será a qualidade do arquivo final, já que o codec terá mais espaço para poder comprimir o arquivo original, necessitando descartar menos informações do arquivo.

Com a popularização do MP3, a taxa de bits de 128 Kbits/s (128000 bits/s = 16 Kbytes/s) foi muito utilizada, já que, no início, essa era a menor taxa de bits que o MP3 poderia utilizar para gerar um arquivo final com boa qualidade. Hoje em dia, com os codecs mais avançados, pode-se gerar arquivos com 64 Kbits/s de qualidade semelhante aos primeiros MP3.

As taxas de bits podem ser divididas em três categorias principais:

• CBR (constant bitrate). O codec utiliza uma taxa de bits constante em todo a duração do arquivo. Isso significa que em momentos de silêncio provavelmente haverá desperdício de espaço, enquanto que em momentos de muita intensidade sonora haverá perda maior de informação acústica.

• VBR (variable bitrate). O codec utiliza uma taxa de bits variável, dessa forma otimizando a utilização do espaço, ao permitir maior uso deste para os momentos mais necessários e reduzindo a taxa de bits ao mínimo nos momentos de silêncio. A maioria dos codecs sem perdas utiliza esse formato.

• ABR (average bitrate). Um tipo específico de VBR que garante que ao final do processo de compressão o arquivo terá uma taxa de bits média pré-definida.

Perdas generativas

Dependendo do algoritmo aplicado, a compressão com perda de dados pode levar à perda generativa (generation loss), perdendo cada vez mais informações à medida que a compressões são feitas sobre compressões.

Compressão com perda de dados

Existem dois esquemas básicos de compressão com perda de dados:

Em codecs de transformação, amostras de imagem ou som são tomadas, cortadas em segmentos pequenos, transformadas em um novo espaço de base, e quantizadas. Os valores quantizados resultantes são então codificados.

Em codecs de previsão, dados codificados anteriores ou subseqüentes são usados para prever a atual amostra de som ou quadro de imagem. A

/ EDOA / 23

diferença entre os dados previstos e os reais, junto com qualquer informação extra necessária para reproduzir a previsão, é então quantizada e codificada.

Em alguns sistemas as duas técnicas são combinadas, com codecs de transformação sendo usados para comprimir os sinais diferenciais gerados pelo estágio de previsão.

Comparação entre compressão com perda e compressão sem perda de dados

Comparação

A vantagem dos métodos de compressão com perda de dados sobre os sem perda de dados é que normalmente consegue-se um ficheiro comprimido de menor dimensão, mantendo, no entanto, uma qualidade mínima em relação ao original, conforme o objectivo que se pretende.

A compressão com perda de dados é normalmente usada em som, imagens e vídeo/animação. A razão de compressão (ou seja, a dimensão do ficheiro comprimido comparado com o original, ou por comprimir) dos codecs de vídeo é quase sempre superior às obtidas em som e imagens fixas. O som pode ser comprimido a uma razão de 10:1 (o ficheiro comprimido ocupa 1 décimo do original), sem perda muito notável de qualidade, como ocorre com o formato de som em MP3 ou WMA (windows media audio), com taxas de até 320 Kbps de áudio (um CD contém dados de áudio a 1411,2 Kbps). Já o vídeo pode ser comprimido a uma razão 300:1. As imagens fixas são normalmente comprimidas a uma razão de 10:1, tal como no som, mas neste caso a qualidade é bastante afetada, optando-se normalmente por uma razão menor, 2:1, por exemplo.

Quando um utilizador recebe um ficheiro comprimido com perda de dados, (por exemplo, para reduzir o tempo de download), esse ficheiro posteriormente descomprimido pode ser bem diferente do original ao nível do bit e, no entanto, ser quase idêntico numa observação normal para o olho ou ouvido humano. Muitos métodos /algoritmos de compressão recorrem a limitações da anatomia humana tomando em conta, por exemplo, que o olho humano apenas pode visionar certas freqüências da luz. O modelo psicoacústico descreve como o som pode ser muito comprimido sem que se perceba a degradação da qualidade do sinal sonoro. Os erros/falhas, causados pela compressão com perda de dados, que sejam perceptíveis para o olho ou ouvido humano são conhecidos por artefactos de compressão (compression artifacts).

• Métodos de compressão com perda de dados

Imagens fixas

/ EDOA / 24

• Fractal compression

• JPEG

• JPEG 2000, sucessor do JPEG.

• Wavelet compression

• Cartesian Perceptual Compression (CPC)

• DjVu

• ICER, utilizado pelo Mars Rovers: relacionado com JPEG2000 em seu uso de wavelets

• Filmes/animações

• Flash (também suporta JPEG sprites)

• H.261

• H.263

• H.264/MPEG-4 AVC

• MNG (suporta JPEG sprites)

• Motion JPEG

• MPEG-1 Part 2

• MPEG-2 Part 2

• MPEG-4 Part 2

• Ogg Theora (sem restrições de patentes)

• Sorenson video codec

• VC-1

• Som

• Música

• AAC - utilizado pela Apple Computer

• ADPCM

• ATRAC

/ EDOA / 25

• Dolby AC-3

• DTS

• MP2

• MP3

• Musepack

• Ogg Vorbis (sem restrições de patentes)

• Windows Media Audio (WMA)- criado pela Microsoft

• Voz

• CELP

• G.711

• G.726

• HILN

• Adaptive Multi-Rate (AMR) (used by GSM cell carriers, such as T-Mobile)

• Speex (sem restrições de patentes)

CHAPTER FIVE

GráficosUma imagem é uma representação visual de um objeto. Em termos computacionais, uma imagem digital é a representação de uma imagem bidimensional usando números binários codificados de modo a permitir seu armazenamento, transferência, impressão ou reprodução, e seu processamento por meios eletrônicos.

O armazenamento dos dados que compõe uma imagem digital em um arquivo binário pode se realizar utilizando diferentes formatos gráficos, cada um dos quais oferece diferentes possibilidades com respeito à resolução da imagem, a gama de cores, a compatibilidade, a rapidez de carregamento, etc.

A finalidade última de um formato gráfico é armazenar uma imagem buscando um equilíbrio adequado entre qualidade, peso final do arquivo e

/ EDOA / 26

compatibilidade entre plataformas. Para isso, cada formato se baseia em uma ou mais técnicas diferentes, que podem incluir codificação especial, métodos de compressão, métodos de dithering, etc.

Geralmente, todo arquivo gráfico começa com um cabeçalho (header) de estrutura variável, que indica ao programa que solicite as características da imagem que armazena (tipo, tamanho, resolução, modo de cor, profundidade de cor, número de cores da paleta se houver, etc).

A seguir se encontram os dados próprios da imagem, geralmente comprimidos com um algoritmo específico desse formato, que contém informação sobre a cor de cada pixel da imagem (mapas de bits) ou uma tabela com as características próprias de cada objeto (gráficos vetoriais). Em caso de se usar uma paleta de cores, a informação sobre tal paleta também deverá estar contida no arquivo.

Tipos

Mapa de bits

Uma imagem digital do tipo mapa de bits, ou bitmap, ou ainda matricial, é aquela que em algum momento apresenta uma correspondência bit-a-bit entre os pontos do mapa de bits e os pontos da imagem reproduzida na tela de um monitor. Um mapa de bits é a representação em duas dimensões de uma imagem como um conjunto finito de pontos definidos por valores numéricos, formando uma matriz matemática ou malha de pontos, onde cada ponto é um pixel.

Tipicamente, cada ponto de uma imagem é decomposto em uma tripla de cores e cada proporção relativa é transformada em valores numéricos que permitem que eles sejam recuperados. No modelo conhecido como RGB, por exemplo, a imagem é decomposta nas cores vermelho, verde e azul, estabelecendo para cada um dessas cores um valor entre o máximo possível de reprodução daquela cor e o mínimo, ou seja, a ausência total dela. A soma dos três valores resulta num ponto colorido da imagem final.

Imagem vetorial

Uma imagem vetorial é um tipo de imagem gerada a partir de descrições

/ EDOA / 27

geométricas de formas, diferente das imagens chamadas mapa de bits, que são geradas a partir de pontos minúsculos diferenciados por suas cores. Uma imagem vetorial normalmente é composta por curvas, elipses, polígonos, texto, entre outros elementos, isto é, utilizam vetores matemáticos para sua descrição. Em um trecho de desenho sólido, de uma cor apenas, um programa vetorial apenas repete o padrão, não tendo que armazenar dados para cada pixel.

Por serem baseados em vetores de funções matemáticas, esses gráficos geralmente são mais leves (ocupam menos espaço em mídias de armazenamento) e não perdem qualidade ao serem ampliados, já que as funções matemáticas adequam-se facilmente à escala, o que não ocorre com gráficos raster que utilizazam métodos de interpolação na tentativa de preservar a qualidade. Outra vantagem do desenho vetorial é a possibilidade de isolar objetos e zonas, tratando-as independentemente.

Pixel

Pixel (aglutinação de Picture e Element, ou seja, elemento de imagem) é o menor elemento num dispositivo de exibição (como por exemplo um monitor), ao qual é possivel atribuir-se uma cor. De uma forma mais simples, um pixel é o menor ponto que forma uma imagem digital, sendo que o conjunto de milhares de pixels formam a imagem inteira.

A cada ponto da imagem exibida na tela ou papel corresponde um pixel desta grade, de forma que a maioria das imagens requer um número muito grande de pixels para ser representada completamente. Nos melhores monitores cada um destes pontos é capaz de exibir 256 tonalidades diferentes (o equivalente a 8 bits) e combinando tonalidades dos três pontos é então possível exibir pouco mais de 16.7 milhões de cores diferentes. Por exemplo, uma imagem comum de 800 pixels de largura por 600 de altura necessita de 3 bytes para representar cada pixel (um para cada cor primária RGB) e mais 54 bytes de cabeçalho. Isso totaliza 1.440.054 bytes. Embora a representação de imagens na memória RAM seja feita geralmente em bitmaps, quando se fala em um grande número de imagens armazenadas em discos magnéticos e transmissão de dados via redes surge a necessidade de compressão desses arquivos, para reduzir o espaço ocupado e o tempo de transmissão.

Processamento

Processamento de imagem é qualquer forma de processamento de dados no qual a entrada e saída são imagens tais como fotografias ou quadros de vídeo. Ao contrário do tratamento de imagens, que preocupa-se somente na manipulação de figuras para sua representação final, o processamento de

/ EDOA / 28

imagens é um estágio para novos processamentos de dados tais como aprendizagem de máquina ou reconhecimento de padrões. A maioria das técnicas envolve o tratamento da imagem como um sinal bi-dimensional, no qual são aplicados padrões de processamento de sinal.

A analise quantitativa e a interpretação de imagens representa atualmente um ponto de apoio importante em diversas disciplinas científicas. Tal é o caso por exemplo na ciência dos materiais, na biofísica, na medicina, na física da matéria condensada, etc. Na realidade a diversidade de aplicações do processamento de imagens, está associada diretamente a análise da informação.

Algumas décadas atrás o processamento de imagem era feito majoritariamente de forma analógica, através de dispositivos ópticos. Apesar disso, devido ao grande aumento de velocidades dos computadores, tais técnicas foram gradualmente substituídas por métodos digitais.

O processamento digital de imagem é geralmente mais versátil, confiável e preciso, além de ser mais fácil de implementar que seus duais analógicos. Hardware especializado ainda é usado para o processamento digital de imagem, contando com arquiteturas de computador paralelas para tal, em sua maioria no processamento de vídeos. O processamento de imagens é, em sua maioria, feito por computadores pessoais.

Os elementos de um sistema de processamento de imagens de uso genérico são mostrados na figura abaixo. Este diagrama permite representar desde sistemas de baixo custo até sofisticadas estações de trabalho utilizadas em aplicações que envolvem intenso uso de imagens. Ele abrange as principais operações que se pode efetuar sobre uma imagem, a saber: aquisição, armazenamento, processamento e exibição. Além disso, uma imagem pode ser transmitida â distância utilizando meios de comunicação disponíveis.

/ EDOA / 29

Câmeras de vídeoCâmeras fotográficas

Scanners

Discos ópticosDiscos magnéticosFitas magnéticas

Videotape

Monitores de vídeoImpressoras

PlottersComputador

Armazenamento

SaídaProcessamentoAquisição

Aquisição

A etapa de aquisição tem como função converter uma imagem em uma representação numérica adequada para o processamento digital subseq¸ente. Este bloco compreende dois elementos principais. O primeiro é um dispositivo físico sensível a uma faixa de energia no espectro eletromagnético (como raio X, ultravioleta, espectro visível ou raios infravermelhos), que produz na saída um sinal elétrico proporcional ao nível de energia detetado. O segundo - o digitalizador propriamente dito - converte o sinal elétrico analógico em informação digital, isto

é, que pode ser representada através de bits 0s e 1s. Um módulo de aquisição de imagens é normalmente conhecido pelo nome de frame grabber. Os capítulos 2 e 7 deste livro trazem mais

detalhes sobre os aspectos envolvidos na aquisição de imagens digitais.

Armazenamento

O armazenamento de imagens digitais é um dos maiores desafios no projeto de sistemas de processamento de imagens, em razão da grande quantidade de bytes necessários para tanto. Este armazenamento pode ser dividido em trÍs categorias: (1) armazenamento de curta duração de uma imagem, enquanto ela é utilizada nas várias etapas do processamento, (2) armazenamento de massa para operações de recuperação de imagens relativamente rápidas, e (3) arquivamento de imagens, para recuperação

/ EDOA / 30

futura quando isto se fizer necessário. O espaço de armazenamento requerido é normalmente especificado em bytes (8 bits) e seus múltiplos: KB (kilobyte - 1000 bytes), MB (megabyte - 1 milhão de bytes), GB (gigabyte - 1 bilhão de bytes) e TB (terabyte - 1 trilhão de bytes).

Processamento

O processamento de imagens digitais envolve procedimentos normalmente expressos sob forma algorítmica. Em função disto, com exceção das etapas de aquisição e exibição, a maioria das funções de processamento de imagens pode ser implementada via software. O uso de hardware especializado para processamento de imagens somente será necessário em situações nas quais

certas limitações do computador principal (por exemplo, velocidade de transferência dos dados através do barramento) forem intoleráveis.

Transmissão

Imagens digitalizadas podem ser transmitidas â distância utilizando redes de computadores e protocolos de comunicação já existentes. O grande desafio da transmissão de imagens à distância é a grande quantidade de bytes que se necessita transferir de uma localidade a outra, muitas vezes através de canais de comunicação de baixa velocidade e banda passante estreita. Este problema é ainda mais sério quando se deseja transmitir seq¸ências de vídeo (imagens em movimento com áudio associado) em tempo real, onde outros fatores, como por exemplo sincronização, devem ser considerados. Nestes casos, o uso de técnicas de compressão e descompressão de imagens, como as descritas no capítulo 6, é mandatório.

Exibição

O monitor de vídeo é um elemento fundamental de um sistema de processamento de imagens. Os monitores em uso atualmente são capazes de exibir imagens com resolução de pelo menos 640 x 480 pixels com 256 cores distintas. A tecnologia mais usual ainda é o TRC (Tubo de Raios Catódicos).

Image enhancement

O termo enhancement esta associado a melhoria da qualidade de uma imagem, com o objetivo posterior de ser julgado por um observador humano. De uma forma geral nós vamos trabalhar nos níveis de cinza da imagem, transformando-os para aumentar o contraste ou para colocar em evidência alguma região de interesse particular. Alguns exemplos deste tipo de técnica é a subtração da imagem por uma imagem referência, a utilização de cores-falsas, a utilização de filtros espaciais, a correção de deformações espaciais devido a ótica ou devido a uma variação de homogeneidade da

/ EDOA / 31

iluminação de fundo. Os sistemas dedicados a melhorar a qualidade da imagem trabalham geralmente muito rápido, pois são construídos em hardware ou firmeware, permitindo rapidamente ao usuário um julgamento sobre várias imagens processadas, segundo o tipo de tratamento. Esta técnica é encontrada na maioria dos programas de tratamento de imagens ou fotografias que estão atualmente no mercado, mas com algoritmos implementados em software, para computadores do tipo PC.