ERCEMAPI 2009
 29 de Outubro
 Parnaíba-PI




 MC 5: Técnicas de Processamento
         é
 Digital de Imagens com Java
 Iális Cavalcante – Engenharia da Computação
 UFC / Campus de Sobral
Objetivos

  • Apresentar técnicas básicas que envolvem
    Processamento Digital de Imagens (PDI);

  • Apresentar APIs Java voltada para PDI;

  • Desenvolver uma pequena aplicação em
                      p q       p ç
    Java para descrição de regiões.
E quem é o apresentador?
Agenda
1. Introdução
2. APIs Java para Imagem
2 API J           I
3.
3 Técnicas de Processamento Digital de
   Imagens (PDI)

4. Proposta de um Aplicativo de PDI

5. Considerações Finais
• Vi ã Geral sobre PDI
              Visão G l b
            • Aplicações Reais




1. INTRODUÇÃO
Introdução
 • PDI possui alguns conceitos em comum com
   Visão Computacional e Computação Gráfica
   (caso de Análise de Imagens - FootScanAge).
              á

 • Pixels formam uma imagem – função f(x,y)

 • Primeiros registros de estudo – NASA (Guerra
   Fria)

 • Aplicações Multidisciplinares
Comparativo



    Imagem                                         Imagem
                   Processamento de Imagens




                              Dado



  Computação Gráfica
  C    t ã G áfi                          Visão Computacional
Definição de Imagem
Histórico




           1921
                                                 1922

      Anos 20 – Sistema Bartlane
      Transmissão de Imagens via cabo submarino
                        g
      Uma semana para três horas – Londres para Nova York
Histórico




        Anos 20 (1925) – Sistema Bartlane
        Aumento para cinco níveis de brilho
Histórico




      Primeira imagem da Lua.
      Obtida pela nave espacial americana Ranger 7.
                                                 7
      31 de julho de 1964, 9:09 (17 minutos antes do impacto).
Aplicações em Saúde                90
                                               1
                             120                   60
                                           0.8


                                          0.6
                       150                               30
                                         0.4
                                         04


                                         0.2


                 180                                           0




                       210                               330




                             240                   300

                                   270
Aplicações em Saúde
Aplicações na Indústria Petrolífera
Aplicações na Agropecuária
Aplicações na Biologia
 p    ç            g
Aplicações em Imagens SAR
• API JAI
     • API I
           ImageJ
                J




2. APIS JAVA PARA IMAGEM
Formatos de Imagens

 • TIFF, GIF, PNG, JPEG, BMP, PBM, PGM,
   PMN

 • P d i d nos anos 80 e 90.
   Padronizados          90

 • Suportados pela maioria das APIs e
   linguagens
   ling agens de p og amação
                 programação.
Uso da linguagem Java
                                                   Why Java?

• Atrativos:
       i
   – Livre;
   – Portável (“write once, run anywhere”);
   – Sintaxe similar à linguagem C;
   – Possui facilidade de internacionalização dos caracteres;
   – Vasta documentação;
   – Coletor de lixo (para desalocação automática de 
     memória);
   – Facilidade de criação de programação distribuída e 
     concorrente;
   – P di
     Paradigma Orientado a Objetos.
                 O i t d Obj t
Java Advanced Imaging (JAI) API
                 g g(     )


                              PlanarImage

               ColorModel                        Raster

                ColorSpace                    SampleModel


                                               DataBuffer


