Documente noi - cercetari, esee, comentariu, compunere, document
Referate categorii

Achizitia si afisarea imaginilor in JAI

Achizitia si afisarea imaginilor in JAI


Toate aplicatiile de procesare a imaginilor trebuie sa execute niste operatii de baza, cum ar fi achizitia, afisarea si inregistrarea imaginilor. Imaginile pot fi achizitionate de la multe surse, care includ fisier de pe disc, retea, etc. Imaginile pot fi achizitionate, procesate si imediat afisate, sau scrise intr-un fisier pe disc pentru a putea fi afisate mai tarziu.

JAI ofera programatorului flexibilitatea de a procesa si afisa o imagine in mod imediat sau sa amane afisarea imaginii procesate pana cand apare o cerere specifica pentru aceasta.

Achizitia si afisarea imaginilor folosind mecanismele din JAI este prezentata in Exemplul 14. Acest exemplu este o aplicatie care preia un singur argument care este calea si numele fisierului care trebuie citit, iar aplicatia citeste acest fisier imagine folosind operatorul “FileLoad” si afiseaza imaginea cu ajutorul unei componente de afisare de tipul ScrollingImagePanel.




Exemplul 14. Program pentru citirea si afisarea unui fisier imagine

// se specifca clasele care se importa
import java.awt.image.renderable.ParameterBlock;
import java.io.File;
import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.RenderedOp;
import javax.media.jai.widget.ScrollingImagePanel;

public class FileTest extends WindowContainer else if(args.length == 1)
new FileTest(fileName);
}

public FileTest(String fileName)


1. Date imagine in JAI


Datele imagine reprezinta o arie tridimensionala de pixeli, asa cum arata Figura 9., fiecare din aceste trei arii formeaza cate o banda. Numarul de linii specifica inaltimea benzii imaginii, iar numarul de coloane specifica latimea benzii imaginii.






Imaginile monocrome, de exemplu imaginile grayscale, au doar o singura banda. Imaginile color au trei sau mai multe benzi, dar benzile nu neaparat reprezinta o culoare, de exemplu imaginile din satelit pot fi achizitionate avand mai multe benzi spectrale, de exemplu rosu, verde, albastru si infrarosu.

O imagine este esantionata intr-o grila dreptunghiulara de pixeli. Fiecare pixel are o coordonata (x, y) care corespunde locatiei de pe imagine. In JAI, locatia pixelului (0, 0) este in coltul din stanga sus al imaginii, cu valorile coordonatelor x crescatoare spre dreapta si valorile coordonatelor y crescatoare in jos.

In JAI API, unitatea de baza pentru stocarea imaginilor sunt obiectele DataBuffer. Acestea sunt un fel de obiecte de stocare brute, care stocheaza toate esantioanele din compozitia unei imagini, dar nu contin nici o informatie despre felul cum aceste esantioane sunt organizate ca pixeli. Aceasta informatie este stocata intr-un obiect SampleModel. Clasa SampleModel contine metode pentru derivarea datelor pixel dintr-un DataBuffer.

JAI suporta mai multe tipuri de date imagine, asa ca clasa DataBuffer are urmatoarele subclase, fiecare reprezentand un tip diferit de date:

DataBufferByte – stocheaza date intern ca si bytes (valori pe 8 biti).

DataBufferShort – stocheaza date intern ca si short (valori pe 16 biti)

DataBufferUShort – stocheaza date intern ca si unsigned short (valori pe 16 biti)

DataBufferInt – stocheaza date intern ca si intregi (valori pe 32 biti)

DataBufferFloat – stocheaza date intern ca si valori flotante in precizie simpla.

DataBufferBuffer – stocheaza date intern ca si valori flotante in precizie dubla.

JAI suporta si alte formate de date imagine, pe langa cele oferite de pachetul java.awt.image (vezi paragraful 3.4.), dar clasa SampleModel furnizeaza si urmatoarele tipuri de modele de esantioane:

ComponentSampleModelJAI – utilizat la extragerea pixelilor din imagini care stocheaza date esantion astfel incat fiecare esantion al unui pixel ocupa un element data din DataBuffer.

FloatComponentSampleModel – stocheaza n esantioane care formeaza un pixel in n arii de elemente data separate, toate acestea sunt stocate in acelasi segment a obiectului DataBuffer.

Combinatia dintre un obiect DataBuffer, un obiect SampleModel si un element origine constituie o unitate de stocare a imaginilor de tip multi-pixel si este concretizata prin clasa Raster (vezi paragraful 3.2.).


2. Tipuri imagine in JAI


JAI API furnizeaza o serie de clase pentru descrierea datelor imagine de diferite tipuri. Aceste clase sunt organizate intr-o ierarhie care este expusa in Figura 10.

