Sei sulla pagina 1di 146

Introduo ao Processamento de Imagens Digitais em Java / API JAI

Escola de Vero da Unifesp

Rafael Santos

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

1 /146

Objetivo

Apresentar conceitos, tcnicas e exemplos bsicos de aplicao de processamento de imagens digitais. Implementaes em Java opcionalmente com a API JAI (Java Advanced Imaging). Parte reduzida do livro on-line Java Image Processing Cookbook (http://www.lac.inpe.br/JIPCookbook/index.jsp). Cdigo!

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

2 /146

Introduo

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

3 /146

Aplicaes de Processamento de Imagens

Sensoriamento Remoto:

Geologia (estudo da composio da superfcie). Agricultura (determinao da cobertura vegetal). Engenharia Florestal (idem). Cartografia (mapeamento da superfcie). Meteorologia.

Medicina e Biologia. Astronomia (macro) e Fsica (micro). Produo e Controle de Qualidade. Segurana e Monitoramento. Documentos, Web, etc.
http://www.lac.inpe.br/~rafael.santos 4 /146

Fevereiro/2010

Imagens Digitais

Imagem = matriz de pixels. Pixel = medida, conjunto de medidas ou ndice para tabela de valores. Metadados: dados adicionais sobre a imagem.

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

5 /146

Imagens e Pixels
34 29 105 12 30 105 34 29 105 34 29 105 34 29 105 12 30 105 34 29 105
Fevereiro/2010

34 42 42 29 49 49 105 97 97 34 14 34 29 48 29 105 97 105 34 69 36 29 76 54 105 97 104 12 85 113 30 103 108 105 85 72 34 58 100 29 53 123 105 105 66 34 42 90 29 49 115 105 97 78 42 35 85 49 41 103 97 105 85

34 29 105 34 29 105 12 30 105 36 54 104 90 115 78 107 136 58 111 132 60

12 42 30 49 105 97 42 34 49 29 97 105 12 42 30 49 105 97 34 34 29 29 105 105 14 34 48 29 97 105 85 42 103 49 85 97 105 42 119 49 86 97


6 /146

http://www.lac.inpe.br/~rafael.santos

Tipos mais comuns

Cmera Digital

3264x2448 elementos sensores Resoluo: no se aplica 3 bandas Cada pixel discretizado com valores entre 0 e 255

Scanner

Array mvel de elementos sensores Resoluo: 2400 DPI ou mais 3 bandas Discretizao varivel
http://www.lac.inpe.br/~rafael.santos 7 /146

Fevereiro/2010

Outros Tipos de Imagens Digitais

No somos limitados imagens como as de cmeras e scanners!


Pixels podem ter mais que trs valores associados a eles. Pixels podem ter valores fora do tradicional intervalo [0, 255]. Pixels no precisam representar valores inteiros ou positivos! Imagens multispectrais e hiperspectrais. Imagens de modelos de terreno, mdicas (Raio-X), etc.

Exemplos:

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

8 /146

Outros Tipos de Imagens Digitais

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

9 /146

Outros Tipos de Imagens Digitais

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

10 /146

Imagens Digitais: Multiespectrais

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

11 /146

Imagens Digitais: Hiperespectrais

http://www.cossa.csiro.au/hswww/Overview.htm

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

12 /146

Processamento de Imagens em Java

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

13 /146

Processamento de Imagens em Java

Preciso saber Java?


Ajuda e muito, mas no imprescindvel. Experincia com C++, C#, outras linguagens pode ajudar.

Todo o cdigo est no livro on-line (http://www.lac.inpe.br/JIPCookbook), completo e comentado.

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

14 /146

Processamento de Imagens em Java


Popularidade e flexibilidade de Java. Temos APIs para representao, visualizao e I/O simples de imagens como parte do JSE. Temos a API Java Advanced Imaging para operaes muito mais poderosas, flexveis e complexas! E a questo da performance?

Melhor do que esperado! No estou preocupado com real time. Mais valor clareza e simplicidade de cdigo.

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

15 /146

Processamento de Imagens em Java: JAI


Java (Swing) tem classes e operadores bsicos. Java Advanced Imaging


API adicional (download separado). Projeto do java.net pblico mas no totalmente aberto.

Muitos operadores especficos para processamento de imagens. Execuo postergada e cadeias de operadores. Representao mais poderosa e flexvel de imagens (tiles). Alguns operadores acelerados (implementao nativa). Dvida: ter apoio da Oracle?

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

16 /146

Representao de Imagens em Java

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

17 /146

Representao de Imagens: Java

RenderedImage
ColorModel
ColorSpace

Raster
SampleModel DataBuffer

Formato de representao na memria diferente de formato de arquivo! Existem limitaes mtuas.


http://www.lac.inpe.br/~rafael.santos 18 /146

Fevereiro/2010

Representao de Imagens: TiledImage (JAI)

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

19 /146

Representao de Imagens
RenderedImage

WritableRenderedImage

BufferedImage

ImageJAI

PlanarImage

RenderedOp

API JAI
Fevereiro/2010 http://www.lac.inpe.br/~rafael.santos

TiledImage
20 /146

Criando Imagens em Java

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

21 /146

Criando Imagens (sem JAI) Imagens simples (RGB, puro preto-e-branco, nveis de cinza; pixels so arrays de bytes). 1. Criamos instncia de BufferedImage. 2. Criamos instncia de WritableRaster associada BufferedImage. 3. Manipulamos os pixels do WritableRaster.

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

22 /146

Criando Imagens (sem JAI)


public static void main(String[] args) throws IOException { int width = 256; int height = 256; BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB); WritableRaster raster = image.getRaster(); int[] cor1 = new int[]{255,0,0}; int[] cor2 = new int[]{0,0,255}; int cont=0; for(int h=0;h<height;h++) for(int w=0;w<width;w++) { if ((((w/32)+(h/32)) % 2) == 0) raster.setPixel(w,h,cor1); else raster.setPixel(w,h,cor2); } ImageIO.write(image,"PNG",new File("checkerboard.png")); }
Fevereiro/2010 http://www.lac.inpe.br/~rafael.santos 23 /146

Criando Imagens (com JAI) Imagens simples (RGB, puro preto-e-branco, nveis de cinza) ou multibandas; pixels podem ser arrays de qualquer tipo nativo. 1. Criamos instncia de SampleModel usando RasterFactory. 2. Criamos um TiledImage com este SampleModel. 3. Criamos um WritableRaster a partir da TiledImage. 4. Manipulamos os pixels do WritableRaster.

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

24 /146

Criando Imagens (com JAI)


intwidth=640;intheight=640; SampleModelsampleModel= RasterFactory.createBandedSampleModel(DataBuffer.TYPE_BYTE, width,height,1); TiledImagetiledImage= newTiledImage(0,0,width,height,0,0,sampleModel,null); WritableRasterwr=tiledImage.getWritableTile(0,0); for(inth=0;h<height/32;h++) for(intw=0;w<width/32;w++) { int[]fill=newint[32*32];//Ablockofpixels... Arrays.fill(fill,(int)(Math.random()*256)); wr.setSamples(w*32,h*32,32,32,0,fill); } JAI.create("filestore",tiledImage, "jaigl.png","PNG");

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

25 /146

Criando Imagens (com JAI) Para imagens com tiles um pouco mais complicado... 1. Criamos instncia de SampleModel usando RasterFactory. 2. Criamos um TiledImage com este SampleModel. 3. Para cada tile:
1. criamos um WritableRaster a partir da TiledImage. 2. Manipulamos os pixels do WritableRaster.

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

26 /146

Criando Imagens (com JAI)


intwidth=483;intheight=483; inttWidth=64;inttHeight=64; SampleModelsampleModel= RasterFactory.createBandedSampleModel(DataBuffer.TYPE_BYTE, tWidth,tHeight,3); ColorModelcm=TiledImage.createColorModel(sampleModel); TiledImagetiledImage= newTiledImage(0,0,width,height,0,0,sampleModel,cm); //Createthecolors. int[]red=newint[]{255,0,0}; int[]green=newint[]{0,255,0}; int[]blue=newint[]{0,0,255}; int[]yellow=newint[]{255,255,0}; int[]black=newint[]{0,0,0};

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

27 /146

Criando Imagens (com JAI)


for(intth=tiledImage.getMinTileY();th<=tiledImage.getMaxTileY();th++) for(inttw=tiledImage.getMinTileX();tw<=tiledImage.getMaxTileX();tw++) { WritableRasterwr=tiledImage.getWritableTile(tw,th); for(intih=0;ih<tHeight;ih++) for(intiw=0;iw<tWidth;iw++) { intw=wr.getMinX()+iw; inth=wr.getMinY()+ih; if((w>=17)&&(w<17+216)&&(h>=17)&&(h<17+216)) wr.setPixel(w,h,red); elseif((w>=250)&&(w<250+216)&&(h>=17)&&(h<17+216)) wr.setPixel(w,h,green); elseif((w>=17)&&(w<17+216)&&(h>=250)&&(h<250+216)) wr.setPixel(w,h,yellow); elseif((w>=250)&&(w<250+216)&&(h>=250)&&(h<250+216)) wr.setPixel(w,h,blue); elsewr.setPixel(w,h,black); } }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

28 /146

Criando Imagens (com JAI)


TIFFEncodeParamtep=newTIFFEncodeParam(); tep.setWriteTiled(true); tep.setTileSize(tWidth,tHeight); JAI.create("filestore",tiledImage,"rgbtile.tiff","TIFF",tep);

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

29 /146

Armazenando e Recuperando Imagens

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

30 /146

Entrada e Sada

Sem JAI (BufferedImage):


public static void main(String[] args) throws IOException { File f = new File(args[0]); BufferedImage image = ImageIO.read(f); System.out.println("Dimenses: "+ image.getWidth()+"x"+image.getHeight()+" pixels"); }

Com JAI (PlanarImage):


public static void main(String[] args) throws IOException { PlanarImage image = JAI.create("fileload",args[0]); System.out.println("Dimenses: "+ image.getWidth()+"x"+image.getHeight()+" pixels"); }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

31 /146

Entrada e Sada

Sem JAI (BufferedImage):


public static void main(String[] args) throws IOException { int width = 256; int height = 256; BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB); ... ImageIO.write(image,"PNG",new File("checkerboard.png")); }

Com JAI (PlanarImage):


public static void main(String[] args) throws IOException { ... TiledImage tiledImage = new TiledImage(0,0,width,height,0,0,sampleModel,colorModel); ... JAI.create("filestore",tiledImage,"floatpattern.tif","TIFF"); }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

32 /146

Acesso Direto a Pixels

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

33 /146

Acesso a pixels (sem JAI)


public static void main(String[] args) throws IOException { File f = new File(args[0]); BufferedImage imagem = ImageIO.read(f); Memria! Raster raster = imagem.getRaster(); int[] pixel = new int[3]; int brancos = 0; for(int h=0;h<imagem.getHeight();h++) for(int w=0;w<imagem.getWidth();w++) { raster.getPixel(w,h,pixel); if ((pixel[0] == 255) && (pixel[1] == 255) && (pixel[2] == 255)) brancos++; } System.out.println(brancos+" pixels brancos"); }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

34 /146

Acesso a pixels (com JAI)


public static void main(String[] args) throws IOException { File f = new File(args[0]); BufferedImage imagem = ImageIO.read(f); RandomIter iterator = RandomIterFactory.create(imagem,null); int[] pixel = new int[3]; int brancos = 0; for(int h=0;h<imagem.getHeight();h++) for(int w=0;w<imagem.getWidth();w++) { iterator.getPixel(w,h,pixel); if ((pixel[0] == 255) && (pixel[1] == 255) && (pixel[2] == 255)) brancos++; } System.out.println(brancos+" pixels brancos"); }

Existem tambm RectIter e RookIter.


http://www.lac.inpe.br/~rafael.santos 35 /146

Fevereiro/2010

Exibindo Imagens

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

36 /146

Visualizao de Imagens

Componentes de interfaces grficas para mostrar imagens. Geralmente bem simples, melhorias como interatividade, processamento, etc. ficam por conta do programador...

o que fcil de fazer graas ao mecanismo de herana!

Conhecimentos de programao de interfaces grficas em Java so teis: s conhecimento de design no adiantam.


Componentes de UI JFrame

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

37 /146

Display de Imagens (sem JAI)


public static void main(String[] args) throws IOException { BufferedImage image = ImageIO.read(new File(args[0])); JFrame frame = new JFrame("Display Image: "+args[0]); ImageIcon icon = new ImageIcon(image); JLabel imageLabel = new JLabel(icon); frame.getContentPane().add(new JScrollPane(imageLabel)); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(600,300); frame.setVisible(true); }

BufferedImage ImageIcon JLabel (JScrollPane).

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

38 /146

Display de Imagens (sem JAI)

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

39 /146

Display de Imagens (com JAI)


public static void main(String[] args) throws IOException { BufferedImage image = ImageIO.read(new File(args[0])); JFrame frame = new JFrame("Display Image: "+args[0]); DisplayJAI display = new DisplayJAI(image); frame.getContentPane().add(new JScrollPane(display)); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(600,300); frame.setVisible(true); }

DisplayJAI mais flexvel, permite alguma interao (no implementada). No parte da API JAI (!?).

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

40 /146

Exibindo Imagens (Solues Especficas)

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

41 /146

Imagens Sincronizadas

Componente que mostra duas imagens sincronizadas:

Modificao no viewport de uma causa modificao no viewport da outra.

Composio de instncias de DisplayJAI.

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

42 /146

Imagens Sincronizadas

Exibio de duas instncias de DisplayJAI de forma sincronizada.

public class DisplayTwoSynchronizedImages extends JPanel implements AdjustmentListener { protected DisplayJAI dj1; protected DisplayJAI dj2; protected JScrollPane jsp1; protected JScrollPane jsp2;

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

43 /146

Imagens Sincronizadas
public DisplayTwoSynchronizedImages(RenderedImage im1, RenderedImage im2) { super(); // Cria componente com duas imagens com JScrollPanes setLayout(new GridLayout(1,2)); dj1 = new DisplayJAI(im1); dj2 = new DisplayJAI(im2); jsp1 = new JScrollPane(dj1); jsp2 = new JScrollPane(dj2); add(jsp1); add(jsp2); // Registra listeners para os scroll bars do JScrollPanes jsp1.getHorizontalScrollBar().addAdjustmentListener(this); jsp1.getVerticalScrollBar().addAdjustmentListener(this); jsp2.getHorizontalScrollBar().addAdjustmentListener(this); jsp2.getVerticalScrollBar().addAdjustmentListener(this); }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

44 /146

Imagens Sincronizadas
public void adjustmentValueChanged(AdjustmentEvent e) { if (e.getSource() == jsp1.getHorizontalScrollBar()) jsp2.getHorizontalScrollBar().setValue(e.getValue()); if (e.getSource() == jsp1.getVerticalScrollBar()) jsp2.getVerticalScrollBar().setValue(e.getValue()); if (e.getSource() == jsp2.getHorizontalScrollBar()) jsp1.getHorizontalScrollBar().setValue(e.getValue()); if (e.getSource() == jsp2.getVerticalScrollBar()) jsp1.getVerticalScrollBar().setValue(e.getValue()); } }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

45 /146

Imagens Sincronizadas: Exemplo


public class Borda { public static void main(String[] args) { PlanarImage imagem = JAI.create("fileload", args[0]); float[] kernelMatrix = { -1, -2, -1, 0, 0, 0, 1, 2, 1 }; KernelJAI kernel = new KernelJAI(3,3,kernelMatrix); PlanarImage bordas = JAI.create("convolve",imagem,kernel); JFrame frame = new JFrame("Bordas horizontais"); frame.add(new DisplayTwoSynchronizedImages(imagem,bordas)); frame.pack(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

46 /146

Imagens Sincronizadas: Exemplo

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

47 /146

Imagens Substitutas

Uso de imagens substitutas (surrogate images): Criamos uma imagem normalizada com pixels entre valores 0-255 Transformamos o tipo da imagem para bytes. Uma classe que herda de DisplayJAI pode executar estes passos.

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

48 /146

Imagens Substitutas
public class DisplaySurrogateImage extends DisplayJAI { protected PlanarImage surrogateImage; protected int width,height; public DisplaySurrogateImage(PlanarImage image) { width = image.getWidth(); height = image.getHeight(); // Recuperamos valores extremos da imagem. ParameterBlock pbMaxMin = new ParameterBlock(); pbMaxMin.addSource(image); PlanarImage extrema = JAI.create("extrema", pbMaxMin); double[] allMins = (double[])extrema.getProperty("minimum"); double[] allMaxs = (double[])extrema.getProperty("maximum"); double minValue = allMins[0]; double maxValue = allMaxs[0]; for(int v=1;v<allMins.length;v++) { if (allMins[v] < minValue) minValue = allMins[v]; if (allMaxs[v] > maxValue) maxValue = allMaxs[v]; }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

49 /146

Imagens Substitutas
// Reescalamos os nveis de cinza da imagem. double[] subtract = new double[1]; subtract[0] = minValue; double[] multiplyBy = new double[1]; multiplyBy[0] = 255./(maxValue-minValue); ParameterBlock pbSub = new ParameterBlock(); pbSub.addSource(image); pbSub.add(subtract); surrogateImage = (PlanarImage)JAI.create("subtractconst",pbSub); ParameterBlock pbMult = new ParameterBlock(); pbMult.addSource(surrogateImage); pbMult.add(multiplyBy); surrogateImage = (PlanarImage)JAI.create("multiplyconst",pbMult); // Convertemos para bytes. ParameterBlock pbConvert = new ParameterBlock(); pbConvert.addSource(surrogateImage); pbConvert.add(DataBuffer.TYPE_BYTE); surrogateImage = JAI.create("format", pbConvert); // Usamos esta imagem para display. set(surrogateImage); } }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

50 /146

Imagens Substitutas
public class DemonstraDisplaySurrogateImage { public static void main(String[] args) { PlanarImage image = JAI.create("fileload", args[0]); JFrame frame = new JFrame("Mostrando "+args[0]); frame.getContentPane().add( new JScrollPane(new DisplaySurrogateImage(image))); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setVisible(true); } }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

51 /146

Imagens Substitutas: LUTs


Uso de imagens substitutas (surrogate images) com LUTs: Look-up Tables (LUTs): tabela de cores.
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 1 2 2 2 1 0 0 0 0 0 0 1 1 2 2 2 3 2 1 1 0 0 0 1 1 1 2 2 3 2 2 1 1 1 0 0 0 1 1 2 3 2 2 2 1 1 0 0 0 0 0 0 1 2 2 2 1 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ndice 0 1 2 3 R G B 1 0

0 131 255 233 0

0 124

255 255 255

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

52 /146

Imagens Substitutas: LUTs


publicvoidsetLUT(short[][]lut) { SampleModelsampleModel=surrogateImage.getSampleModel(); SampleModelnewSampleModel= RasterFactory.createBandedSampleModel(DataBuffer.TYPE_BYTE, sampleModel.getWidth(),sampleModel.getHeight(),3); byte[]reds=newbyte[256]; byte[]greens=newbyte[256]; byte[]blues=newbyte[256]; for(inti=0;i<256;i++) { reds[i]=(byte)lut[i][0]; greens[i]=(byte)lut[i][1]; blues[i]=(byte)lut[i][2]; } ColorModelcolorModel=newIndexColorModel(8,256,reds,greens,blues); ImageLayoutlayout=newImageLayout(surrogateImage); layout.setColorModel(colorModel); HashMap<RenderingHints.Key,ImageLayout>map= newHashMap<RenderingHints.Key,ImageLayout>(); map.put(JAI.KEY_IMAGE_LAYOUT,layout); RenderingHintshints=newRenderingHints(map); ParameterBlockpb=newParameterBlock(); pb.addSource(surrogateImage); PlanarImagenewSurrogateImage=JAI.create("format",pb,hints); set(newSurrogateImage); }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

53 /146

Imagens Substitutas: LUTs


/**Theinvertedgraylut*/ publicfinalstaticshort[][]invGray() { short[][]lut=newshort[256][3]; for(shorti=0;i<256;i++) { lut[i][0]=(short)(255i); lut[i][1]=(short)(255i); lut[i][2]=(short)(255i); } returnlut; } /**Thesinlut(rgborder)*/ publicfinalstaticshort[][]sin_rgb() { short[][]lut=newshort[256][3]; for(shorti=0;i<256;i++) { lut[i][0]=(short)(127*(1+Math.sin(Math.PI*(i127)/255))); lut[i][1]=(short)(127*(1+Math.sin(Math.PI*(i)/255))); lut[i][2]=(short)(127*(1+Math.sin(Math.PI*(i+127)/255))); } returnlut; } Fevereiro/2010 http://www.lac.inpe.br/~rafael.santos 54 /146

Imagens Substitutas: LUTs

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

55 /146

Desenhando em Imagens

Podemos obter contextos grficos de BufferedImages e PlanarImages..

.. e us-los para desenhar sobre a imagem.

As imagens so modificadas (na memria) e podem ser visualizadas e/ou armazenadas com os grficos.

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

56 /146

Desenhando em Imagens
BufferedImagebaseImage=ImageIO.read(newFile("sjc_region.png")); int[][]coords=newint[][]{ {714,219}, {822,256}, {797,329}, {710,300}, {711,293}, {666,271}}; Path2D.FloatregionOfInterest=newPath2D.Float(); booleanisFirst=true; doublefirstX=0,firstY=0; for(int[]coord:coords) { intx=coord[0];inty=coord[1]; if(isFirst) { regionOfInterest.moveTo(x,y); firstX=x; firstY=y; isFirst=false; } else{regionOfInterest.lineTo(x,y);} } regionOfInterest.lineTo(firstX,firstY); Fevereiro/2010 http://www.lac.inpe.br/~rafael.santos 57 /146

Desenhando em Imagens
Path2D.FloatpathForWholeImage=newPath2D.Float(); pathForWholeImage.moveTo(0,0); pathForWholeImage.lineTo(baseImage.getWidth(),0); pathForWholeImage.lineTo(baseImage.getWidth(),baseImage.getHeight()); pathForWholeImage.lineTo(0,baseImage.getHeight()); pathForWholeImage.lineTo(0,0); AreawholeImage=newArea(pathForWholeImage); wholeImage.subtract(newArea(regionOfInterest)); Graphics2Dg2d=(Graphics2D)baseImage.getGraphics(); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setColor(newColor(255,255,255,100)); g2d.fill(wholeImage); g2d.setStroke(newBasicStroke(5f)); g2d.setColor(newColor(255,0,0,200)); g2d.draw(regionOfInterest); JFrameframe=newJFrame("Highlightingimageregions"); ImageIconicon=newImageIcon(baseImage); JLabellabel=newJLabel(icon); frame.getContentPane().add(newJScrollPane(label)); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack();frame.setVisible(true); Fevereiro/2010 http://www.lac.inpe.br/~rafael.santos 58 /146

Desenhando em Imagens

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

59 /146

Operadores da API JAI

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

60 /146

Operadores da API JAI: Introduo


Classe JAI prov mtodo create. Vrios operadores so registrados, chamados de forma unificada. Parmetros (se houver) so passados atravs de instncia de ParameterBlock. Mtodo retorna instncia de RenderedOp cast para PlanarImage se necessrio.

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

61 /146

Relembrando: Representao de Imagens


RenderedImage

WritableRenderedImage

BufferedImage

ImageJAI

PlanarImage

RenderedOp

API JAI
Fevereiro/2010 http://www.lac.inpe.br/~rafael.santos

TiledImage
62 /146

Operadores da API JAI: invert

Inverte os valores dos pixels.


Tipos com sinal: sada = -entrada Tipos sem sinal: sada = mximo - entrada

public static void main(String[] args) { PlanarImage input = JAI.create("fileload", args[0]); PlanarImage output = JAI.create("invert", input); JFrame frame = new JFrame(); frame.setTitle("Invert image "+args[0]); frame.getContentPane().add( new DisplayTwoSynchronizedImages(input,output)); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setVisible(true); }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

63 /146

Operadores da API JAI: invert

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

64 /146

Operadores da API JAI: binarize

Transforma pixels em valores binrios por comparao com constante (1 se constante).


public static void main(String[] args) { PlanarImage imagem = JAI.create("fileload", args[0]); ParameterBlock pb = new ParameterBlock(); pb.addSource(imagem); pb.add(127.0); PlanarImage binarizada = JAI.create("binarize", pb); JFrame frame = new JFrame("Imagem binarizada"); frame.add(new DisplayTwoSynchronizedImages(imagem,binarizada)); frame.pack(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

65 /146

Operadores da API JAI: binarize

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

66 /146

Operadores da API JAI: convolve

Convoluo com um kernel.

Este exemplo: suavizao.

public static void main(String[] args) { PlanarImage imagem = JAI.create("fileload", args[0]); float[] kernelMatrix = { 1f/25f, 1f/25f, 1f/25f, 1f/25f, 1f/25f, 1f/25f, 1f/25f, 1f/25f, 1f/25f, 1f/25f, 1f/25f, 1f/25f, 1f/25f, 1f/25f, 1f/25f, 1f/25f, 1f/25f, 1f/25f, 1f/25f, 1f/25f, 1f/25f, 1f/25f, 1f/25f, 1f/25f, 1f/25f}; KernelJAI kernel = new KernelJAI(5,5,kernelMatrix); PlanarImage bordas = JAI.create("convolve",imagem,kernel); JFrame frame = new JFrame("Suavizao da imagem"); frame.add(new DisplayTwoSynchronizedImages(imagem,bordas)); frame.pack(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

67 /146

Operadores da API JAI: convolve

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

68 /146

Operadores da API JAI: convolve

Convoluo com um kernel.

Este exemplo: deteco de bordas horizontais (Sobel).

public static void main(String[] args) { PlanarImage imagem = JAI.create("fileload", args[0]); float[] kernelMatrix = { -1, -2, -1, 0, 0, 0, 1, 2, 1 }; KernelJAI kernel = new KernelJAI(3,3,kernelMatrix); PlanarImage bordas = JAI.create("convolve",imagem,kernel); JFrame frame = new JFrame("Bordas horizontais"); frame.add(new DisplayTwoSynchronizedImages(imagem,bordas)); frame.pack(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

69 /146

Operadores da API JAI: convolve

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

70 /146

Operadores da API JAI: dilate

Expanso de regies da imagem com elemento estrutural.


public static void main(String[] args) { PlanarImage imagem = JAI.create("fileload", args[0]); float[] estrutura = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}; KernelJAI kernel = new KernelJAI(7,7,estrutura); ParameterBlock p = new ParameterBlock(); p.addSource(imagem); p.add(kernel); PlanarImage dilatada = JAI.create("dilate",p); JFrame frame = new JFrame("Imagem dilatada"); frame.add(new DisplayTwoSynchronizedImages(imagem,dilatada)); frame.pack(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

71 /146

Operadores da API JAI: dilate

Regies brancas so dilatadas!


Fevereiro/2010 http://www.lac.inpe.br/~rafael.santos 72 /146

Operadores da API JAI: erode

Reduo de regies da imagem com elemento estrutural.


public static void main(String[] args) { PlanarImage imagem = JAI.create("fileload", args[0]); float[] estrutura = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}; KernelJAI kernel = new KernelJAI(7,7,estrutura); ParameterBlock p = new ParameterBlock(); p.addSource(imagem); p.add(kernel); PlanarImage erodida = JAI.create("erode",p); JFrame frame = new JFrame("Imagem erodida"); frame.add(new DisplayTwoSynchronizedImages(imagem,erodida)); frame.pack(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

73 /146

Operadores da API JAI: erode

Regies brancas so dilatadas!


Fevereiro/2010 http://www.lac.inpe.br/~rafael.santos 74 /146

Operadores da API JAI: rotate

Rotao dos pixels da imagem em redor de um ponto.


public static void main(String[] args) { PlanarImage imagem = JAI.create("fileload",args[0]); float angle = (float)Math.toRadians(45); // Usamos o centro da imagem para rotao float centerX = imagem.getWidth()/2f; float centerY = imagem.getHeight()/2f; ParameterBlock pb = new ParameterBlock(); pb.addSource(imagem); pb.add(centerX); pb.add(centerY); pb.add(angle); pb.add(new InterpolationBilinear()); PlanarImage rotacionada = JAI.create("rotate", pb); JFrame frame = new JFrame("Imagem rotacionada"); frame.add(new DisplayTwoSynchronizedImages(imagem,rotacionada)); frame.pack(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

75 /146

Operadores da API JAI: rotate

Coordenadas dos cantos da imagem rotacionada: (-39, -136) (558, 461)

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

76 /146

Translao da Origem de Imagens


Original Regio para recorte
Origem 200,200 Tamanho 400x300

Regio recortada
Mnimo 200,200 Tamanho 400x300 Mximo 600,500
Fevereiro/2010

Recorte e translao

Mnimo 0,0 Tamanho 400x300 Mximo 400,300

http://www.lac.inpe.br/~rafael.santos

77 /146

Operadores da API JAI: rotate

JAI permite imagens com pixels com coordenadas negativas!


DisplayJAI, ImageIO e JAI.create(filestore) no. Soluo: mover a origem da imagem com o operador translate.

public static void main(String[] args) { PlanarImage imagem = JAI.create("fileload",args[0]); float angle = (float)Math.toRadians(45); // Usamos o centro da imagem para rotao float centerX = imagem.getWidth()/2f; float centerY = imagem.getHeight()/2f; ParameterBlock pb = new ParameterBlock(); pb.addSource(imagem); pb.add(centerX); pb.add(centerY); pb.add(angle); pb.add(new InterpolationBilinear()); PlanarImage rotacionada = JAI.create("rotate", pb);
Fevereiro/2010 http://www.lac.inpe.br/~rafael.santos 78 /146

Operadores da API JAI: rotate


// Ajustamos a origem da imagem pb = new ParameterBlock(); pb.addSource(rotacionada); pb.add((float)-rotacionada.getMinX()); pb.add((float)-rotacionada.getMinY()); PlanarImage rotacionadaOK = JAI.create("translate",pb,null); JFrame frame = new JFrame("Imagem rotacionada"); frame.add( new DisplayTwoSynchronizedImages(imagem,rotacionadaOK)); frame.pack(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

79 /146

Operadores da API JAI: rotate

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

80 /146

Operadores da API JAI: scale

Aumenta ou diminui a quantidade de pixels na imagem.

Valores dos pixels podem ser interpolados.

public static void main(String[] args) { PlanarImage imagem = JAI.create("fileload",args[0]); float scale = 0.3f; ParameterBlock pb = new ParameterBlock(); pb.addSource(imagem); pb.add(scale); pb.add(scale); pb.add(0.0F); pb.add(0.0F); pb.add(new InterpolationNearest()); PlanarImage reescalada = JAI.create("scale", pb); JFrame frame = new JFrame("Imagem reescalada"); frame.add(new DisplayTwoSynchronizedImages(imagem,reescalada)); frame.pack(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); }
Fevereiro/2010 http://www.lac.inpe.br/~rafael.santos 81 /146

Operadores da API JAI: scale

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

82 /146

Operadores da API JAI: crop, translate, scale

Pequena aplicao que recorta e amplia uma regio em uma imagem. Parmetros passados pela linha de comando.

public static void main(String[] args) { PlanarImage imagem = JAI.create("fileload",args[0]); ParameterBlock pb = new ParameterBlock(); float x = Float.parseFloat(args[1]); float y = Float.parseFloat(args[2]); float w = Float.parseFloat(args[3]); float h = Float.parseFloat(args[4]); float z = Float.parseFloat(args[5]);

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

83 /146

Operadores da API JAI: crop, translate, scale


// Recorta pb.addSource(imagem); pb.add(x); pb.add(y); pb.add(w); pb.add(h); PlanarImage recortada = JAI.create("crop",pb,null); // Reposiciona pb = new ParameterBlock(); pb.addSource(recortada); pb.add((float)-x); pb.add((float)-y); PlanarImage recortadaOK = JAI.create("translate",pb,null);

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

84 /146

Operadores da API JAI: crop, translate, scale


// Amplia (2 verses) pb = new ParameterBlock(); pb.addSource(recortadaOK); pb.add(z); pb.add(z); pb.add(0.0F); pb.add(0.0F); pb.add(new InterpolationNearest()); PlanarImage resultado1 = JAI.create("scale", pb); pb = new ParameterBlock(); pb.addSource(recortadaOK); pb.add(z); pb.add(z); pb.add(0.0F); pb.add(0.0F); pb.add(new InterpolationBicubic(2)); PlanarImage resultado2 = JAI.create("scale", pb);

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

85 /146

Operadores da API JAI: crop, translate, scale


JFrame frame = new JFrame("Recorte ampliado"); frame.add( new DisplayTwoSynchronizedImages(resultado1,resultado2)); frame.pack(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); }

java wvc/operadores/Recorta astro013.jpg 461 896 24 27 20


Fevereiro/2010 http://www.lac.inpe.br/~rafael.santos 86 /146

Operadores da API JAI: histogram

Operador sem imagem resultante: calcula histogramas em uma imagem.

Histogramas so recuperadors como propriedades do RenderedOp resultante.

public static void main(String[] args) { PlanarImage image = JAI.create("fileload", args[0]); // Primeiro histograma com 256 bins. ParameterBlock pb1 = new ParameterBlock(); pb1.addSource(image); pb1.add(null); pb1.add(1); pb1.add(1); pb1.add(new int[]{256}); pb1.add(new double[]{0}); pb1.add(new double[]{256}); PlanarImage dummyImage1 = JAI.create("histogram", pb1); Histogram histo1 = (Histogram)dummyImage1.getProperty("histogram");
Fevereiro/2010 http://www.lac.inpe.br/~rafael.santos 87 /146

Operadores da API JAI: histogram


// Segundo histograma com 32 bins. ParameterBlock pb2 = new ParameterBlock(); pb2.addSource(image); pb2.add(null); pb2.add(1); pb2.add(1); pb2.add(new int[]{32}); pb2.add(new double[]{0}); pb2.add(new double[]{256}); PlanarImage dummyImage2 = JAI.create("histogram", pb2); Histogram histo2 = (Histogram)dummyImage2.getProperty("histogram"); // Exibimos os histogramas usando um componente especfico. JFrame f = new JFrame("Histogramas"); DisplayHistogram dh1 = new DisplayHistogram(histo1,"256 bins"); dh1.setBinWidth(2); dh1.setHeight(160); dh1.setIndexMultiplier(1); DisplayHistogram dh2 = new DisplayHistogram(histo2,"32 bins"); dh2.setBinWidth(16); dh2.setHeight(160);dh2.setIndexMultiplier(8); dh2.setSkipIndexes(2); f.getContentPane().setLayout(new GridLayout(2,1)); f.getContentPane().add(dh1); f.getContentPane().add(dh2); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.pack(); f.setVisible(true); }
Fevereiro/2010 http://www.lac.inpe.br/~rafael.santos 88 /146

Operadores da API JAI: histogram

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

89 /146

Aplicao: Pan Sharpening


Alguns satlites tem bandas com resolues diferentes. Podemos usar combinaes de bandas (cores e pancromticas) para obter melhor resoluo espacial.

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

90 /146

Aplicao: Pan Sharpening


PlanarImageiRed=JAI.create("fileload",args[0]); PlanarImageiGreen=JAI.create("fileload",args[1]); PlanarImageiBlue=JAI.create("fileload",args[2]); PlanarImagepanImage=JAI.create("fileload",args[3]); ParameterBlockpb=newParameterBlock(); pb.addSource(iRed); pb.addSource(iGreen); pb.addSource(iBlue); PlanarImagergbImage=JAI.create("bandmerge",pb);

pb=newParameterBlock(); pb.addSource(rgbImage); floatscaleX=(1f*panImage.getWidth()/iRed.getWidth()); floatscaleY=(1f*panImage.getHeight()/iRed.getHeight()); pb.add(scaleX); pb.add(scaleY); rgbImage=JAI.create("scale",pb);

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

91 /146

Aplicao: Pan Sharpening


IHSColorSpaceihs=IHSColorSpace.getInstance(); ColorModelIHSColorModel= newComponentColorModel(ihs, newint[]{8,8,8}, false,false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); pb=newParameterBlock(); pb.addSource(rgbImage); pb.add(IHSColorModel); RenderedImageimageIHS=JAI.create("colorconvert",pb); PlanarImage[]IHSBands=newPlanarImage[3]; for(intband=0;band<3;band++) { pb=newParameterBlock(); pb.addSource(imageIHS); pb.add(newint[]{band}); IHSBands[band]=JAI.create("bandselect",pb); }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

92 /146

Aplicao: Pan Sharpening


ImageLayoutimageLayout=newImageLayout(); imageLayout.setColorModel(IHSColorModel); imageLayout.setSampleModel(imageIHS.getSampleModel()); RenderingHintsrendHints= newRenderingHints(JAI.KEY_IMAGE_LAYOUT,imageLayout); pb=newParameterBlock(); pb.addSource(panImage); pb.addSource(IHSBands[1]); pb.addSource(IHSBands[2]); RenderedImagepanSharpenedIHSImage= JAI.create("bandmerge",pb,rendHints); pb=newParameterBlock(); pb.addSource(panSharpenedIHSImage); pb.add(rgbImage.getColorModel());//RGBcolormodel PlanarImagefinalImage=JAI.create("colorconvert",pb); JFrameframe=newJFrame("IHSPanSharpening"); frame.add(newDisplayTwoSynchronizedImages(rgbImage,finalImage)); frame.pack(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true);
Fevereiro/2010 http://www.lac.inpe.br/~rafael.santos 93 /146

Aplicao: Pan Sharpening

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

94 /146

Aplicao: Pan Sharpening

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

95 /146

Criando Novos Operadores com a API JAI

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

96 /146

Criando Novos Operadores

Qual tipo de operao estamos implementando?


SourcelessOpImage: operadores sem imagens de entrada. PointOpImage: pixels da sada dependem dos mesmos pixels da entrada. AreaOpImage: pixels da sada dependem de rea ao redor dos da entrada. GeometricOpImage: pixels da sada podem depender de todos da entrada. StatisticsOpImage: operadores que calculam estatsticas sobre imagem de entrada.

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

97 /146

Criando Novos Operadores Receita de bolo (relativamente) simples para imagens renderizadas. 1. Criar classe que herda de XXXOpImage.

Como XXXOpImage abstrata, devemos implementar mtodos que fazem o processamento (quase sempre computeTile).

2. Criar classe que implementa RenderedImageFactory.

Implementa mtodo create.

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

98 /146

Criando Novos Operadores 3. Criar classe que implementa OperationDescriptor ou herda de OperationDescriptorImpl, que descreve os parmetros e valores default do operador. 4. Registrar o novo operador junto ao OperationRegistry e RIFRegistry (podemos criar mtodo para registro na classe do passo anterior).

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

99 /146

Novo Operador: segmenta3

Segmentador por limiar semelhante a binarize, mas com 2 limiares. Classe que herda de PointOpImage.

Contm construtor para inicializar atributos e mtodo computeTile.

public class Segmenta3OpImage extends PointOpImage { private RenderedImage source; private int threshold1,threshold2;

Passo 1

public Segmenta3OpImage(RenderedImage source,int th1,int th2, ImageLayout layout,RenderingHints hints, boolean b) { super(source,layout,hints,b); this.source = source; this.threshold1 = th1; this.threshold2 = th2; }
Fevereiro/2010 http://www.lac.inpe.br/~rafael.santos 100 /146

Novo Operador: segmenta3


public Raster computeTile(int x,int y) { Raster r = source.getTile(x,y); int minX = r.getMinX(); int minY = r.getMinY(); int width = r.getWidth(); int height = r.getHeight(); // Criamos um WritableRaster da regio sendo considerada. WritableRaster wr = r.createCompatibleWritableRaster(minX,minY,width,height); for(int l=0;l<r.getHeight();l++) for(int c=0;c<r.getWidth();c++) for(int b=0;b<r.getNumBands();b++) { int p = r.getSample(c+minX,l+minY,b); if (p < threshold1) p = 0; else if (p > threshold2) p = 255; else p = 127; wr.setSample(c+minX,l+minY,b,p); } return wr; }
Fevereiro/2010 http://www.lac.inpe.br/~rafael.santos

Passo 1

101 /146

Novo Operador: segmenta3 Passo 2


public class Segmenta3RIF implements RenderedImageFactory { public RenderedImage create(ParameterBlock paramBlock, RenderingHints hints) { RenderedImage source = paramBlock.getRenderedSource(0); int threshold1 = paramBlock.getIntParameter(0); int threshold2 = paramBlock.getIntParameter(1); ImageLayout layout = new ImageLayout(source); return new Segmenta3OpImage(source,threshold1,threshold2, layout,hints,false); } }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

102 /146

Novo Operador: segmenta3 Passo 3


public class Segmenta3Descriptor extends OperationDescriptorImpl { private static final String opName = "segmenta3"; private static final String vendorName = "Hypothetical Image Processing Lab"; private static final String[][] resources = { {"GlobalName", opName}, {"LocalName", opName}, {"Vendor", vendorName}, {"Description","A simple 3-level image segmentation operator"}, {"DocURL", "http://www.lac.inpe.br/~rafael.santos"}, {"Version", "1.0"}, {"arg0Desc", "First Threshold Value"}, {"arg1Desc", "Second Threshold Value"} }; private static final String[] supportedModes = {"rendered"};

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

103 /146

Novo Operador: segmenta3 Passo 3


private static final String[] paramNames = {"1st threshold", "2nd threshold"}; private static final Class[] paramClasses = {Integer.class, Integer.class}; private static final Object[] paramDefaults = {new Integer(85), new Integer(170) }; private static final Range[] validParamValues = { new Range(Integer.class, Integer.MIN_VALUE, Integer.MAX_VALUE), new Range(Integer.class, Integer.MIN_VALUE, Integer.MAX_VALUE) }; private static final int numSources = 1; private static boolean registered = false;

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

104 /146

Novo Operador: segmenta3


public Segmenta3Descriptor() { super(resources,supportedModes,numSources,paramNames, paramClasses,paramDefaults,validParamValues); }

Passo 3/4

public static void register() { if (!registered) { OperationRegistry op = JAI.getDefaultInstance().getOperationRegistry(); Segmenta3Descriptor desc = new Segmenta3Descriptor(); op.registerDescriptor(desc); Segmenta3RIF rif = new Segmenta3RIF(); RIFRegistry.register(op,opName,vendorName,rif); registered = true; } }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

105 /146

Novo Operador: segmenta3


public static void main(String[] args) { Segmenta3Descriptor.register(); PlanarImage imagem = JAI.create("fileload", args[0]); ParameterBlock p = new ParameterBlock(); p.addSource(imagem); p.add(new Integer(120)); p.add(new Integer(200)); PlanarImage resultado = JAI.create("segmenta3",p); JFrame frame = new JFrame("Imagem binarizada"); frame.add(new DisplayTwoSynchronizedImages(imagem,resultado)); frame.pack(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

106 /146

Novo Operador: contapixels

Conta nmero de pixels com cor semelhante a um parmetro (com tolerncia). Classe que herda de StatisticsOpImage.

Contm construtor para inicializar atributos e vrios mtodos para acumular estatsticas.

public class ContaPixelsOpImage extends StatisticsOpImage { private Color target; private Float tolerance; private Long count;

Passo 1

public ContaPixelsOpImage(RenderedImage source, Color target,Float tolerance) { super(source,null,source.getMinX(),source.getMinY(),1,1); this.target = target; this.tolerance = tolerance; count = null; }
Fevereiro/2010 http://www.lac.inpe.br/~rafael.santos 107 /146

Novo Operador: contapixels Passo 1


protected void accumulateStatistics(String name, Raster raster, Object stats) { if (count == null) count = new Long(0); int r,g,b; for(int l=0;l<raster.getHeight();l++) for(int c=0;c<raster.getWidth();c++) { int x = raster.getMinX()+c; int y = raster.getMinY()+l; r = raster.getSample(x,y,0); g = raster.getSample(x,y,1); b = raster.getSample(x,y,2); float dist = (target.getRed()-r)*(target.getRed()-r)+ (target.getGreen()-g)*(target.getGreen()-g)+ (target.getBlue()-b)*(target.getBlue()-b); if (dist<=tolerance*tolerance) count++; } }
Fevereiro/2010 http://www.lac.inpe.br/~rafael.santos 108 /146

Novo Operador: contapixels


protected Object createStatistics(String arg0) { if (count == null) count = new Long(0); return count; } protected String[] getStatisticsNames() { return new String[]{"count"}; } public Object getProperty(String name) { if (count == null) super.getProperty(name); return count; }

Passo 1

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

109 /146

Novo Operador: contapixels Passo 2


public class ContaPixelsRIF implements RenderedImageFactory { public RenderedImage create(ParameterBlock paramBlock, RenderingHints hints) { RenderedImage source = paramBlock.getRenderedSource(0); Color target = (Color)paramBlock.getObjectParameter(0); Float tolerance = (Float)paramBlock.getObjectParameter(1); return new ContaPixelsOpImage(source,target,tolerance); } }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

110 /146

Novo Operador: contapixels Passo 3


public class ContaPixelsDescriptor extends OperationDescriptorImpl { private static final String opName = "contapixels"; private static final String vendorName = "Hypothetical Image Processing Lab"; private static final String[][] attributes = { {"GlobalName", opName}, {"LocalName", opName}, {"Vendor", vendorName}, {"Description", "A simple RGB pixel counting operator"}, {"DocURL", "http://www.lac.inpe.br/~rafael.santos"}, {"Version", "1.0"}, {"arg0Desc", "Target value (color used for similarity)"}, {"arg1Desc", "Tolerance value"}, }; private static final String[] modes = {"rendered"};

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

111 /146

Novo Operador: contapixels Passo 3


private static final int numSources = 1; private static final String[] paramNames = {attributes[6][0], attributes[7][0]}; private static final Class[] paramClasses = {Color.class, Float.class}; private static final Object[] paramDefaults = { new Color(0,0,0),new Float(0) }; private static boolean registered = false; public ContaPixelsDescriptor() { super(attributes,modes,numSources,paramNames, paramClasses,paramDefaults,null); }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

112 /146

Novo Operador: contapixels Passo 4


public static void register() { if (!registered) { OperationRegistry op = JAI.getDefaultInstance().getOperationRegistry(); ContaPixelsDescriptor desc = new ContaPixelsDescriptor(); op.registerDescriptor(desc); ContaPixelsRIF rif = new ContaPixelsRIF(); RIFRegistry.register(op,opName,vendorName,rif); registered = true; } }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

113 /146

Novo Operador: contapixels


public static void main(String[] args) { ContaPixelsDescriptor.register(); PlanarImage input = JAI.create("fileload", args[0]); int r = Integer.parseInt(args[1]); int g = Integer.parseInt(args[2]); int b = Integer.parseInt(args[3]); float t = Float.parseFloat(args[4]); Color color = new Color(r,g,b); ParameterBlock p = new ParameterBlock(); p.addSource(input); p.add(color); p.add(t); PlanarImage output = JAI.create("contapixels",p); Long count = (Long)output.getProperty("count"); System.out.println("Existem "+count+ " pixels com cores semelhantes a "+color); }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

114 /146

Extras: I/O

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

115 /146

Que formatos so suportados?


public static void main(String[] args) { String[] iFormatos = ImageIO.getReaderMIMETypes(); System.out.println("Leitura: "); for(String f:iFormatos) { System.out.print(f+" "); } System.out.println("\nGravao: "); String[] oFormatos = ImageIO.getWriterMIMETypes(); for(String f:oFormatos) { System.out.print(f+" "); } System.out.println(); }
Leitura: image/jpeg image/png image/x-png image/vnd.wap.wbmp image/gif image/bmp Gravao: image/png image/jpeg image/x-png image/vnd.wap.wbmp image/bmp image/gif

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

116 /146

Compactando Imagens

Forma mais simples: abrir imagem em formato menos compactado e salvar em formato mais compactado. Lembrar sempre que existe perda de informaes com JPEG e GIF! Mtodo mais inteligente: controlar a compactao.

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

117 /146

Como compactar mais?


public static void main(String[] args) throws IOException { // Load the image (it is hard-coded here to make the code // simpler). String imageFile = "/tmp/folhas.tif"; BufferedImage i = ImageIO.read(new File(imageFile)); showImage("Original Image", i); // Show results with different compression ratio. compressAndShow(i, 0.5f); }

Veja mais em http://www.lac.inpe.br/JIPCookbook Fevereiro/2010 http://www.lac.inpe.br/~rafael.santos 118 /146

Como compactar mais?


public static void compressAndShow(BufferedImage image, float quality) throws IOException { // Get a ImageWriter for jpeg format. Iterator<ImageWriter> writers = ImageIO.getImageWritersBySuffix("jpeg"); if (!writers.hasNext()) throw new IllegalStateException("No writers found"); ImageWriter writer = (ImageWriter) writers.next(); // Create the ImageWriteParam to compress the image. ImageWriteParam param = writer.getDefaultWriteParam(); param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); param.setCompressionQuality(quality); // The output will be a ByteArrayOutputStream (in memory) ByteArrayOutputStream bos = new ByteArrayOutputStream(32768); ImageOutputStream ios = ImageIO.createImageOutputStream(bos); writer.setOutput(ios); writer.write(null, new IIOImage(image, null, null), param); ios.flush(); // otherwise the buffer size will be zero! // From the ByteArrayOutputStream create a RenderedImage. ByteArrayInputStream in = new ByteArrayInputStream(bos.toByteArray()); RenderedImage out = ImageIO.read(in); int size = bos.toByteArray().length; showImage("Compressed to " + quality + ": " + size + " bytes", out); } Veja mais em http://www.lac.inpe.br/JIPCookbook Fevereiro/2010 http://www.lac.inpe.br/~rafael.santos 119 /146

Como compactar mais?


private static void showImage(String title,RenderedImage image) { JFrame f = new JFrame(title); f.getContentPane().add(new DisplayJAI(image)); f.pack(); f.setVisible(true); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }

Original

0.5

0.1

Veja mais em http://www.lac.inpe.br/JIPCookbook Fevereiro/2010 http://www.lac.inpe.br/~rafael.santos 120 /146

Extras: Pixels

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

121 /146

Mini-aplicao: Converso RGB IHS


IHS: Intensity, Hue and Saturation. Cores representadas por:


Intensity: brilho percebido da cor, 0 a 100% (preto = 0%). Hue (croma): cor bruta, 0 a 359 graus (0 graus = vermelho). Saturation: intensidade da cor, 0 a 100% (branco = 100%).

Variantes: HSV, HSB, HSL, etc.

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

122 /146

Mini-aplicao: Converso RGB IHS

Integrao de imagens de diferentes sensores

RGB IHS, substitui banda I por banda de maior resoluo, converte novamente IHS RGB RGB IHS, manipula brilho e contraste da banda I, converte novamente IHS RGB

Manipulao de contraste e brilho

Nosso exemplo: converte RGB IHS, substitui I e S por 100% constantes, reconverte para RGB.

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

123 /146

Mini-aplicao: Converso RGB IHS


public class RGBtoIHS { public static void main(String[] args) { PlanarImage imagem = JAI.create("fileload", args[0]); // Converte para o modelo de cores IHS. IHSColorSpace ihs = IHSColorSpace.getInstance(); ColorModel modeloIHS = new ComponentColorModel(ihs, new int []{8,8,8}, false,false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE) ; ParameterBlock pb = new ParameterBlock(); pb.addSource(imagem); pb.add(modeloIHS); RenderedImage imagemIHS = JAI.create("colorconvert", pb);

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

124 /146

Mini-aplicao: Converso RGB IHS


// Extramos as bandas I, H e S. RenderedImage[] bandas = new RenderedImage[3]; for(int band=0;band<3;band++) { pb = new ParameterBlock(); pb.addSource(imagemIHS); pb.add(new int[]{band}); bandas[band] = JAI.create("bandselect",pb); } // Criamos bandas constantes para as bandas I e S. pb = new ParameterBlock(); pb.add((float)imagem.getWidth()); pb.add((float)imagem.getHeight()); pb.add(new Byte[]{(byte)255}); RenderedImage novaIntensidade = JAI.create("constant",pb); pb = new ParameterBlock(); pb.add((float)imagem.getWidth()); pb.add((float)imagem.getHeight()); pb.add(new Byte[]{(byte)255}); RenderedImage novaSaturao = JAI.create("constant",pb);

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

125 /146

Mini-aplicao: Converso RGB IHS


// Juntamos as bandas H e as I e S constantes. // Devemos passar um RenderingHint que indica que o modelo // de cor IHS ser usado. ImageLayout imageLayout = new ImageLayout(); imageLayout.setColorModel(modeloIHS); imageLayout.setSampleModel(imagemIHS.getSampleModel()); RenderingHints rendHints = new RenderingHints(JAI.KEY_IMAGE_LAYOUT,imageLayout); pb = new ParameterBlock(); pb.addSource(novaIntensidade); pb.addSource(bandas[1]); pb.addSource(novaSaturao); RenderedImage imagemIHSModificada = JAI.create("bandmerge", pb, rendHints); // Convertemos de volta para RGB. pb = new ParameterBlock(); pb.addSource(imagemIHSModificada); pb.add(imagem.getColorModel()); // Imagem original era em RGB! RenderedImage imagemFinal = JAI.create("colorconvert", pb);

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

126 /146

Mini-aplicao: Converso RGB IHS


JFrame frame = new JFrame("Modificao via IHS"); frame.add(new DisplayTwoSynchronizedImages(imagem,imagemFinal)); frame.pack(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

127 /146

Extras: Display

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

128 /146

Mini-aplicao: Visualizador com cone

Mostra imagens grandes com pequeno cone e pan.

public class DisplayThumbnail extends DisplayJAI implements MouseMotionListener,MouseListener { private PlanarImage originalImage; private float scale; private int imageXTiles,imageYTiles; private int imageTileWidth,imageTileHeight; private int imageWidth,imageHeight; private int visibleRegionWidth,visibleRegionHeight; private int thumbWidth,thumbHeight; // The size of the border around the thumbnail. private final int border = 10; // The scaled viewport (dimensions are scaled/translated by the border). private Rectangle2D scaledViewport; private Color viewportColor; // Colors to be used when the mouse is/isn't over the viewport. private static Color viewportOn = new Color(120,255,120); private static Color viewportOff = new Color(0,192,0); // Coordinates obtained when we click (press) the mouse button to start // dragging the viewport. private int lastX,lastY; // Those coordinates represent the region where we can safely drag the // viewport without "falling outside" the image boundaries. private int minValidX,minValidY,maxValidX,maxValidY;

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

129 /146

Mini-aplicao: Visualizador com cone


public DisplayThumbnail(PlanarImage image,float scale, int width,int height) { this.scale = scale; originalImage = image; visibleRegionWidth = width; visibleRegionHeight = height; // Get some stuff about the image. imageXTiles = image.getNumXTiles(); imageYTiles = image.getNumYTiles(); imageTileWidth = image.getTileWidth(); imageTileHeight = image.getTileHeight(); imageWidth = image.getWidth(); imageHeight = image.getHeight(); // Must create a thumbnail image using that scale. ParameterBlock pb = new ParameterBlock(); pb.addSource(image); pb.add(scale); pb.add(scale); pb.add(0.0F); pb.add(0.0F); pb.add(new InterpolationNearest()); PlanarImage thumbnail = JAI.create("scale", pb, null); // Let's get the width and height of the thumbnail. thumbWidth = thumbnail.getWidth(); thumbHeight = thumbnail.getHeight();

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

130 /146

Mini-aplicao: Visualizador com cone


// Now let's add a border. pb = new ParameterBlock(); pb.addSource(thumbnail); pb.add(new Integer(border)); pb.add(new Integer(border)); pb.add(new Integer(border)); pb.add(new Integer(border)); pb.add(new BorderExtenderConstant(new double[]{0,0,128})); thumbnail = JAI.create("border",pb); // Shift the image to the original position pb = new ParameterBlock(); pb.addSource(thumbnail); pb.add(1.0f*border); pb.add(1.0f*border); thumbnail = JAI.create("translate",pb,null); // Use this thumbnail as the image for the DisplayJAI component. set(thumbnail); // We'd like to listen to mouse movements. addMouseMotionListener(this); addMouseListener(this); // Initially the scaled viewport will be positioned at border,border. scaledViewport = new Rectangle2D.Float(border,border,width*scale,height*scale); // We assume that the mouse is off the viewport. viewportColor = viewportOff; }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

131 /146

Mini-aplicao: Visualizador com cone


public synchronized void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D)g; // Paint the tile grid. g2d.setColor(Color.YELLOW); g2d.setComposite(AlphaComposite.getInstance( AlphaComposite.SRC_OVER,0.5f)); float x1,x2,y1,y2; // Vertical tiles' boundaries. x1 = x2 = border; y1 = border; y2 = border+thumbHeight; for(int tx=0;tx<=imageXTiles;tx++) { g2d.drawLine((int)x1,(int)y1,(int)x2,(int)y2); x1 += imageTileWidth*scale; x2 += imageTileWidth*scale; }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

132 /146

Mini-aplicao: Visualizador com cone


// Horizontal tiles' boundaries. x1 = border; x2 = border+thumbWidth; y1 = y2 = border; for(int ty=0;ty<=imageYTiles;ty++) { g2d.drawLine((int)x1,(int)y1,(int)x2,(int)y2); y1 += imageTileHeight*scale; y2 += imageTileHeight*scale; } // Paint a red border. g2d.setColor(Color.RED); g2d.drawRect(border,border,thumbWidth,thumbHeight); // Paint the viewport. g2d.setColor(viewportColor); g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,1f)); Stroke stroke = new BasicStroke(2f); g2d.setStroke(stroke); g2d.draw(scaledViewport); }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

133 /146

Mini-aplicao: Visualizador com cone


public void mouseMoved(MouseEvent e) { int x = e.getX(); int y = e.getY(); // Ignore events outside the border. if ((x < border) || (y < border) || (x > border+thumbWidth) || (y > border+thumbHeight)) return; // Are we inside the viewport rectangle ? if (scaledViewport.contains(x,y)) viewportColor = viewportOn; else viewportColor = viewportOff; // Hopefully it will repaint only the needed section. Rectangle repaintBounds = new Rectangle((int)scaledViewport.getX()-5, (int)scaledViewport.getY()-5, (int)scaledViewport.getWidth()+10, (int)scaledViewport.getHeight()+10); repaint(repaintBounds); }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

134 /146

Mini-aplicao: Visualizador com cone


public void mousePressed(MouseEvent e) { // Store the new dragging starting points. lastX = e.getX(); lastY = e.getY(); // Calculate the new window w/ viewport movements. minValidX = lastX-(int)scaledViewport.getX()+border; minValidY = lastY-(int)scaledViewport.getY()+border; maxValidX = border+thumbWidth-(int)scaledViewport.getWidth()+ (lastX-(int)scaledViewport.getX()); maxValidY = border+thumbHeight-(int)scaledViewport.getHeight()+ (lastY-(int)scaledViewport.getY()); } public void mouseDragged(MouseEvent e) { int x = e.getX(); int y = e.getY(); if (x > maxValidX) x = maxValidX-1; if (x < minValidX) x = minValidX; if (y > maxValidY) y = maxValidY-1; if (y < minValidY) y = minValidY; if ((x >= minValidX) && (y >= minValidY) && (x <= maxValidX) && (y <= maxValidY)) { updateLocation(x, y); lastX = x; lastY = y; } } Fevereiro/2010 http://www.lac.inpe.br/~rafael.santos 135 /146

Mini-aplicao: Visualizador com cone


public void updateLocation(int x,int y) { // Store the approximate region where the viewport was before the change. Rectangle initBounds = new Rectangle((int)scaledViewport.getX()-5, (int)scaledViewport.getY()-5, (int)scaledViewport.getWidth()+10, (int)scaledViewport.getHeight()+10); // Recalculate new position for the viewport, based on mouse coordinates. double origX = scaledViewport.getX()+x-lastX; double origY = scaledViewport.getY()+y-lastY; // Reposition the viewport. scaledViewport.setFrame(origX,origY, scaledViewport.getWidth(),scaledViewport.getHeight()); // Store the approximate region where the viewport is after the change. Rectangle finalBounds = new Rectangle((int)scaledViewport.getX()-5, (int)scaledViewport.getY()-5, (int)scaledViewport.getWidth()+10, (int)scaledViewport.getHeight()+10); // Repaint only that section. repaint(finalBounds.union(initBounds)); }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

136 /146

Mini-aplicao: Visualizador com cone


public PlanarImage getImage() { // Get the boundaries in the original image coordinates. float fromX = (float)Math.round((scaledViewport.getX()-border)/scale); float fromY = (float)Math.round((scaledViewport.getY()-border)/scale); float width = (float)Math.round(scaledViewport.getWidth()/scale); float height = (float)Math.round(scaledViewport.getWidth()/scale); // Fix rounding errors to avoid exceptions on the crop. fromX = Math.min(fromX,(imageWidth-visibleRegionWidth)); fromY = Math.min(fromY,(imageHeight-visibleRegionHeight)); // Create a ParameterBlock with information for the cropping. ParameterBlock pb = new ParameterBlock(); pb.addSource(originalImage); pb.add(fromX); pb.add(fromY); pb.add(width); pb.add(height); // Create the output image by cropping the input image. PlanarImage output = JAI.create("crop",pb,null); // Translate the image origin. pb = new ParameterBlock(); pb.addSource(output); pb.add(-fromX); pb.add(-fromY); // Create the output image by translating itself. return JAI.create("translate",pb,null); }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

137 /146

Mini-aplicao: Visualizador com cone


public Rectangle getCroppedImageBounds() { int fromX = (int)Math.round((scaledViewport.getX()-border)/scale); int fromY = (int)Math.round((scaledViewport.getY()-border)/scale); int width = (int)Math.round(scaledViewport.getWidth()/scale); int height = (int)Math.round(scaledViewport.getWidth()/scale); return new Rectangle(fromX,fromY,width,height); } public Rectangle getViewportBounds() { Rectangle temp = scaledViewport.getBounds(); temp.setBounds((int)temp.getX()-border,(int)temp.getY()-border, (int)temp.getWidth(),(int)temp.getHeight()); return temp; }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

138 /146

Mini-aplicao: Visualizador com cone


public class DisplayThumbnailApp extends JFrame implements MouseMotionListener { private DisplayThumbnail dt; private DisplayJAI dj; private JLabel world,view; public DisplayThumbnailApp(PlanarImage image,int dWidth,int dHeight) { super("Interactive Thumbnail Example"); SpringLayout layout = new SpringLayout(); Container contentPane = getContentPane(); contentPane.setLayout(layout); dt = new DisplayThumbnail(image,0.05f,dWidth,dHeight); dt.addMouseMotionListener(this); dj = new DisplayJAI(dt.getImage()); dj.setPreferredSize(new Dimension(dWidth,dHeight)); dj.setMinimumSize(new Dimension(dWidth,dHeight)); dj.setMaximumSize(new Dimension(dWidth,dHeight)); JPanel borderDisplay = new JPanel(new BorderLayout()); borderDisplay.add(dj); borderDisplay.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED)); JLabel worldL = new JLabel("World: "); world = new JLabel(""); JLabel viewL = new JLabel("Thumb: "); view = new JLabel(""); contentPane.add(dt); contentPane.add(borderDisplay); contentPane.add(worldL); contentPane.add(world); contentPane.add(viewL); contentPane.add(view); (organizao do layout removida) setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setResizable(false); pack(); setVisible(true); }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

139 /146

Mini-aplicao: Visualizador com cone


public void mouseDragged(MouseEvent e) { dj.set(dt.getImage()); // Gets some information about the viewport and cropped image. Rectangle crop = dt.getCroppedImageBounds(); Rectangle viewp = dt.getViewportBounds(); // Change the labels' contents with this information. world.setText(""+crop.x+","+crop.y+ " ("+crop.width+"x"+crop.height+")"); view.setText(""+viewp.x+","+viewp.y+ " ("+viewp.width+"x"+viewp.height+")"); } public void mouseMoved(MouseEvent e) { } public static void main(String[] args) { PlanarImage image = JAI.create("fileload", args[0]); new DisplayThumbnailApp(image,640,640); }

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

140 /146

Mini-aplicao: Visualizador com cone

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

141 /146

Outros Tpicos

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

142 /146

Tpicos para Pesquisa e Desenvolvimento

Processamento por pixels x processamento por regies


Imagens de alta resoluo Novos algoritmos de classificao Modelagem de conhecimento Modelos de mistura Inteligncia artificial

http://gras.ku.dk/software/ecognition.htm

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

143 /146

Para saber mais...

http://www.lac.inpe.br/JIPCookbook http://www.lac.inpe.br/~rafael.santos Introductory Digital Image Processing: A Remote Sensing Perspective (John R. Jensen) Digital Image Processing Algorithms and Applications (Ioannis Pitas) Digital Image Processing (Rafael C. Gonzalez, Richard E. Woods)

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

144 /146

Para saber mais...


Fundamentals of Digital Image Processing (Anil K. Jain) Classification Methods for Remotely Sensed Data (Brandt Tso, Paul M. Mather) Pattern Recognition and Image Analysis (Earl Gose, Richard Johnsonbaugh, Steve Jost)

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

145 /146

Para saber mais...

Fuzzy Algorithms: With Applications to Image Processing and Pattern Recognition (Zheru Chi, H. Yan, Z.R. Chi, Hong Yan, Tuan Pham) The Pocket Handbook of Image Processing Algorithms In C (Harley R. Myler, Arthur R. Weeks) Intelligence: The Eye, the Brain, and the Computer (Martin A. Fischler, Oscar Firschein)

Fevereiro/2010

http://www.lac.inpe.br/~rafael.santos

146 /146