Estrutura da classe de suporte a imagem na API JAI. Adaptado de Santos (2004).
Java Advanced Imaging (JAI) API
                 g g(     )
 • Leitura/Escrita de Imagens

 public class EScomJAI {
   public static void main(String[] args) {
       // leitura da imagem
       PlanarImage i
       Pl      I      image = JAI
                               JAI.create("fileload", "L
                                       t ("fil l d" "Lenna.png");
                                                              ")
       double[][] bandCombine = {{0.21f,0.71f,0.08f,0.0f}};
       // conversão do modelo de cores
       image = JAI.create("BandCombine", image, bandCombine);
       // escrita do arquivo
       JAI.create("filestore",image,"lennagl.png","PNG");
   }
 }
ImageJ API
          Plugin     Plugin    Plugin    Plugin     Plugin




                              ImageJ



                       AWT




                                Java


  Estrutura geral da API ImageJ. Adaptado de Burger & Burge (2009).
ImageJ API Software

 • Uso de plugins expande a comunidade de
   desenvolvedores;;

 • Di
   Disponibiliza um software com a execução
         ibili        ft                 ã
   de todas as funcionalidades
   implementadas;
Listagem: ExibeImagem.java
 public class ExibeImagem extends JFrame {
     public ExibeImagem() throws IOException { // início do construtor
             BufferedImage imagem = ImageIO.read(new File(“Lenna.png”));
             String infoImagem = “Dimensões: ”+imagem.getWidth()+
             “x”+imagem.getHeight()+“ Bandas: ”+ imagem.getRaster().getNumBands();
             ImageIcon icone = new ImageIcon(imagem);
             JLabel labImagem = new JLabel(icone);
             (…) // adiciona labImagem e infoImage à interface
             this.setVisible(true);
      } // fim do construtor
      // Método principal
      p
      public static void main(String args[]){
                                (    g g []){
             try{ // tratamento de exceção de E/S
                         ExibeImagem appExibeImg = new ExibeImagem();
             }
             }catch(IOException exc){
                    (        p        ){
                          System.out.println(“Erro de leitura! ”+exc.getMessage());
             }
     } // fim do método principal
 } // fim da classe
Resultado: ExibeImagem.java




  Imagem Original. Fonte: Imagem
adaptada de http://www.lenna.org/.
   p           p //            g/
                                     Imagem exibida pela classe.
•   Tipos de Imagens
         •   Realce
         •   Segmentação
         •   Morfologia Matemática




3. TÉCNICAS DE
PROCESSAMENTO
DIGITAL DE IMAGENS
Técnicas de Base para Aplicativo

 • Realce – Negativo e Filtragem (Passa-Baixa e
   Passa-Alta )

 • Segmentação – Limiarização e Watershed

 • Morfologia Matemática – Erosão Dilatação
                           Erosão, Dilatação,
   Abertura e Fechamento
Tipos de Imagens




 Imagem Binária
    g              Imagem em
                        g           Imagem Colorida
                                       g
                  Níveis de Cinza
CMYK




RGB




HSV
double[][] bandCombine = { {R, G, B, 0.0f} };
image = JAI.create("BandCombine", image, bandCombine);




    R = 1.0f                 R = 0.0f                R = 0.0f
    G = 0.0f                 G = 1.0f                G = 0.0f
    B = 0.0f                 B = 0.0f                B = 1.0f
Negativo de uma Imagem
  g                g
• Negativo de uma Imagem
  – Realce com processamento ponto-a-ponto
                              ponto a ponto
  – Aplicações em imagens médicas
  – Reverter a ordem do preto para o branco
     • Intensidade da imagem de saída diminui
     • Intensidade da entrada aumenta
     • s=L–1–r
Negativo de uma Imagem
  g                g
s = T(r)
Claro




                      T(r)
    ro
Escur




                                                 Imagem Original

                                         r
             Escuro           Claro
         Função de Transformação
            ç                ç




                             Imagem Processada
Presença de Ruído em Imagens

• Distorções em uma imagem afetam a
         õ                     f
  percepção da sua real informação;

• Uma distorção crítica é a presença de ruído;
  – Implica em nova informação na imagem;

• Normalmente os ruídos são definidos por
                                      p
  uma distribuição estatística:
  – modelo gaussiano, speckle, poisson, etc.
           g        , p      ,p       ,
Efeito do Ruído




   Imagem Original




       Mudanças de Perspectivas
            ç          p
Efeito do Ruído




   Imagem Ruidosa
    “Sal e Pimenta”




        Mudanças de Perspectivas
             ç          p
Efeito do Ruído




   Imagem Ruidosa
      Speckle




       Mudanças de Perspectivas
            ç          p
Efeito do Ruído


                                     Presença de ruído Poisson.


    Imagem Original




              Presença de ruído   Presença de ruído Speckle.
               “Sal e pimenta”.
Realce com Processamento por Máscara




     (1)             (2)




             (3)              (4)
Realce com Processamento por Máscara




            Exemplo de Máscara (3x3)




• g(x,y) = T[f(x,y)] (T opera em uma vizinhança de
  g( ,y)    [ ( ,y)] ( p                      ç
  pixels)
• z5’ = R = w1z1 + w2z1+ ... + w9z9 (Filtro Linear)
                                     (            )
  – z5’: soma ponderada de pixels na vizinhança de z5
• z5 = max(zk, k = 1, 2, ... 9)          (Filtro Não-Linear)
                                                 Não Linear)
  – Não satisfaz a condição de um filtro linear
Tipos de Filtragem
  p            g

 • A distribuição de valores na máscara
   define o tipo de filtragem:
              p           g
   – Passa-alta
      • Aguçamento das bordas;
   – Passa-baixa
      •S
       Supressão d ruído, b
              ã de íd borramento d imagem;
                              t da i
   – Passa-banda
      • Restauração da imagem.
Detectores de Bordas (Gradiente – Passa-Alta)




Imagem Original                     Filtro de Prewitt




                  Filtro de Sobel                       Filtro de Roberts
Definição de Gradiente




      (a)                     (b)         s = [1 2 1; 0 0 0; -1 -2 -1];
                                          A = zeros(10);
                                                    ( );
Figura
Fig a – (a) Imagem original; (b) Imagem
                        o iginal
                                          A(3:7,3:7) = ones(5);
após aplicação do filtro de Sobel.
                                          H = conv2(A,s);
                                          mesh(H)
Filtro de Suavização (passa-baixa)
• São úteis para redução de ruído e borramento de
  imagens
  – Detalhes são perdidos
      • O tamanho da máscara (ou seja vizinhança) determina o grau
                                   seja,
        de suavização e perda de detalhes.
  – Os elementos da máscara devem ser números positivos
                                              p
  – Exemplo: Média Local




  – R = 1/9 (1z1 + 1z2 + ... +1z9)              normalizado: dividido por 9
Filtro por mediana (não-linear)
• Substitua f(x,y) pela mediana [f(x’,y’)] onde (x’,y’) pertence a 
  vizinhança
          ç
• Muito efetivo na remoção do ruído com componentes do 
  tipo espigada (“spike”, ocorrências aleatórias de valores 
  brancos e pretos)
• Preserva melhor as bordas
• Exemplo:
                 10   20   20
                                                Ordenar
                 20   15   20        (10,15,20,20,20,20,20,25,100)

                 25   20   100



   – Mediana = 20, então substitua (15) por (20)
Filtragem da Mediana




  Imagem Ruidosa                   Filtragem com Janela 3x3
   “Sal e Pimenta”




              Filtragem com Janela 5x5            Filtragem com Janela 7x7
Limiarização
         ç

 • Comprime a faixa de nível de cinza de pouco
                        í
   interesse
   – Inclinação da linha entre [0,1]
 • Alargamento da faixa de nível de cinza de maior
   interesse
      – Inclinação da linha monotonicamente crescente


   – r1 = r2
   – s1 = 0 e s2 = L – 1
Limiarização
         ç
   s = T(r)
 Claro




                       T(r)
     ro
 Escur




                                                  Imagem Original

                                      r
              Escuro          Claro
    Função de Transformação




                              Imagem Processada
Limiarização
         ç




 Imagem Original   Limiar de 130




                      Limiar de 140   Limiar de 150
Watershed

 • Conside ando uma imagem em tom de cinza como
   Considerando ma                   cin a
   uma superfície topográfica:
   – Todos os vales foram perfurados na sua área mais
     funda da superfície;
   – Toda a superfície é lentamente preenchida por água,
     este irá progressivamente inundar todas as bacias da
     imagem;
      • Represas podem ser aumentadas onde a água vem de dois
        pontos distintos, podendo se unir;
               distintos
   – Ao fim da inundação, cada bacia é cercada por cumes
     (represas) representando seu limite.
   – Este processo define a divisão das regiões presentes
     na imagem.
Watershed




 Imagem Original   Imagem em Níveis de Cinza




                      Imagem com Marcadores    Imagem Final
Watershed




Animação sobre Watershed. Fonte: http://cmm.ensmp.fr/~beucher/wtshed.html.
Watershed

 • O objetos das imagens são definidos como
   Os bj t d i              ã d fi id
   as regiões de muitos valores de escala de
   cinza constantes.
    i        t t

 • O operador gradiente irá realçar os limites
   dos objetos (fim da inundação).
         j     (              ç )

 • Os marcadores indicam, de forma bruta,
                   indicam           bruta
   onde os objetos estão localizados na imagem
   (ponto de partida da inundação).
Morfologia Matemática
        • Elemento Estruturante (EE):
                  – Structuring Element (SE)
                  – Pequeno conjunto usado para reconhecer a
                    morfologia do objeto de interesse em uma imagem.
                        f l     d b      d
                  – Forma e tamanho devem ser adaptados para as
                    propriedades geométricas da imagem processada.
                          i d d        ét i   d i               d

0.5
05

 1                                                        1                                                       1

1.5
                                                          2                                                       2
 2
                                                          3                                                       3
2.5

 3                                                        4                                                       4

3.5
                                                          5                                                       5
 4
                                                          6                                                       6
4.5

 5                                                        7                                                       7

5.5                                                       0.5   1   1.5   2   2.5   3   3.5   4   4.5   5   5.5       1   2   3   4   5   6   7
  0.5   1   1.5   2   2.5   3   3.5   4   4.5   5   5.5
Morfologia Matemática
 • Erosão e Dilatação
 • A partir destes: Abertura e Fechamento
     p
Morfologia Matemática

 • Erosão não é o inverso da dilatação!
   – Uma erosão seguida de uma dilatação nem
     sempre retorna a imagem original.

      •B   quadrado 3x3
Morfologia Matemática




   Imagem Original                               Resultado da Erosão




            R

Elemento Estruturante
     Raio = 11
                        Resultado da Dilatação
Morfologia Matemática
• Abertura
   – Resultado da erosão seguida da dilatação;
       • Usando o mesmo elemento estruturante.

       • γB(X) = δB(εB(X))


   – Propriedades:
       • Idempotente;
       • Crescente;
       • Anti-extensiva; ?
                                          (a)                      (b)
                             Figura–Abertura com EE circular: (a) imagem original
                             e (b) sobreposição do resultado.
                               ( )      p ç
Resultado da abertura é sempre menor ou igual à
imagem original.
Morfologia Matemática
• Fechamento
   – Dual da Abertura;
   – Resultado da dilatação seguida da erosão
       • Usando o mesmo elemento estruturante.
       • φB(X) = εB(δB(X))


   – Propriedades:
       • Idempotente;
       • Crescente;
       • Extensiva; ?


Resultado da abertura é                (a)                        (b)
sempre maior ou igual à
           i     i   l     Figura – Fechamento com EE circular:
                           (a) imagem original e (b) sobreposição do resultado.
imagem original.
Morfologia Matemática




   Imagem Original                                Resultado da Abertura




            R

Elemento Estruturante
     Raio = 11
                        Resultado do Fechamento
Morfologia Matemática



 Imagem Original              Resultado da Erosão   Resultado da Dilatação




                   Resultado da Abertura   Resultado do Fechamento
• Definição do aplicativo
                    • Uso da API ImageJ
                    • Desenvolvimento




4. PROPOSTA DE UM
APLICATIVO DE PDI
Fluxograma
  u og a a         Imagem 
                   Ruidosa


                   Filtragem
             (eliminação do ruído)



                 Segmentação
             (separação de regiões)
             (separação de regiões)



                  Objeto está         Não
                     bem                    Pós‐Processamento
                 identificado?

                  Sim
                   Imagem 
                   Imagem
                  Processada
Aplicando Filtro da Mediana
    // objeto “imagem"” da classe java.awt.Image instanciado
    // com a imagem original
    ByteProcessor processador = new ByteProcessor(imagem);
    processador.medianFilter();
    // resultado do filtro é p
                             passado ao objeto “imagem”
                                          j        g
    imagem = processador.createImage();




         Imagem Ruidosa                  Imagem Filtrada
Aplicando Segmentação
   // objeto “imagem” da classe java.awt.Image instanciado
   // com a imagem filtrada
   ByteProcessor processador = new ByteProcessor(imagem);
   // “valorLimiar” é inteiro e que indica o limiar da segmentação
   p
   processador.threshold(valorLimiar);
                          (           );
   // resultado da limiarização é passado ao objeto “imagem”
   imagem = processador.createImage();




          Imagem Filtrada                Imagem Segmentada
Aplicando Fechamento
// objeto “imagem” da classe Image instanciado com a imagem segmentada
ByteProcessor processador = new ByteProcessor(imagem);
// etapa de dilatação - 1o passo do fechamento
processador.dilate(1,0);
imagem = processador.createImage();
processador = new B P
         d           ByteProcessor(imagem);
                                  (i      )
// etapa de erosão - 2o passo do fechamento
p
processador.erode(1,0);
                   ( , );
imagem = processador.createImage();


                                                         Imagem Segmentada




                                                      Imagem Final
Melhor uso de memória

 • E i
   Evitar o acúmulo de variáveis estáticas no
              ú l d       iá i      ái
   método principal
   – Para auxiliar o desempenho do coletor de lixo
     da máquina virtual Java.
 • O uso de variáveis estáticas deve ser
   evitado
   – Ocupam muito recurso de memória
   – São as últimas instâncias a serem eliminadas
     pelo garbage collector
Melhor uso de memória

   Execução do garbage collector:
 • E     ã d      b      ll
   – System.gc() ou

   – Runtime rt = Runtime.getRuntime();
                          g         ();
     rt.gc();
     long mem = rt freeMemory();
                 rt.freeMemory();

 • E     ã frequente d gc() pode resultar
   Execução f      t de () d         lt
   na degradação do desempenho.
Listagem: SegRdI.java (visão geral)
    public class S RdI extends JF
       bli l       SegRdI t d JFrame {
    // atributos
    JPanel painelPrinc, painelBotoes;
    JButton b b b
              btnAbrir, btnProc, b
                                 btnLimpar, b
                                            btnSair;
    File fileName;         ImagePlus imagemIJ;
    // inicialização dos componentes gráficos
    public void iniciaComponentes() { ... }
    // método da ação ao clicar o botão Abrir
    private void abrirActionPerformed(ActionEvent evt) { … }
    // método da ação ao clicar o botão Processar
    private void processarActionPerformed(ActionEvent evt) { … }
    // método da ação ao clicar o botão Limpar
    private void limparActionPerformed(ActionEvent evt) { … }
    // método da ação ao clicar o botão Sair
    private void sairActionPerformed(ActionEvent evt) { System.exit(0); }
    // construtor padrão
    public SegRdI() { this.iniciaComponentes(); }
    // método principal
                 p    p
    public static void main(String[] args) { SegRdI aplicacao = new SegRdI(); }
    } // fim da classe
Listagem: SegRdI.java (inicia interface gráfica)
 public void iniciaComponentes(){
     this.setLayout(new BorderLayout()); painelPrinc = new JPanel();
     painelPrinc.setLayout(new BorderLayout()); this.add(painelPrinc, BorderLayout.CENTER);
     painelBotoes = new JP
        i lB t           JPanel(); painelBotoes.setLayout(new Fl L
                               l()   i lB t       tL    t(     FlowLayout());
                                                                          t())
     this.add(painelBotoes, BorderLayout.SOUTH);

    // adicionando botões
    btnAbrir = new JButton(); painelBotoes.add(btnAbrir); btnAbrir.setText(“ Abrir ... ”);
    btnProc = new JButton(); painelBotoes.add(btnProc); btnProc.setText(“Processar”);
    // -> faz-se o mesmo para os botões “btnLimpar” e “btnSair”
                                         btnLimpar     btnSair

    // configurar ações dos botões
    btnAbrir.addActionListener(new
    btnAbrir addActionListener(new ActionListener() {
           public void actionPerformed(ActionEvent evt) { abrirActionPerformed(evt); } } );
    btnProc.addActionListener( ... ); // relacionar com o método processarActionPerformed
    btnLimpar.addActionListener( ... ); // relacionar com o método limparActionPerformed
           p                     (                                     p
    btnSair.addActionListener( ... ); // relacionar com o método sairActionPerformed

      this.setVisible(true);      this.setSize(450,350);
      this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
 } // fim do método initComponents
Listagem: SegRdI.java (limpar interface)

 private void limparActionPerformed(ActionEvent evt) {
    ImagePlus imp = new ImagePlus();
    ImageCanvas ic = new ImageCanvas(imp);
         g                     g       ( p)
    painelPrinc.removeAll();
    p
    painelPrinc.add(ic,BorderLayout.CENTER);
                   ( ,         y          );
 } // fim do método limparActionPerformed
Listagem: SegRdI.java (abrir imagem)
 private void abrirActionPerformed(ActionEvent evt) {
     // exibe caixa de diálogo para abrir arquivo de imagem
     JFileChooser dialogo = new JFileChooser();
     dialogo.setFileSelectionMode(JFileChooser.FILES_ONLY);
     int result = dialogo.showOpenDialog(this);
     if (result == JFileChooser CANCEL OPTION) return;
                     JFileChooser.CANCEL_OPTION)
     // recupera arquivo selecionado
     fileName = dialogo.getSelectedFile();
     // exibe erro se inválido
     if (fileName == null || fileName.getName().equals(“”)) {
               JOptionPane.showMessageDialog(this, “Nome de Arquivo Inválido”,
               “Nome de Arquivo Inválido”, JOptionPane ERROR MESSAGE);
                                 Inválido” JOptionPane.ERROR_MESSAGE);         return; }
     imagemIJ = new ImagePlus(fileName.toString());
     JScrollPane sp = new JScrollPane( JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
                                   JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
                                   JS llP      HORIZONTAL SCROLLBAR AS NEEDED)
     ImageCanvas ic = new ImageCanvas(imagemIJ); sp.add(ic);
     sp.setSize(imagemIJ.getWidth(), imagemIJ.getHeight());
     painelPrinc.add(sp,BorderLayout.CENTER);
             l       dd(      d           C      )
 } // fim do método abrirActionPerformed
Listagem: SegRdI.java (processamento da imagem - I)

  private void processarActionPerformed(ActionEvent evt) {
      Image image = imagemIJ.getImage();
      ByteProcessor b t P
      B t P            byteProc = new B t P
                                         ByteProcessor(image);
                                                        (i       )
      byteProc.medianFilter();
      image = byteProc.createImage();
      ImagePlus i Filt = new I
      I      Pl imFilt            ImagePlus(“filtragem”,image);
                                         Pl (“filt       ”i       )
      // descobrindo maior valor de nível de cinza
      int max = -1;
      for(int lin = 0; lin < imFilt.getHeight(); lin++)
             for(int col = 0; col < imFilt.getWidth(); col++){
                         int[] pixels = imFilt.getPixel(col, lin);
                         if (pixels[0]>max) max = pixels[0]; }
      image = imFilt.getImage(); byteProc = new ByteProcessor(image);
      // aplicando a segmentação através de limiarização
      byteProc.threshold(max-1);
      image = byteProc.createImage();
      ImagePlus imSeg = new ImagePlus(“segmentacao”,image);
      image = imSeg.getImage(); byteProc = new ByteProcessor(image);
Listagem: SegRdI.java (processamento da imagem - II)

      // inicialmente aplica-se a dilatação
      byteProc.dilate(1,0);
      image = b t P
      i          byteProc.createImage();
                              t I      ()
      ImagePlus imDil = new ImagePlus(“dilatacao”,image);
      image = imDil.getImage();           byteProc = new ByteProcessor(image);
      // posteriormente aplica-se a erosão
      byteProc.erode(1,0);
      image = byteProc createImage();
                 byteProc.createImage();
      ImagePlus imErosao = new ImagePlus(“erosao”,image);
      JScrollPane sp = new JScrollPane(
             JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
             JS llP      VERTICAL SCROLLBAR AS NEEDED
             JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
      ImageCanvas ic = new ImageCanvas(imErosao); sp.add(ic);
           g                       g
      sp.setSize(imErosao.getWidth(), imErosao.getHeight());
      painelPrinc.removeAll();
      painelPrinc.add(sp,BorderLayout.CENTER);
      painelPrinc add(sp BorderLayout CENTER);
  } // fim do método processarActionPerformed
Listagem: SegRdI.java (acrescentando escrita)

    // adotando a API Java 2D (alternativa para ImageJ)
    BufferedImage bi = new BufferedImage(imErosao getWidth()
                             BufferedImage(imErosao.getWidth(),
            imErosao.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
    Graphics2D g2 = bi.createGraphics();
        p       g                 p   ();
    g2.drawImage(image, 0, 0, null);
    g2.dispose();
    try { ImageIO.write(bi, "png", new File("imagemFinal.png")); }
    catch(IOException ioe) { System.out.println( ioe.getMessage() ); }

    // ou ainda, misturando com a API JAI
    PlanarImage imagemFinal = JAI.create("awtimage", image);
              g       g                    (       g ,     g );
    JAI.create("filestore",imagemFinal,"imagemFinal.png","PNG");
Aplicativo
Pra
            P encerrar o assunto...
                              t




5. CONSIDERAÇÕES FINAIS
Conclusões e Considerações Finais
                      ç

 • Algumas noções de PDI foram expostas
   para o desenvolvimento de um aplicativo
   específico;
 • Nas APIs Java:
   – a JAI apresenta melhor tratamento de
     entrada/saída;
   – ImageJ traz mais implementações básicas em
                                         á
     sua versão padrão;
   – As duas são bem flexíveis e extensíveis;
                          í            í
   – Pode-se criar um aplicativo combinando as
     duas APIs.
Dúvidas?
Dú id ?
Se gostou então podemos conversar ...
     gostou,

                            ... encontre me aqui:
                                encontre-me


http://engcomp.sobral.ufc.br/professores/ialis/


http://www.linkedin.com/pub/ialis-cavalcante/13/b35/46


http://osum.sun.com/profile/IalisJunior


http://www.slideshare.net/ialis                   ialis@ufc.br
Obrigado, ...
... e vamos para o almoço!

Técnicas de PDI com Java - Ercemapi 2009

  • 1.
    ERCEMAPI 2009 29de Outubro Parnaíba-PI MC 5: Técnicas de Processamento é Digital de Imagens com Java Iális Cavalcante – Engenharia da Computação UFC / Campus de Sobral
  • 2.
    Objetivos •Apresentar técnicas básicas que envolvem Processamento Digital de Imagens (PDI); • Apresentar APIs Java voltada para PDI; • Desenvolver uma pequena aplicação em p q p ç Java para descrição de regiões.
  • 3.
    E quem éo apresentador?
  • 4.
    Agenda 1. Introdução 2. APIsJava para Imagem 2 API J I 3. 3 Técnicas de Processamento Digital de Imagens (PDI) 4. Proposta de um Aplicativo de PDI 5. Considerações Finais
  • 5.
    • Vi ãGeral sobre PDI Visão G l b • Aplicações Reais 1. INTRODUÇÃO
  • 6.
    Introdução • PDIpossui alguns conceitos em comum com Visão Computacional e Computação Gráfica (caso de Análise de Imagens - FootScanAge). á • Pixels formam uma imagem – função f(x,y) • Primeiros registros de estudo – NASA (Guerra Fria) • Aplicações Multidisciplinares
  • 7.
    Comparativo Imagem Imagem Processamento de Imagens Dado Computação Gráfica C t ã G áfi Visão Computacional
  • 8.
  • 9.
    Histórico 1921 1922 Anos 20 – Sistema Bartlane Transmissão de Imagens via cabo submarino g Uma semana para três horas – Londres para Nova York
  • 10.
    Histórico Anos 20 (1925) – Sistema Bartlane Aumento para cinco níveis de brilho
  • 11.
    Histórico Primeira imagem da Lua. Obtida pela nave espacial americana Ranger 7. 7 31 de julho de 1964, 9:09 (17 minutos antes do impacto).
  • 12.
    Aplicações em Saúde 90 1 120 60 0.8 0.6 150 30 0.4 04 0.2 180 0 210 330 240 300 270
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
    • API JAI • API I ImageJ J 2. APIS JAVA PARA IMAGEM
  • 19.
    Formatos de Imagens • TIFF, GIF, PNG, JPEG, BMP, PBM, PGM, PMN • P d i d nos anos 80 e 90. Padronizados 90 • Suportados pela maioria das APIs e linguagens ling agens de p og amação programação.
  • 20.
    Uso da linguagemJava Why Java? • Atrativos: i – Livre; – Portável (“write once, run anywhere”); – Sintaxe similar à linguagem C; – Possui facilidade de internacionalização dos caracteres; – Vasta documentação; – Coletor de lixo (para desalocação automática de  memória); – Facilidade de criação de programação distribuída e  concorrente; – P di Paradigma Orientado a Objetos. O i t d Obj t
  • 21.
    Java Advanced Imaging(JAI) API g g( ) PlanarImage ColorModel Raster ColorSpace SampleModel DataBuffer Estrutura da classe de suporte a imagem na API JAI. Adaptado de Santos (2004).
  • 22.
    Java Advanced Imaging(JAI) API g g( ) • Leitura/Escrita de Imagens public class EScomJAI { public static void main(String[] args) { // leitura da imagem PlanarImage i Pl I image = JAI JAI.create("fileload", "L t ("fil l d" "Lenna.png"); ") double[][] bandCombine = {{0.21f,0.71f,0.08f,0.0f}}; // conversão do modelo de cores image = JAI.create("BandCombine", image, bandCombine); // escrita do arquivo JAI.create("filestore",image,"lennagl.png","PNG"); } }
  • 23.
    ImageJ API Plugin Plugin Plugin Plugin Plugin ImageJ AWT Java Estrutura geral da API ImageJ. Adaptado de Burger & Burge (2009).
  • 24.
    ImageJ API Software • Uso de plugins expande a comunidade de desenvolvedores;; • Di Disponibiliza um software com a execução ibili ft ã de todas as funcionalidades implementadas;
  • 25.
    Listagem: ExibeImagem.java publicclass ExibeImagem extends JFrame { public ExibeImagem() throws IOException { // início do construtor BufferedImage imagem = ImageIO.read(new File(“Lenna.png”)); String infoImagem = “Dimensões: ”+imagem.getWidth()+ “x”+imagem.getHeight()+“ Bandas: ”+ imagem.getRaster().getNumBands(); ImageIcon icone = new ImageIcon(imagem); JLabel labImagem = new JLabel(icone); (…) // adiciona labImagem e infoImage à interface this.setVisible(true); } // fim do construtor // Método principal p public static void main(String args[]){ ( g g []){ try{ // tratamento de exceção de E/S ExibeImagem appExibeImg = new ExibeImagem(); } }catch(IOException exc){ ( p ){ System.out.println(“Erro de leitura! ”+exc.getMessage()); } } // fim do método principal } // fim da classe
  • 26.
    Resultado: ExibeImagem.java Imagem Original. Fonte: Imagem adaptada de http://www.lenna.org/. p p // g/ Imagem exibida pela classe.
  • 27.
    Tipos de Imagens • Realce • Segmentação • Morfologia Matemática 3. TÉCNICAS DE PROCESSAMENTO DIGITAL DE IMAGENS
  • 28.
    Técnicas de Basepara Aplicativo • Realce – Negativo e Filtragem (Passa-Baixa e Passa-Alta ) • Segmentação – Limiarização e Watershed • Morfologia Matemática – Erosão Dilatação Erosão, Dilatação, Abertura e Fechamento
  • 29.
    Tipos de Imagens Imagem Binária g Imagem em g Imagem Colorida g Níveis de Cinza
  • 30.
  • 31.
    double[][] bandCombine ={ {R, G, B, 0.0f} }; image = JAI.create("BandCombine", image, bandCombine); R = 1.0f R = 0.0f R = 0.0f G = 0.0f G = 1.0f G = 0.0f B = 0.0f B = 0.0f B = 1.0f
  • 32.
    Negativo de umaImagem g g • Negativo de uma Imagem – Realce com processamento ponto-a-ponto ponto a ponto – Aplicações em imagens médicas – Reverter a ordem do preto para o branco • Intensidade da imagem de saída diminui • Intensidade da entrada aumenta • s=L–1–r
  • 33.
    Negativo de umaImagem g g s = T(r) Claro T(r) ro Escur Imagem Original r Escuro Claro Função de Transformação ç ç Imagem Processada
  • 34.
    Presença de Ruídoem Imagens • Distorções em uma imagem afetam a õ f percepção da sua real informação; • Uma distorção crítica é a presença de ruído; – Implica em nova informação na imagem; • Normalmente os ruídos são definidos por p uma distribuição estatística: – modelo gaussiano, speckle, poisson, etc. g , p ,p ,
  • 35.
    Efeito do Ruído Imagem Original Mudanças de Perspectivas ç p
  • 36.
    Efeito do Ruído Imagem Ruidosa “Sal e Pimenta” Mudanças de Perspectivas ç p
  • 37.
    Efeito do Ruído Imagem Ruidosa Speckle Mudanças de Perspectivas ç p
  • 38.
    Efeito do Ruído Presença de ruído Poisson. Imagem Original Presença de ruído Presença de ruído Speckle. “Sal e pimenta”.
  • 39.
    Realce com Processamentopor Máscara (1) (2) (3) (4)
  • 40.
    Realce com Processamentopor Máscara Exemplo de Máscara (3x3) • g(x,y) = T[f(x,y)] (T opera em uma vizinhança de g( ,y) [ ( ,y)] ( p ç pixels) • z5’ = R = w1z1 + w2z1+ ... + w9z9 (Filtro Linear) ( ) – z5’: soma ponderada de pixels na vizinhança de z5 • z5 = max(zk, k = 1, 2, ... 9) (Filtro Não-Linear) Não Linear) – Não satisfaz a condição de um filtro linear
  • 41.
    Tipos de Filtragem p g • A distribuição de valores na máscara define o tipo de filtragem: p g – Passa-alta • Aguçamento das bordas; – Passa-baixa •S Supressão d ruído, b ã de íd borramento d imagem; t da i – Passa-banda • Restauração da imagem.
  • 42.
    Detectores de Bordas(Gradiente – Passa-Alta) Imagem Original Filtro de Prewitt Filtro de Sobel Filtro de Roberts
  • 43.
    Definição de Gradiente (a) (b) s = [1 2 1; 0 0 0; -1 -2 -1]; A = zeros(10); ( ); Figura Fig a – (a) Imagem original; (b) Imagem o iginal A(3:7,3:7) = ones(5); após aplicação do filtro de Sobel. H = conv2(A,s); mesh(H)
  • 44.
    Filtro de Suavização(passa-baixa) • São úteis para redução de ruído e borramento de imagens – Detalhes são perdidos • O tamanho da máscara (ou seja vizinhança) determina o grau seja, de suavização e perda de detalhes. – Os elementos da máscara devem ser números positivos p – Exemplo: Média Local – R = 1/9 (1z1 + 1z2 + ... +1z9)              normalizado: dividido por 9
  • 45.
    Filtro por mediana(não-linear) • Substitua f(x,y) pela mediana [f(x’,y’)] onde (x’,y’) pertence a  vizinhança ç • Muito efetivo na remoção do ruído com componentes do  tipo espigada (“spike”, ocorrências aleatórias de valores  brancos e pretos) • Preserva melhor as bordas • Exemplo: 10 20 20 Ordenar 20 15 20 (10,15,20,20,20,20,20,25,100) 25 20 100 – Mediana = 20, então substitua (15) por (20)
  • 46.
    Filtragem da Mediana Imagem Ruidosa Filtragem com Janela 3x3 “Sal e Pimenta” Filtragem com Janela 5x5 Filtragem com Janela 7x7
  • 47.
    Limiarização ç • Comprime a faixa de nível de cinza de pouco í interesse – Inclinação da linha entre [0,1] • Alargamento da faixa de nível de cinza de maior interesse – Inclinação da linha monotonicamente crescente – r1 = r2 – s1 = 0 e s2 = L – 1
  • 48.
    Limiarização ç s = T(r) Claro T(r) ro Escur Imagem Original r Escuro Claro Função de Transformação Imagem Processada
  • 49.
    Limiarização ç Imagem Original Limiar de 130 Limiar de 140 Limiar de 150
  • 50.
    Watershed • Consideando uma imagem em tom de cinza como Considerando ma cin a uma superfície topográfica: – Todos os vales foram perfurados na sua área mais funda da superfície; – Toda a superfície é lentamente preenchida por água, este irá progressivamente inundar todas as bacias da imagem; • Represas podem ser aumentadas onde a água vem de dois pontos distintos, podendo se unir; distintos – Ao fim da inundação, cada bacia é cercada por cumes (represas) representando seu limite. – Este processo define a divisão das regiões presentes na imagem.
  • 51.
    Watershed Imagem Original Imagem em Níveis de Cinza Imagem com Marcadores Imagem Final
  • 52.
    Watershed Animação sobre Watershed.Fonte: http://cmm.ensmp.fr/~beucher/wtshed.html.
  • 53.
    Watershed • Oobjetos das imagens são definidos como Os bj t d i ã d fi id as regiões de muitos valores de escala de cinza constantes. i t t • O operador gradiente irá realçar os limites dos objetos (fim da inundação). j ( ç ) • Os marcadores indicam, de forma bruta, indicam bruta onde os objetos estão localizados na imagem (ponto de partida da inundação).
  • 54.
    Morfologia Matemática • Elemento Estruturante (EE): – Structuring Element (SE) – Pequeno conjunto usado para reconhecer a morfologia do objeto de interesse em uma imagem. f l d b d – Forma e tamanho devem ser adaptados para as propriedades geométricas da imagem processada. i d d ét i d i d 0.5 05 1 1 1 1.5 2 2 2 3 3 2.5 3 4 4 3.5 5 5 4 6 6 4.5 5 7 7 5.5 0.5 1 1.5 2 2.5 3 3.5 4 4.5 5 5.5 1 2 3 4 5 6 7 0.5 1 1.5 2 2.5 3 3.5 4 4.5 5 5.5
  • 55.
    Morfologia Matemática •Erosão e Dilatação • A partir destes: Abertura e Fechamento p
  • 56.
    Morfologia Matemática •Erosão não é o inverso da dilatação! – Uma erosão seguida de uma dilatação nem sempre retorna a imagem original. •B quadrado 3x3
  • 57.
    Morfologia Matemática Imagem Original Resultado da Erosão R Elemento Estruturante Raio = 11 Resultado da Dilatação
  • 58.
    Morfologia Matemática • Abertura – Resultado da erosão seguida da dilatação; • Usando o mesmo elemento estruturante. • γB(X) = δB(εB(X)) – Propriedades: • Idempotente; • Crescente; • Anti-extensiva; ? (a) (b) Figura–Abertura com EE circular: (a) imagem original e (b) sobreposição do resultado. ( ) p ç Resultado da abertura é sempre menor ou igual à imagem original.
  • 59.
    Morfologia Matemática • Fechamento – Dual da Abertura; – Resultado da dilatação seguida da erosão • Usando o mesmo elemento estruturante. • φB(X) = εB(δB(X)) – Propriedades: • Idempotente; • Crescente; • Extensiva; ? Resultado da abertura é (a) (b) sempre maior ou igual à i i l Figura – Fechamento com EE circular: (a) imagem original e (b) sobreposição do resultado. imagem original.
  • 60.
    Morfologia Matemática Imagem Original Resultado da Abertura R Elemento Estruturante Raio = 11 Resultado do Fechamento
  • 61.
    Morfologia Matemática ImagemOriginal Resultado da Erosão Resultado da Dilatação Resultado da Abertura Resultado do Fechamento
  • 62.
    • Definição doaplicativo • Uso da API ImageJ • Desenvolvimento 4. PROPOSTA DE UM APLICATIVO DE PDI
  • 63.
    Fluxograma uog a a Imagem  Ruidosa Filtragem (eliminação do ruído) Segmentação (separação de regiões) (separação de regiões) Objeto está  Não bem  Pós‐Processamento identificado? Sim Imagem  Imagem Processada
  • 64.
    Aplicando Filtro daMediana // objeto “imagem"” da classe java.awt.Image instanciado // com a imagem original ByteProcessor processador = new ByteProcessor(imagem); processador.medianFilter(); // resultado do filtro é p passado ao objeto “imagem” j g imagem = processador.createImage(); Imagem Ruidosa Imagem Filtrada
  • 65.
    Aplicando Segmentação // objeto “imagem” da classe java.awt.Image instanciado // com a imagem filtrada ByteProcessor processador = new ByteProcessor(imagem); // “valorLimiar” é inteiro e que indica o limiar da segmentação p processador.threshold(valorLimiar); ( ); // resultado da limiarização é passado ao objeto “imagem” imagem = processador.createImage(); Imagem Filtrada Imagem Segmentada
  • 66.
    Aplicando Fechamento // objeto“imagem” da classe Image instanciado com a imagem segmentada ByteProcessor processador = new ByteProcessor(imagem); // etapa de dilatação - 1o passo do fechamento processador.dilate(1,0); imagem = processador.createImage(); processador = new B P d ByteProcessor(imagem); (i ) // etapa de erosão - 2o passo do fechamento p processador.erode(1,0); ( , ); imagem = processador.createImage(); Imagem Segmentada Imagem Final
  • 67.
    Melhor uso dememória • E i Evitar o acúmulo de variáveis estáticas no ú l d iá i ái método principal – Para auxiliar o desempenho do coletor de lixo da máquina virtual Java. • O uso de variáveis estáticas deve ser evitado – Ocupam muito recurso de memória – São as últimas instâncias a serem eliminadas pelo garbage collector
  • 68.
    Melhor uso dememória Execução do garbage collector: • E ã d b ll – System.gc() ou – Runtime rt = Runtime.getRuntime(); g (); rt.gc(); long mem = rt freeMemory(); rt.freeMemory(); • E ã frequente d gc() pode resultar Execução f t de () d lt na degradação do desempenho.
  • 69.
    Listagem: SegRdI.java (visãogeral) public class S RdI extends JF bli l SegRdI t d JFrame { // atributos JPanel painelPrinc, painelBotoes; JButton b b b btnAbrir, btnProc, b btnLimpar, b btnSair; File fileName; ImagePlus imagemIJ; // inicialização dos componentes gráficos public void iniciaComponentes() { ... } // método da ação ao clicar o botão Abrir private void abrirActionPerformed(ActionEvent evt) { … } // método da ação ao clicar o botão Processar private void processarActionPerformed(ActionEvent evt) { … } // método da ação ao clicar o botão Limpar private void limparActionPerformed(ActionEvent evt) { … } // método da ação ao clicar o botão Sair private void sairActionPerformed(ActionEvent evt) { System.exit(0); } // construtor padrão public SegRdI() { this.iniciaComponentes(); } // método principal p p public static void main(String[] args) { SegRdI aplicacao = new SegRdI(); } } // fim da classe
  • 70.
    Listagem: SegRdI.java (iniciainterface gráfica) public void iniciaComponentes(){ this.setLayout(new BorderLayout()); painelPrinc = new JPanel(); painelPrinc.setLayout(new BorderLayout()); this.add(painelPrinc, BorderLayout.CENTER); painelBotoes = new JP i lB t JPanel(); painelBotoes.setLayout(new Fl L l() i lB t tL t( FlowLayout()); t()) this.add(painelBotoes, BorderLayout.SOUTH); // adicionando botões btnAbrir = new JButton(); painelBotoes.add(btnAbrir); btnAbrir.setText(“ Abrir ... ”); btnProc = new JButton(); painelBotoes.add(btnProc); btnProc.setText(“Processar”); // -> faz-se o mesmo para os botões “btnLimpar” e “btnSair” btnLimpar btnSair // configurar ações dos botões btnAbrir.addActionListener(new btnAbrir addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { abrirActionPerformed(evt); } } ); btnProc.addActionListener( ... ); // relacionar com o método processarActionPerformed btnLimpar.addActionListener( ... ); // relacionar com o método limparActionPerformed p ( p btnSair.addActionListener( ... ); // relacionar com o método sairActionPerformed this.setVisible(true); this.setSize(450,350); this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); } // fim do método initComponents
  • 71.
    Listagem: SegRdI.java (limparinterface) private void limparActionPerformed(ActionEvent evt) { ImagePlus imp = new ImagePlus(); ImageCanvas ic = new ImageCanvas(imp); g g ( p) painelPrinc.removeAll(); p painelPrinc.add(ic,BorderLayout.CENTER); ( , y ); } // fim do método limparActionPerformed
  • 72.
    Listagem: SegRdI.java (abririmagem) private void abrirActionPerformed(ActionEvent evt) { // exibe caixa de diálogo para abrir arquivo de imagem JFileChooser dialogo = new JFileChooser(); dialogo.setFileSelectionMode(JFileChooser.FILES_ONLY); int result = dialogo.showOpenDialog(this); if (result == JFileChooser CANCEL OPTION) return; JFileChooser.CANCEL_OPTION) // recupera arquivo selecionado fileName = dialogo.getSelectedFile(); // exibe erro se inválido if (fileName == null || fileName.getName().equals(“”)) { JOptionPane.showMessageDialog(this, “Nome de Arquivo Inválido”, “Nome de Arquivo Inválido”, JOptionPane ERROR MESSAGE); Inválido” JOptionPane.ERROR_MESSAGE); return; } imagemIJ = new ImagePlus(fileName.toString()); JScrollPane sp = new JScrollPane( JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); JS llP HORIZONTAL SCROLLBAR AS NEEDED) ImageCanvas ic = new ImageCanvas(imagemIJ); sp.add(ic); sp.setSize(imagemIJ.getWidth(), imagemIJ.getHeight()); painelPrinc.add(sp,BorderLayout.CENTER); l dd( d C ) } // fim do método abrirActionPerformed
  • 73.
    Listagem: SegRdI.java (processamentoda imagem - I) private void processarActionPerformed(ActionEvent evt) { Image image = imagemIJ.getImage(); ByteProcessor b t P B t P byteProc = new B t P ByteProcessor(image); (i ) byteProc.medianFilter(); image = byteProc.createImage(); ImagePlus i Filt = new I I Pl imFilt ImagePlus(“filtragem”,image); Pl (“filt ”i ) // descobrindo maior valor de nível de cinza int max = -1; for(int lin = 0; lin < imFilt.getHeight(); lin++) for(int col = 0; col < imFilt.getWidth(); col++){ int[] pixels = imFilt.getPixel(col, lin); if (pixels[0]>max) max = pixels[0]; } image = imFilt.getImage(); byteProc = new ByteProcessor(image); // aplicando a segmentação através de limiarização byteProc.threshold(max-1); image = byteProc.createImage(); ImagePlus imSeg = new ImagePlus(“segmentacao”,image); image = imSeg.getImage(); byteProc = new ByteProcessor(image);
  • 74.
    Listagem: SegRdI.java (processamentoda imagem - II) // inicialmente aplica-se a dilatação byteProc.dilate(1,0); image = b t P i byteProc.createImage(); t I () ImagePlus imDil = new ImagePlus(“dilatacao”,image); image = imDil.getImage(); byteProc = new ByteProcessor(image); // posteriormente aplica-se a erosão byteProc.erode(1,0); image = byteProc createImage(); byteProc.createImage(); ImagePlus imErosao = new ImagePlus(“erosao”,image); JScrollPane sp = new JScrollPane( JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JS llP VERTICAL SCROLLBAR AS NEEDED JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); ImageCanvas ic = new ImageCanvas(imErosao); sp.add(ic); g g sp.setSize(imErosao.getWidth(), imErosao.getHeight()); painelPrinc.removeAll(); painelPrinc.add(sp,BorderLayout.CENTER); painelPrinc add(sp BorderLayout CENTER); } // fim do método processarActionPerformed
  • 75.
    Listagem: SegRdI.java (acrescentandoescrita) // adotando a API Java 2D (alternativa para ImageJ) BufferedImage bi = new BufferedImage(imErosao getWidth() BufferedImage(imErosao.getWidth(), imErosao.getHeight(), BufferedImage.TYPE_BYTE_BINARY); Graphics2D g2 = bi.createGraphics(); p g p (); g2.drawImage(image, 0, 0, null); g2.dispose(); try { ImageIO.write(bi, "png", new File("imagemFinal.png")); } catch(IOException ioe) { System.out.println( ioe.getMessage() ); } // ou ainda, misturando com a API JAI PlanarImage imagemFinal = JAI.create("awtimage", image); g g ( g , g ); JAI.create("filestore",imagemFinal,"imagemFinal.png","PNG");
  • 76.
  • 77.
    Pra P encerrar o assunto... t 5. CONSIDERAÇÕES FINAIS
  • 78.
    Conclusões e ConsideraçõesFinais ç • Algumas noções de PDI foram expostas para o desenvolvimento de um aplicativo específico; • Nas APIs Java: – a JAI apresenta melhor tratamento de entrada/saída; – ImageJ traz mais implementações básicas em á sua versão padrão; – As duas são bem flexíveis e extensíveis; í í – Pode-se criar um aplicativo combinando as duas APIs.
  • 79.
  • 80.
    Se gostou entãopodemos conversar ... gostou, ... encontre me aqui: encontre-me http://engcomp.sobral.ufc.br/professores/ialis/ http://www.linkedin.com/pub/ialis-cavalcante/13/b35/46 http://osum.sun.com/profile/IalisJunior http://www.slideshare.net/ialis ialis@ufc.br
  • 81.
    Obrigado, ... ... evamos para o almoço!