Clasa PlanarImage. Aceasta clasa este clasa principala pentru definirea imaginilor bidimensionale. PalnarImage implementeaza interfata java.awt.image.RenderedImage, care descrie o imagine segmentata, disponibila doar pentru citire, cu o dispunere a pixelilor descrisa de un obiect SampleModel si unul de tip DataBuffer. Subclasele TiledImage si OpImage manipuleaza variabilele instanta pe care le mostenesc de la PlanarImage, cum ar fi marimea imaginii, originea, dimensiunea segmentului, deplasamentul grilei segmentului, obiectele de tip Vector care pastreaza sursa si destinatia imaginii.

Toate obiectele care nu apartin JAI de tip RenderedImage, dar care se utilizeaza in JAI trebuie convertite in PlanarImage prin mijloace oferite de clasa RenderedImageAdapter si clasa WriteableRenderedImageAdapter.






Clasa TiledImage. JAI API extinde conceptul de segmentare a datelor imagine introdus in Java 2D API. In Java 2D, un segment este una dintre regiunile dreptunghiulare care imparte o imagine intr-o grila regulata. JAI API extinde segmentarea imaginilor prin clasa TiledImage.

Un segment (tile) reprezinta totalitatea elementelor de stocare pentru o regiune dintr-o imagine. Daca o imagine este compusa din trei benzi, fiecare segment contine componente din toate cele trei benzi din datele stocate. Utilizarea imaginilor segmentate imbunatateste performanta aplicatiei prin faptul ca permite ca aplicatia sa proceseze o regiune de imagine dintr-un segment fara sa fie nevoie sa aducem intreaga imagine in memorie.

Clasa TiledImage este o implementare a interfetei WriteableRendered-Image, beneficiind de avantajul interfetei de a descrie imaginea cu segmente multiple. Segmentele de tipul WriteableRenderedImage trebuie sa imparta un SampleModel, care determina latimea, inaltimea si formatul pixelului.

Segmentele formeaza o grila regulata care poate sa ocupe orice regiune dreptunghiulara din plan. Segmentele de pixeli care depasesc limitele imaginii au valori nedefinite.

Continutul unui obiect TiledImage este definit de o singura sursa PlanarImage, furnizata fie la momentul constructiei fie cu ajutorul metodei set. Metoda set asigura un mod de suprascriere selectiva a unei portiuni din TiledImage.

TiledImage suporta manipularea directa a pixelilor prin mijloacele oferite de metoda getWriteableTile. Aceasta metoda returneaza un WritableRaster care poate fi modificat direct.

Un alt mod de a modifica continutul unui TiledImage este apelarea metodei createGraphics. Aceasta metoda returneaza un obiect GraphicsJAI care poate fi folosit pentru desenarea de grafica, text si imagini in maniera AWT.

TiledImage v-a cauza calcularea segmentelor sale doar atunci cand continutul este solicitat. Odata ce un segment este calculat, continutul sau poate fi eliminat daca se determina ca poate fi recalculat in mod identic din sursa. Metoda lockTile forteaza calcularea unui segment si mentinerea lui pe durata de existenta a obiectului TiledImage.

Interfata TileCache. Aceasta interfata este o zona cache comuna pentru segmentele calculate detinute de obiectele OpImage. Acest obiect care se creeaza (de tipul TileCache) are o capacitate data, masurata in segmente. In mod implicit, capacitatea unui TileCache este 300 segmente. Capacitatea implicita a memoriei rezervata pentru un obiect TileCache este 20M bytes.

Un obiect TileCache care va fi utilizat de o operatie anume poate fi conceput in momentul constructiei operatiei, sau printr-un apel la metoda JAI.setTileCache. Aceasta face ca obiectul TileCache sa fie adaugat la setul de indicii de reprezentare.

Interfata TileScheduler permite segmentelor sa fie programate pentru calculare. In diferite implementari, calcularea segmentului se poate realiza prin utilizarea de multithreading si conexiuni in retea multiple in mod simultan pentru a imbunatati performanta.

Clasa SnapshotImage. Aceasta clasa reprezinta componenta principala a motorului de executie amanata. Un SnapshotImage furnizeaza un numar arbitrar de variante sincrone a unui posibil obiect WritableRendered-Image care se modifica. SnapshotImage este responsabila pentru stabilizarea surselor care se modifica pentru a permite executia amanata a operatiilor dependente de astfel de surse.

Orice RenderedImage poate fi utilizat ca sursa pentru un Snapshot-Image. Daca sursa este un WritableRenderedImage, SnapshotImage se va inregistra ca TileObserver si va face copii pentru segmentele care sunt pe cale sa se modifice.

