Introduo ao Processamento de Imagens Digitais em Java / API JAI
Escola de Vero da Unifesp
Rafael Santos
Fevereiro/2010
[Link]
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 ([Link] Cdigo!
Fevereiro/2010
[Link]
2 /146
Introduo
Fevereiro/2010
[Link]
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.
[Link] 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
[Link]
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
[Link]
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
[Link] 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
[Link]
8 /146
Outros Tipos de Imagens Digitais
Fevereiro/2010
[Link]
9 /146
Outros Tipos de Imagens Digitais
Fevereiro/2010
[Link]
10 /146
Imagens Digitais: Multiespectrais
Fevereiro/2010
[Link]
11 /146
Imagens Digitais: Hiperespectrais
[Link]
Fevereiro/2010
[Link]
12 /146
Processamento de Imagens em Java
Fevereiro/2010
[Link]
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 ([Link] completo e comentado.
Fevereiro/2010
[Link]
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
[Link]
15 /146
Processamento de Imagens em Java: JAI
Java (Swing) tem classes e operadores bsicos. Java Advanced Imaging
API adicional (download separado). Projeto do [Link] 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
[Link]
16 /146
Representao de Imagens em Java
Fevereiro/2010
[Link]
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.
[Link] 18 /146
Fevereiro/2010
Representao de Imagens: TiledImage (JAI)
Fevereiro/2010
[Link]
19 /146
Representao de Imagens
RenderedImage
WritableRenderedImage
BufferedImage
ImageJAI
PlanarImage
RenderedOp
API JAI
Fevereiro/2010 [Link]
TiledImage
20 /146
Criando Imagens em Java
Fevereiro/2010
[Link]
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
[Link]
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 = [Link](); 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) [Link](w,h,cor1); else [Link](w,h,cor2); } [Link](image,"PNG",new File("[Link]")); }
Fevereiro/2010 [Link] 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
[Link]
24 /146
Criando Imagens (com JAI)
intwidth=640;intheight=640; SampleModelsampleModel= [Link](DataBuffer.TYPE_BYTE, width,height,1); TiledImagetiledImage= newTiledImage(0,0,width,height,0,0,sampleModel,null); WritableRasterwr=[Link](0,0); for(inth=0;h<height/32;h++) for(intw=0;w<width/32;w++) { int[]fill=newint[32*32];//Ablockofpixels... [Link](fill,(int)([Link]()*256)); [Link](w*32,h*32,32,32,0,fill); } [Link]("filestore",tiledImage, "[Link]","PNG");
Fevereiro/2010
[Link]
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
[Link]
26 /146
Criando Imagens (com JAI)
intwidth=483;intheight=483; inttWidth=64;inttHeight=64; SampleModelsampleModel= [Link](DataBuffer.TYPE_BYTE, tWidth,tHeight,3); ColorModelcm=[Link](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
[Link]
27 /146
Criando Imagens (com JAI)
for(intth=[Link]();th<=[Link]();th++) for(inttw=[Link]();tw<=[Link]();tw++) { WritableRasterwr=[Link](tw,th); for(intih=0;ih<tHeight;ih++) for(intiw=0;iw<tWidth;iw++) { intw=[Link]()+iw; inth=[Link]()+ih; if((w>=17)&&(w<17+216)&&(h>=17)&&(h<17+216)) [Link](w,h,red); elseif((w>=250)&&(w<250+216)&&(h>=17)&&(h<17+216)) [Link](w,h,green); elseif((w>=17)&&(w<17+216)&&(h>=250)&&(h<250+216)) [Link](w,h,yellow); elseif((w>=250)&&(w<250+216)&&(h>=250)&&(h<250+216)) [Link](w,h,blue); [Link](w,h,black); } }
Fevereiro/2010
[Link]
28 /146
Criando Imagens (com JAI)
TIFFEncodeParamtep=newTIFFEncodeParam(); [Link](true); [Link](tWidth,tHeight); [Link]("filestore",tiledImage,"[Link]","TIFF",tep);
Fevereiro/2010
[Link]
29 /146
Armazenando e Recuperando Imagens
Fevereiro/2010
[Link]
30 /146
Entrada e Sada
Sem JAI (BufferedImage):
public static void main(String[] args) throws IOException { File f = new File(args[0]); BufferedImage image = [Link](f); [Link]("Dimenses: "+ [Link]()+"x"+[Link]()+" pixels"); }
Com JAI (PlanarImage):
public static void main(String[] args) throws IOException { PlanarImage image = [Link]("fileload",args[0]); [Link]("Dimenses: "+ [Link]()+"x"+[Link]()+" pixels"); }
Fevereiro/2010
[Link]
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); ... [Link](image,"PNG",new File("[Link]")); }
Com JAI (PlanarImage):
public static void main(String[] args) throws IOException { ... TiledImage tiledImage = new TiledImage(0,0,width,height,0,0,sampleModel,colorModel); ... [Link]("filestore",tiledImage,"[Link]","TIFF"); }
Fevereiro/2010
[Link]
32 /146
Acesso Direto a Pixels
Fevereiro/2010
[Link]
33 /146
Acesso a pixels (sem JAI)
public static void main(String[] args) throws IOException { File f = new File(args[0]); BufferedImage imagem = [Link](f); Memria! Raster raster = [Link](); int[] pixel = new int[3]; int brancos = 0; for(int h=0;h<[Link]();h++) for(int w=0;w<[Link]();w++) { [Link](w,h,pixel); if ((pixel[0] == 255) && (pixel[1] == 255) && (pixel[2] == 255)) brancos++; } [Link](brancos+" pixels brancos"); }
Fevereiro/2010
[Link]
34 /146
Acesso a pixels (com JAI)
public static void main(String[] args) throws IOException { File f = new File(args[0]); BufferedImage imagem = [Link](f); RandomIter iterator = [Link](imagem,null); int[] pixel = new int[3]; int brancos = 0; for(int h=0;h<[Link]();h++) for(int w=0;w<[Link]();w++) { [Link](w,h,pixel); if ((pixel[0] == 255) && (pixel[1] == 255) && (pixel[2] == 255)) brancos++; } [Link](brancos+" pixels brancos"); }
Existem tambm RectIter e RookIter.
[Link] 35 /146
Fevereiro/2010
Exibindo Imagens
Fevereiro/2010
[Link]
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
[Link]
37 /146
Display de Imagens (sem JAI)
public static void main(String[] args) throws IOException { BufferedImage image = [Link](new File(args[0])); JFrame frame = new JFrame("Display Image: "+args[0]); ImageIcon icon = new ImageIcon(image); JLabel imageLabel = new JLabel(icon); [Link]().add(new JScrollPane(imageLabel)); [Link](JFrame.EXIT_ON_CLOSE); [Link](600,300); [Link](true); }
BufferedImage ImageIcon JLabel (JScrollPane).
Fevereiro/2010
[Link]
38 /146
Display de Imagens (sem JAI)
Fevereiro/2010
[Link]
39 /146
Display de Imagens (com JAI)
public static void main(String[] args) throws IOException { BufferedImage image = [Link](new File(args[0])); JFrame frame = new JFrame("Display Image: "+args[0]); DisplayJAI display = new DisplayJAI(image); [Link]().add(new JScrollPane(display)); [Link](JFrame.EXIT_ON_CLOSE); [Link](600,300); [Link](true); }
DisplayJAI mais flexvel, permite alguma interao (no implementada). No parte da API JAI (!?).
Fevereiro/2010
[Link]
40 /146
Exibindo Imagens (Solues Especficas)
Fevereiro/2010
[Link]
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
[Link]
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
[Link]
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 [Link]().addAdjustmentListener(this); [Link]().addAdjustmentListener(this); [Link]().addAdjustmentListener(this); [Link]().addAdjustmentListener(this); }
Fevereiro/2010
[Link]
44 /146
Imagens Sincronizadas
public void adjustmentValueChanged(AdjustmentEvent e) { if ([Link]() == [Link]()) [Link]().setValue([Link]()); if ([Link]() == [Link]()) [Link]().setValue([Link]()); if ([Link]() == [Link]()) [Link]().setValue([Link]()); if ([Link]() == [Link]()) [Link]().setValue([Link]()); } }
Fevereiro/2010
[Link]
45 /146
Imagens Sincronizadas: Exemplo
public class Borda { public static void main(String[] args) { PlanarImage imagem = [Link]("fileload", args[0]); float[] kernelMatrix = { -1, -2, -1, 0, 0, 0, 1, 2, 1 }; KernelJAI kernel = new KernelJAI(3,3,kernelMatrix); PlanarImage bordas = [Link]("convolve",imagem,kernel); JFrame frame = new JFrame("Bordas horizontais"); [Link](new DisplayTwoSynchronizedImages(imagem,bordas)); [Link](); [Link](JFrame.EXIT_ON_CLOSE); [Link](true); } }
Fevereiro/2010
[Link]
46 /146
Imagens Sincronizadas: Exemplo
Fevereiro/2010
[Link]
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
[Link]
48 /146
Imagens Substitutas
public class DisplaySurrogateImage extends DisplayJAI { protected PlanarImage surrogateImage; protected int width,height; public DisplaySurrogateImage(PlanarImage image) { width = [Link](); height = [Link](); // Recuperamos valores extremos da imagem. ParameterBlock pbMaxMin = new ParameterBlock(); [Link](image); PlanarImage extrema = [Link]("extrema", pbMaxMin); double[] allMins = (double[])[Link]("minimum"); double[] allMaxs = (double[])[Link]("maximum"); double minValue = allMins[0]; double maxValue = allMaxs[0]; for(int v=1;v<[Link];v++) { if (allMins[v] < minValue) minValue = allMins[v]; if (allMaxs[v] > maxValue) maxValue = allMaxs[v]; }
Fevereiro/2010
[Link]
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(); [Link](image); [Link](subtract); surrogateImage = (PlanarImage)[Link]("subtractconst",pbSub); ParameterBlock pbMult = new ParameterBlock(); [Link](surrogateImage); [Link](multiplyBy); surrogateImage = (PlanarImage)[Link]("multiplyconst",pbMult); // Convertemos para bytes. ParameterBlock pbConvert = new ParameterBlock(); [Link](surrogateImage); [Link](DataBuffer.TYPE_BYTE); surrogateImage = [Link]("format", pbConvert); // Usamos esta imagem para display. set(surrogateImage); } }
Fevereiro/2010
[Link]
50 /146
Imagens Substitutas
public class DemonstraDisplaySurrogateImage { public static void main(String[] args) { PlanarImage image = [Link]("fileload", args[0]); JFrame frame = new JFrame("Mostrando "+args[0]); [Link]().add( new JScrollPane(new DisplaySurrogateImage(image))); [Link](JFrame.EXIT_ON_CLOSE); [Link](); [Link](true); } }
Fevereiro/2010
[Link]
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
[Link]
52 /146
Imagens Substitutas: LUTs
publicvoidsetLUT(short[][]lut) { SampleModelsampleModel=[Link](); SampleModelnewSampleModel= [Link](DataBuffer.TYPE_BYTE, [Link](),[Link](),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); [Link](colorModel); HashMap<[Link],ImageLayout>map= newHashMap<[Link],ImageLayout>(); [Link](JAI.KEY_IMAGE_LAYOUT,layout); RenderingHintshints=newRenderingHints(map); ParameterBlockpb=newParameterBlock(); [Link](surrogateImage); PlanarImagenewSurrogateImage=[Link]("format",pb,hints); set(newSurrogateImage); }
Fevereiro/2010
[Link]
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+[Link]([Link]*(i127)/255))); lut[i][1]=(short)(127*(1+[Link]([Link]*(i)/255))); lut[i][2]=(short)(127*(1+[Link]([Link]*(i+127)/255))); } returnlut; } Fevereiro/2010 [Link] 54 /146
Imagens Substitutas: LUTs
Fevereiro/2010
[Link]
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
[Link]
56 /146
Desenhando em Imagens
BufferedImagebaseImage=[Link](newFile("sjc_region.png")); int[][]coords=newint[][]{ {714,219}, {822,256}, {797,329}, {710,300}, {711,293}, {666,271}}; [Link]=[Link](); booleanisFirst=true; doublefirstX=0,firstY=0; for(int[]coord:coords) { intx=coord[0];inty=coord[1]; if(isFirst) { [Link](x,y); firstX=x; firstY=y; isFirst=false; } else{[Link](x,y);} } [Link](firstX,firstY); Fevereiro/2010 [Link] 57 /146
Desenhando em Imagens
[Link]=[Link](); [Link](0,0); [Link]([Link](),0); [Link]([Link](),[Link]()); [Link](0,[Link]()); [Link](0,0); AreawholeImage=newArea(pathForWholeImage); [Link](newArea(regionOfInterest)); Graphics2Dg2d=(Graphics2D)[Link](); [Link](RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); [Link](newColor(255,255,255,100)); [Link](wholeImage); [Link](newBasicStroke(5f)); [Link](newColor(255,0,0,200)); [Link](regionOfInterest); JFrameframe=newJFrame("Highlightingimageregions"); ImageIconicon=newImageIcon(baseImage); JLabellabel=newJLabel(icon); [Link]().add(newJScrollPane(label)); [Link](JFrame.EXIT_ON_CLOSE); [Link]();[Link](true); Fevereiro/2010 [Link] 58 /146
Desenhando em Imagens
Fevereiro/2010
[Link]
59 /146
Operadores da API JAI
Fevereiro/2010
[Link]
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
[Link]
61 /146
Relembrando: Representao de Imagens
RenderedImage
WritableRenderedImage
BufferedImage
ImageJAI
PlanarImage
RenderedOp
API JAI
Fevereiro/2010 [Link]
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 = [Link]("fileload", args[0]); PlanarImage output = [Link]("invert", input); JFrame frame = new JFrame(); [Link]("Invert image "+args[0]); [Link]().add( new DisplayTwoSynchronizedImages(input,output)); [Link](JFrame.EXIT_ON_CLOSE); [Link](); [Link](true); }
Fevereiro/2010
[Link]
63 /146
Operadores da API JAI: invert
Fevereiro/2010
[Link]
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 = [Link]("fileload", args[0]); ParameterBlock pb = new ParameterBlock(); [Link](imagem); [Link](127.0); PlanarImage binarizada = [Link]("binarize", pb); JFrame frame = new JFrame("Imagem binarizada"); [Link](new DisplayTwoSynchronizedImages(imagem,binarizada)); [Link](); [Link](JFrame.EXIT_ON_CLOSE); [Link](true); }
Fevereiro/2010
[Link]
65 /146
Operadores da API JAI: binarize
Fevereiro/2010
[Link]
66 /146
Operadores da API JAI: convolve
Convoluo com um kernel.
Este exemplo: suavizao.
public static void main(String[] args) { PlanarImage imagem = [Link]("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 = [Link]("convolve",imagem,kernel); JFrame frame = new JFrame("Suavizao da imagem"); [Link](new DisplayTwoSynchronizedImages(imagem,bordas)); [Link](); [Link](JFrame.EXIT_ON_CLOSE); [Link](true); }
Fevereiro/2010
[Link]
67 /146
Operadores da API JAI: convolve
Fevereiro/2010
[Link]
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 = [Link]("fileload", args[0]); float[] kernelMatrix = { -1, -2, -1, 0, 0, 0, 1, 2, 1 }; KernelJAI kernel = new KernelJAI(3,3,kernelMatrix); PlanarImage bordas = [Link]("convolve",imagem,kernel); JFrame frame = new JFrame("Bordas horizontais"); [Link](new DisplayTwoSynchronizedImages(imagem,bordas)); [Link](); [Link](JFrame.EXIT_ON_CLOSE); [Link](true); }
Fevereiro/2010
[Link]
69 /146
Operadores da API JAI: convolve
Fevereiro/2010
[Link]
70 /146
Operadores da API JAI: dilate
Expanso de regies da imagem com elemento estrutural.
public static void main(String[] args) { PlanarImage imagem = [Link]("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(); [Link](imagem); [Link](kernel); PlanarImage dilatada = [Link]("dilate",p); JFrame frame = new JFrame("Imagem dilatada"); [Link](new DisplayTwoSynchronizedImages(imagem,dilatada)); [Link](); [Link](JFrame.EXIT_ON_CLOSE); [Link](true); }
Fevereiro/2010
[Link]
71 /146
Operadores da API JAI: dilate
Regies brancas so dilatadas!
Fevereiro/2010 [Link] 72 /146
Operadores da API JAI: erode
Reduo de regies da imagem com elemento estrutural.
public static void main(String[] args) { PlanarImage imagem = [Link]("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(); [Link](imagem); [Link](kernel); PlanarImage erodida = [Link]("erode",p); JFrame frame = new JFrame("Imagem erodida"); [Link](new DisplayTwoSynchronizedImages(imagem,erodida)); [Link](); [Link](JFrame.EXIT_ON_CLOSE); [Link](true); }
Fevereiro/2010
[Link]
73 /146
Operadores da API JAI: erode
Regies brancas so dilatadas!
Fevereiro/2010 [Link] 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 = [Link]("fileload",args[0]); float angle = (float)[Link](45); // Usamos o centro da imagem para rotao float centerX = [Link]()/2f; float centerY = [Link]()/2f; ParameterBlock pb = new ParameterBlock(); [Link](imagem); [Link](centerX); [Link](centerY); [Link](angle); [Link](new InterpolationBilinear()); PlanarImage rotacionada = [Link]("rotate", pb); JFrame frame = new JFrame("Imagem rotacionada"); [Link](new DisplayTwoSynchronizedImages(imagem,rotacionada)); [Link](); [Link](JFrame.EXIT_ON_CLOSE); [Link](true); }
Fevereiro/2010
[Link]
75 /146
Operadores da API JAI: rotate
Coordenadas dos cantos da imagem rotacionada: (-39, -136) (558, 461)
Fevereiro/2010
[Link]
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
[Link]
77 /146
Operadores da API JAI: rotate
JAI permite imagens com pixels com coordenadas negativas!
DisplayJAI, ImageIO e [Link](filestore) no. Soluo: mover a origem da imagem com o operador translate.
public static void main(String[] args) { PlanarImage imagem = [Link]("fileload",args[0]); float angle = (float)[Link](45); // Usamos o centro da imagem para rotao float centerX = [Link]()/2f; float centerY = [Link]()/2f; ParameterBlock pb = new ParameterBlock(); [Link](imagem); [Link](centerX); [Link](centerY); [Link](angle); [Link](new InterpolationBilinear()); PlanarImage rotacionada = [Link]("rotate", pb);
Fevereiro/2010 [Link] 78 /146
Operadores da API JAI: rotate
// Ajustamos a origem da imagem pb = new ParameterBlock(); [Link](rotacionada); [Link]((float)-[Link]()); [Link]((float)-[Link]()); PlanarImage rotacionadaOK = [Link]("translate",pb,null); JFrame frame = new JFrame("Imagem rotacionada"); [Link]( new DisplayTwoSynchronizedImages(imagem,rotacionadaOK)); [Link](); [Link](JFrame.EXIT_ON_CLOSE); [Link](true); }
Fevereiro/2010
[Link]
79 /146
Operadores da API JAI: rotate
Fevereiro/2010
[Link]
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 = [Link]("fileload",args[0]); float scale = 0.3f; ParameterBlock pb = new ParameterBlock(); [Link](imagem); [Link](scale); [Link](scale); [Link](0.0F); [Link](0.0F); [Link](new InterpolationNearest()); PlanarImage reescalada = [Link]("scale", pb); JFrame frame = new JFrame("Imagem reescalada"); [Link](new DisplayTwoSynchronizedImages(imagem,reescalada)); [Link](); [Link](JFrame.EXIT_ON_CLOSE); [Link](true); }
Fevereiro/2010 [Link] 81 /146
Operadores da API JAI: scale
Fevereiro/2010
[Link]
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 = [Link]("fileload",args[0]); ParameterBlock pb = new ParameterBlock(); float x = [Link](args[1]); float y = [Link](args[2]); float w = [Link](args[3]); float h = [Link](args[4]); float z = [Link](args[5]);
Fevereiro/2010
[Link]
83 /146
Operadores da API JAI: crop, translate, scale
// Recorta [Link](imagem); [Link](x); [Link](y); [Link](w); [Link](h); PlanarImage recortada = [Link]("crop",pb,null); // Reposiciona pb = new ParameterBlock(); [Link](recortada); [Link]((float)-x); [Link]((float)-y); PlanarImage recortadaOK = [Link]("translate",pb,null);
Fevereiro/2010
[Link]
84 /146
Operadores da API JAI: crop, translate, scale
// Amplia (2 verses) pb = new ParameterBlock(); [Link](recortadaOK); [Link](z); [Link](z); [Link](0.0F); [Link](0.0F); [Link](new InterpolationNearest()); PlanarImage resultado1 = [Link]("scale", pb); pb = new ParameterBlock(); [Link](recortadaOK); [Link](z); [Link](z); [Link](0.0F); [Link](0.0F); [Link](new InterpolationBicubic(2)); PlanarImage resultado2 = [Link]("scale", pb);
Fevereiro/2010
[Link]
85 /146
Operadores da API JAI: crop, translate, scale
JFrame frame = new JFrame("Recorte ampliado"); [Link]( new DisplayTwoSynchronizedImages(resultado1,resultado2)); [Link](); [Link](JFrame.EXIT_ON_CLOSE); [Link](true); }
java wvc/operadores/Recorta [Link] 461 896 24 27 20
Fevereiro/2010 [Link] 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 = [Link]("fileload", args[0]); // Primeiro histograma com 256 bins. ParameterBlock pb1 = new ParameterBlock(); [Link](image); [Link](null); [Link](1); [Link](1); [Link](new int[]{256}); [Link](new double[]{0}); [Link](new double[]{256}); PlanarImage dummyImage1 = [Link]("histogram", pb1); Histogram histo1 = (Histogram)[Link]("histogram");
Fevereiro/2010 [Link] 87 /146
Operadores da API JAI: histogram
// Segundo histograma com 32 bins. ParameterBlock pb2 = new ParameterBlock(); [Link](image); [Link](null); [Link](1); [Link](1); [Link](new int[]{32}); [Link](new double[]{0}); [Link](new double[]{256}); PlanarImage dummyImage2 = [Link]("histogram", pb2); Histogram histo2 = (Histogram)[Link]("histogram"); // Exibimos os histogramas usando um componente especfico. JFrame f = new JFrame("Histogramas"); DisplayHistogram dh1 = new DisplayHistogram(histo1,"256 bins"); [Link](2); [Link](160); [Link](1); DisplayHistogram dh2 = new DisplayHistogram(histo2,"32 bins"); [Link](16); [Link](160);[Link](8); [Link](2); [Link]().setLayout(new GridLayout(2,1)); [Link]().add(dh1); [Link]().add(dh2); [Link](JFrame.EXIT_ON_CLOSE); [Link](); [Link](true); }
Fevereiro/2010 [Link] 88 /146
Operadores da API JAI: histogram
Fevereiro/2010
[Link]
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
[Link]
90 /146
Aplicao: Pan Sharpening
PlanarImageiRed=[Link]("fileload",args[0]); PlanarImageiGreen=[Link]("fileload",args[1]); PlanarImageiBlue=[Link]("fileload",args[2]); PlanarImagepanImage=[Link]("fileload",args[3]); ParameterBlockpb=newParameterBlock(); [Link](iRed); [Link](iGreen); [Link](iBlue); PlanarImagergbImage=[Link]("bandmerge",pb);
pb=newParameterBlock(); [Link](rgbImage); floatscaleX=(1f*[Link]()/[Link]()); floatscaleY=(1f*[Link]()/[Link]()); [Link](scaleX); [Link](scaleY); rgbImage=[Link]("scale",pb);
Fevereiro/2010
[Link]
91 /146
Aplicao: Pan Sharpening
IHSColorSpaceihs=[Link](); ColorModelIHSColorModel= newComponentColorModel(ihs, newint[]{8,8,8}, false,false, [Link], DataBuffer.TYPE_BYTE); pb=newParameterBlock(); [Link](rgbImage); [Link](IHSColorModel); RenderedImageimageIHS=[Link]("colorconvert",pb); PlanarImage[]IHSBands=newPlanarImage[3]; for(intband=0;band<3;band++) { pb=newParameterBlock(); [Link](imageIHS); [Link](newint[]{band}); IHSBands[band]=[Link]("bandselect",pb); }
Fevereiro/2010
[Link]
92 /146
Aplicao: Pan Sharpening
ImageLayoutimageLayout=newImageLayout(); [Link](IHSColorModel); [Link]([Link]()); RenderingHintsrendHints= newRenderingHints(JAI.KEY_IMAGE_LAYOUT,imageLayout); pb=newParameterBlock(); [Link](panImage); [Link](IHSBands[1]); [Link](IHSBands[2]); RenderedImagepanSharpenedIHSImage= [Link]("bandmerge",pb,rendHints); pb=newParameterBlock(); [Link](panSharpenedIHSImage); [Link]([Link]());//RGBcolormodel PlanarImagefinalImage=[Link]("colorconvert",pb); JFrameframe=newJFrame("IHSPanSharpening"); [Link](newDisplayTwoSynchronizedImages(rgbImage,finalImage)); [Link](); [Link](JFrame.EXIT_ON_CLOSE); [Link](true);
Fevereiro/2010 [Link] 93 /146
Aplicao: Pan Sharpening
Fevereiro/2010
[Link]
94 /146
Aplicao: Pan Sharpening
Fevereiro/2010
[Link]
95 /146
Criando Novos Operadores com a API JAI
Fevereiro/2010
[Link]
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
[Link]
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
[Link]
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
[Link]
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); [Link] = source; this.threshold1 = th1; this.threshold2 = th2; }
Fevereiro/2010 [Link] 100 /146
Novo Operador: segmenta3
public Raster computeTile(int x,int y) { Raster r = [Link](x,y); int minX = [Link](); int minY = [Link](); int width = [Link](); int height = [Link](); // Criamos um WritableRaster da regio sendo considerada. WritableRaster wr = [Link](minX,minY,width,height); for(int l=0;l<[Link]();l++) for(int c=0;c<[Link]();c++) for(int b=0;b<[Link]();b++) { int p = [Link](c+minX,l+minY,b); if (p < threshold1) p = 0; else if (p > threshold2) p = 255; else p = 127; [Link](c+minX,l+minY,b,p); } return wr; }
Fevereiro/2010 [Link]
Passo 1
101 /146
Novo Operador: segmenta3 Passo 2
public class Segmenta3RIF implements RenderedImageFactory { public RenderedImage create(ParameterBlock paramBlock, RenderingHints hints) { RenderedImage source = [Link](0); int threshold1 = [Link](0); int threshold2 = [Link](1); ImageLayout layout = new ImageLayout(source); return new Segmenta3OpImage(source,threshold1,threshold2, layout,hints,false); } }
Fevereiro/2010
[Link]
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", "[Link] {"Version", "1.0"}, {"arg0Desc", "First Threshold Value"}, {"arg1Desc", "Second Threshold Value"} }; private static final String[] supportedModes = {"rendered"};
Fevereiro/2010
[Link]
103 /146
Novo Operador: segmenta3 Passo 3
private static final String[] paramNames = {"1st threshold", "2nd threshold"}; private static final Class[] paramClasses = {[Link], [Link]}; private static final Object[] paramDefaults = {new Integer(85), new Integer(170) }; private static final Range[] validParamValues = { new Range([Link], Integer.MIN_VALUE, Integer.MAX_VALUE), new Range([Link], Integer.MIN_VALUE, Integer.MAX_VALUE) }; private static final int numSources = 1; private static boolean registered = false;
Fevereiro/2010
[Link]
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 = [Link]().getOperationRegistry(); Segmenta3Descriptor desc = new Segmenta3Descriptor(); [Link](desc); Segmenta3RIF rif = new Segmenta3RIF(); [Link](op,opName,vendorName,rif); registered = true; } }
Fevereiro/2010
[Link]
105 /146
Novo Operador: segmenta3
public static void main(String[] args) { [Link](); PlanarImage imagem = [Link]("fileload", args[0]); ParameterBlock p = new ParameterBlock(); [Link](imagem); [Link](new Integer(120)); [Link](new Integer(200)); PlanarImage resultado = [Link]("segmenta3",p); JFrame frame = new JFrame("Imagem binarizada"); [Link](new DisplayTwoSynchronizedImages(imagem,resultado)); [Link](); [Link](JFrame.EXIT_ON_CLOSE); [Link](true); }
Fevereiro/2010
[Link]
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,[Link](),[Link](),1,1); [Link] = target; [Link] = tolerance; count = null; }
Fevereiro/2010 [Link] 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<[Link]();l++) for(int c=0;c<[Link]();c++) { int x = [Link]()+c; int y = [Link]()+l; r = [Link](x,y,0); g = [Link](x,y,1); b = [Link](x,y,2); float dist = ([Link]()-r)*([Link]()-r)+ ([Link]()-g)*([Link]()-g)+ ([Link]()-b)*([Link]()-b); if (dist<=tolerance*tolerance) count++; } }
Fevereiro/2010 [Link] 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) [Link](name); return count; }
Passo 1
Fevereiro/2010
[Link]
109 /146
Novo Operador: contapixels Passo 2
public class ContaPixelsRIF implements RenderedImageFactory { public RenderedImage create(ParameterBlock paramBlock, RenderingHints hints) { RenderedImage source = [Link](0); Color target = (Color)[Link](0); Float tolerance = (Float)[Link](1); return new ContaPixelsOpImage(source,target,tolerance); } }
Fevereiro/2010
[Link]
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", "[Link] {"Version", "1.0"}, {"arg0Desc", "Target value (color used for similarity)"}, {"arg1Desc", "Tolerance value"}, }; private static final String[] modes = {"rendered"};
Fevereiro/2010
[Link]
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 = {[Link], [Link]}; 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
[Link]
112 /146
Novo Operador: contapixels Passo 4
public static void register() { if (!registered) { OperationRegistry op = [Link]().getOperationRegistry(); ContaPixelsDescriptor desc = new ContaPixelsDescriptor(); [Link](desc); ContaPixelsRIF rif = new ContaPixelsRIF(); [Link](op,opName,vendorName,rif); registered = true; } }
Fevereiro/2010
[Link]
113 /146
Novo Operador: contapixels
public static void main(String[] args) { [Link](); PlanarImage input = [Link]("fileload", args[0]); int r = [Link](args[1]); int g = [Link](args[2]); int b = [Link](args[3]); float t = [Link](args[4]); Color color = new Color(r,g,b); ParameterBlock p = new ParameterBlock(); [Link](input); [Link](color); [Link](t); PlanarImage output = [Link]("contapixels",p); Long count = (Long)[Link]("count"); [Link]("Existem "+count+ " pixels com cores semelhantes a "+color); }
Fevereiro/2010
[Link]
114 /146
Extras: I/O
Fevereiro/2010
[Link]
115 /146
Que formatos so suportados?
public static void main(String[] args) { String[] iFormatos = [Link](); [Link]("Leitura: "); for(String f:iFormatos) { [Link](f+" "); } [Link]("\nGravao: "); String[] oFormatos = [Link](); for(String f:oFormatos) { [Link](f+" "); } [Link](); }
Leitura: image/jpeg image/png image/x-png image/[Link] image/gif image/bmp Gravao: image/png image/jpeg image/x-png image/[Link] image/bmp image/gif
Fevereiro/2010
[Link]
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
[Link]
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/[Link]"; BufferedImage i = [Link](new File(imageFile)); showImage("Original Image", i); // Show results with different compression ratio. compressAndShow(i, 0.5f); }
Veja mais em [Link] Fevereiro/2010 [Link] 118 /146
Como compactar mais?
public static void compressAndShow(BufferedImage image, float quality) throws IOException { // Get a ImageWriter for jpeg format. Iterator<ImageWriter> writers = [Link]("jpeg"); if (![Link]()) throw new IllegalStateException("No writers found"); ImageWriter writer = (ImageWriter) [Link](); // Create the ImageWriteParam to compress the image. ImageWriteParam param = [Link](); [Link](ImageWriteParam.MODE_EXPLICIT); [Link](quality); // The output will be a ByteArrayOutputStream (in memory) ByteArrayOutputStream bos = new ByteArrayOutputStream(32768); ImageOutputStream ios = [Link](bos); [Link](ios); [Link](null, new IIOImage(image, null, null), param); [Link](); // otherwise the buffer size will be zero! // From the ByteArrayOutputStream create a RenderedImage. ByteArrayInputStream in = new ByteArrayInputStream([Link]()); RenderedImage out = [Link](in); int size = [Link]().length; showImage("Compressed to " + quality + ": " + size + " bytes", out); } Veja mais em [Link] Fevereiro/2010 [Link] 119 /146
Como compactar mais?
private static void showImage(String title,RenderedImage image) { JFrame f = new JFrame(title); [Link]().add(new DisplayJAI(image)); [Link](); [Link](true); [Link](JFrame.EXIT_ON_CLOSE); }
Original
0.5
0.1
Veja mais em [Link] Fevereiro/2010 [Link] 120 /146
Extras: Pixels
Fevereiro/2010
[Link]
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
[Link]
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
[Link]
123 /146
Mini-aplicao: Converso RGB IHS
public class RGBtoIHS { public static void main(String[] args) { PlanarImage imagem = [Link]("fileload", args[0]); // Converte para o modelo de cores IHS. IHSColorSpace ihs = [Link](); ColorModel modeloIHS = new ComponentColorModel(ihs, new int []{8,8,8}, false,false, [Link], DataBuffer.TYPE_BYTE) ; ParameterBlock pb = new ParameterBlock(); [Link](imagem); [Link](modeloIHS); RenderedImage imagemIHS = [Link]("colorconvert", pb);
Fevereiro/2010
[Link]
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(); [Link](imagemIHS); [Link](new int[]{band}); bandas[band] = [Link]("bandselect",pb); } // Criamos bandas constantes para as bandas I e S. pb = new ParameterBlock(); [Link]((float)[Link]()); [Link]((float)[Link]()); [Link](new Byte[]{(byte)255}); RenderedImage novaIntensidade = [Link]("constant",pb); pb = new ParameterBlock(); [Link]((float)[Link]()); [Link]((float)[Link]()); [Link](new Byte[]{(byte)255}); RenderedImage novaSaturao = [Link]("constant",pb);
Fevereiro/2010
[Link]
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(); [Link](modeloIHS); [Link]([Link]()); RenderingHints rendHints = new RenderingHints(JAI.KEY_IMAGE_LAYOUT,imageLayout); pb = new ParameterBlock(); [Link](novaIntensidade); [Link](bandas[1]); [Link](novaSaturao); RenderedImage imagemIHSModificada = [Link]("bandmerge", pb, rendHints); // Convertemos de volta para RGB. pb = new ParameterBlock(); [Link](imagemIHSModificada); [Link]([Link]()); // Imagem original era em RGB! RenderedImage imagemFinal = [Link]("colorconvert", pb);
Fevereiro/2010
[Link]
126 /146
Mini-aplicao: Converso RGB IHS
JFrame frame = new JFrame("Modificao via IHS"); [Link](new DisplayTwoSynchronizedImages(imagem,imagemFinal)); [Link](); [Link](JFrame.EXIT_ON_CLOSE); [Link](true); } }
Fevereiro/2010
[Link]
127 /146
Extras: Display
Fevereiro/2010
[Link]
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
[Link]
129 /146
Mini-aplicao: Visualizador com cone
public DisplayThumbnail(PlanarImage image,float scale, int width,int height) { [Link] = scale; originalImage = image; visibleRegionWidth = width; visibleRegionHeight = height; // Get some stuff about the image. imageXTiles = [Link](); imageYTiles = [Link](); imageTileWidth = [Link](); imageTileHeight = [Link](); imageWidth = [Link](); imageHeight = [Link](); // Must create a thumbnail image using that scale. ParameterBlock pb = new ParameterBlock(); [Link](image); [Link](scale); [Link](scale); [Link](0.0F); [Link](0.0F); [Link](new InterpolationNearest()); PlanarImage thumbnail = [Link]("scale", pb, null); // Let's get the width and height of the thumbnail. thumbWidth = [Link](); thumbHeight = [Link]();
Fevereiro/2010
[Link]
130 /146
Mini-aplicao: Visualizador com cone
// Now let's add a border. pb = new ParameterBlock(); [Link](thumbnail); [Link](new Integer(border)); [Link](new Integer(border)); [Link](new Integer(border)); [Link](new Integer(border)); [Link](new BorderExtenderConstant(new double[]{0,0,128})); thumbnail = [Link]("border",pb); // Shift the image to the original position pb = new ParameterBlock(); [Link](thumbnail); [Link](1.0f*border); [Link](1.0f*border); thumbnail = [Link]("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 [Link](border,border,width*scale,height*scale); // We assume that the mouse is off the viewport. viewportColor = viewportOff; }
Fevereiro/2010
[Link]
131 /146
Mini-aplicao: Visualizador com cone
public synchronized void paintComponent(Graphics g) { [Link](g); Graphics2D g2d = (Graphics2D)g; // Paint the tile grid. [Link]([Link]); [Link]([Link]( 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++) { [Link]((int)x1,(int)y1,(int)x2,(int)y2); x1 += imageTileWidth*scale; x2 += imageTileWidth*scale; }
Fevereiro/2010
[Link]
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++) { [Link]((int)x1,(int)y1,(int)x2,(int)y2); y1 += imageTileHeight*scale; y2 += imageTileHeight*scale; } // Paint a red border. [Link]([Link]); [Link](border,border,thumbWidth,thumbHeight); // Paint the viewport. [Link](viewportColor); [Link]([Link](AlphaComposite.SRC_OVER,1f)); Stroke stroke = new BasicStroke(2f); [Link](stroke); [Link](scaledViewport); }
Fevereiro/2010
[Link]
133 /146
Mini-aplicao: Visualizador com cone
public void mouseMoved(MouseEvent e) { int x = [Link](); int y = [Link](); // Ignore events outside the border. if ((x < border) || (y < border) || (x > border+thumbWidth) || (y > border+thumbHeight)) return; // Are we inside the viewport rectangle ? if ([Link](x,y)) viewportColor = viewportOn; else viewportColor = viewportOff; // Hopefully it will repaint only the needed section. Rectangle repaintBounds = new Rectangle((int)[Link]()-5, (int)[Link]()-5, (int)[Link]()+10, (int)[Link]()+10); repaint(repaintBounds); }
Fevereiro/2010
[Link]
134 /146
Mini-aplicao: Visualizador com cone
public void mousePressed(MouseEvent e) { // Store the new dragging starting points. lastX = [Link](); lastY = [Link](); // Calculate the new window w/ viewport movements. minValidX = lastX-(int)[Link]()+border; minValidY = lastY-(int)[Link]()+border; maxValidX = border+thumbWidth-(int)[Link]()+ (lastX-(int)[Link]()); maxValidY = border+thumbHeight-(int)[Link]()+ (lastY-(int)[Link]()); } public void mouseDragged(MouseEvent e) { int x = [Link](); int y = [Link](); 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 [Link] 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)[Link]()-5, (int)[Link]()-5, (int)[Link]()+10, (int)[Link]()+10); // Recalculate new position for the viewport, based on mouse coordinates. double origX = [Link]()+x-lastX; double origY = [Link]()+y-lastY; // Reposition the viewport. [Link](origX,origY, [Link](),[Link]()); // Store the approximate region where the viewport is after the change. Rectangle finalBounds = new Rectangle((int)[Link]()-5, (int)[Link]()-5, (int)[Link]()+10, (int)[Link]()+10); // Repaint only that section. repaint([Link](initBounds)); }
Fevereiro/2010
[Link]
136 /146
Mini-aplicao: Visualizador com cone
public PlanarImage getImage() { // Get the boundaries in the original image coordinates. float fromX = (float)[Link](([Link]()-border)/scale); float fromY = (float)[Link](([Link]()-border)/scale); float width = (float)[Link]([Link]()/scale); float height = (float)[Link]([Link]()/scale); // Fix rounding errors to avoid exceptions on the crop. fromX = [Link](fromX,(imageWidth-visibleRegionWidth)); fromY = [Link](fromY,(imageHeight-visibleRegionHeight)); // Create a ParameterBlock with information for the cropping. ParameterBlock pb = new ParameterBlock(); [Link](originalImage); [Link](fromX); [Link](fromY); [Link](width); [Link](height); // Create the output image by cropping the input image. PlanarImage output = [Link]("crop",pb,null); // Translate the image origin. pb = new ParameterBlock(); [Link](output); [Link](-fromX); [Link](-fromY); // Create the output image by translating itself. return [Link]("translate",pb,null); }
Fevereiro/2010
[Link]
137 /146
Mini-aplicao: Visualizador com cone
public Rectangle getCroppedImageBounds() { int fromX = (int)[Link](([Link]()-border)/scale); int fromY = (int)[Link](([Link]()-border)/scale); int width = (int)[Link]([Link]()/scale); int height = (int)[Link]([Link]()/scale); return new Rectangle(fromX,fromY,width,height); } public Rectangle getViewportBounds() { Rectangle temp = [Link](); [Link]((int)[Link]()-border,(int)[Link]()-border, (int)[Link](),(int)[Link]()); return temp; }
Fevereiro/2010
[Link]
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(); [Link](layout); dt = new DisplayThumbnail(image,0.05f,dWidth,dHeight); [Link](this); dj = new DisplayJAI([Link]()); [Link](new Dimension(dWidth,dHeight)); [Link](new Dimension(dWidth,dHeight)); [Link](new Dimension(dWidth,dHeight)); JPanel borderDisplay = new JPanel(new BorderLayout()); [Link](dj); [Link]([Link]([Link])); JLabel worldL = new JLabel("World: "); world = new JLabel(""); JLabel viewL = new JLabel("Thumb: "); view = new JLabel(""); [Link](dt); [Link](borderDisplay); [Link](worldL); [Link](world); [Link](viewL); [Link](view); (organizao do layout removida) setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setResizable(false); pack(); setVisible(true); }
Fevereiro/2010
[Link]
139 /146
Mini-aplicao: Visualizador com cone
public void mouseDragged(MouseEvent e) { [Link]([Link]()); // Gets some information about the viewport and cropped image. Rectangle crop = [Link](); Rectangle viewp = [Link](); // Change the labels' contents with this information. [Link](""+crop.x+","+crop.y+ " ("+[Link]+"x"+[Link]+")"); [Link](""+viewp.x+","+viewp.y+ " ("+[Link]+"x"+[Link]+")"); } public void mouseMoved(MouseEvent e) { } public static void main(String[] args) { PlanarImage image = [Link]("fileload", args[0]); new DisplayThumbnailApp(image,640,640); }
Fevereiro/2010
[Link]
140 /146
Mini-aplicao: Visualizador com cone
Fevereiro/2010
[Link]
141 /146
Outros Tpicos
Fevereiro/2010
[Link]
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
[Link]
Fevereiro/2010
[Link]
143 /146
Para saber mais...
[Link] [Link] 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
[Link]
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
[Link]
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
[Link]
146 /146