Mai multe versiuni ale fiecarui segment sunt pastrate intern, atat timp cat se cere. SnapshotImage permite monitorizarea acestor cereri si poate sa simplifice urmatoarele cereri pentru segmente, fara sa fie nevoie sa facem o copie.

Atunci cand se utilizeaza ca si sursa, apelurile la metoda getTile vor fi transmise spre sursa, cu alte cuvinte obiectele SnapshotImage sunt complet transparente. Prin apelul createSnapshot o instanta a unei subclase PlanarImage care nu este publica va fi creata si returnata. Obiectul PlanarImage va returna intotdeauna segmente de imagini cu continut ca si in momentul constructiei lui.

Clasa RemoteImage. Aceasta clasa este o subclasa a PlanarImage care reprezinta o imagine pe un server distant. Un obiect RemoteImage poate fi construit dintr-un RenderedImage sau dintr-un lant de procesare a imaginilor care este fie de tip Rendered, fie Renderable.

Clasa CollectionImage. Aceasta clasa este o superclasa abstracta pentru clasele care reprezinta grupuri de imagini. Exemple de grupuri de imagini sunt piramidele (ImagePyramid), secventele temporale (TimeSequence) si feliile plane suprapuse pentru a forma un volum (ImageStack).

Clasa ImageSequence. Aceasta clasa reprezinta o secventa de imagini asociata cu niste indecsi temporali si o pozitie a camerei, cu scopul de a reprezenta secvente video sau fotografie dependenta de timp.

Imaginile sunt de tipul ImageJAI, indecsii temporali sunt de tipul long, iar pozitiile camerei sunt de tipul Point. Acest triplet este reprezentat printr-un obiect de tipul SequentialImage.

Clasa ImageStack. Clasa ImageStack reprezinta o stiva de imagini, fiecare cu o orientare spatiala definita intr-un sistem de coordonate.

Imaginile sunt de tipul PlanarImage, coordonatele sunt de tipul javax.media.jai.Coordinate. Aceste date sunt reprezentate printr-un obiect javax.media.jai.CoordinateImage.

Clasa ImageMIPMap. O imagine de tip harta MIP este o stiva de imagini cu o relatie fixa intre feliile adiacente. Fiind data felia cu cea mai mare rezolutie, celelalte pot fi obtinute prin derivare folosind operatii specifice. Datele pot fi extrase felie cu felie sau prin iteratori speciali.

O imagine harta MIP (MIP vine din lmba latina multim im parvo” care inseamna multe lucruri in spatii mici ) este similara cu o alocare de textura. La alocarea texturilor, imaginea harta MIP contine versiuni de diferite marimi ale aceleiasi imagini in aceeasi locatie. Pentru utilizarea acestei alocari a texturilor, trebuie furnizate toate marimile imaginii in putere de 2 din cea mai mare imagine la o harta de 1x1.



Clasa ImageMIPMap preia sursa originala la cel mai mare nivel de rezolutie, considerat a fi nivelul 0 si un lant RenderedOp care defineste modul in care imaginea de la nivelul de rezolutie imediat inferior este derivata din nivelul de rezolutie curent.

Lantul RenderedOp poate sa aiba mai multe operatii, dar prima operatie din lant trebuie sa preia doar o singura imagine sursa, care este imaginea de la nivelul de rezolutie curent.

Clasa ImagePyramid. Aceasta clasa implementeaza o operatie piramida (pyramid) asupra unui obiect RenderedImage. Prin aceasta clasa se poate genera imagini aditionale prin medierea succesiva a unui bloc de 2x2 pixeli, fiecare data se elimina toate celelalte coloane si randuri de pixeli. De exemplu, pentru o imagine de tip RenderedImage de 1024x1024, vom avea imagini de 512x512, 256x256 si tot asa pana la 1x1.

In practica, imaginile de rezolutie mai mica pot fi derivate prin executia unui lant de operatii in mod repetat care subesantioneaza felia de imagine cu rezolutie mai mare. In mod similar, odata ce o felie de imagine este obtinuta, feliile de imagine cu rezolutia mai mare pot fi derivate prin executia unui alt lant de operatiuni in mod repetat care supraesantioneaza felia de imagine cu rezolutia mai mica. De asemenea, un al treilea lant de operatii poate fi folosit pentru gasirea diferentelor dintre felia originala a imaginii si felia rezultata obtinuta prin prima subesantionare apoi supraesantionand felia originala.

Clasa MultiResolutionRenderableImage. Aceasta clasa produce reprezentari bazate pe un set de obiecte RenderedImage de diferite rezolutii. Obiectul este construit dintr-o dimensiune specificata si un vector de obiecte RenderdImage care reprezinta imagini cu rezolutii progresiv mai mici.


3. Streamuri


JAI API extinde tipurile de streamuri din Java prin adaugarea de sapte clase de tip stream “seekable” (vezi Figura 11.) Tabelul 14. descrie pe scurt fiecare dintre aceste noi clase.






Noile clase de tip seekable sunt utilizate pentru aducerea in avans (in cache) a datelor imagine care sunt citite, metodele lor pot fi folosite la cautarea prin date inapoi sau inainte fara a fi nevoie sa recitim datele. Acest lucru este important pentru tipuri de date imagine care sunt segmentate sau nu pot fi recitite usor pentru a localiza o anume informatie importanta.



Clasa

Descriere

SeekableStream

Clasa abstracta care combina functionalitatile lui InputStream si RandomAccessFile, cu abilitatile de a citi tipuri de date primitive in format little-endian.

FileSeekableStream

Furnizeaza functionalitate SeekableStream asupra datelor stocate intr-un obiect File

ByteArraySeekable

Stream

Implementeaza functionalitate SeekableStream asupra datelor stocate intr-o arie de bytes

SegmentedSeekable

Stream

Furnizeaza informatii despre un subset al altui SeekableStream care contine o serie de segmente cu o pozitie de start data in fluxul sursei si lungime. Fluxul rezultat se comporta ca si un SeekableStream obisnuit.

ForwardSeekable

Stream

Furnizeaza functionalitate SeekableStream asupra datelor dintr-un InputStream cu adaugare de date minima, dar nu permite cautari inapoi. Poate fi utilizat cu formate de intrare care suporta streaming, evitand nevoia de a aduce in avans (cache) datele de intrare.

FileCacheSeekable

Stream

Furnizeaza functionalitate SeekableStream asupra datelor dintr-un InputStream cu adaugare de date minima, dar nu permite cautari inapoi. Poate fi utilizat cu formate de intrare care suporta streaming, evitand nevoia de a aduce in avans (cache) datele de intrare. In circumstantele in care nu permit crearea unui fisier temporar (de exemplu, datorita securitatii sau absenta unui disc local), poate fi utilizata MemoryCache-SeekableStream.

MemoryCache

SeekableStream

Furnizeaza functionalitate SeekableStream asupra datelor dintr-un InputStream, folosind un cache in memorie pentru a permite cautarea inapoi. Aceasta clasa se utilizeaza atunci cand securitatea sau lipsa accesului la un disc local nu poate fi facuta cu FileCacheSeekableStream.

Tabelul 14. Clasele stream din JAI


Pentru a citi date imagine dintr-un fisier este nevoie de abilitatea de cautare inainte si inapoi prin date si de a citi informatiile care descriu imaginea. Cea mai buna cale pentru a face datele sa poata fi cautate este printr-un cache, un fisier temporar stocat pe discul local sau in memorie. Cea mai preferata metoda de a stoca datele este discul local, dar nu intotdeauna este posibil. Din motive de securitate, sau la sistemele fara disc, crearea unui fisier cache pe disc nu este intotdeauna permisa. Atunci cand un fisier cache nu este permis, se poate utiliza un cache in memorie.

Clasa SeekableStream permite cautarea in datele de intrare, in mod similar cu clasa RandomAccessFile. Interfata DataInput este suportata si extinsa pentru a include suport pentru reprezentare little-endian a tipurilor de date fundamentale.

SeekableStream adauga cateva metode read la cele existente din clasa java.io.DataInput, incluzand metode pentru citirea datelor in ordine little-endian, deoarece in Java toate valorile sunt scrise in stilul big-endian. Cu toate acestea, JAI necesita metode pentru citirea de date care nu sunt produse de Java, date care sunt produse pe alte platforme si care sunt in stilul little-endian.

Pe langa metodele obisnuite furnizate de clasa InputStream, clasa RandomAccessFile implementeaza metodele getFilePointer si seek. Metoda canSeekBackwards returneaza true daca este posibila cautarea inapoi in stream fata de valoarea curenta obtinuta cu metoda getFilePointer.

Exista cateva subclase ale SeekableStream care se gasesc in pachetul com.sun.media.jai.codec. Trei clase sunt furnizate cu scopul de adaptare a unui obiect standard InputStream la interfata SeekableStream. Clasa Forward-SeekableStream nu permite cautarea inapoi, dar este foarte performanta. Clasa FileCacheSeekableStream mentine o copie a tuturor datelor citite de la intrare intr-un fisier temporar. Acest fisier va fi eliminat automat atunci cand FileSeekableStream este finalizat, sau cand JVM iese din program in mod normal.

Clasa FileCacheSeekableStream are scopul de a fi eficienta in limite rezonabile in relatie cu utilizarea spatiului de pe disc. Atunci cand crearea unui fisier temporar nu este posibila, se foloseste clasa MemoryCacheSeekable-Stream. Aceasta clasa creeaza un bufer foarte mare in memorie pentru a stoca datele din stream si este de preferat sa fie evitata. Clasa FileSeekableStream acopera clasa File sau clasa RandomAccessFile si executa o operatie limitata de aducere in avans a datelor (caching) pentru a evita operatiile I/O prea dese.

Metoda wrapInputStream este furnizata pentru a construi o instanta potrivita a SeekableStream a carui date sunt furnizate de un InputStream dat. Cel care apeleaza, prin mijloace ale parametrului canSeekBackwards, determina daca este necesar suportul pentru cautari in urma.


4. Citirea fisierelor imagine


Arhitectura de codare JAI este compusa din codoare si decodoare capabile de a citi si scrie cateva formate de fisiere imagine rastru.

Exista mai multe formate de fisiere imagine rastru, cele mai multe dintre ele au fost create pentru a suporta stocarea si interschimbarea imaginilor. Unele formate au ajuns sa fie utilizate pe scara larga si sunt considerate standarde de facto. Alte formate, care sunt foarte importante pentru anumiti vendori software, sunt mai putin utilizate.

JAI suporta in mod direct cateva dintre cele mai utilizate formate de fisiere imagine (listate in Tabelul 15.). Pentru alte formate, se pot adauga noi codoare de fisiere, pe baza arhitecturii de extindere a JAI API.

Un fisier imagine are in mod obisnuit cel putin doua parti un header de fisier si datele imagine. Headerul contine campuri cu informatii despre datele imagine care urmeaza. Acest header trebuie sa furnizeze toate informatiile necesare pentru reconstructia imaginii originale din datele imagine stocate. Datele imagine pot sau nu sa fie comprimate.


Numele formatului de fisier

Descriere

BMP

Fisier imagine de tip Microsoft Windows bitmap

FPX

Format FlashPix

GIF

Format Graphics Interchange Format

JPEG

Format de fisier imagine dezvoltat de Joint Photographic Experts Group

PNG

Format Portable Network Graphics

PNM

Format de fisier Portable aNy Map. Include formatele PBM, PGM si PPM.

TIFF

Format de fisier imagine Tag Image File Format



Tabelul 15. Formate de fisiere  imagine suportate de JAI


Principala clasa pentru decodarea si codarea imaginilor este ImageCodec. Subclasele acestei clase pot sa execute recunoasterea unui format de fisier fie prin inspectia a unui header de lungime fixa sau prin accesul arbitrar la streamul de date sursa. Fiecare subclasa ImageCodec implementeaza una din cele doua metode de recunoastere a fisierelor imagine. Codecul la inceput apeleaza metoda getNumHeaderBytes, care fie returneaza 0 daca accesul arbitrar la stream este necesar, sau returneaza numarul de bytes din header necesari pentru a recunoaste formatul. In functie de ce returneaza metoda getNumHeaderBytes, codorul citeste streamul sau headerul.

Odata ce codecul a determinat formatul de imagine, prin metoda citirii streamului sau cea a headerului, el returneaza numele codecului asociat cu formatul de imagine detectat. Daca nu este inregistrat nici un codec cu acel nume, se returneaza null. Numele codecului defineste subclasa care este apelata, care decodeaza imaginea.

Pentru cele mai multe tipuri de imagine, JAI ofera optiunea de a citi fisierul cu date imagine ca obiect java.io.File sau ca una din subclasele de tipul java.io.InputStream.

JAI ofera cativa operatori de fisier pentru citirea fisierelor cu date imagine, listati in Tebelul 16.


Operator

Descriere

AWTImage

Importa o imagine AWT standard in JAI

BMP

Citeste date BMP dintr-un stream de intrare

FileLoad

Citeste o imagine dintr-un fisier

FPX

Citeste date FlashPix dintr-un stream de intrare

FPXFile

Citeste un fisier standard FlashPix

GIF

Citeste date GIF dintr-un stream de intrare

JPEG

Citeste un fisier standard JPEG (JFIF)

PNG

Citeste un stream de intrare PNG

PNM

Citeste un fisier standard PNM, inclusiv imagini PBM, PGM si PPM in format ASCII sau brut.

Stream

Citeste obiecte de tip java.io.InputStream

TIFF

Citeste date TIFF 6.0 dintr-un stream de intrare.

URL

Creeaza o imagine sursa care este specificata de un URL

Tabelul 16. Operatori pentru fisiere imagine


In exemplul urmator (Exemplul 15.) se prezinta cateva fragmente de program in care se exemplifica utilizarea diferitilor operatori pentru fisiere.


Exemplul 15. Utilizarea diferitilor operatori pentru fisiere

// exemplu operatie stream
// incarcarea imaginii sursa dintr-un stream
RenderedImage im = JAI.create('stream', stream);

// exemplu de operatie fileload
// incarca imaginea sursa dintr-un fisier
RenderedImage src = (RenderedImage)JAI.create('fileload', fileName)

// exemplu de citire a unei imagini FPX
// specifica numele fisierului
File file = new File(filename);
// specifica rezolutia fisierului
ImageDecodeParam param = new FPXDecodeParam(resolution);

// creeaza operatia FPX pentru citirea fisierului.
ImageDecoder decoder = ImageCodec.createImageDecoder('fpx',
file, param);
RenderedImage im = decoder.decodeAsRenderedImage();
ScrollingImagePanel p = new ScrollingImagePanel(im,
Math.min(im.getWidth(), 800) + 20,
Math.min(im.getHeight(), 800) + 20);

// exemplu de citire a imaginilor BMP
// acopera un obiect InputStream dintr-un SeekableStream.
InputStream is = new FileInputStream(filename);
SeekableStream s = SeekableStream.wrapInputStream(is, false);// creeaza obiectul ParameterBlock si este adaugat SeekableStream.
ParameterBlock pb = new ParameterBlock();
pb.add(s);
// executa operatia BMP
op = JAI.create('BMP', pb);

// exemplu de citire a fisierelor imagine PNG
// crearea obiectului ParameterBlock.
InputStream image = new FileInputStream(filename);
ParameterBlock pb = new ParameterBlock();
pb.add(image);
// creeaza operatia PNG.
op = JAI.create('PNG', pb);

// exemplu de citire a fisierelor imagine PNM
// creeaza obiectul ParameterBlock.
InputStream image = new FileInputStream(filename);
ParameterBlock pb = new ParameterBlock();
pb.add(image);
// creeaza operatia PNM
op = JAI.create('PNM', pb);

// exemplu de citire a unei imagini AWT
// creeaza ParameterBlock.
ParameterBlock pb = new ParameterBlock();
pb.add(image);
// creeaza o operatie AWTImage.
PlanarImage im = (PlanarImage)JAI.create('awtImage', pb);

// exemplu de citire a unei imagini de tip URL
// defineste o imagine URL.
url = new URL('http://www/img/k.gif');
// citeste imaginea de la URL-ul specificat.
RenderedOp src = JAI.create('url', url);

5. Reformatarea imaginilor


Operatia Format reformateaza o imagine printr-o operatie cast asupra pixelilor unei imagini, la un anumit tip de data, inlocuind obiectele SampleModel si ColorModel a unei imagini si restructurand stilul de grila de segmente. Valorile pixelilor din imaginea destinatie sunt definite de urmatorul pseudocod:

dst[x][y][b] = cast(src[x][y][b], dataType)

where dataType is one of the constants

DataBuffer.TYPE_BYTE,

DataBuffer.TYPE_SHORT,

DataBuffer.TYPE_USHORT,

DataBuffer.TYPE_INT,

DataBuffer.TYPE_FLOAT,

or DataBuffer.TYPE_DOUBLE.

Obiectele de iesire SampleModel, ColorModel si stilul grilei de segmente sunt specificate prin transmiterea unui obiect ImageLayout ca si RenderingHint numit ImageLayout. Atunci cand este posibil, imaginea de iesire va avea un SampleModel compatibil cu acel specificat in indiciul de reprezentare. Pentru tipurile de datele de iesire float si double va fi folosit un obiect ComponentSampleModel cu privire la valoarea parametrului hint.


6. Conversia unei imagini Rendered in Renderable


Pentru a utiliza un DAG de tip Renderable cu un tip de imagine non-Renderable, imaginea trebuie mai intai convertita din tipul Rendered in tipul Renderable. De exemplu, pentru a folosi o imagine obtinuta de la un server distant intr-un lant Renderable, trebuie tratata imaginea sursa ca si RenderedImage, apoi convertita la RenderableImage pentru urmatoarele procesari.

Operatia Renderable produce un obiect RenderableImage dintr-o sursa RenderedImage. Obiectul RenderableImage care este produs este format dintr-o piramida” de obiecte RenderedImage la rezolutii progresiv mai mici. Imaginile cu rezolutiile mai mici sunt produse prin invocarea lantului de operatii specificat prin parametrul downSampler asupra imaginii de la nivelul de rezolutie imediat superior al piramidei. Lantul de operatii downSampler trebuie sa adere la specificatiile descrise pentru constructorii clasei ImageMIPMap, care accepta acest tip de parametru.

Numarul de nivele din piramida va fi astfel incat cea mai mare dimensiune (latime sau inaltime) a nivelului de piramida cu cea mai mica rezolutie sa fie mai mic sau egal cu valoarea parametrului maxLowResDim, care trebuie sa fie pozitiv. Valoarea implicita pentru maxLowResDim este 64, ceea ce inseamna ca nivelul de piramida cu rezolutia cea mai mica va fi imaginea cu dimensiunea cea mai mare egala cu 64 pixeli sau mai mica.

Parametrii operatiei Renderable sunt descrisi in Tabelul 1


Parametru

Tip

Descriere

Valoare implicita

downSamples

RenderedOp

Lantul de operatii utilizat pentru derivarea imaginilor cu rezolutie mai mica



Filtru trece jos

maxLowResDim

Integer

Dimensiunea maxima a nivelului de piramida cu rezolutia cea mai mica.

64

minX

Float

Coordonata independenta de reprezentare X minima a destinatiei

0.0F

minZ

Float

Coordonata independenta de reprezentare Y minima a destinatiei

0.0F

height

Float

Inaltimea independenta de reprezentare

1.0F

Tabelul 1 Parametrii operatiei Renderable


Exemplul 16. demonstreaza o operatie Renderable. Valorile implicite sunt folosite pentru toti cei cinci parametrii ai operatiei. Rezultatul operatiei poate fi transmis la urmatoarea operatie din graf.


Exemplul 16. Convertirea unui RenderedImage la Renderable

// deriva obiectul  RenderableImage din sursa RenderedImage.
ParameterBlock pb = new ParameterBlock();
pb.addSource(src);
pb.add(null).add(null).add(null).add(null).add(null);
// creeaza operatia Renderable.
RenderableImage ren = JAI.createRenderable('renderable', pb);

Crearea unei imagini constante


Operatia constant defineste o imagine Rendered multi-banda si segmentata, unde toate valorile pixelilor din aceeasi banda au valoare constanta. Numarul de benzi a imaginii este determinat de numarul de valori de pixeli constanti furnizati ca parametrii. Tipul de data este determinat de tipul constantei din prima intrare.

Exemplul urmator (Exemplul 1) ilustreaza o operatie constant.



Exemplul 1 Program pentru citirea si afisarea unui fisier imagine

// creeaza obiectul ParameterBlock.
Byte[] bandValues = new Byte[1];
bandValues[0] = alpha1;
pb = new ParameterBlock();
pb.add(new Float(src1.getWidth()));// latimea
pb.add(new Float(src1.getHeight()));  // inaltimea
pb.add(bandValues); // valorile benzilor
// creeaza operatia constant.
PlanarImage afa1 = (PlanarImage)JAI.create('constant', pb);

8. Afisarea imaginilor


JAI utilizeaza modelul BufferedImage din Java2D pentru a afisa imaginile. Clasa BufferedImage gestioneaza o imagine in memorie si furnizeaza modalitati de stocare a datelor pixel, interpreteaza datele pixel si reprezinta datele pixel la un context Graphics2D.

Afisarea imaginilor in JAI poate fi facuta prin mai multe moduri. Pentru inceput, apelul metodei drawRenderedImage asupra obiectului Graphics2D poate fi folosit pentru a produce o reprezentare imediata. O alta metoda este instantierea unei componente de afisare care raspunde la cererile utilizatorului cum ar fi derularea sau translatarea si de asemenea expunerea evenimentelor si obtinerea datelor imagine dintr-o sursa RenderedImage. Aceasta tehnica permite ca datele imagine sa fie calculate la cerere.

Pentru acest scop JAI furnizeaza o componenta de afisare, disponibila in pachetul javax.media.jai.widget, numita ScrollingImagePanel. Aceasta clasa preia un obiect RenderedImage si o latime si inaltime specifica si creeaza un panou cu bare de derulare, iar imaginea este asezata in centrul panoului.

Odata ce ScrollingImagePanel este creat, acesta poate fi asezat oriunde intr-un Frame, la fel ca si orice alt panou din AWT. Exemplul 18. demonstreaza utilizarea unui astfel de panou.


Exemplul 18. Exemplu de utilizare a unui ScrollingImagePanel

// preia inaltimea si latimea imaginii
int width = image.getWidth();
int height = image.getHeight();
// ataseaza imaginea la panoul derulabil pentru afisare.
ScrollingImagePanel panel = new ScrollingImagePanel(
image, width, height);
// creeaza un obiect Frame care va contine panoul.
Frame window = new Frame('Examplu cu ScrollingImagePanel ');
window.add(panel);
window.pack();
window.show();

JAI extinde clasa java.awt.Canvas cu clasa ImageCanvas, care permite reprezentarea unei imagini intr-o suprafata de desenare (canvas) Aceasta clasa mosteneste metode de la java.awt.Component, permitand folosirea acelorasi metode la tratarea evenimentelor pentru tastatura si mouse, ca si la clasa Canvas.

Clasa ImageCanvas este o componenta de afisare simpla pentru un RenderedImage si poate fi utilizata in orice context in care este nevoie de un Canvas. Clasa ImageCanvas monitorizeaza evenimentele de redimensionare si reimprospatare si la nevoie cere in mod automat segmente de la sursa sa.


9. Spatii de culoare JAI


JAI utilizeaza trei clase de baza pentru gestiunea culorilor:

ColorModel – descrie un mod particular prin care valorile pixelilor sunt mapate la culori. Un obiect ColorModel este de obicei asociat cu un obiect Image sau BufferedImage si furnizeaza informatia necesara pentru a interpreta corect valorile pixelilor. Aceasta clasa este definita in pachetul java.awt.image.

ColorSpace – reprezinta un sistem pentru masurarea culorilor, in mod obisnuit folosind trei valori sau componente separate. Clasa ColorSpace contine metode pentru conversia intre spatiul de culoare original si una sau doua spatii de culoare standard, CIEXYZ si RGB. Aceasta clasa este definita in pachetul java.awt.color.

Color – reprezinta o culoare fixa, definita prin componentele sale intr-un obiect ColorSpace. Aceasta clasa este definita in pachetul java.awt.

Un obiect ColorModel este utilizat pentru interpretarea datelor pixel dintr-o imagine. Aceasta include:

Maparea componentelor din benzile unei imagini la componentele unui spatiu de culoare particular.

Extragerea componentelor pixelului din datele pixel impachetate.

Obtinerea de componente multiple dintr-o singura banda folosind masti.

Conversia datelor pixel printr-un tabel de cautare.

Pentru a determina valoarea culorii a unui pixel particular dintr-o imagine, trebuie cunoscut modul in care informatia de culoare este codata in fiecare pixel. Obiectul ColorModel asociat unei imagini incapsuleaza datele si metodele necesare pentru translatarea valorii unui pixel spre si de la componentele sale de culoare constituente.

JAI suporta cinci modele de culoare:

DirectColorModel – lucreaza cu valorile pixelilor care reprezinta informatie despre culori RGB si canal alfa ca si esantioane separate si impacheteaza toate esantioanele pentru un singur pixel intr-un singur int, short, sau byte. Aceasta clasa poate fi utilizata doar cu spatii de culoare de tipul ColorSpace.TYPE RGB

IndexColorModel – lucreaza cu valorile pixelilor care reprezinta un singur esantion care este un index intr-o harta de culori fixa in spatiul de culoare RGB implicit. Harta de culori specifica componentele de rosu, verde, albastru si optional alfa corespunzatoare pentru fiecare index.

ComponentColorModel – poate sa manevreze un obiect arbitrar ColorSpace  si o arie de componente de culoare pentru a se potrivi cu spatiul de culoare. Acest model poate fi folosit pentru a reprezenta cele mai utilizate modele culoare pe cele mai utilizate dispozitive grafice (GraphicsDevice).

PackedColorModel – clasa de baza pentru modele care reprezinta valorile pixelilor in care sunt incorporate componentele de culoare in mod direct in bitii unui pixel intreg. Un astfel de obiect stocheaza informatia de impachetare care descrie modul in care componentele de culoare si alfa sunt extrase din canal. Obiectele DirectColorModel sunt de tipul PackedColorModel.

FloatDoubleColorModel – lucreaza cu valorile pixelilor care reprezinta informatie de culoare si alfa ca si esantioane separate, folosind elemente float si double.

Urmatorul exemplu (Exemplul 19.) prezinta constructia unui obiect ComponentColorModel pentru un model de culoare RGB.


Exemplul 19. Crearea unui model de culoare RGB

// Creeaza un model de culoare RGB
int[] bits = ;
ColorModel colorModel = new
ComponentColorModel(ColorSpace.getInstance(
ColorSpace.CS_sRGB), bits, false, false,
Transparency.OPAQUE, DataBuffer.TYPE_BYTE);

Cantitatea de transparenta a unei imagini este specificata de valoarea alfa. O valoare alfa de 0.0 specifica o transparenta totala, iar o valoare alfa de 1.0 specifica o opacitate totala.

Imaginile pot sa transporte informatie de transparenta, cunoscuta sub denumirea de canal alfa, pentru fiecare pixel din imagine. Valoarea alfa este importanta atunci cand culorile se suprapun. Valoarea alfa specifica cat de mult din culoarea reprezentata anterior trebuie sa fie afisata.