Sunteți pe pagina 1din 95

7.

Procesare de imagini n Java

n acest capitol sunt prezentate elementele de baz privind procesarea


de imagini n Java. Dup o scurt prezentare a evoluiei procesrii de imagini n
Java, este abordat pe scurt modelul de mpingere Java AWT (Abstract
Windowing Toolkit), urmat de prezentarea mai amnunit a modelului de mod
imediat Java 2D i a modelului de tragere JAI (Java Advanced Imaging).
Acest capitol cuprinde informaii legate doar de procesarea de imagini
i nu se ocup de alte aspecte implementate de API-urile AWT i Java 2D, cum
ar fi elemente de grafic, interfa cu utilizatorul, tiprire, etc. Aceste aspecte
sunt tratate n diverse cri i documentaii, multe dintre ele fiind disponibile
gratuit pe Web. Cele mai notabile documentaii n aceast direcie sunt The
Java Tutorial i Java 2 SDK Standard Edition Documentation disponibile pe
site-ul firmei Sun.
Java AWT i Java 2D API fac parte din Java 2 Standard Edition. JAI
API extinde platforma Java pentru dezvoltarea aplicaiilor i applet-urilor de
procesare de imagini avansate n Java.

7.1. Evoluia procesrii de imagini n Java

Procesrile de imagini n Java au fost suportate nc de la prima


apariie, prin intermediul pachetelor java.awt i java.awt.image.
Primele versiuni ale Java AWT API au fost constituite dintr-un pachet
de clase utile care urmreau afiarea de imagini aflate n Internet, dar fr nici o
funcie necesar pentru procesrile de imagini mai complexe. Acest pachet
permitea generarea de imagini simple prin desenarea de linii i forme. De
asemenea se putea citi un numr foarte mic de formate de fiiere de imagine
(doar formatele GIF i JPEG), prin intermediul unui obiect de tip Toolkit din
pachetul java.awt. Odat citit, imaginea putea fi doar afiat, deoarece nu prea
existau operatori pentru procesarea ei.
Java 2D API extinde pachetul de nceput AWT prin adugarea unui
suport mai ridicat pentru operaii generale de grafic i afiare de imagini. Java
2D a adugat clase speciale pentru definirea de primitive geometrice,
formatarea textelor, definirea fonturilor, spaii de culoare i reprezentare de
imagini. Noile clase suport un set limitat de operatori de procesare de imagini
cum ar fi blurr, sharpen, transformri geometrice, mbuntire de contrast i
binarizare. Extensiile Java 2D au fost adugate la nucleul Java AWT odat cu
lansarea platformei J2SE (Java 2 Standard Edition) versiunea 1.2.
Aplicaiile mai pretenioase au nevoie ns de un API de procesare a
imaginilor cu faciliti mult mai dezvoltate. Astfel au fost create de ctre
diverse companii o serie de API-uri de procesare de imagini care au avut un

1
succes destul de remarcabil, dar nici unul dintre acestea nu au fost universal
acceptate deoarece au euat n a se adresa unui segment specific al domeniului
procesrilor de imagini sau nu aveau putere n a ndeplini anumite nevoi. Astfel
multe companii au trebuit s-i elaboreze propria implementare n ncercarea de
a ndeplinii aceste nevoi.
Experiena acumulat de ctre industrie i mediile universitare n
crearea unor biblioteci de procesare de imagini, utilitatea acestor biblioteci
peste o mare varietate de domenii de aplicabilitate i reacia utilizatorilor la
aceste biblioteci a condus la crearea JAI (Java Advanced Imaging) API.
JAI este conceput pentru a suporta procesri de imagini folosind
limbajul de programare Java ntr-un mod ct mai general posibil, adresndu-se
unui domeniu ct mai larg al aplicaiilor de procesare de imagini. n acelai
timp, JAI prezint un model de programare simplu care poate fi folosit cu
uurin n aplicaii fr a fi nevoie s se cunoasc toate fazele din construcia
API-ului.
JAI extinde mai departe platforma Java (incluznd Java 2D API)
permind astfel ca procesrile de imagini de mare performan s fie
ncorporate n applet-uri i aplicaii Java. JAI este un set de clase care
furnizeaz funcionaliti legate de procesarea de imagini dincolo de cele
obinute la Java 2D i Java Foundation Classes, dar fiind n acelai timp
compatibil cu aceste API-uri.
JAI implementeaz un set de resurse de baz n procesarea de imagini
care includ lucrul cu seciuni de imagine, regiuni de interes i execuie amnat.
JAI ofer de asemenea operatori de baz n procesarea de imagini care includ
muli operatori punctuali i spaiali obinuii, precum i operatori n domeniul
frecven. JAI ncapsuleaz formate de date imagine i invocare de metode
distant printr-un obiect imagine reutilizabil, permind unui fiier imagine,
unui obiect imagine de reea, sau unui flux de date n timp real s poat fi
procesate n mod identic.
JAI este proiectat s satisfac cerinele oricrei aplicaii de procesare
de imagini, acest API fiind foarte extensibil, permind ca noi operaii s fie
adugate.
JAI suport trei modele de procesare de imagini:
Modelul producer/consumer (productor/consumator) de mpingere,
care este modelul de baz AWT.
Modelul de mod imediat (Java 2D), care este un model AWT mai
avansat.
Model de tip pipeline de tragere, care este un model specific JAI.
Urmtorul tabel (Tabelul 7.1) contureaz cteva trsturi pentru
fiecare dintre aceste modele de procesare a imaginilor.

2
Modelul de Modelul de mod Modelul de tragere
mpingere imediat
Image BufferedImage RenderableImage
Interfee/clase
importante ImageProducer Raster RenderableImageO
ImageConsumer BufferedImageOp p
ImageObserver RasterOp (Java 2D API)
(JDK 1.0.X, (Java 2D API) RenderedOp
1.1.X) RenderableOp
TiledImage
(Java Advanced Imaging)
Procesare Interfa de Stocheaz/proceseaz
Avantaje
condus de programare mai doar datele necesare
disponibilitatea simpl Permite evaluarea
imaginii (de Modelul cel mai amnat
exemplu n reea) des utilizat
Imagini
procesate
incremental
Necesit Necesit alocare Interfa de programare
Dezavantaje
transferul (dar nu de memorie a ntregii mai complex
procesarea) imagini Implementare mai
imaginilor Necesit complex
complete procesarea de
Interfa de imagini ntregi
programare
complex
Tabelul 7.1. Modele de procesare a imaginilor n Java

7.2. Modelul de mpingere AWT

Modelul de mpingere este implementat n pachetul de clase java.awt


i este un model simplu de filtre de productori i consumatori
(producer/consumer) pentru procesarea de imagini. O imagine este reprezentat
de un obiect de tip Image i este o abstractizare care nu este manipulat direct,
ci mai degrab este folosit pentru a obine o referin ctre un alt obiect care
implementeaz interfaa ImageProducer. Obiectele care implementeaz aceast
interfa sunt apoi ataate la obiecte care implementeaz interfaa
ImageConsumer.
Obiectele filtru implementeaz amndou interfeele, de productor i
consumator i pot s joace rolul de surs sau destinaie pentru datele imagine.

3
Datele imagine au asociate un obiect ColorModel care descrie configuraia
pixelilor din imagine, precum i modul de interpretare a datelor.
Pentru a procesa imagini folosind modelul de mpingere, un obiect Image
este obinut dintr-o surs oarecare, de exemplu printr-un apel la metoda
Applet.getImage(). Metoda Image.getSource() poate apoi fi folosit pentru a
obine ImageProducer-ul pentru acel Image. O serie de obiecte de tip
FilteredImageSource pot fi ataate la ImageProducer, fiecare filtru fiind un
ImageConsumer a imaginii surs precedente.
Clasa FilteredImageSource este o implementare a interfeei
ImageProducer care preia o imagine i un obiect filtru i le folosete pentru a
produce date imagine coninnd imaginea filtrat. n fragmentul de cod urmtor
(Exemplul 7.1.) se prezint o filtrare a unei imagini folosind un filtru de
convoluie:

Exemplul 7.1. Utilizarea modelului de mpingere pentru realizarea


unei operaii de convoluie a unei imagini
Image src = getImage(getDocumentBase(),floare.gif);
ImageProducer prod = src.getSource();
ImageFilter filter = new BufferedImageFilter(
new ConvolveOp(new Kernel(3,3, new float[] {0.3F,0.1F,-
0.3F,1.3F,2F,0.3F,0.3F,0.1F,-0.3F,})));
Image img = createImage(new FilteredImageSource
(src.getSource(),filter));

Procesarea de imagini n AWT definete doar cteva filtre simple


pentru ajustarea imaginilor i pentru manipulri ale canalelor de culoare.
Destinaia final a imaginilor filtrate este un obiect Image, care poate
fi creat printr-un apel la metoda Component.createImage(). Odat creat
consumatorul de imagine, imaginea poate fi desenat pe ecran printr-un apel la
metoda Image.getGraphics() pentru a obine un obiect de tip Graphics, care
reprezint un dispozitiv ecran, urmat de apelul Graphics.drawImage().
Procesrile de imagini din AWT au fost concepute pentru a facilita
afiarea de imagini ntr-un browser Web. n acest context o imagine poate fi
rezident undeva n reea i nu se poate garanta c acea imagine va fi
disponibil atunci cnd este nevoie, aa c modelul AWT nu foreaz filtrarea
imaginii sau completarea afirii imaginii, fiind un model n ntregime de
mpingere.
Un ImageConsumer nu poate niciodat s solicite datele, el trebuie s
atepte dup ImageProducer pentru a mpinge datele spre el. n mod similar,
un ImageConsumer nu are nici o informaie despre momentul cnd datele vor fi
trimise n ntregime, acesta trebuie s atepte un apel la metoda
ImageComplete() pentru ca s afle cnd are imaginea complet. O aplicaie

4
poate de asemenea instania un obiect de tip ImageObserver dac dorete s fie
ntiinat despre ncheierea unei operaii de procesare a imaginilor.
Procesrile de imagini din AWT nu au adoptat ideea unei imagini care
este susinut prin stocarea ei permanent. Att timp ct sunt furnizate metodele
pentru a converti o arie de memorie de intrare ntr-un ImageProducer, sau
pentru a captura o arie de memorie dintr-un ImageProducer, nu exist noiunea
de obiect imagine persistent care s poat fi reutilizat. Atunci cnd este nevoie
de date de la un Image, trebuie s obinem o referin spre ImageProducer-ul
imaginii.
Modelul AWT nu poate fi folosit pentru dezvoltarea de cod de
procesare a imaginilor foarte performant din cauza modelului de mpingere,
lipsei unui obiect imagine persistent, modelului restricionat al unui filtru
imagine i a unui numr mic de formate de date imagine. De asemenea lipsesc
cteva concepte de baz care sunt des folosite n procesarea de imagini, cum ar
fi operaiile executate pe o regiune de interes a unei imagini.
n Tabelul 7.2. sunt prezentate clasele i interfeele care sunt folosite
de modelul de mpingere AWT.

Clasa/Interfaa Descriere
Image Superclas pentru toate clasele care reprezint
imagini grafice
ColorModel Clas abstract care ncapsuleaz metodele pentru
translatarea valorii unui pixel spre componentele
culorii (ex. , rou, verde, albastru) i o
component alfa.
FilteredImageSource O implementare a interfeei ImageProducer care
preia imaginea existent i un obiect filtru i le
utilizeaz pentru a produce date imagine pentru o
nou versiune filtrat a imaginii originale
ImageProducer Interfa pentru obiectele care pot produce date
imagine pentru obiecte Image. Fiecare imagine
conine un ImageProducer care este folosit pentru
reconstrucia imaginii oricnd este nevoie, de
exemplu, atunci cnd imaginea este scalat i are
alte dimensiuni, sau cnd limea sau nlimea
imaginii este solicitat.
ImageConsumer Interfa pentru obiectele care i manifest
interesul asupra datelor imagine prin interfaa
ImageProducer. Cnd este adugat un
consumator la un productor de imagine,
productorul trimite toate datele despre imagine
folosind apeluri de metode definite n aceast

5
interfa.
ImageObserver Interfa asincron de actualizare pentru
recepionarea de notificri cu privire la
informaiile despre un obiect Image, n timp ce
imaginea se construiete.
Tabelul 7.2. Clasele i interfeele modelului de mpingere

7.3. Modelul de mod imediat Java 2D

Pentru a diminua unele dintre restriciile modelului de procesare AWT


original i pentru a furniza un nivel mai ridicat de abstractizare, a fost elaborat
o nou specificaie denumit Java 2D API. Acest nou API extinde capacitile
AWT pentru grafica bidimensional i pentru procesarea de imagini. n
realitate, pachetul Java 2D este unificat cu AWT i este o component a
platformei Java 2 Standard Edition.
Imaginile n Java 2D API sunt compuse din dou componente
principale:
Date imagine brute care reprezint pixeli
Informaia necesar pentru interpretarea pixelilor
n ceea ce privete procesarea de imagini, Java 2D API reine cteva
elemente din modelul AWT productor/consumator, dar adaug conceptul de
date imagine persistente bazate pe memorie, set extensibil de filtre imagine 2D,
o varietate mare de formate de imagine i modele de culoare i o reprezentare
mai sofisticat a dispozitivelor de ieire. Java 2D introduce noiunea de
reprezentare a imaginilor independent de rezoluie prin introducerea
interfeelor Renderable i Rendered, permindu-se imaginilor s fie trase
printr-un lan de operaii filtru, cu rezoluia imaginii selectat prin contextul
reprezentrii.
n Figura 7.1 este prezentat modelul de gestiune general a imaginilor
din Java 2D, care este controlat de ctre clasa BufferedImage.

BufferedImage

Raster ColorModel

SampleModel

ColorSpace
DataBuffer

Figura 7.1. Structura de gestiune a imaginilor


furnizat de clasa BufferedImage
6
Un obiect de tip BufferedImage poate fi creat direct n memorie i
utilizat pentru a pstra i manipula date imagine obinute de la un fiier sau de
la un URL. Un BufferedImage poate fi afiat folosind orice obiect Graphics2D
ca dispozitiv de afiare, sau reprezentat spre orice alt destinaie folosind un
context Graphics2D adecvat. Un obiect de tip BufferedImage conine dou alte
obiecte: un Raster i un ColorModel.
Clasa Raster asigur gestiunea datelor imagine. Acesta reprezint o
arie dreptunghiular dintr-o imagine care stocheaz datele imagine n memorie
i de asemenea un mecanism pentru crearea a mai multor sub-imagini dintr-un
singur bufer de date imagine. Aceast clas asigur metode pentru accesul la
pixeli specifici dintr-o imagine. Un obiect Raster conine dou alte obiecte, un
DataBuffer i un SampleModel.
Clasa DataBuffer pstreaz datele pixelului n memorie. Clasa
SampleModel interpreteaz datele din bufer i furnizeaz pixeli individuali sau
regiuni de pixeli dreptunghiulare.
Regulile pentru interpretarea pixelilor sunt ncapsulate ntr-un obiect
ColorModel, de exemplu dac valorile trebuie interpretate n mod direct sau ca
culori indexate. Astfel pentru ca un pixel s fie afiat, acesta trebuie s fie
mperecheat cu un model de culoare.
Pachetul java.awt.image conine cteva implementri ale clasei
ColorModel, incluznd acele pentru reprezentri mpachetate i pe componente
ale pixelului. Tot acest pachet furnizeaz clase suplimentare care definesc
operaii de filtrare asupra unor obiecte BufferedImage i Raster. Fiecare
operaie de procesare este concretizat printr-o clas care implementeaz
interfaa BufferedImageOp, sau interfaa RasterOp, sau amndou. Clasa de
operaii definete metodele de filtrare prin care se efectueaz manipularea
imaginii. n Figura 7.2. este ilustrat modelul de baz pentru procesrile de
imagini din Java 2D API.

Operaie de procesare a
imaginilor

filtru Imagine
Imagine surs destinaie

Figura 7.2. Modelul de procesare a imaginilor

7
Operaiile suportate includ:
Transformare affine
Scalare de amplitudine
Modificare cu tabele de cutare (lookup table)
Combinare liniar a benzilor
Conversie de culori
Convoluie
Elemente dat sunt primitive tip utilizate ca uniti de stocare a datelor
imagine. Elementele dat sunt membrii individuali ai unei arii DataBuffer.
Configuraia elementelor n buferul de date este independent de interpretarea
datelor ca pixeli de ctre obiectul SampleModel al imaginii.
Eantioanele sunt membrii distinci de pixeli ai unei imagini. Un
obiect SampleModel asigur un mecanism pentru convertirea elementelor din
DataBuffer n pixeli i eantioanele sale. Eantioanele unui pixel pot s
reprezinte valori de baz ntr-un model de culoare particular, de exemplu, un
pixel dintr-un model de culoare RGB este compus din trei eantioane: red,
green i blue.
Componentele sunt valori ale pixelilor independente de interpretarea
culorilor. Distincia dintre component i eantion este folositoare pentru
IndexColorModel, unde componentele pixelului sunt indexate ntr-un
LookupTable.
O band este o component a spaiului de culoare a unei imagini. De
exemplu, componentele de rou, verde i albastru reprezint benzile dintr-o
imagine RGB. Datele pixelilor pot fi stocate n mai multe moduri, iar Java 2D
suport dou dintre acestea: organizare pe benzi i arie regulat de pixeli.
Stocarea pe benzi a pixelilor determin ca un pixel s fie format dintr-
o dat eantion de la aceeai poziie n fiecare band. Stocarea pixelilor ntr-o
arie organizeaz datele imagine n pixeli, astfel avem o singur arie coninnd
toi pixelii, iar benzile sunt constituite dintr-un set de eantioane la aceeai
poziie de index pentru fiecare pixel.
Un obiect ColorSpace ncapsuleaz regulile care guverneaz modul n
care un set de msurri corespund unei culori anume. Implementrile clasei
ColorSpace din pachetul java.awt.color reprezint cele mai utilizate spaii de
culoare, incluznd RGB sau scal de gri. Un spaiu de culoare reprezint nite
reguli pentru modul cum vor fi interpretate valorile culorilor.
Separaia spaiului de culoare de modelul de culoare asigur o
flexibilitate sporit la reprezentarea i conversia culorilor dintr-un anumit spaiu
al culorii n altul.

8
7.3.1. Clasa BufferedImage

Clasa BufferedImage este clasa principal care suport procesarea de


imagini n modul imediat. Aceast clas gestioneaz imaginea n memorie
asigurnd metode de stocare, interpretare i reprezentare a datelor pixelilor spre
un context Graphics sau Graphics2D. Pentru a crea un obiect BufferedImage,
se apeleaz metoda Component.createImage. Aceasta returneaz un obiect de
tip BufferedImage a crui caracteristici de reprezentare se potrivesc cu cele ale
componentei folosite pentru creare. Imaginea creat este opac i are culorile
de suprafa i fundal ale obiectului Component, cu posibilitatea de modificare
a transparenei. Acest lucru este exemplificat pe seciunea de cod urmtoare
(Exemplul 7.2).

Exemplul 7.2. Utilizarea clasei BufferedImage

BufferedImage offImg;

public Graphics2D
createMyG2D(Graphics g) {
Graphics2D g2 = null;
int width = getSize().width;
int height = getSize().height;
if (offImg == null || offImg.getWidth()
!= width || offImg.getHeight() != height) {
offImg = (BufferedImage)
createImage(width, height);
}
if (offImg != null) {
g2 = offImg.createGraphics();
g2.setBackground(getBackground());
}
// terge componenta
g2.clearRect(0, 0, width, height);
return g2;
}

Clasa BufferedImage poate fi folosit la pregtirea elementelor grafice


n afara ecranului i apoi afiarea lor pe ecran. Aceast tehnic este folositoare
atunci cnd un element grafic este utilizat n mod repetat.
Facilitile pachetului java.awt permit folosirea buferelor de pregtire
n afara ecranului, astfel modificarea unei imagini se face n acelai mod ca i

9
cum ea ar fi afiat ntr-o fereastr. Toate facilitile de reprezentare Java 2D
pot fi aplicate atunci cnd se lucreaz cu imagini n afara ecranului.
Cea mai simpl metod de a crea o imagine, care poate fi folosit ca i
un bufer n afara ecranului, este prin apelul metodei Component.createImage.
Clasa BufferedImage suport cteva tipuri de imagine predefinite:
TYPE_3BYTE_BGR imagine cu componente de culoare RGB
pe 8 bii, corespunztoare modelului de culoare RGB din
Windows, cu culorile Blue, Green i Red stocate pe 3 bytes.
TYPE_4BYTE_ABGR imagine cu componente de culoare
RGBA pe 8 bii, cu culorile Blue, Green i Red stocate pe 3 bytes
i un byte pentru canalul alfa.
TYPE_4BYTE_ABGR_PRE imagine cu componente de
culoare RGBA pe 8 bii cu culorile Blue, Green i Red stocate pe
3 bytes i un byte pentru alfa
TYPE_BYTE_BINARY imagine opac pe 1, 2 sau 4 bii
TYPE_BYTE_GRAY imagine scal de gri pe un unsigned byte,
neindexat.
TYPE_BYTE_INDEXED imagine pe un byte indexat.
TYPE_CUSTOM imagine nerecunoscut, de tip utilizator.
TYPE_INT_ARGB_PRE imagine cu componente de culoare
RGBA pe 8 bii compus din pixeli integer.
TYPE_INT_ARGB imagine cu componente de culoare RGBA
pe 8 bii compus din pixeli integer.
TYPE_INT_BGR imagine cu componente de culoare RGBA pe
8 bii, corespunztor pentru modelele de culoare din Windows sau
Solaris, cu culorile Blue, Green i Red mpachetate n pixeli
integer.
TYPE_INT_RGB reprezint o imagine cu componente de
culoare RGB pe 8 bii mpachetate n pixeli integer.
TYPE_USHORT_555_RGB imagine cu componente de culoare
5-5-5 RGB (5-bii Red, 5-bii Green, 5-bii Blue) fr canal alfa.
TYPE_USHORT_565_RGB imagine cu componente de culoare
5-6-5 RGB (5-bii Red, 6-bii Green, 5-bii Blue) fr canal alfa.
TYPE_INT_GRAY imagine n scal de gri stocat pe tipul
unsignrd short, neindexat.
Pentru reprezentarea ntr-un obiect de tip BufferedImage, se apeleaz
metoda BufferedImage.createGraphics, care returneaz un obiect Graphics2D.
Cu acest obiect se pot apela toate metodele pentru reprezentarea primitivelor
grafice, sau reprezentarea altor imagini n imagine. n fragmentul de cod
urmtor (Exemplul 7.3.) se ilustreaz utilizarea buferrii n afara ecranului:

10
Exemplul 7.3. Exemplu de utilizare a buferrii n afara ecranului
public void update(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
if(firstTime) {
Dimension dim = getSize();
int w = dim.width;
int h = dim.height;
area = new Rectangle(dim);
bi = (BufferedImage)createImage(w, h);
big = bi.createGraphics();
rect.setLocation(w/2-50, h/2-25);
big.setStroke(new BasicStroke(8.0f));
firstTime = false;
}
// terge suprafaa care a fost desenat anterior
big.setColor(Color.white);
big.clearRect(0, 0, area.width, area.height);
// Deseneaz i umple un nou dreptunghi n bufer.
big.setPaint(drept1);
big.draw(rect);
big.setPaint(drept2);
big.fill(rect);
// Deseneaz un buffered image pe ecran.
g2.drawImage(bi, 0, 0, this);
}

7.3.1.1. Manipularea datelor de tipul BufferedImage

n afar de desenarea direct ntr-un obiect BufferedImage, se pot


accesa i manipula datele pixelilor dintr-o imagine n mai multe moduri. Acest
lucru este util dac se implementeaz interfaa de filtrare BufferedImageOp.
Se poate utiliza metodele BufferedImage.setRGB pentru a modifica n
mod direct valoarea unui pixel sau a unei arii de pixeli la o valoare RGB
specificat. De asemenea se poate manipula datele pixelului prin intermediul
unui obiect WritableRaster asociat cu un BufferedImage.

7.3.1.2. Filtrarea i reprezentarea unui BufferedImage

Operaia de filtrare se poate aplica la un BufferedImage utiliznd un


obiect care implementeaz interfaa BufferedImageOp.
Pentru a reprezenta o imagine buferat ntr-un context specific se
apeleaz una dintre metodele drawImage din contextul obiectului Graphics. De

11
exemplu, atunci cnd se reprezint folosind metoda Component.paint, se
apeleaz drawImage asupra obiectului de afiare grafic transmis la metod
(vezi Exemplul 7.4).

Exemplul 7.4. Reprezentarea unui BufferedImage


public void paint(Graphics g) {
if (getSize().width <= 0 || getSize().height <= 0)
return;
Graphics2D g2 = (Graphics2D) g;
if (offImg != null && isShowing()) {
g2.drawImage(offImg, 0, 0, this);
}
}

7.3.2. Gestiunea i manipularea obiectelor rastru

Un obiect BufferedImage utilizeaz un obiect Raster pentru gestiunea


ariilor dreptunghiulare de date pixel. Clasa Raster conine cmpuri pentru
coordonatele sistem a imaginii lime, nlime i origine. Un obiect Raster
utilizeaz dou obiecte pentru gestiunea datelor pixelilor, un obiect DataBuffer
i un obiect SampleModel. Obiectul DataBuffer stocheaz datele pixelilor
pentru rastru, iar obiectul SampleModel furnizeaz interpretarea datelor
pixelilor din obiectul DataBuffer.
De cele mai multe ori, nu este nevoie s crem un obiect Raster n
mod direct deoarece este furnizat odat cu crearea obiectelor BufferedImage.
Cu toate acestea, unul dintre constructorii BufferedImage permite crearea unui
Raster prin trecerea printr-un obiect WritableRaster.
Clasa Raster furnizeaz un numr de metode statice pentru crearea de
obiecte Raster cu obiectele de tip DataBuffer i SampleModel specificate ca
parametrii. Aceste metode sunt utile atunci cnd se implementeaz clase de
tipul RasterOp pentru filtrare.
Clasa Raster ncorporeaz conceptul de raster printe i raster copil.
Acest lucru poate s mbunteasc eficiena de stocare prin permiterea
construirii oricrui numr de imagini buferate din acelai printe. Printele i
copii si reprezint acelai bufer de date, iar fiecare copil are un deplasament i
limite pentru ai putea identifica poziia imaginii din bufer. Un copil i
identific apartenena prin intermediul metodei getParent.
Pentru a crea un subrastru, se apeleaz metoda Raster.createSubRaster.
Dac se creeaz un subrastru, se poate identifica aria printelui care-l acoper i
deplasamentul de la originea printelui.
Clasa Raster definete mai multe metode de acces la pixeli i la datele
pixelilor. Acest lucru este util atunci cnd se implementeaz interfaa RasterOp,

12
care asigur filtrare la nivel de rastru i manipulare a datelor imagine sau atunci
cnd se implementeaz orice metod care are nevoie s execute manipulri de
pixeli de nivel inferior.
Metodele Raster.getPixel permit preluarea unui pixel individual care
este returnat ca eantion individual dintr-o arie. Metodele
Raster.getDataElements returneaz o poriune specificat a imaginii
neinterpretat din DataBuffer. Metoda Raster.getSample returneaz eantioane
cu un pixel individual. Metoda getSamples returneaz o band pentru o regiune
specificat dintr-o imagine. Buferul de date i modelul de eantioane poate fi de
asemenea accesat prin intermediul variabilelor instan a clasei Raster. Aceste
obiecte asigur mijloace suplimentare pentru accesarea i interpretarea datelor
pixel a unui obiect Raster.
Subclasa WritableRaster asigur metode pentru modificarea datelor
pixel i a eantioanelor. Obiectul Raster asociat cu un obiect BufferedImage
formeaz un obiect WritableRaster, asigurnd acces total la manipularea datelor
pixel.

7.3.3. Date imagine i bufere de date

Obiectele de tip DataBuffer aparinnd unui Raster reprezint o arie de


date imagine. La crearea unui Raster n mod direct sau prin intermediul
constructorilor BufferedImage, se poate specifica limea i nlimea, mpreun
cu un obiect SampleModel pentru datele imagine. Aceste informaii sunt
folosite la crearea unui DataBuffer cu tipul de dat i dimensiune
corespunztoare.
Exist patru subclase a DataBuffer, fiecare reprezentnd un tip diferit
de date element:
DataBufferByte valori pe 8 bii
DataBufferInt valori pe 32 bii
DataBufferShort valori pe 16 bii
DataBufferUShort reprezint valori de tip short fr semn.
Elementele sunt membrii discrei ai unei arii din buferul de date, iar
componentele sau eantioanele sunt valori discrete care mpreun formeaz un
pixel. Exist diverse alocri ntre un tip de element particular din DataBuffer i
un tip particular de pixel reprezentat de un obiect SampleModel. Aceast
alocare este implementat de diversele subclase ale clasei SampleModel i
furnizeaz o modalitate de extragere de pixeli dintr-un DataBuffer specific.
Datele imagine pot fi accesate n mod direct ntr-un DataBuffer, dar
este mai uor i mai convenabil s se acceseze prin intermediul metodelor din
clasele Raster i WritableRaster.
Clasele pentru reprezentarea datelor imagine sunt prezentate n
Tabelul 7.3.

13
Clasa Descrierea
DataBuffer Acoper unul sau mai multe arii de date.
Fiecare arie de date ne este refereniat ca i
un grup.
Raster Reprezint o arie dreptunghiular de pixeli i
furnizeaz metode pentru obinerea de date
imagine.
SampleModel Extrage eantioane de pixeli din imagini.
WriteableRaster Furnizeaz metode pentru stocarea datelor
imagine i motenete metode pentru
obinerea datelor imagine de la printele ei,
clasa Raster.
Tabelul 7.3. Clasele utilizate de Java 2D pentru
reprezentarea datelor imagine

7.3.4. Extragerea datelor pixel dintr-un obiect SampleModel

Clasa abstract SampleModel definete metode pentru extragerea


eantioanelor dintr-o imagine fr a cunoate modalitatea n care datele imagine
sunt stocate. Clasa conine cmpuri pentru monitorizarea nlimii i limii
datelor imagine din obiectul DataBuffer asociat i pentru descrierea unui numr
de benzi i a tipului de dat pentru acel bufer. Metodele SampleModel asigur
date imagine ca i colecie de pixeli, fiecare pixel fiind format dintr-un numr
de eantioane sau componente.
Pachetul java.awt.image furnizeaz cinci tipuri de modele de
eantioane:
ComponentSampleModel utilizat pentru extragerea pixelilor din
imaginile care stocheaz eantioanele n arii de elemente dat separate al
unui segment dintr-un DataBuffer.
BandedSampleModel utilizat pentru extragerea pixelilor din
imaginile care stocheaz fiecare eantion ntr-un element dat separat cu
benzile stocate ntr-o secven de elemente dat.
PixelInterleavedSampleModel utilizat pentru extragerea pixelilor din
imaginile care stocheaz fiecare eantion ntr-un element dat separat cu
pixeli stocai ntr-o secven de elemente dat.
MultiPixelPackedSampleModel utilizat pentru extragerea pixelilor
din imaginile cu o singur band care stocheaz mai muli pixeli cu un
singur eantion ntr-un singur element dat.
SinglePixelPackedSampleModel utilizat pentru extragerea pixelilor
din imaginile care stocheaz date eantion pentru un singur pixel ntr-o
singur arie de elemente dat din primul segment al unui DataBuffer.

14
Datele pixel oferite de SampleModel pot fi corelate direct cu un mod
de reprezentare a datelor culoare dintr-un model de culoare particular, n funcie
de datele surs. De exemplu, n datele imagine ale unei fotografii eantioanele
pot s reprezinte date RGB. n datele imagine de la un dispozitiv de prelucrare
a imaginilor medicale eantioanele pot s reprezinte tipuri diferite de date ca de
exemplu temperatura sau densitatea oaselor.
Exist trei categorii de metode pentru accesarea datelor imagine.
Metodele getPixel returneaz un pixel ntreg ca i o arie cu o singur valoare
pentru fiecare eantion. Metodele getDataElement asigur accesul la datele
brute, neinterpretate stocate n DataBuffer. Metodele getSample asigur accesul
la componentele pixelului pentru o band specific.

7.3.5. Modele i date culoare

Ca o completare la obiectul Raster n gestiunea datelor imagine, clasa


BufferedImage include un obiect ColorModel pentru interpretarea acestor date
ca i valori de culoare pixel. Clasa abstract ColorModel definete metode
pentru transformarea datelor pixel dintr-o imagine ntr-o valoare culoare din
spaiul de culoare ColorSpace asociat.
Pachetul java.awt.image furnizeaz patru tipuri de modele de culoare:
PackedColorModel un model abstract care reprezint valorile
pixelilor care au componente de culoare coninute direct n biii unui
pixel de tip integer. Clasa DirectColorModel este o subclas a
PackedColorModel.
DirectColorModel un model de culoare care reprezint valorile
pixelilor care au componente de culoare RGB coninute direct n biii
pixelului nsui.
ComponentColorModel un model de culoare care poate manipula un
spaiu de culoare ColorSpace arbitrar i o arie de componente de culoare
care s se potriveasc spaiului de culoare.
IndexColorModel un model de culoare care reprezint valorile
pixelilor care sunt indici ntr-o hart de culori fix din spaiul de culoare
RGB.
SampleModel furnizeaz modelul de culoare ColorModel bazndu-se
pe datele din DataBuffer, apoi ColorModel interpreteaz datele ca i culoare.
O tabel de cutare (lookup table) conine date pentru una sau mai
multe canale sau componente imagine. De exemplu, arii separate pentru R, G i
B. Pachetul java.awt.image definete dou tipuri de tabele de cutare care
extinde clasa abstract LookupTable, unul care conine date byte i unul care
conine date short i anume ByteLookupTable i ShortLookupData.

15
7.3.6. Procesare i mbuntire de imagini n Java 2D

Pachetul java.awt.image furnizeaz o pereche de interfee care


definesc operaii asupra obiectelor BufferedImage i Raster: BufferedImageOp
i RasterOp.
Cele mai importante clase care implementeaz aceste interfee sunt:
AffineTransformOp, BandCombineOp, ConvolveOp, LookupOp, RescaleOp.
Aceste clase pot fi utilizate pentru transformri geometrice, blur, sharpen,
mbuntire de contrast, binarizare i modificarea culorilor imaginilor.
Fragmentul de cod urmtor (Exemplul 7.5.) exemplific o operaie de
detecie de margini aplicat asupra unei imagini folosind o operaie de
convoluie:

Exemplul 7.5. Detecie de margini folosind Java 2D


float[] elements = { 0.0f, -1.0f, 0.0f,
-1.0f, 4.f, -1.0f,
0.0f, -1.0f, 0.0f, };
...
BufferedImage bimg = new
BufferedImage(bw,bh,BufferedImage.TYPE_INT_RGB);
Kernel kernel = new Kernel(3, 3, elements);
ConvolveOp cop = new ConvolveOp(kernel,
ConvolveOp.EDGE_NO_OP, null);
cop.filter(bi,bimg);

Urmtorul fragment de cod (Exemplul 7.6.) demonstreaz o operaie


de manipulare a imaginilor folosind tabele de cutare (lookup table):

Exemplul 7.6. Manipulare de tip lookup table


byte reverse[] = new byte[256];
for (int j=0; j<200; j++) {
reverse[j]=(byte)(256-j);
}
ByteLookupTable blut=new ByteLookupTable(0, reverse);
LookupOp lop = new LookupOp(blut, null);
lop.filter(bi,bimg);

O operaie de rescalare a unei imagini este prezentat n fragmentul de


cod care urmeaz (Exemplul 7.7.):

16
Exemplul 7.7. Operaie de rescalare
RescaleOp rop = new RescaleOp(1.5f, 1.0f, null);
rop.filter(bi,bimg);

Urmtorul fragment de cod (Exemplul 7.8.) ilustreaz modul de


utilizare a uneia dintre clasele de procesare a imaginilor, ConvolveOp. n acest
exemplu fiecare pixel din imaginea surs este mediat n mod egal cu cei opt
pixeli nconjurtori.

Exemplul 7.8. Utilizarea clasei ConvolveOp


float weight = 1.0f/9.0f;
float[] elements = new float[9]; // creaz o arie 2D
// umple aria cu 9 elemente egale
for (i = 0; i < 9; i++) {
elements[i] = weight;
}
// utilizeaz aria de elemente ca i argument la crearea unui Kernel
// (nucleu de convoluie)
private Kernel myKernel = new Kernel(3, 3, elements);
public ConvolveOp simpleBlur = new ConvolveOp(myKernel);
// sourceImage i destImage sunt instane a BufferedImage
simpleBlur.filter(sourceImage, destImage) // aplic blur

Variabila simpleBlur din exemplul anterior conine o nou instan a


ConvolveOp care implementeaz o operaie blur asupra unui BufferedImage sau
a unui Raster. Presupunnd c sourceImage i destImage sunt dou instane ale
BufferedImage, atunci cnd este apelat metoda filter, care este metoda
principal a clasei ConvolveOp. Aceast metod aloc valori pentru fiecare
pixel din imaginea destinaie prin medierea pixelului corespunztor din
imaginea surs cu cei opt pixeli nconjurtori.
Prin modificarea nucleului de convoluie se poate executa alte tipuri de
convoluii, cum ar fi blurring (Gaussian blur, radial blur, motion blur),
sharpening, operaii de netezire, etc.
Urmtorul fragment de cod (Exemplul 7.9.) ilustreaz sharpening
folosind operaia de convoluie:

Exemplul 7.9. Operaie sharpening utiliznd convoluia


float[] elements = { 0.0f, -1.0f, 0.0f,
-1.0f, 5.f, -1.0f,
0.0f, -1.0f, 0.0f, };

17
...
Kernel kernel = new Kernel(3,3,elements);
ConvolveOp cop = new ConvolveOp(kernel,
ConvolveOp.EDGE_NO_OP, null);
cop.filter(bi,bimg);

7.3.7. Independena de reprezentare

Independena reprezentrii reprezint abilitatea de a descrie o imagine


aa cum dorim noi s apar, independent de orice parametru specific ei, cum ar
fi rezoluia, dimensiunea fizic, tipul dispozitivului de ieire, calitatea culorilor,
calitatea tonal i viteza de reprezentare.
Pentru o descriere a unei imagini independent de reprezentare sunt
necesare dou elemente principale:
O surs care nu este reprezentat, numit i surs independent de
rezoluie. Pentru o imagine static, aceasta reprezint conceptual, aria de
captur a unei camere ideale antrenat asupra unei scene reale, aceasta
lipsindu-i orice dimensiuni logice. Camera ideal are o lentil ideal care
are posibilitatea de zooming infinit. Imaginea se poate considera c este
proiectat pe orice suprafa (dispozitiv de afiare), are dimensiuni, are
un raport de aspect nativ (acela a dispozitivului de captur) i poate s
aib proprieti care pot fi interogate.
Operatori pentru descrierea modului de modificare a caracterului unei
imagini, independent de destinaia final.
Sursa nereprezentat i operatorii specific caracterul vizual al
imaginii pe care ar trebui s-l aib atunci cnd este reprezentat. Aceast
specificaie poate apoi fi asociat cu orice dispozitiv, dimensiune a
dispozitivului de afiare sau calitate a reprezentrii.
Arhitectura Java AWT API integreaz un model de independen a
reprezentrii n paralel cu un model dependent de dispozitiv. Partea de
independen a reprezentrii a arhitecturii este un superset al modelului
tradiional de procesare dependent de dispozitiv i nu este un nlocuitor pentru
acesta.
Arhitectura Java AWT suport adaptare dependent de context, lucru
care este potrivit pentru surse aflate n reea. Adaptarea dependent de context
este un mecanism prin care calitatea optim a unei imagini este garantat n
orice context.
Java AWT este o arhitectur sincron. Acest lucru are cteva avantaje,
cum ar fi un model de programare simplificat i controale explicite asupra
tipului i ordinii rezultatelor, dar are i cteva dezavantaje i anume faptul c nu
este potrivit noiunii de reprezentare progresiv sau resurse disponibile n reea.

18
7.3.8. Straturi de reprezentare

Arhitectura Java AWT API furnizeaz dou straturi integrate de


prelucrare a imaginilor: stratul Renderable i stratul Rendered.
Stratul Renderable este un strat independent de reprezentare. Stratul
Renderable furnizeaz surse de imagini care pot fi optimal reutilizate de mai
multe ori n contexte diferite, cum ar fi afiarea pe ecran sau imprimarea.
Stratul ofer operatori de procesare de imagini care accept parametrii
independeni de reprezentare. Aceti parametri pot fi legai sub forma de
lanuri. Stratul este n esen sincron, n sensul c trage imaginea prin lan
oricnd o reprezentare (de exemplu spre un dispozitiv de afiare sau un fiier)
este solicitat. O solicitare se face la destinaia (sink) a lanului i este transmis
pe lan n sus spre surs. Asemenea cereri sunt specifice de context (de exemplu
specific dispozitivului) i lanul se adapteaz la acest context. Doar datele
necesare pentru context sunt produse.
Sursele imagine i operatorii din stratul paralel Rendered sunt
specifice de context. Un obiect RenderedImage este o imagine care a fost
reprezentat pentru a satisface nevoile unui context. Operatorii din stratul
Rendered pot fi de asemenea legai mpreun pentru a forma lanuri. Acetia
primesc parametrii dependeni de context. Ca i stratul Renderable, stratul
Rendered implementeaz un model sincron de tragere.
Structural, stratul Renderable este subtil, el nu se ocup cu procesarea
pixelilor; mai degrab uzeaz de obiecte operator din stratul Rendered. Acest
lucru este posibil deoarece clasele operatorilor din stratul Rendered pot s
implementeze interfaa ContextualRenderedImageFactory, care le permite s se
adapteze la diferite contexte. Deoarece operatorii din stratul Renderable
implementeaz aceast interfa, acetia gzduiesc n ntregime operaiile
specifice. Toat inteligena necesar pentru funcionarea celor dou straturi,
Renderable i Rendered sunt inute ntr-o singur clas. Acest lucru simplific
munca de a scrie noi operatori i de a face controlabil arhitectura de extensii.
n Figura 7.3. se ilustreaz un lan Renderable. Lanul are ataat o
destinaie (un obiect Graphics2D), dar nici un pixel nu circul prin lan
deocamdat.

Surs Operator Obiect


reprezentabil reprezentabil Graphics2D

ParameterBlock

Figura 7.3. Exemplu de lan Renderable


19
Stratul Renderable are marele avantaj c simplific n mare msur
munca de procesare de imagini. De exemplu, un lan de operatori Renderable
rmn editabili, parametrii folosii pentru construcia lanului pot fi modificai
n mod repetitiv. Acest lucru nu va face s se nceap calcularea vreo unui
pixel, n schimb pixelii sunt calculai doar atunci cnd este nevoie,
reprezentarea fiind obinut de la RenderableImage cu transmiterea definit de
contextele de reprezentare.

7.3.9. Context de reprezentare

Stratul Renderable permite construcia unui lan de operatori


RenderableImageOps conectai la o surs RenderableImage. Captul acestui
lan reprezint o nou surs RenderableImage. Efectul este c
RenderableImageOps trebuie s implementeze aceeai interfa ca i sursele
(RenderableImage). Unei astfel de surse i se poate cere s furnizeze diverse
obiecte RenderedImage specifice unui context corespunztor. Dimensiunea
necesar n pixeli pentru RenderedImage n spaiul dispozitivului trebuie
specificat. Aceast informaie este furnizat sub forma unei transformri din
spaiul utilizator a sursei Renderable spre spaiul dispozitivului dorit.
Alte informaii pot fi date sursei sau lanului pentru a-l ajuta s
funcioneze n mod optimal pentru un anume context, de exemplu o preferin
pentru vitez n detrimentul calitii imaginii. Asemenea informaii se
furnizeaz sub forma unui tabel extensibil de indicii.
Arhitectura definete aceti parametri colectivi ca i context de
reprezentare. Parametrii sunt gzduii de o clas RenderContext, care formeaz
o legtur fundamental ntre straturile Renderable i Rendered. O surs
RenderableImage i un RenderContext, produc ca rezultat o reprezentare
specific, sau altfel spus un RenderedImage. Acest lucru este efectuat de lanul
Renderable instaniind un lan de obiecte de strat Rendered. ntr-un lan de
obiecte RenderedImages corespunztoare unui context specific, obiectul
RenderedImage din capt este returnat la utilizator.

7.3.10. Clasele Renderable i Rendered

Stratul Renderable ofer avantajul independenei de reprezentare,


eliminnd nevoia de a lucra n mod direct cu pixeli, simplificnd foarte mult
manipularea imaginilor. Cu toate acestea, n multe cazuri este necesar s se
lucreze direct cu pixeli i n acest caz se va folosi stratul Rendered.

20
7.3.10.1. Stratul Renderable

Stratul Renderable este definit de ctre interfaa RenderableImage.


Orice clas care implementeaz aceast interfa este o imagine surs
Renderable i este de ateptat s se adapteze la contextul de reprezentare
RenderContext. Obiectele de tip RenderContext sunt refereniate printr-un
sistem de coordonate definite de utilizator. Una din funciile principale ale
clasei RenderContext este s defineasc alocarea spaiului utilizator i spaiul
specific dispozitivului pentru o reprezentare dorit.
Un lan n acest strat reprezint un lan de obiecte RenderableImage,
mai precis este un lan de obiecte RenderableImageOp (clas care
implementeaz interfaa RenderableImage).
Clasa RenderableImageOp preia funcionalitatea unei operaii
specifice prin intermediul unui parametru furnizat la momentul instanierii.
Acest parametru este numele unei clase care implementeaz interfaa
ContextualRenderedImageFactory. Fiecare instaniere a RenderableImageOp
deriv din funcionalitiile specifice claselor specificate prin nume. n acest
sens, stratul Renderable este puternic dependent de stratul Rendered.
Clasele i interfeele utilizate de stratul Renderable sunt prezentate n
Tabelul 7.4.

Clasa/Interfaa Descrierea
RenderableImage O interfa comun pentru imagini
independente de reprezentare
ContextualRenderedImage- Furnizeaz o interfa pentru funcionalitate
Factory care poate s difere ntre instane diferite de
RenderableImageOp.
ParameterBlock ncapsuleaz toate informaiile despre sursele
i parametrii necesari de ctre
RenderableImageOp i alte clase viitoare care
manipuleaz lanuri de operatori de procesare.
RenderableImageOp Se ocup de aspectele Renderable a unei
operaii cu ajutorul unei instane asociate de
ContextualRenderedImageFactory (CRIF).
RenderableImageProducer O clas adaptoare care implementeaz
ImageProducer i permite producerea
asincron a unui RenderableImage.
RenderContext ncapsuleaz informaia necesar pentru a
produce o reprezentare specific dintr-un
RenderableImage.
Tabelul 7.4. Clasele i interfeele utilizate de stratul Renderable

21
Un alt bloc implicat n construcia unui RenderableImageOp este
ParameterBlock. Clasa ParameterBlock gzduiete sursele pentru operaie i
parametrii sau alte obiecte pe care acel operator le poate cere. Parametrii sunt
versiuni independente de reprezentare ai parametrilor care controleaz
operatorul.
Lanul Renderable este construit prin instanierea fiecrui obiect
succesiv de tipul RenderableImageOp, fiind transmis n ultimul obiect
RenderableImage ca i surs n obiectul ParameterBlock. Acestui lan i se
poate cere s furnizeze un numr de reprezentri spre spaii dispozitiv specifice
prin intermediul metodei getImage.
Acest lan, odat construit rmne editabil. Parametrii pentru operaiile
specifice din lan i structura propriuzis a lanului se poate schimba. Acest
lucru se poate realiza prin apelul metodei setParameterBlock, modificnd
parametrii de control sau/i sursele. Aceste modificri afecteaz viitoarele
obiecte RenderedImage derivate din punctele din lan care se gsesc n zona
inferioar zonei unde sa fcut modificrile. Obiectele RenderedImage care sunt
obinute mai devreme din lanul Renderable sunt fixe i complet independente
de lanul din care au fost derivate.

7.3.10.2. Stratul Rendered

Stratul Rendered a fost conceput s funcioneze n cooperare cu stratul


Renderable. Stratul Renderable include surse i operaii pentru reprezentarea
specific unui dispozitiv a imaginilor sau a reprezentrilor. Stratul Rendered
este definit de interfaa RenderedImage. Aceast interfa este implementat de
clasa BufferedImage.
Operatorii din acest strat sunt obiecte RenderedImage care preiau alte
obiecte RenderedImage ca surs. Lanurile pot fi construite n aceeai msur
ca i la stratul Renderable. O secven de obiecte RenderedImage este
instaniat, fiecare prelund ultimul Operator
obiect RenderedImage ca i surs.
Rendered
n Figura 7.4., atunci cnd utilizatorul invoc metoda Graphics-
2D.drawImage, un context de reprezentare este construit i utilizat pentru a
apela metoda getImage de la operatorul Renderable. Un operator Rendered,
pentru a face de fapt o procesare a pixelilor este construit i ataat la sursa i la
destinaia operatorului Renderable ParameterBlock
i i este furnizat o clon a blocului de
parametri a operatorului Renderable. Pixelii vor curge prin operatorul
Rendered la obiectul Graphics2D. Lanul operatorului Renderable rmne
disponibilSurs
pentru a produce mai multe reprezentri oricnd metoda
Operator getImage
Graphics2D
Renderable
este apelat. Renderable

RenderContext

22 ParameterBlock drawImage

Figura 7.4. Derivarea unei reprezentri din lanul


Renderable
n Tabelul 7.5. sunt prezentate clasele i interfeele utilizate de stratul
Rendered.

Clasa/Interfaa Descriere
RenderedImage O interfa comun pentru obiecte
care conin sau pot produce date
imagine sub form de obiecte Raster.
BufferedImage O subclas care descrie un obiect
Image cu un bufer de date imagine
accesibil.
WritableRenderedImage O interfa comun pentru obiecte
care conin sau pot produce date
imagine care pot fi modificate sau/i
suprascrise.
Tabelul 7.5. Clasele i interfeele din stratul Rendered

7.4. Modelul de tragere JAI

JAI este un API care face parte din grupul Java Media API i este
clasificat ca fiind o extensie standard a platformei Java. JAI furnizeaz
funcionaliti utile n procesarea de imagini dincolo de posibilitile oferite de
Java Foundation Classes (setul de clase de baz din Java), fiind totodat
compatibil cu acesta.
JAI ofer mai multe avantaje pentru dezvoltatorii de aplicaii, n
comparaie cu alte soluii de prelucrare a imaginilor. Cele mai importante dintre
acestea vor fi expuse n cele ce urmeaz.

23
Prelucrare de imagini independent de platform. Majoritatea API-
urilor specializate pe prelucrarea de imagini sunt destinate pentru un singur
sistem de operare, ns JAI urmrete un model bazat pe biblioteci Java, ceea ce
i confer independen de platform. Implementri ale aplicaiilor JAI vor
putea s ruleze pe orice calculator cu Java VM. Acest lucru face ca JAI s fie cu
adevrat un API de prelucrri de imagini independent de platform i care
furnizeaz o interfa standard la posibilitiile de prelucrri de imagini ale unei
platforme. Asta nseamn c se poate scrie o aplicaie o singur dat i se va
putea rula oriunde (conform sintagmei Write once, run anywhere).
Prelucrare de imagini distribuit. JAI este de asemenea foarte
potrivit pentru prelucrri de imagini n aplicaii client-server prin mijloacele
oferite de arhitectura de reea a platformei Java i prin tehnologiile de execuie
la distan. Execuia la distan se bazeaz pe Java RMI (Remote Method
Invocation). Java RMI permite ca codul Java de la client s invoce metode din
obiecte care se afl pe un alt calculator fr a muta aceste obiecte la client.
API orientat pe obiecte. Ca i Java, JAI este total orientat pe obiecte.
n JAI, imaginile i operaiile de procesare de imagini sunt definite ca obiecte.
JAI unific noiunea de imagine i operator prin faptul c amndou sunt
subclase ale aceluiai printe.
Un obiect operator este instaniat cu una sau mai multe imagini surs
i ali parametri. Acest obiect operator poate apoi deveni o imagine surs pentru
urmtorul obiect operator. Conexiunea dintre obiecte definete un flux de date
procesate. Graful editabil rezultat de operaii de procesare de imagini poate fi
definit i instaniat dup necesiti.
Flexibil i extensibil. Orice API pentru procesri de imagini trebuie s
suporte cel puin cteva tehnologii de baz, cum ar fi achiziia i afiarea
imaginilor, manipulri de baz, mbuntiri de imagini, manipulri geometrice
i analiz de imagini. JAI furnizeaz un set de baz de operatori necesari pentru
a susine tehnologiile de procesri de imagini. Aceti operatori suport multe
dintre funciile necesare ntr-o aplicaie de procesare de imagini. Deoarece
anumite aplicaii necesit operaii speciale de procesri de imagini care sunt
foarte rar folosite, pentru aceste aplicaii, JAI furnizeaz o infrastructur care
permite ca soluii particulare s poat fi adugate la nucleul JAI API.
JAI deine de asemenea un set de standarde de metode de compresie i
decopresie de imagini. Setul de baz se bazeaz pe standarde internaionale
pentru cele mai comune tipuri de fiiere comprimate. De asemenea JAI suport
adugarea de codoare i decodoare mai speciale, care sunt folosite de aplicaii.
Independena de dispozitivul de reprezentare. Procesarea de
imagini poate fi specificat de coordonate independente de dispozitiv. Modul de
reprezentare JAI trateaz toate imaginile surs ca fiind independente de afiare.
Se poate obine astfel un graf (sau lan) de operaii de vizualizare fr a ne

24
preocupa de rezoluia sau dimensiunile imaginii surs, JAI ocupndu-se de
toate aceste aspecte.
Puternic i performant. JAI suport formate de imagine complexe,
incluznd imagini cu pn la trei dimensiuni i un numr arbitrar de benzi,
precum i muli algoritmi de procesare de imagini i operatori de procesare.
Pentru a spori performana n procesarea imaginilor, pentru anumite
platforme (actual pentru Solaris i Windows), JAI este implementat cu cod
nativ, incluznd implementri ultra-optimizate care se bazeaz pe accelerare
hardware i posibilitile multimedia ale platformei, cum ar fi instruciuni
MMX pentru procesoarele Intel i VIS pentru UltraSparc.
Interoperabilitate. JAI este integrat cu celelalte API-uri Java Media,
fiind posibil astfel dezvoltarea de aplicaii multimedia foarte avansate pe
platforma Java. JAI funcioneaz bine cu celelalte API-uri, cum ar fi Java 3D
sau tehnologiile bazate pe componente JavaBeans.

7.4.1. Programare n Java Advanced Imaging

JAI API este construit pe fundaia Java 2D API pentru a permite


aplicaii mai puternice i generale de procesri de imagini. JAI API adaug
urmtoarele concepte:
Imagini multisegmentate
Execuie amnat
Procesare de imagini n reea
Gestiunea proprietilor imaginilor
Operatori imagine cu surse multiple
Date imagine tridimensionale
Combinaia dintre segmentare i execuie amnat permite optimizri
de rulare cu un model destul de simplu. Noi operatori pot fi adugai i noi
operatori pot participa ca obiecte de prim clas n modelul de execuie
amnat.
JAI API de asemenea furnizeaz un grad destul de mare de
compatibilitate cu modelele de procesare Java AWT i Java 2D. Operatorii JAI
pot s lucreze direct cu obiectele Java 2D BufferedImage sau cu orice alte
obiecte imagine care implementeaz interfaa RenderedImage. JAI suport
acelai model independent de reprezentare ca i Java 2D API, folosind
coordonate independente de dispozitiv. JAI suport de asemenea stilul de
desenare de la Java 2D pe amndou tipurile de imagini, Rendered i
Renderable folosind interfaa Graphics.
JAI API nu utilizeaz interfeele de productor/consumator de imagine
care au fost introduse n Java AWT i folosite mai apoi n Java 2D. n schimb,
JAI API necesit ca imaginile surs s participe la modelul de procesare de
tragere prin rspunsul la cereri pentru arii arbitrare, fcnd imposibil de

25
instaniat un ImageProducer direct ca surs. Este posibil, totui, s instaniem
un ImageProducer ceea ce face ca datele imagine JAI API s fie disponibile la
aplicaii AWT mai vechi.
Similitudinile JAI cu Java 2D API sunt evidente, deoarece este
dependent de abstractizrile definite n Java 2D API. n general, ntregul
mecanism pentru tratarea imaginilor de tip Renderable i Rendered,
eantioanele pixelilor i stocarea datelor este susinut i de JAI. Principalele
puncte comune ale celor dou API (JAI i Java 2D) sunt:
Interfeele RenderableImage i RenderedImage definite n Java 2D API sunt
folosite ca baz pentru abstractizri de nivel nalt. JAI permite crearea i
manipularea grafurilor direcionale aciclice de obiecte implementnd
aceste interfee.
Obiectul principal de date, TiledImage, implementeaz interfaa
WritableRenderedImage i poate conine o gril regulat de segmente de
obiecte Raster. Spre deosebire de BufferedImage din Java 2D API,
TiledImage nu necesit s fie prezent un obiect ColorModel pentru
interpretare fotometric a imaginii sale.
Obiectele operator din JAI sunt mult mai sofisticate dect n Java 2D API.
Obiectul operator fundamental, OpImage, furnizeaz suport foarte bogat
pentru extensibilitate spre noi operatori dincolo de posibilitile Java 2D
API. JAI are un mecanism bazat pe regitri care automatizeaz selecia de
operaii asupra unei RenderedImage.
Obiectele SampleModel, DataBuffer i Raster din Java 2D API sunt portate
n JAI fr nici o modificare, cu excepia c se permite folosirea tipurilor
double i float ca tipuri fundamentale de date a unui DataBuffer n adaos la
tipurile existente, byte, short i int.
Clasele de date JAI. JAI introduce dou noi tipuri de clase de date
care extind clasa de date DataBuffer din Java 2D. n Tabelul 7.6. sunt
prezentate aceste clase.

Clasa Descriere
DataBufferFloat Stocheaz date intern sub form de float.
DataBufferDouble Stocheaz date intern sub form de double.
Tabelul 7.6. Clasele utilizate pentru datele imagine din JAI

O operaie de procesare de imagini n JAI poate fi descris pe scurt n


urmtorii patru pai (JAI Programming, 1999):
1. Obinerea unei s-au unor imagini surs. Imaginile pot fi obinute prin trei
modaliti:
ncrcarea dintr-un fiier imagine cum ar fi GIF, TIFF, JPEG, etc.
Obinerea unei imagini de la o alt surs de date, cum ar fi un server
distant.

26
Generarea unei imagini intern.
2. Definirea unui graf de prelucrri de imagini. Acest lucru este un proces
n dou etape:
Definirea operatorilor imagine.
Definirea unei relaii printe/copil ntre surse i destinaii.
3. Evaluarea grafului folosind unul din urmtoarele trei modele de
execuie:
Modelul de execuie Rendered (modul imediat).
Modelul de execuie Renderable (modul amnat).
Modelul de execuie la disten (modul distant).
4. Procesarea rezultatului. Aici avem patru posibiliti:
Salvarea imaginii ntr-un fiier
Afiarea imaginii pe ecran
Tiprirea imaginii la imprimant sau la alt dispozitiv
Trimiterea imaginii la un alt API, de exemplu Swing.

7.4.1.1. Grafuri i procesare de grafuri

n JAI orice operaie este definit ca obiect. Un obiect operator este


instaniat cu nici una sau cu mai multe imagini surs i ali parametri care
definesc operaia. Doi sau mai muli operatori pot fi cuplai, astfel nct primul
operator devine imaginea surs pentru urmtorul operator. Prin legarea unui
operator de un altul, se creeaz un graf de procesare de imagini sau lan.
n forma cea mai simpl, un graf de procesare de imagini este un lan
de obiecte operator cu una sau mai multe imagini surs la un capt i o imagine
destinaie la cellalt. Graful astfel creat este cunoscut sub denumirea de graf
aciclic direcionat (DAG directed acyclic graph), unde fiecare obiect este un
nod n graf, iar referinele la obiecte formeaz ramuri. (Figura 7.5.)

im0 im1
constant constant

im1
Noduri add
Ramuri

Component de
afiare 27

Figura 7.5. Exemplu de DAG


Structura unui graf poate fi considerat ca fiind produs de operaii, iar
forma grafului este folositoare la vizualizarea acestor operaii. Un DAG este un
graf care nu conine cicluri. Acest lucru nseamn c pe o rut de la un nod A
spre un nod B nu mai exist o cale de ntoarcere.
JAI extinde independena de reprezentare, care a fost introdus n Java
2D API. Cu ajutorul independenei de reprezentare se poate descrie o imagine
aa cum dorim noi s apar, independent de orice instan specific. JAI
prezint un mod Renderable prin felul n care trateaz toate sursele imagine ca
i independente de reprezentare. Se poate construi un graf (sau lan) de operaii
Renderable fr a ne interesa rezoluia sau dimensiunile imaginii surs, JAI
ocupndu-se de toate aceste detalii.
JAI a introdus dou tipuri de grafuri: Rendered i Renderable.
Grafuri Rendered. Grafurile Rendered sunt forma cea mai simpl de
reprezentare n JAI. Grafurile Renderable au avantajul independenei de
reprezentare, eliminnd nevoia de a lucra direct cu pixeli, n schimb grafurile
Rendered sunt utile atunci cnd este necesar s lucrm direct cu pixeli. Un graf
Rendered proceseaz imaginea n modul imediat. Pentru orice nod din graf,
imaginea surs este considerat ca o evaluare la momentul n care este
instaniat i adugat la graf, sau ca o nou operaie adugat la lan.
Un graf Rendered este compus din noduri de obiecte Rendered. Aceste
noduri sunt de obicei instane ale clasei RenderedOp, dar poate fi i o subclas
a clasei PlanarImage, care este versiunea JAI a clasei RenderedImage.
Imaginile surs sunt obiecte care implementeaz interfaa
RenderedImage. Aceste surse sunt specificate ca parametri n construcia unor
noi obiecte imagine. Fragmentul de cod urmtor (Exemplul 7.10.) exemplific
construirea unui lan Rendered.

Exemplul 7.10. Exemplu de lan Rendered


import javax.jai.*;
import javax.jai.widget.*;
import java.awt.Frame;

public class AddExample extends Frame {


// ScrollingImagePanel este un obiect pentru afiare
// conine un obiect Graphics2D
// (de ex., ca imagine destinaie).

28
ScrollingImagePanel imagePanel1;
// constructorul clasei
public AddExample(ParameterBlock param1,
ParameterBlock param2) {
// creaz o imagine constant
RenderedOp im0 = JAI.create("constant", param1);
// creaz o alt imagine constant
RenderedOp im1 = JAI.create("constant", param2);
// adun cele dou imagini mpreun
RenderedOp im2 = JAI.create("add", im0, im1);
// Afieaz imaginea ntr-o fereastr glisant
imagePanel1 = new ScrollingImagePanel(im2, 100,
100);
// ataeaz obiectul de afiare la cadrul principal
add(imagePanel1);
}
}

Primele trei linii din exemplu specific pachetele i clasele care se


import. Clasele care ncep cu javax.jai sunt clasele JAI. Acest exemplu
definete un obiect de tip cadru (Frame) care conine un obiect pentru afiarea
imaginilor (ScrollingImagePanel). Pentru simplicitatea prezentrii, toate
aciunile executate de aceast clas sunt definite n constructor. Acest
constructor primete dou obiecte de tip ParameterBlock, utilizate n
construcia a dou imagini de tip constant, care vor fi adunate mpreun pentru
a crea imaginea destinaie. n cele din urm se afieaz imaginea destinaie ntr-
o fereastr cu bare de defilare i apoi este ataat la cadrul principal.
Din momentul n care pixelii ncep s curg, graful acestei procesri
v-a arta ca n Figura 7.6., ntregul proces fiind condus de ctre componenta de
afiare. Imaginile surs nu sunt ncrcate i nici un pixel nu este produs pn
cnd componenta de afiare le cere.

im0 im1
ConstantOpImage ConstantOpImage

im1
AddOpImage

Component
de afiare

29
Figura 7.6. Exemplu de lan Rendered
Grafuri Renderable. Grafurile Renderable nu sunt evaluate la
momentul n care se specific. Evaluarea este amnat pn cnd apare o cerere
specific pentru o reprezentare. Acest proces este cunoscut sub numele de
execuie amnat (deferred execution).
ntr-un graf Renderable, dac o imagine surs trebuie s se schimbe
nainte s fie o cerere pentru reprezentare, schimbarea va fi reflectat la ieire.
Acest proces este posibil datorit modelului de tragere, unde procesul care
cere imaginea, trage imaginea prin lan, lucru care este n opoziie cu modelul
de mpingere din procesrile AWT.
Un graf Renderable este alctuit din obiecte noduri care
implementeaz interfaa RenderableImage, dar de obicei se folosete obiecte de
tipul RenderableOp. Pe msur ce se construiete graful Renderable, sursele
din fiecare nod sunt specificate prin topologia grafului. Sursa unui graf
Renderable este un obiect de tip RenderableImage.
Fragmentul de cod urmtor (Exemplul 7.11.) reprezint un exemplu de
graf Renderable. Acest exemplu citete un fiier n format TIFF, inverseaz
valorile pixelilor i adun o valoare constant la pixeli.

Exemplul 7.11. Exemplu de graf Renderable


// Preia o surs Rendered din sursa fiier TIFF
// obiectul ParameterBlock `pb0' conine numele
// sursei (fiier, URL, etc.). Obiectele `hints0',
// `hints1' i `hints2' conin indiciile de reprezentare i se
// presupune c sunt create n afara acestui fragment de cod.
RenderedOp sourceImg = JAI.create("TIFF", pb0);
// Se obine obiectul RenderableImage
// din sursa RenderedImage.
ParameterBlock pb = new ParameterBlock();
pb.addSource(sourceImg);
pb.add(null).add(null).add(null).add(null).add(null);
// creeaz o operaie Renderable.
RenderableImage ren = JAI.createRenderable("renderable", pb);
// creeaz blocul de parametrii pentru primul operand.
ParameterBlock pb1 = new ParameterBlock();
pb1.addSource(ren);
// Creeaz primul operand din lanul Renderable ca
// operaie de inversare.
RenderableOp Op1 = JAI.createRenderable("invert", pb1);

30
// creeaz blocul de parametrii pentru cel de-al doilea operand.
// constanta cu care se adun este "2".
ParameterBlock pb2 = new ParameterBlock();
pb2.addSource(Op1); // Op1 ca i surs
pb2.add(2.0f); // 2.0f ca i constant
// Creeaz al doilea operand ca i operaie de adunare
// cu o constant.
RenderableOp Op2 = JAI.createRenderable("addconst", pb2);
// Creeaz contextul de reprezentare.
AffineTransform screenResolution = ...;
RenderContext rc = new RenderContext(screenResolution);
// creeaz o reprezentare.
RenderedImage rndImg1 = Op2.createRendering(rc);
// Afieaz reprezentarea folosind screenResolution.
imagePanel1 = new ScrollingImagePanel(rndImg1, 100, 100);

Graful asociat lanului Renderable este prezentat n Figura 7.7.

Imagine surs
RenderableOp

Op1
RenderableOp

Op2
RenderableOp

Figura 7.7. Exemplu de lan Renderable

Graful Renderable poate fi gndit ca i un model care, atunci cnd este


reprezentat, provoac instanierea unui graf Rendered paralel pentru
ndeplinirea procesrilor actuale. n graful din exemplul de mai sus se produc
urmtoarele:
Atunci cnd este apelat metoda Op2.createRendering, aceasta
apeleaz recursiv metoda Op1.createRendering cu argumentul
RenderContext rc.
Operaia Op1 apeleaz apoi metoda sourceImg.getImage, cu rc ca
argument. Obiectul sourceImg creeaz un nou obiect RenderedImage

31
pentru pstrarea pixelilor surs la rezoluia necesar i i introduce n
lan. Acesta returneaz la Op1 o referin spre acest obiect.
Op1 folosete apoi OperationRegistry ca s gseasc un obiect de
tipul ContextualRenderedImageFactory (CRIF) care poate s execute
o operaie invert. Obiectul rezultat RenderedOp returnat de ctre
CRIF este introdus n lan cu referina returnat de sourceImg ca i
surs.
Referina ctre obiectul invert de tip RenderedImage este returnat
la Op2, care repet procesul, crend un obiect addconst de tip
RenderedOp, introducndu-l n lan i returnnd o referin ctre
rndImg1.
La sfrit, obiectul rndImg1 este utilizat la apelul lui
ScrollingImagePanel s afieze rezultatul pe ecran.
Dup crearea obiectului ScrollingImagePanel, lanurile Renderable i
Rendered vor arta ca i n Figura 7.8.

Imagine surs
RenderableOp

Op1 (NoName) surs


RenderableOp RenderedOp

Op2 (NoName) invert


RenderableOp RenderedOp

(NoName) addconst
RenderedOp

rndImg1
RenderedOp

ImagePanel1
(component de afiare)

Figura 7.8. Grafuri Renderable i Rendered dup


apelul metodei getImage
32
n acest moment n lan, nu se proceseaz nici un pixel. Doar atunci
cnd obiectul ScrollingImagePanel necesit s afieze pixeli pe ecran se
creeaz obiectele OpImage i pixelii sunt trai prin lanul Rendered, lucru
executat n ultima linie de cod a exemplului:
imagePanel1 = new ScrollingImagePanel(rndImg1, 100, 100);

Reutilizarea grafurilor. De cele mai multe ori, este mai potrivit s


modificm un graf existent i s-l reutilizm, dect s crem un graf aproape
identic. Amndou tipurile de grafuri, Rendered i Renderable, sunt editabile cu
anumite restricii.
Iniial, un nod dintr-un graf Rendered este modificabil, n sensul c pot
fi atribuite noi surse, care sunt considerate c vor fi evaluate n momentul cnd
sunt atribuite, iar valorile parametrilor lor pot fi modificai. Cu toate acestea,
odat ce reprezentarea are loc, nodul va fi ngheat iar sursele i parametrii lui
nu pot fi schimbai.
Un lan de noduri Rendered poate fi clonat fr ca nodurile lui s fie
ngheate cu ajutorul metodei RenderedOp.createInstance. Folosind aceast
metod, un graf Rendered poate fi configurat i reutilizat dup dorin i de
asemenea serializat i transmis prin reea.
Clasa RenderedOp furnizeaz cteva metode pentru reconfigurarea
unui nod Rendered. Metodele setParameter pot fi folosite pentru modificarea
parametrilor din noduri. Metoda setOperationName poate fi utilizat la
schimbarea numelui operaiei. Metoda setParameterBlock poate fi folosit la
schimbarea obiectului de tip ParameterBlock din noduri.
Deoarece grafurile Renderable nu sunt evaluate pn cnd exist o
cerere specific pentru reprezentare, nodurile pot fi editate n orice moment.
Singura problem n editarea grafurilor Renderable este introducerea de cicluri,
care trebuie evitat.
Clasa RenderableOp furnizeaz cteva metode pentru reconfigurarea
unui nod Renderable. Metodele setParameter pot fi folosite pentru modificarea
parametrilor nodurilor. Metoda setParameterBlock poate fi folosit la
schimbarea obiectelor PrameterBlock din noduri. Metoda setProperty poate fi
folosit la modificarea proprietii locale a unui nod. Metoda setSource poate fi
folosit la modificarea sursei pentru un nod.

7.4.1.2. Clasele de baz din JAI API

JAI este compus din mai multe clase grupate n cinci pachete:
javax.media.jai conine interfeele i clasele de baz.

33
jaxax.media.jai.iterator conine clase i interfee iterator, care sunt utile
pentru scrierea operaiilor extensie.
javax.media.jai.operator conine clase care descriu toi operatorii de
procesare a imaginilor.
javax.media.jai.widget conine interfee i clase pentru crearea de
suprafee i ferestre cu bare de derulare simple pentru afiarea imaginilor.
com.sun.media.jai.codec conine clase i interfee utile n decodarea i
codarea fiierelor imagine.
Clasa JAI. Clasa JAI nu poate fi instaniat, ea este format dintr-o
colecie de metode statice care asigur o sintax simpl pentru crearea de
grafuri de tip Renderable i Rendered. Majoritatea metodelor din aceast clas
sunt folosite pentru a crea un RenderedImage, lund ca argumente un
ParameterBlock i un RenderingHints. Exist o singur metod pentru a crea
un RenderableImage, cu argumente de tip ParameterBlock i RenderingHints.
Aceast clas deine cteva variante de metode create, toate acestea
preiau surse i parametrii n mod direct i construiesc un obiect
ParameterBlock automat.
Clasa PlanarImage. Clasa PlanarImage este clasa principal pentru
descrierea imaginilor bidimensionale n JAI. Aceast clas implementeaz
interfaa RenderedImage din Java 2D API, TiledImage i OpImage.
Interfaa RenderedImage descrie o imagine segmentat, disponibil
doar pentru citire cu un model al pixelului descris de tipurile SampledModel i
DataBuffer. Fiecare segment este o suprafa dreptunghiular de dimensiune
identic, aezat pe o gril regulat. Toate segmentele se folosesc de un acelai
obiect SampleModel. n plus, fa de posibilitile oferite RenderedImage,
PlanarImage menine conexiunile dintre surs i destinaie, dintre nodurile
grafurilor Rendered. Deoarece nodurile grafului sunt conectate bidirecional,
garbage-collector-ul necesit un mic ajutor pentru a detecta atunci cnd o
poriune din graf nu mai este refereniat de codul utilizator i poate fi eliberat.
Clasa PlanarImage se ocup de acest lucru prin folosirea referinelor slabe
(Weak References API) din Java 2.
Orice obiecte RenderedImage din exteriorul API sunt acoperite
pentru a produce o instan de PlanarImage. Acest lucru permite ca API s
utilizeze funcionalitile suplimentare din PlanarImage pentru toate imaginile.
Clasa CollectionImage. CollectionImage este o superclas abstract
pentru patru clase i reprezint colecii de obiecte PlanarImage:
ImageStack reprezint imagini bidimensionale care sunt aezate ntr-un
spaiu tridimensional. Imaginile necesit s fie aezate paralel una cu
cealalt.
ImageSequence reprezint o secven de imagini cu marcajul de timp
asociat i poziiile camerei. Este folosit pentru a reprezenta imagini video
sau fotografii dependente de timp.

34
ImagePyramid reprezint o serie de imagini de rezoluie progresiv mai
mic, fiecare derivat din ultima prin mijloacele unui operator de
procesare.
ImageMIPMap reprezint o stiv de imagini cu o relaie operaional fix
ntre prile adiacente.
Clasa TiledImage. Clasa TiledImage reprezint imagini coninnd mai
multe segmente aranjate ntr-o gril. Segmentele formeaz o gril regulat, care
poate s ocupe orice regiune dreptunghiular din plan.
Clasa implementeaz interfaa WritableRenderedImage din Java 2D
API, de asemenea extinde clasa PlanarImage. Clasa permite ca segmentele s
poat fi validate pentru scriere, dup ce datele pixelului vor fi accesate direct.
De asemenea aceasta are o metod createGraphics care permite ca coninutul
s fie modificat utiliznd apeluri de desenare din Java 2D API.
Aceast clas conine iniial o gril care este goal, pe msur ce
fiecare segment este solicitat, se iniializeaz cu date dintr-o surs
PlanarImage. Dup ce un segment este iniializat, coninutul su poate fi
modificat. O regiune de interes (ROI) arbitrar poate fi umplut cu date copiate
dintr-o surs PlanarImage.
Clasa conine o metod care permite desenarea unui obiect
Graphics2D ntr-un obiect TiledImage. Acest lucru este util la adugarea de
text, linii, sau a altor obiecte grafice simple la o imagine.
Clasa OpImage. OpImage este clasa printe pentru toate operaiile de
procesare a imaginilor, cum ar fi:
AreaOpImage pentru operatori imagine care necesit doar o regiune
dreptunghiular fix n jurul pixelului surs pentru a calcula fiecare pixel
destinaie.
PointOpImage pentru operatori imagine care necesit doar un singur
pixel surs pentru a calcula fiecare pixel destinaie.
SourcelessOpImage pentru operatori imagine care nu au imagine surs.
StatisticsOpImage pentru operatori imagine care calculeaz statistica pe
o regiune dat dintr-o imagine, cu o frecven de eantionare dat.
UntiledOpImage pentru operaii uni-surs n care valorile tuturor
pixelilor din imaginea surs contribuie la valoarea fiecrui pixel din
imaginea destinaie.
WrapOpImage pentru operatori imagine care execut o acoperire de
imagine.
ScaleOpImage pentru operatori extensie care execut scalare i necesit
mapare regresiv rectilinie i adugare prin dimensiunile filtrului de
reeantionare.
Clasa OpImage este capabil s determine care arii surs sunt
suficiente pentru calcularea unei arii date din destinaie prin mijloace furnizate
de utilizator i anume metoda mapDestRect. Pentru majoritatea operaiilor,

35
aceast metod este furnizat de o subclas standard a clasei OpImage, cum ar
fi PointOpImage sau AreaOpImage.
Clasa RenderableOp. Aceast clas aduce o reprezentare uoar
(lightweight) a unei operaii in spaiul Renderable. Obiectele de tipul
RenderableOp sunt create n mod normal folosind metoda createRenderable
din clasa JAI i poate fi modificat dup dorin. De asemenea, clasa
implementeaz interfaa RenderableImage, aa c poate fi interogat pentru
dimensiunile sale independente de reprezentare.
Atunci cnd un obiect RenderableOp trebuie s fie reprezentat, acesta
utilizeaz un obiect OperationRegistry pentru localizarea unui obiect de tipul
ContextualRenderedImageFactory pentru a executa conversia din spaiul
Renderable n RenderedImage.
Clasa RenderedOp. Este un obiect lightweight similar cu
RebderableOp care stocheaz un nume de operaie, ParameterBlock i
RenderingHints i poate fi adugat ntr-un graf Rendered. Exist dou metode
pentru producerea i reprezentarea unui RenderedOp:
Implicit orice apel la o metod RenderedImage din RenderedOp
provoac crearea reprezentrii. Aceast reprezentare este n mod obinuit
compus dintr-un lan de obiecte OpImage cu o geometrie similar cu cea a
lanului RenderedOp.
Explicit un apel la metoda createInstance cloneaz obiectul
RenderedOp i sursa lui, rezultnd un nou lan Rendered cu aceleai surse
non-RenderedOp (de exemplu, obiecte TiledImage) ca i lanul original.
Obiectele RenderedOp care nu au fost reprezentate pot avea sursele i
parametrii modificai. Sursele sunt considerate evaluate din momentul n care
sunt conectate la un obiect RenderedOp.

7.4.1.3. Operatori JAI

JAI API specific un set de baz de operatori de procesare de imagini.


Categoriile generale de operatori de procesare de imagini suportai includ:
Operatori punctuali
Operatori de arie
Operatori geometrici
Operatori de cuantizare a culorii
Operatori de fiier
Operatori n frecven
Operatori statistici
Operatori de extragere a muchiilor
Ali operatori
De asemenea JAI API suport abstractizri pentru mai multe tipuri de
colecii de imagini, cum ar fi imagini dependente de timp i piramide de

36
imagini. Acestea au ca scop simplificarea operaiilor asupra coleciilor de
imagini i permite dezvoltarea de operatori care lucreaz direct cu aceste
abstractizri.
Operatori punctuali. Operatorii punctuali permit modificarea
modului n care datele ocup un domeniu disponibil de nivele de gri. Operatorii
punctuali transform imaginea de intrare ntr-o imagine de ieire n aa fel nct
fiecare pixel de ieire depinde doar de pixelul corespunztor de la intrare.
Operatorii punctuali nu modific relaia spaial dintr-o imagine.
Cteva exemple de operatori punctuali sunt descrise n Tabelul 7.7.

Operator Descriere
Add Preia dou imagini surs Rendered sau
Renderable i adun fiecare pereche de pixeli,
cte un pixel de la fiecare imagine surs de la
poziia i banda corespunztoare.
BandCombine Preia o imagine surs Rendered sau
Renderable i calculeaz un set de combinaii
liniare arbitrare asupra benzilor folosind o
matrice specific.
Composite Preia dou imagini surs Rendered sau
Renderable i combin cele dou imagini
bazndu-se pe valorile alfa a fiecrui pixel.
Invert Preia o imagine surs Rendered sau
Renderable i inverseaz valorile pixelilor.
Tabelul 7.7. Exemple de operatori punctuali din JAI

Operatori de arie. Operatorii de arie execut transformri geometrice


care are ca rezultat repoziionarea pixelilor dintr-o imagine. Pixelii sunt
repoziionai de la coordonatele spaiale iniiale x i y din imaginea de intrare la
noi coordonate n imaginea de ieire folosind transformri matematice.
Exist dou tipuri de operaii de arie de baz: liniare i neliniare.
Operaiile liniare sunt translaia, rotaia i scalarea. Operaiile neliniare,
cunoscute i sub numele de transformri de acoperire, sunt de curbare i de
deformare. Cteva dintre aceste operaii sunt prezentate n Tabelul 7.8.

Operator Descriere
Border Preia o imagine surs Rendered i i adaug o
bordur n jurul ei.
BoxFilter Preia o imagine surs Rendered i determin
intensitatea unui pixel din imagine prin medierea
pixelilor surs din interiorul unei arii
dreptunghiulare din jurul acelui pixel.

37
Convolve Preia o imagine surs Rendered i execut o
operaie spaial care calculeaz fiecare eantion
de ieire prin nmulirea elementelor unui nucleu
cu eantioanele nconjurtoare unui eantion
particular.
Crop Preia o imagine surs Rendered sau Renderable
i ajusteaz imaginea la o arie specificat.
MedianFilter Preia o imagine surs Rendered i o trece printr-
un filtru neliniar care este util pentru eliminarea
linilor sau pixelilor izolai, pstrnd n mare
nfiarea imaginii.
Tabelul 7.8. Operatori de arie

Operatori geometrici. Operatorii geometrici permit modificarea


orientrii, mrimii i formei unei imagini. Cteva exemple de astfel de operatori
JAI se gsesc n Tabelul 7.9.

Operator Descriere
Affine Preia o surs Rendered sau Renderable i execut o
alocare affine
Rotate Preia o imagine surs Rendered sau Renderable i o
rotete n jurul unui punct dat cu un unghi dat,
specificat n radiani.
Scale Preia o imagine surs Rendered sau Renderable i
translateaz i redimensioneaz imaginea.
Shear Preia o imagine surs Rendered sau Renderable i
execut o ntindere (shearing) spaial pe
orizontal i vertical
Translate Preia o imagine surs Rendered sau Renderable i
copiaz imaginea la o nou locaie din plan.
Transpose Preia o imagine surs Rendered sau Renderable i o
ntoarce sau o rotete.
Wrap Preia o imagine surs Rendered sau Renderable i
execut o operaie de ntindere general a imaginii
Tabelul 7.9. Operatori geometrici

Operatori de cuantizare a culorii. Cuantizarea culorii este des


folosit pentru a micora conturarea amplitudinii pentru cadre bufer cu mai
puin de 8 bii adncime sau pentru cadre bufer de culoare cu mai puin de 24
bii adncime. Operatori de cuantizare a culorii sunt prezentai n Tabelul 7.10.

Operator Descriere

38
ErrorDiffusion Preia o surs Rendered sau Renderable i execut
cuantizarea culorii prin cutarea celei mai apropiate
culori pentru fiecare pixel dintr-o palet de culori
dat i difuzarea erorii de cuantizare a culorii n
partea de jos i dreapta a pixelului
OrderedDither Preia o surs Rendered sau Renderable i execut
cuantizarea culorii prin cutarea celei mai apropiate
culori pentru fiecare pixel dintr-un cub de culori dat
i translatarea valorii indexului rezultat cu o
cantitate pseudoaleatoare determinat de valorile
date de masca dither
Tabelul 7.10. Operatorii de cuantizare a culorii

Operatori de fiier. Operatorii de fiier sunt utilizai pentru a citi i a


scrie fiiere imagine. Cteva exemple de operatori de fiier sunt prezentai n
Tabelul 7.11.

Operator Descriere
AWTImage Convertete un obiect standard java.awt.Image ntr-
o imagine Rendered
BMP Citete un flux de intrare standard BMP
Encode Preia o imagine surs Rendered i scrie imaginea la
un obiect OutputStream n formatul specificat
folosind parametrii de codare dai.
FileLoad Citete o imagine dintr-un fiier
FileStore Preia o imagine surs Rendered i scrie imaginea
ntr-un fiier dat n formatul specificat folosind
parametrii de codare furnizai.
TIFF Citete date de tip TIFF 6.0 dintr-un
SeekableStream
URL Creeaz o imagine de ieire a crui surs este
specificat de un URL
Tabelul 7.11. Exemple de operatori de fiier

Operatori n frecven. Operatorii n frecven sunt folosii pentru a


descompune o imagine din forma spaial ntr-o form din domeniul frecven.
Operatorii sunt de asemenea disponibili pentru a executa operaia invers a
transformrii n frecven, n care imaginea este convertit din domeniul
frecven napoi n forma ei spaial.
JAI suport mai multe tipuri de transformri n frecven. Cea mai
utilizat transformare este transformta Fourier, dar JAI utilizeaz forma discret
a acestei transformate cunoscut sub numele de transformata Fourier discret,

39
precum i transformata discret cosinus mpreun cu variantele lor de
transformri inverse. Cteva exemple de operatori n domeniul frecven sunt
prezentai n Tabelul 7.12.

Operator Descriere
DCT Preia o imagine surs Rendered sau Renderable i
calculeaz transformata discret cosinus (DCT)
par a imaginii. Fiecare band a imaginii destinaie
este derivat prin executarea unei transformri
DCT bidimensionale asupra benzii corespunztoare
din imaginea surs.
DFT Preia o imagine surs Rendered sau Renderable i
calculeaz transformata discret Fourier a imaginii.
Phase Preia o imagine surs Rendered sau Renderable
coninnd date complexe i calculeaz unghiul
fazei pentru fiecare pixel.
Tabelul 7.12. Exemple de operatori n domeniul frecven

Operatori statistici. Operatorii statistici furnizeaz mijloace de


analiz a coninutului unei imagini. Operatorii statistici din JAI sunt prezentai
n Tabelul 7.13.

Operator Descriere
Extrema Preia o surs imagine Rendered, citete o regiune
specific din imagine i gsete valorile minime i
maxime ale valorilor pixelilor pentru fiecare band
din acea regiune de imagine. Datele imagine trec
prin acest operator nemodificate.
Histogram Preia o imagine surs Rendered, citete o regiune
specific din imagine i genereaz o histogram
bazndu-se pe valorile pixelilor din acea regiune de
imagine. Datele histogramei sunt stocate ntr-un
obiect de tip javax.media.jai.Histogram obinut de
la utilizator, acesta putndu-se obine printr-un apel
la metoda getProperty asupra acestei operaii cu
numele proprietii histogram. Valoarea de retur
va fi de tipul javax.media.jai.Histogram. Datele
imagine trec neschimbate prin aceast operaie.
Mean Preia o surs imagine Rendered, citete o regiune
specific i calculeaz valoarea medie pentru
fiecare band din interiorul unei regiuni dintr-o
imagine. Datele imagine trec neschimbate prin

40
aceast operaie.
Tabelul 7.13. Operatori statistici

Operatori de extragere a muchiilor. Operatorii de extragere a


muchiilor permit mbuntirea muchiilor imaginii, reducnd imaginea doar la
detaliile muchiilor. mbuntirea muchiilor se face prin intermediul unor filtre
spaiale care detecteaz o denivelare de strlucire a pixelilor specific din
interiorul unui grup de pixeli dintr-o imagine. O denivelare precipitat de
strlucire indic prezena unei muchii.
Operatorul GradientMagnitude preia o imagine surs Rendered i
calculeaz intensitatea vectorului gradient a imaginii pe dou direcii
ortogonale.
Ali operatori. Acetia sunt operatori care nu se ncadreaz n
categoriile de mai sus. Un astfel de operator din JAI este Renderable, care preia
o imagine surs Rendered i produce un obiect RenderableImage constituind o
piramid de obiecte RenderedImage la valori ale rezoluiei progresiv mai
mic.

7.4.1.4. Crearea operaiilor

Obiectele operaii sunt create n cele mai multe cazuri folosind


metodele (metode create din clasa JAI) care vor fi expuse n cele ce urmeaz.
Pentru grafurile Renderable exist patru variaii pentru crearea de
operaii n modul Renderable. De exemplu:
RenderableOp im = JAI.createRenderable("operationName",
paramBlock);
Metoda JAI.createRenderable creeaz un nod operaie Renderable
care preia doi parametrii:
Un nume de operaie
O surs i un set de parametrii pentru operaia coninut n blocul
de parametrii
Pentru grafurile Rendered exist mult mai multe variaii ale metodelor
de creare (metode JAI.create) a operaiilor n modul Rendered.
Exist dou versiuni ale metodei create care nu sunt statice,
identificate ca createNS. Aceste metode pot fi utilizate cu o instan specific a
clasei JAI i ar trebui utilizat doar atunci cnd rezultatul final returnat este un
singur obiect RenderedImage. Sursa sau sursele furnizate pot fi o colecie de
imagini sau o colecie de colecii. n cele ce urmeaz se prezint un exemplu de
utilizare a acestei metode:
RenderedOp im = JAI.createNS("operationName",
source, param1, param2)

41
Indiciile de reprezentare asociate cu aceast instan a JAI sunt
suprapuse cu indiciile furnizate la aceast metod, indiciile vor fi o uniune
dintre indiciile instanei i indiciile date prin parametru.
Numele operaiei descrie operatorul care va fi creat i este un string.
Blocul de parametrii conine sursa operaiei i un set de parametrii
utilizai de operaie. Coninutul blocului de parametri depinde de operaia care
se creeaz i poate fi doar numele imaginii surs sau poate conine toi
parametrii operatorului. Blocurile de parametrii ncapsuleaz toate informaiile
despre sursele i parametrii utilizai de operaie. Parametrii specificai de ctre
blocul de parametri sunt obiecte.
Aceste obiecte de control, parametri i surse, pot fi editate prin metoda
setParameterBlock pentru a afecta operaii specifice sau chiar structura lanului
de reprezetare. Modificrile afecteaz viitoarele obiecte RenderedImage
derivate din punctele lanului din aval de unde s-a fcut modificarea.
Exist dou clase separate pentru a specifica blocurile de parametrii:
java.awt.image.renderable.ParameterBlock clasa principal
pentru specificarea i schimbarea blocurilor de parametrii.
javax.media.jai.ParameterBlockJAI extinde ParameterBlock
prin permiterea utilizrii a valorilor implicite a parametrilor i
utilizrii numelor de parametrii.
Blocul de parametrii trebuie s conin acelai numr de surse i
parametri n funcie de necesitatea operaiei, cu excepia cnd se folosete
ParameterBlockJAI care furnizeaz valori implicite. Pentru unele operaii,
valorile implicite ale parametrilor nu sunt disponibile i de aceea ele trebuie
furnizate.
Sursele sunt adugate la blocul de parametrii cu metoda addSource. n
exemplul urmtor se creeaz un nou ParameterBlock numit pb i apoi metoda
addSource este utilizat la adugarea imaginii surs im0 la blocul de parametrii.
ParameterBlock pb = new ParameterBlock();
pb.addSource(im0);
Pentru adugarea a dou surse la un bloc de parametrii, se utilizeaz
dou apeluri la metoda addSource.
ParameterBlock pb = new ParameterBlock();
pb.addSource(im0);
pb.addSource(im1);
n cazul folosirii clasei ParameterBlock, parametrii operaiei sunt
adugai la ParameterBlock cu metoda ParameterBlock.add. Exemplul urmtor
adaug dou valori la obiectul ParameterBlock numit pb, care a fost creat n
exemplul anterior.
pb.add(150);
pb.add(200);

42
Metoda add poate fi utilizat cu toate tipurile de date suportate: byte,
short, integer, long, float i double. Atunci cnd se utilizeaz obiectul
ParameterBlock, toi parametrii pe care o operaie are nevoie trebuie s fie
adugai, altfel operaia va eua.
La utilizarea clasei ParameterBlockJAI, deoarece obiectul conine deja
valori implicite pentru parametrii la momentul construciei, parametrii trebuie
schimbai cu metodele ParameterBlockJAI.set(value, index).
Exemplul urmtor (Exemplul 7.12.) arat crearea unui Parameter-
BlockJAI cu intenia de a fi furnizat unei operaii de rotire. Operaia de rotire
preia patru parametrii: xOrigin, yOrigin, angle i interpolation. Valorile
implicite pentru xOrigin i yOrigin sunt 0.0F pentru amndou. n acest
exemplu, aceste dou valori nu sunt modificate, deoarece valorile implicite sunt
suficiente pentru operaie. Ceilali doi parametri (angle i interpolation) au
valoarea implicit null i astfel necesit modificarea valorilor. Imaginea surs
trebuie de asemenea specificat.

Exemplul 7.12. Utilizarea obiectelor ParameterBlockJAI pentru


efectuarea operaiilor
// Specific metoda de interpolaie utilizat
interp = Interpolation.create(Interpolation.INTERP_NEAREST);
// creeaz ParameterBlockJAI i adaug interpolaia la el
ParameterBlockJAI pb = new ParameterBlockJAI();
pb.addSource(im); // imaginea surs
pb.set(1.2F, "angle"); // unghiul de rotaie n radiani
pb.set(interp, "interpolation"); // metoda de interpolaie

7.4.1.5. Indicii de reprezentare

Indiciile de reprezentare reprezint un set de indicii care descriu modul


n care obiectele sunt reprezentate. Indiciile de reprezentare sunt ntotdeauna
opionale pentru orice operaie.
Indiciile de reprezentare specific diferii algoritmi de reprezentare
cum ar fi antialiasing, interpolaie alfa i dithering. Multe dintre indicii permit
alegerea dintre calitatea reprezentrii i vitez, alte indicii pot s porneasc sau
s opreasc diferite opiuni de reprezentare, cum ar fi antialiasing i metric
fracional. Exist dou clase separate pentru specificarea indiciilor de
reprezentare:
java.awt.RenderingHints conine indiciile de reprezentare care pot fi
folosite de ctre clasa Graphics2D i clasele care implementeaz Raster i
BufferedImageOp.
javax.media.jai.JAI furnizeaz metode pentru definirea cheilor pentru
indicii de reprezentare specifice JAI.

43
Clasa RenderingHints creeaz indicii de reprezentare specifice Java
AWT. Pentru a modifica indiciile de reprezentare, se creeaz un obiect
RenderingHints i se transmite unei metode JAI.create asupra creia dorim s
acioneze. Modificnd un indiciu de reprezentare nu se garanteaz c un anume
algoritm de reprezentare va fi folosit, deoarece nu toate platformele suport
modificarea codului de reprezentare.
n codul urmtor, indiciile de reprezentare sunt setate pe calitate.
qualityHints = new
RenderingHints(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
Odat ce un obiect RenderingHints a fost creat, indiciile pot fi utilizate
ntr-o operaie folosind o metod JAI.create.
Fiecare instan a unui obiect JAI conine un set de indicii de
reprezentare care va fi folosit pentru toate crerile de imagini sau colecii de
imagini. Indiciile sunt combinate cu orice alte indicii furnizate metodei
JAI.create. Indiciile furnizate direct au preceden asupra indicilor obinuite.
Atunci cnd o nou instan JAI este construit, indiciile ei sunt iniializate la o
copie a indiciilor asociate cu instana implicit. Indiciile asociate cu alte
instane, incluznd instana implicit, pot fi manipulate folosind metodele
getRenderingHints, setRenderingHints i clearRenderingHints. Pentru
manipularea individual a indiciilor se folosesc metodele getRenderingHint,
setRenderingHint i removeRenderingHint.
Codul urmtor (Exemplul 7.13.) este un exemplu de reprezentare a
unei imagini cu indicii de reprezentare pentru o operaie de scalare. Indiciul de
reprezentare specific originea imaginii destinaie modificat la 200x200.

Exemplul 7.13. Utilizarea indiciilor de reprezentare


// creeaz blocul de parametrii pentru operaia de scalare.
ParameterBlock pb = new ParameterBlock();
pb.addSource(im0); // imaginea surs
pb.add(4.0F); // factorul de scalare x
pb.add(4.0F); // factorul de scalare y
pb.add(interp); // metoda de interpolaie
// Specificarea indiciilor de reprezentare
layout = new ImageLayout();
layout.setMinX(200);
layout.setMinY(200);
RenderingHints rh =
new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout);
// crearea operaiei de scalare.
PlanarImage im2 = (PlanarImage)JAI.create("scale", pb, layout)

44
7.4.2. Achiziia i afiarea imaginilor n JAI

Toate aplicaiile de procesare a imaginilor trebuie s execute nite


operaii de baz, cum ar fi achiziia, afiarea i nregistrarea imaginilor.
Imaginile pot fi achiziionate de la multe surse, care includ fiier de pe disc,
reea, etc. Imaginile pot fi achiziionate, procesate i imediat afiate, sau scrise
ntr-un fiier pe disc pentru a putea fi afiate mai trziu.
JAI ofer programatorului flexibilitatea de a procesa i afia o imagine
n mod imediat sau s amne afiarea imaginii procesate pn cnd apare o
cerere specific pentru aceasta.
Achiziia i afiarea imaginilor folosind mecanismele din JAI este
prezentat n Exemplul 7.14. Acest exemplu este o aplicaie care preia un
singur argument care este calea i numele fiierului care trebuie citit, iar
aplicaia citete acest fiier imagine folosind operatorul FileLoad i afieaz
imaginea cu ajutorul unei componente de afiare de tipul ScrollingImagePanel.

Exemplul 7.14. Program pentru citirea i afiarea unui fiier


imagine
// se specifc clasele care se import
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 {


public static void main(String args[]) {
String fileName = null;
// verific dac este furnizat argumentul
if(args.length != 1) {
System.exit(0);
} else if(args.length == 1) {
fileName = args[0];
}
new FileTest(fileName);
}

public FileTest(String fileName) {


// citete imaginea din calea specificat
RenderedOp img = JAI.create("fileload", fileName);
// afieaz numele fiierului n bara de titlu

45
setTitle(getClass().getName()+": "+fileName);
// afieaz imaginea
add(new ScrollingImagePanel(img, img.getWidth(),
img.getHeight()));
pack();
show();
}
}

7.4.2.1. Date imagine n JAI

Datele imagine reprezint o arie tridimensional de pixeli, aa cum


arat Figura 7.9., fiecare din aceste trei arii formeaz cte o band. Numrul de
linii specific nlimea benzii imaginii, iar numrul de coloane specific
limea benzii imaginii.

(0,0,2) x
(0,0,1)
(0,0,0)

(x,y,2)
(x,y,1)
(x,y,0)
Figura 7.9. Structura unei imagini cu mai
multe benzi

Imaginile monocrome, de exemplu imaginile grayscale, au doar o


singur band. Imaginile color au trei sau mai multe benzi, dar benzile nu
neaprat reprezint o culoare, de exemplu imaginile din satelit pot fi
achiziionate avnd mai multe benzi spectrale, de exemplu rou, verde, albastru
i infrarou.
O imagine este eantionat ntr-o gril dreptunghiular de pixeli.
Fiecare pixel are o coordonat (x, y) care corespunde locaiei de pe imagine. n
JAI, locaia pixelului (0, 0) este n colul din stnga sus al imaginii, cu valorile
coordonatelor x cresctoare spre dreapta i valorile coordonatelor y cresctoare
n jos.

46
n JAI API, unitatea de baz pentru stocarea imaginilor sunt obiectele
DataBuffer. Acestea sunt un fel de obiecte de stocare brute, care stocheaz toate
eantioanele din compoziia unei imagini, dar nu conin nici o informaie despre
felul cum aceste eantioane sunt organizate ca pixeli. Aceast informaie este
stocat ntr-un obiect SampleModel. Clasa SampleModel conine metode pentru
derivarea datelor pixel dintr-un DataBuffer.
JAI suport mai multe tipuri de date imagine, aa c clasa DataBuffer
are urmtoarele subclase, fiecare reprezentnd un tip diferit de date:
DataBufferByte stocheaz date intern ca i bytes (valori pe 8 bii).
DataBufferShort stocheaz date intern ca i short (valori pe 16 bii)
DataBufferUShort stocheaz date intern ca i unsigned short (valori
pe 16 bii)
DataBufferInt stocheaz date intern ca i ntregi (valori pe 32 bii)
DataBufferFloat stocheaz date intern ca i valori flotante n precizie
simpl.
DataBufferBuffer stocheaz date intern ca i valori flotante n
precizie dubl.
JAI suport i alte formate de date imagine, pe lng cele oferite de
pachetul java.awt.image (vezi paragraful 7.3.4.), dar clasa SampleModel
furnizeaz i urmtoarele tipuri de modele de eantioane:
ComponentSampleModelJAI utilizat la extragerea pixelilor din
imagini care stocheaz date eantion astfel nct fiecare eantion al
unui pixel ocup un element dat din DataBuffer.
FloatComponentSampleModel stocheaz n eantioane care formeaz
un pixel n n arii de elemente dat separate, toate acestea sunt stocate
n acelai segment a obiectului DataBuffer.
Combinaia dintre un obiect DataBuffer, un obiect SampleModel i un
element origine constituie o unitate de stocare a imaginilor de tip multi-pixel i
este concretizat prin clasa Raster (vezi paragraful 7.3.2.).

7.4.2.2. Tipuri imagine n JAI

JAI API furnizeaz o serie de clase pentru descrierea datelor imagine


de diferite tipuri. Aceste clase sunt organizate ntr-o ierarhie care este expus n
Figura 7.10.
Clasa PlanarImage. Aceast clas este clasa principal pentru
definirea imaginilor bidimensionale. PalnarImage implementeaz interfaa
java.awt.image.RenderedImage, care descrie o imagine segmentat, disponibil
doar pentru citire, cu o dispunere a pixelilor descris de un obiect SampleModel
i unul de tip DataBuffer. Subclasele TiledImage i OpImage manipuleaz
variabilele instan pe care le motenesc de la PlanarImage, cum ar fi mrimea

47
imaginii, originea, dimensiunea segmentului, deplasamentul grilei segmentului,
obiectele de tip Vector care pstreaz sursa i destinaia imaginii.
Toate obiectele care nu aparin JAI de tip RenderedImage, dar care se
utilizeaz n JAI trebuie convertite n PlanarImage prin mijloace oferite de
clasa RenderedImageAdapter i clasa WriteableRenderedImageAdapter.

java.awt.Image

implements
PlanarImage ImageJAI

TiledImage CollectionImage

SnapshotImage ImageSequence

RemoteImage ImageStack

ImageMIPMap

ImagePyramid

Figura 7.10. Ierarhia de tipuri imagine n JAI

Clasa TiledImage. JAI API extinde conceptul de segmentare a datelor


imagine introdus n Java 2D API. n Java 2D, un segment este una dintre
regiunile dreptunghiulare care mparte o imagine ntr-o gril regulat. JAI API
extinde segmentarea imaginilor prin clasa TiledImage.
Un segment (tile) reprezint totalitatea elementelor de stocare pentru o
regiune dintr-o imagine. Dac o imagine este compus din trei benzi, fiecare
segment conine componente din toate cele trei benzi din datele stocate.
Utilizarea imaginilor segmentate mbuntete performana aplicaiei prin
faptul c permite ca aplicaia s proceseze o regiune de imagine dintr-un
segment fr s fie nevoie s aducem ntreaga imagine n memorie.
Clasa TiledImage este o implementare a interfeei WriteableRendered-
Image, beneficiind de avantajul interfeei de a descrie imaginea cu segmente
multiple. Segmentele de tipul WriteableRenderedImage trebuie s mpart un
SampleModel, care determin limea, nlimea i formatul pixelului.

48
Segmentele formeaz o gril regulat care poate s ocupe orice
regiune dreptunghiular din plan. Segmentele de pixeli care depesc limitele
imaginii au valori nedefinite.
Coninutul unui obiect TiledImage este definit de o singur surs
PlanarImage, furnizat fie la momentul construciei fie cu ajutorul metodei set.
Metoda set asigur un mod de suprascriere selectiv a unei poriuni din
TiledImage.
TiledImage suport manipularea direct a pixelilor prin mijloacele
oferite de metoda getWriteableTile. Aceast metod returneaz un
WritableRaster care poate fi modificat direct.
Un alt mod de a modifica coninutul unui TiledImage este apelarea
metodei createGraphics. Aceast metod returneaz un obiect GraphicsJAI
care poate fi folosit pentru desenarea de grafic, text i imagini n manier
AWT.
TiledImage v-a cauza calcularea segmentelor sale doar atunci cnd
coninutul este solicitat. Odat ce un segment este calculat, coninutul su poate
fi eliminat dac se determin c poate fi recalculat n mod identic din surs.
Metoda lockTile foreaz calcularea unui segment i meninerea lui pe durata de
existen a obiectului TiledImage.
Interfaa TileCache. Aceast interfa este o zon cache comun
pentru segmentele calculate deinute de obiectele OpImage. Acest obiect care se
creeaz (de tipul TileCache) are o capacitate dat, msurat n segmente. n
mod implicit, capacitatea unui TileCache este 300 segmente. Capacitatea
implicit a memoriei rezervat pentru un obiect TileCache este 20M bytes.
Un obiect TileCache care va fi utilizat de o operaie anume poate fi
conceput n momentul construciei operaiei, sau printr-un apel la metoda
JAI.setTileCache. Aceasta face ca obiectul TileCache s fie adugat la setul de
indicii de reprezentare.
Interfaa TileScheduler permite segmentelor s fie programate pentru
calculare. n diferite implementri, calcularea segmentului se poate realiza prin
utilizarea de multithreading i conexiuni n reea multiple n mod simultan
pentru a mbunti performana.
Clasa SnapshotImage. Aceast clas reprezint componenta
principal a motorului de execuie amnat. Un SnapshotImage furnizeaz un
numr arbitrar de variante sincrone a unui posibil obiect WritableRendered-
Image care se modific. SnapshotImage este responsabil pentru stabilizarea
surselor care se modific pentru a permite execuia amnat a operaiilor
dependente de astfel de surse.
Orice RenderedImage poate fi utilizat ca surs pentru un Snapshot-
Image. Dac sursa este un WritableRenderedImage, SnapshotImage se va
nregistra ca TileObserver i va face copii pentru segmentele care sunt pe cale
s se modifice.

49
Mai multe versiuni ale fiecrui segment sunt pstrate intern, att timp
ct se cere. SnapshotImage permite monitorizarea acestor cereri i poate s
simplifice urmtoarele cereri pentru segmente, fr s fie nevoie s facem o
copie.
Atunci cnd se utilizeaz ca i surs, apelurile la metoda getTile vor fi
transmise spre surs, cu alte cuvinte obiectele SnapshotImage sunt complet
transparente. Prin apelul createSnapshot o instan a unei subclase
PlanarImage care nu este public va fi creat i returnat. Obiectul
PlanarImage va returna ntotdeauna segmente de imagini cu coninut ca i n
momentul construciei lui.
Clasa RemoteImage. Aceast clas este o subclas a PlanarImage
care reprezint o imagine pe un server distant. Un obiect RemoteImage poate fi
construit dintr-un RenderedImage sau dintr-un lan de procesare a imaginilor
care este fie de tip Rendered, fie Renderable.
Clasa CollectionImage. Aceast clas este o superclas abstract
pentru clasele care reprezint grupuri de imagini. Exemple de grupuri de
imagini sunt piramidele (ImagePyramid), secvenele temporale (TimeSequence)
i feliile plane suprapuse pentru a forma un volum (ImageStack).
Clasa ImageSequence. Aceast clas reprezint o secven de imagini
asociat cu nite indeci temporali i o poziie a camerei, cu scopul de a
reprezenta secvene video sau fotografie dependent de timp.
Imaginile sunt de tipul ImageJAI, indecii temporali sunt de tipul long,
iar poziiile camerei sunt de tipul Point. Acest triplet este reprezentat printr-un
obiect de tipul SequentialImage.
Clasa ImageStack. Clasa ImageStack reprezint o stiv de imagini,
fiecare cu o orientare spaial definit ntr-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 hart MIP este o stiv de
imagini cu o relaie fix ntre feliile adiacente. Fiind dat felia cu cea mai mare
rezoluie, celelalte pot fi obinute prin derivare folosind operaii specifice.
Datele pot fi extrase felie cu felie sau prin iteratori speciali.
O imagine hart MIP (MIP vine din lmba latin multim im parvo
care nseamn multe lucruri n spaii mici) este similar cu o alocare de
textur. La alocarea texturilor, imaginea hart MIP conine versiuni de diferite
mrimi ale aceleiai imagini n aceeai locaie. Pentru utilizarea acestei alocri
a texturilor, trebuie furnizate toate mrimile imaginii n putere de 2 din cea mai
mare imagine la o hart de 1x1.
Clasa ImageMIPMap preia sursa original la cel mai mare nivel de
rezoluie, considerat a fi nivelul 0 i un lan RenderedOp care definete modul

50
n care imaginea de la nivelul de rezoluie imediat inferior este derivat din
nivelul de rezoluie curent.
Lanul RenderedOp poate s aib mai multe operaii, dar prima
operaie din lan trebuie s preia doar o singur imagine surs, care este
imaginea de la nivelul de rezoluie curent.
Clasa ImagePyramid. Aceast clas implementeaz o operaie
piramid (pyramid) asupra unui obiect RenderedImage. Prin aceast clas se
poate genera imagini adiionale prin medierea succesiv a unui bloc de 2x2
pixeli, fiecare dat se elimin toate celelalte coloane i rnduri de pixeli. De
exemplu, pentru o imagine de tip RenderedImage de 1024x1024, vom avea
imagini de 512x512, 256x256 i tot aa pn la 1x1.
n practic, imaginile de rezoluie mai mic pot fi derivate prin
execuia unui lan de operaii n mod repetat care subeantioneaz felia de
imagine cu rezoluie mai mare. n mod similar, odat ce o felie de imagine este
obinut, feliile de imagine cu rezoluia mai mare pot fi derivate prin execuia
unui alt lan de operaiuni n mod repetat care supraeantioneaz felia de
imagine cu rezoluia mai mic. De asemenea, un al treilea lan de operaii poate
fi folosit pentru gsirea diferenelor dintre felia original a imaginii i felia
rezultat obinut prin prima subeantionare apoi supraeantionnd felia
original.
Clasa MultiResolutionRenderableImage. Aceast clas produce
reprezentri bazate pe un set de obiecte RenderedImage de diferite rezoluii.
Obiectul este construit dintr-o dimensiune specificat i un vector de obiecte
RenderdImage care reprezint imagini cu rezoluii progresiv mai mici.

7.4.2.3. Streamuri

JAI API extinde tipurile de streamuri din Java prin adugarea de apte
clase de tip stream seekable (vezi Figura 7.11.). Tabelul 7.14. descrie pe
scurt fiecare dintre aceste noi clase.

InputStream

implements
SeekableStream DataInput

File ByteArray Segmented Forward FileCache MemoryCache


Seekable Seekable Seekable Seekable Seekable Seekable
Stream Stream Stream Stream Stream Stream

Figura 7.11. Clasele stream din JAI 51


Noile clase de tip seekable sunt utilizate pentru aducerea n avans (n
cache) a datelor imagine care sunt citite, metodele lor pot fi folosite la cutarea
prin date napoi sau nainte fr a fi nevoie s recitim datele. Acest lucru este
important pentru tipuri de date imagine care sunt segmentate sau nu pot fi
recitite uor pentru a localiza o anume informaie important.

Clasa Descriere
SeekableStream Clas abstract care combin funcionalitile lui
InputStream i RandomAccessFile, cu abilitile
de a citi tipuri de date primitive n format little-
endian.
FileSeekableStream Furnizeaz funcionalitate SeekableStream
asupra datelor stocate ntr-un obiect File
ByteArraySeekable Implementeaz funcionalitate SeekableStream
Stream asupra datelor stocate ntr-o arie de bytes
SegmentedSeekable Furnizeaz informaii despre un subset al altui
Stream SeekableStream care conine o serie de segmente
cu o poziie de start dat n fluxul sursei i
lungime. Fluxul rezultat se comport ca i un
SeekableStream obinuit.
ForwardSeekable Furnizeaz funcionalitate SeekableStream
Stream asupra datelor dintr-un InputStream cu adugare
de date minim, dar nu permite cutri napoi.
Poate fi utilizat cu formate de intrare care
suport streaming, evitnd nevoia de a aduce n
avans (cache) datele de intrare.
FileCacheSeekable Furnizeaz funcionalitate SeekableStream
Stream asupra datelor dintr-un InputStream cu adugare
de date minim, dar nu permite cutri napoi.
Poate fi utilizat cu formate de intrare care
suport streaming, evitnd nevoia de a aduce n
avans (cache) datele de intrare. n circumstanele
n care nu permit crearea unui fiier temporar (de
exemplu, datorit securitii sau absena unui
disc local), poate fi utilizat MemoryCache-
SeekableStream.
MemoryCache Furnizeaz funcionalitate SeekableStream

52
SeekableStream asupra datelor dintr-un InputStream, folosind un
cache n memorie pentru a permite cutarea
napoi. Aceast clas se utilizeaz atunci cnd
securitatea sau lipsa accesului la un disc local nu
poate fi fcut cu FileCacheSeekableStream.
Tabelul 7.14. Clasele stream din JAI

Pentru a citi date imagine dintr-un fiier este nevoie de abilitatea de


cutare nainte i napoi prin date i de a citi informaiile care descriu imaginea.
Cea mai bun cale pentru a face datele s poat fi cutate este printr-un cache,
un fiier temporar stocat pe discul local sau n memorie. Cea mai preferat
metod de a stoca datele este discul local, dar nu ntotdeauna este posibil. Din
motive de securitate, sau la sistemele fr disc, crearea unui fiier cache pe disc
nu este ntotdeauna permis. Atunci cnd un fiier cache nu este permis, se
poate utiliza un cache n memorie.
Clasa SeekableStream permite cutarea n datele de intrare, n mod
similar cu clasa RandomAccessFile. Interfaa DataInput este suportat i
extins pentru a include suport pentru reprezentare little-endian a tipurilor de
date fundamentale.
SeekableStream adaug cteva metode read la cele existente din clasa
java.io.DataInput, incluznd metode pentru citirea datelor n ordine little-
endian, deoarece n Java toate valorile sunt scrise n stilul big-endian. Cu toate
acestea, JAI necesit metode pentru citirea de date care nu sunt produse de
Java, date care sunt produse pe alte platforme i care sunt n stilul little-endian.
Pe lng metodele obinuite furnizate de clasa InputStream, clasa
RandomAccessFile implementeaz metodele getFilePointer i seek. Metoda
canSeekBackwards returneaz true dac este posibil cutarea napoi n stream
fa de valoarea curent obinut cu metoda getFilePointer.
Exist cteva subclase ale SeekableStream care se gsesc n pachetul
com.sun.media.jai.codec. Trei clase sunt furnizate cu scopul de adaptare a unui
obiect standard InputStream la interfaa SeekableStream. Clasa Forward-
SeekableStream nu permite cutarea napoi, dar este foarte performant. Clasa
FileCacheSeekableStream menine o copie a tuturor datelor citite de la intrare
ntr-un fiier temporar. Acest fiier va fi eliminat automat atunci cnd
FileSeekableStream este finalizat, sau cnd JVM iese din program n mod
normal.
Clasa FileCacheSeekableStream are scopul de a fi eficient n limite
rezonabile n relaie cu utilizarea spaiului de pe disc. Atunci cnd crearea unui
fiier temporar nu este posibil, se folosete clasa MemoryCacheSeekable-
Stream. Aceast clas creeaz un bufer foarte mare n memorie pentru a stoca
datele din stream i este de preferat s fie evitat. Clasa FileSeekableStream

53
acoper clasa File sau clasa RandomAccessFile i execut o operaie limitat de
aducere n avans a datelor (caching) pentru a evita operaiile I/O prea dese.
Metoda wrapInputStream este furnizat pentru a construi o instan
potrivit a SeekableStream a crui date sunt furnizate de un InputStream dat.
Cel care apeleaz, prin mijloace ale parametrului canSeekBackwards, determin
dac este necesar suportul pentru cutri n urm.

7.4.2.4. Citirea fiierelor imagine

Arhitectura de codare JAI este compus din codoare i decodoare


capabile de a citi i scrie cteva formate de fiiere imagine rastru.
Exist mai multe formate de fiiere imagine rastru, cele mai multe
dintre ele au fost create pentru a suporta stocarea i interschimbarea imaginilor.
Unele formate au ajuns s fie utilizate pe scar larg i sunt considerate
standarde de facto. Alte formate, care sunt foarte importante pentru anumii
vendori software, sunt mai puin utilizate.
JAI suport n mod direct cteva dintre cele mai utilizate formate de
fiiere imagine (listate n Tabelul 7.15.). Pentru alte formate, se pot aduga noi
codoare de fiiere, pe baza arhitecturii de extindere a JAI API.
Un fiier imagine are n mod obinuit cel puin dou pri: un header
de fiier i datele imagine. Headerul conine cmpuri cu informaii despre
datele imagine care urmeaz. Acest header trebuie s furnizeze toate
informaiile necesare pentru reconstrucia imaginii originale din datele imagine
stocate. Datele imagine pot sau nu s fie comprimate.

Numele formatului Descriere


de fiier
BMP Fiier imagine de tip Microsoft Windows bitmap
FPX Format FlashPix
GIF Format Graphics Interchange Format
JPEG Format de fiier imagine dezvoltat de Joint
Photographic Experts Group
PNG Format Portable Network Graphics
PNM Format de fiier Portable aNy Map. Include
formatele PBM, PGM i PPM.
TIFF Format de fiier imagine Tag Image File Format
Tabelul 7.15. Formate de fiiere imagine suportate de JAI

Principala clas pentru decodarea i codarea imaginilor este


ImageCodec. Subclasele acestei clase pot s execute recunoaterea unui format
de fiier fie prin inspecia a unui header de lungime fix sau prin accesul
arbitrar la streamul de date surs. Fiecare subclas ImageCodec implementeaz

54
una din cele dou metode de recunoatere a fiierelor imagine. Codecul la
nceput apeleaz metoda getNumHeaderBytes, care fie returneaz 0 dac
accesul arbitrar la stream este necesar, sau returneaz numrul de bytes din
header necesari pentru a recunoate formatul. n funcie de ce returneaz
metoda getNumHeaderBytes, codorul citete streamul sau headerul.
Odat ce codecul a determinat formatul de imagine, prin metoda citirii
streamului sau cea a headerului, el returneaz numele codecului asociat cu
formatul de imagine detectat. Dac nu este nregistrat nici un codec cu acel
nume, se returneaz null. Numele codecului definete subclasa care este
apelat, care decodeaz imaginea.
Pentru cele mai multe tipuri de imagine, JAI ofer opiunea de a citi
fiierul cu date imagine ca obiect java.io.File sau ca una din subclasele de tipul
java.io.InputStream.
JAI ofer civa operatori de fiier pentru citirea fiierelor cu date
imagine, listai n Tebelul 7.16.

Operator Descriere
AWTImage Import o imagine AWT standard n JAI
BMP Citete date BMP dintr-un stream de intrare
FileLoad Citete o imagine dintr-un fiier
FPX Citete date FlashPix dintr-un stream de intrare
FPXFile Citete un fiier standard FlashPix
GIF Citete date GIF dintr-un stream de intrare
JPEG Citete un fiier standard JPEG (JFIF)
PNG Citete un stream de intrare PNG
PNM Citete un fiier standard PNM, inclusiv imagini
PBM, PGM i PPM n format ASCII sau brut.
Stream Citete obiecte de tip java.io.InputStream
TIFF Citete date TIFF 6.0 dintr-un stream de intrare.
URL Creeaz o imagine surs care este specificat de un
URL
Tabelul 7.16. Operatori pentru fiiere imagine

n exemplul urmtor (Exemplul 7.15.) se prezint cteva fragmente de


program n care se exemplific utilizarea diferiilor operatori pentru fiiere.

Exemplul 7.15. Utilizarea diferiilor operatori pentru fiiere


// exemplu operaie stream
// ncrcarea imaginii surs dintr-un stream
RenderedImage im = JAI.create("stream", stream);
...

55
// exemplu de operaie fileload
// ncarc imaginea surs dintr-un fiier
RenderedImage src = (RenderedImage)JAI.create("fileload", fileName)
...
// exemplu de citire a unei imagini FPX
// specific numele fiierului
File file = new File(filename);
// specific rezoluia fiierului
ImageDecodeParam param = new FPXDecodeParam(resolution);

// creeaz operaia FPX pentru citirea fiierului.


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
// acoper un obiect InputStream dintr-un SeekableStream.
InputStream is = new FileInputStream(filename);
SeekableStream s = SeekableStream.wrapInputStream(is,
false); // creeaz obiectul ParameterBlock i este adugat
SeekableStream.
ParameterBlock pb = new ParameterBlock();
pb.add(s);
// execut operaia BMP
op = JAI.create("BMP", pb);
...
// exemplu de citire a fiierelor imagine PNG
// crearea obiectului ParameterBlock.
InputStream image = new FileInputStream(filename);
ParameterBlock pb = new ParameterBlock();
pb.add(image);
// creeaz operaia PNG.
op = JAI.create("PNG", pb);
...
// exemplu de citire a fiierelor imagine PNM
// creeaz obiectul ParameterBlock.
InputStream image = new FileInputStream(filename);
ParameterBlock pb = new ParameterBlock();
pb.add(image);

56
// creeaz operaia PNM
op = JAI.create("PNM", pb);
...
// exemplu de citire a unei imagini AWT
// creeaz ParameterBlock.
ParameterBlock pb = new ParameterBlock();
pb.add(image);
// creeaz o operaie AWTImage.
PlanarImage im = (PlanarImage)JAI.create("awtImage", pb);
...
// exemplu de citire a unei imagini de tip URL
// definete o imagine URL.
url = new URL("http://www/img/k.gif");
// citete imaginea de la URL-ul specificat.
RenderedOp src = JAI.create("url", url);

7.4.2.5. Reformatarea imaginilor

Operaia Format reformateaz o imagine printr-o operaie cast asupra


pixelilor unei imagini, la un anumit tip de dat, nlocuind obiectele
SampleModel i ColorModel a unei imagini i restructurnd stilul de gril de
segmente. Valorile pixelilor din imaginea destinaie sunt definite de urmtorul
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 ieire SampleModel, ColorModel i stilul grilei de
segmente sunt specificate prin transmiterea unui obiect ImageLayout ca i
RenderingHint numit ImageLayout. Atunci cnd este posibil, imaginea de ieire
va avea un SampleModel compatibil cu acel specificat n indiciul de
reprezentare. Pentru tipurile de datele de ieire float i double va fi folosit un
obiect ComponentSampleModel cu privire la valoarea parametrului hint.

7.4.2.6. Conversia unei imagini Rendered n Renderable

Pentru a utiliza un DAG de tip Renderable cu un tip de imagine non-


Renderable, imaginea trebuie mai nti convertit din tipul Rendered n tipul

57
Renderable. De exemplu, pentru a folosi o imagine obinut de la un server
distant ntr-un lan Renderable, trebuie tratat imaginea surs ca i
RenderedImage, apoi convertit la RenderableImage pentru urmtoarele
procesri.
Operaia Renderable produce un obiect RenderableImage dintr-o surs
RenderedImage. Obiectul RenderableImage care este produs este format dintr-o
piramid de obiecte RenderedImage la rezoluii progresiv mai mici. Imaginile
cu rezoluiile mai mici sunt produse prin invocarea lanului de operaii
specificat prin parametrul downSampler asupra imaginii de la nivelul de
rezoluie imediat superior al piramidei. Lanul de operaii downSampler trebuie
s adere la specificaiile descrise pentru constructorii clasei ImageMIPMap,
care accept acest tip de parametru.
Numrul de nivele din piramid va fi astfel nct cea mai mare
dimensiune (lime sau nlime) a nivelului de piramid cu cea mai mic
rezoluie s fie mai mic sau egal cu valoarea parametrului maxLowResDim,
care trebuie s fie pozitiv. Valoarea implicit pentru maxLowResDim este 64,
ceea ce nseamn c nivelul de piramid cu rezoluia cea mai mic va fi
imaginea cu dimensiunea cea mai mare egal cu 64 pixeli sau mai mic.
Parametrii operaiei Renderable sunt descrii n Tabelul 7.17.

Parametru Tip Descriere Valoare


implicit

downSamples RenderedO Lanul de operaii utilizat Filtru
p pentru derivarea imaginilor trece jos
cu rezoluie mai mic
maxLowResDi Integer Dimensiunea maxim a 64
m nivelului de piramid cu
rezoluia cea mai mic.
minX Float Coordonata independent de 0.0F
reprezentare X minim a
destinaiei
minZ Float Coordonata independent de 0.0F
reprezentare Y minim a
destinaiei
height Float nlimea independent de 1.0F
reprezentare
Tabelul 7.17. Parametrii operaiei Renderable

58
Exemplul 7.16. demonstreaz o operaie Renderable. Valorile
implicite sunt folosite pentru toi cei cinci parametrii ai operaiei. Rezultatul
operaiei poate fi transmis la urmtoarea operaie din graf.

Exemplul 7.16. Convertirea unui RenderedImage la Renderable


// deriv obiectul RenderableImage din sursa RenderedImage.
ParameterBlock pb = new ParameterBlock();
pb.addSource(src);
pb.add(null).add(null).add(null).add(null).add(null);
// creeaz operaia Renderable.
RenderableImage ren = JAI.createRenderable("renderable", pb);

7.4.2.7. Crearea unei imagini constante

Operaia constant definete o imagine Rendered multi-band i


segmentat, unde toate valorile pixelilor din aceeai band au valoare
constant. Numrul de benzi a imaginii este determinat de numrul de valori de
pixeli constani furnizai ca parametrii. Tipul de dat este determinat de tipul
constantei din prima intrare.
Exemplul urmtor (Exemplul 7.17.) ilustreaz o operaie constant.

Exemplul 7.17. Program pentru citirea i afiarea unui fiier


imagine
// creeaz obiectul ParameterBlock.
Byte[] bandValues = new Byte[1];
bandValues[0] = alpha1;
pb = new ParameterBlock();
pb.add(new Float(src1.getWidth())); // limea
pb.add(new Float(src1.getHeight())); // nlimea
pb.add(bandValues); // valorile benzilor
// creeaz operaia constant.
PlanarImage afa1 = (PlanarImage)JAI.create("constant", pb);

7.4.2.8. Afiarea imaginilor

JAI utilizeaz modelul BufferedImage din Java2D pentru a afia


imaginile. Clasa BufferedImage gestioneaz o imagine n memorie i furnizeaz
modaliti de stocare a datelor pixel, interpreteaz datele pixel i reprezint
datele pixel la un context Graphics2D.

59
Afiarea imaginilor n JAI poate fi fcut prin mai multe moduri.
Pentru nceput, apelul metodei drawRenderedImage asupra obiectului
Graphics2D poate fi folosit pentru a produce o reprezentare imediat. O alt
metod este instanierea unei componente de afiare care rspunde la cererile
utilizatorului cum ar fi derularea sau translatarea i de asemenea expunerea
evenimentelor i obinerea datelor imagine dintr-o surs RenderedImage.
Aceast tehnic permite ca datele imagine s fie calculate la cerere.
Pentru acest scop JAI furnizeaz o component de afiare, disponibil
n pachetul javax.media.jai.widget, numit ScrollingImagePanel. Aceast clas
preia un obiect RenderedImage i o lime i nlime specific i creeaz un
panou cu bare de derulare, iar imaginea este aezat n centrul panoului.
Odat ce ScrollingImagePanel este creat, acesta poate fi aezat
oriunde ntr-un Frame, la fel ca i orice alt panou din AWT. Exemplul 7.18.
demonstreaz utilizarea unui astfel de panou.

Exemplul 7.18. Exemplu de utilizare a unui ScrollingImagePanel


// preia nlimea i limea imaginii
int width = image.getWidth();
int height = image.getHeight();
// ataeaz imaginea la panoul derulabil pentru afiare.
ScrollingImagePanel panel = new ScrollingImagePanel(
image, width, height);
// creeaz un obiect Frame care va conine 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 ntr-o suprafa de desenare (canvas).
Aceast clas motenete metode de la java.awt.Component, permind
folosirea acelorai metode la tratarea evenimentelor pentru tastatur i mouse,
ca i la clasa Canvas.
Clasa ImageCanvas este o component de afiare simpl pentru un
RenderedImage i poate fi utilizat n orice context n care este nevoie de un
Canvas. Clasa ImageCanvas monitorizeaz evenimentele de redimensionare i
remprosptare i la nevoie cere n mod automat segmente de la sursa sa.

7.4.2.9. Spaii de culoare JAI

JAI utilizeaz trei clase de baz pentru gestiunea culorilor:

60
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 i furnizeaz informaia necesar
pentru a interpreta corect valorile pixelilor. Aceast clas este definit
n pachetul java.awt.image.
ColorSpace reprezint un sistem pentru msurarea culorilor, n mod
obinuit folosind trei valori sau componente separate. Clasa
ColorSpace conine metode pentru conversia ntre spaiul de culoare
original i una sau dou spaii de culoare standard, CIEXYZ i RGB.
Aceast clas este definit n pachetul java.awt.color.
Color reprezint o culoare fix, definit prin componentele sale ntr-
un obiect ColorSpace. Aceast clas este definit n 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
spaiu de culoare particular.
Extragerea componentelor pixelului din datele pixel mpachetate.
Obinerea de componente multiple dintr-o singur band folosind
mti.
Conversia datelor pixel printr-un tabel de cutare.
Pentru a determina valoarea culorii a unui pixel particular dintr-o
imagine, trebuie cunoscut modul n care informaia de culoare este codat n
fiecare pixel. Obiectul ColorModel asociat unei imagini ncapsuleaz datele i
metodele necesare pentru translatarea valorii unui pixel spre i de la
componentele sale de culoare constituente.
JAI suport cinci modele de culoare:
DirectColorModel lucreaz cu valorile pixelilor care reprezint
informaie despre culori RGB i canal alfa ca i eantioane separate i
mpacheteaz toate eantioanele pentru un singur pixel ntr-un singur
int, short, sau byte. Aceast clas poate fi utilizat doar cu spaii de
culoare de tipul ColorSpace.TYPE_RGB.
IndexColorModel lucreaz cu valorile pixelilor care reprezint un
singur eantion care este un index ntr-o hart de culori fix n spaiul
de culoare RGB implicit. Harta de culori specific componentele de
rou, verde, albastru i opional alfa corespunztoare pentru fiecare
index.
ComponentColorModel poate s manevreze un obiect arbitrar
ColorSpace i o arie de componente de culoare pentru a se potrivi cu
spaiul de culoare. Acest model poate fi folosit pentru a reprezenta cele
mai utilizate modele culoare pe cele mai utilizate dispozitive grafice
(GraphicsDevice).

61
PackedColorModel clas de baz pentru modele care reprezint
valorile pixelilor n care sunt ncorporate componentele de culoare n
mod direct n biii unui pixel ntreg. Un astfel de obiect stocheaz
informaia de mpachetare care descrie modul n care componentele de
culoare i alfa sunt extrase din canal. Obiectele DirectColorModel sunt
de tipul PackedColorModel.
FloatDoubleColorModel lucreaz cu valorile pixelilor care reprezint
informaie de culoare i alfa ca i eantioane separate, folosind
elemente float i double.
Urmtorul exemplu (Exemplul 7.19.) prezint construcia unui obiect
ComponentColorModel pentru un model de culoare RGB.

Exemplul 7.19. Crearea unui model de culoare RGB


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

Cantitatea de transparen a unei imagini este specificat de valoarea


alfa. O valoare alfa de 0.0 specific o transparen total, iar o valoare alfa de
1.0 specific o opacitate total.
Imaginile pot s transporte informaie de transparen, cunoscut sub
denumirea de canal alfa, pentru fiecare pixel din imagine. Valoarea alfa este
important atunci cnd culorile se suprapun. Valoarea alfa specific ct de mult
din culoarea reprezentat anterior trebuie s fie afiat.

7.4.3. Procesarea imaginilor folosind JAI

Procesarea imaginilor utiliznd JAI API cuprinde operaii de


manipulare, mbuntire, transformare geometric i analiz a imaginilor.

7.4.3.1. Manipularea imaginilor

Obiectele i metodele JAI pentru manipularea imaginilor sunt utilizate


pentru mbuntire i modificare geometric a imaginilor i pentru a extrage
informaie din imagini. Manipularea imaginilor cuprinde:
Controlul regiunilor de interes ROI (Region of Interest)
Operatori relaionali
Operatori logici

62
Operatori aritmetici
Efect de vibraie (dithering)
Fixarea (clamping) valorilor pixelilor
Copierea benzilor

Controlul regiunilor de interes. De obicei, orice mbuntire a unei


imagini se produce asupra ntregii imagini. Dar operaia de mbuntire a
imaginii poate s mbunteasc poriuni dintr-o imagine, celelalte poriuni ale
imaginii pot s piard detalii, de aceea operaia de mbuntire trebuie limitat
la o regiune specific a imaginii.
Pentru a restriciona operaia de mbuntire a imaginii la o regiune
specific din imagine, se creeaz o masc regiune de interes. O regiune de
interes (Region of Interest - ROI) este conceptual o masc de valori true sau
false. Masca ROI controleaz care pixel surs din imagine trebuie procesat i
care pixel destinaie trebuie nregistrat.
JAI suport dou tipuri diferite de mti ROI: masc boolean i
valoare de prag. Clasa ROIShape utilizeaz o masc boolean, care permite
efectuarea de operaii rapid i folosind moduri de stocare compacte. Clasa ROI
permite specificarea unei valori de prag, valorile pixelilor mai mari sau egale cu
o valoare de prag sunt incluse n ROI. Valorile pixelilor mai mici dect valoarea
pragului sunt excluse din ROI.
Regiunea de interes este definit de cele mai multe ori folosind un
obiect ROIShape, care stocheaz aria folosind clase java.awt.Shape. Aceste
clase definesc o arie ca i o descriere geometric a conturului ei. Clasa ROI
stocheaz o arie ca i o imagine cu o singur band.
Un ROI poate fi ataat unei imagini ca i proprietate.
Operatori relaionali. Operatorii relaionali ai JAI permit efectuarea
urmtoarelor operaii, folosind dou imagini surs i o imagine destinaie:
Gsirea pixelilor celor mai mari din dou imagini surs i stocarea
rezultatelor n destinaie (Max).
Gsirea pixelilor celor mai mici din dou imagini surs i stocarea
rezultatelor n destinaie (Min).
Operatorii relaionali necesit ca amndou imaginile surs i
destinaie s aib acelai tip de dat i numr de benzi. Mrimea celor dou
imagini (nlimea i limea), nu trebuie s fie neaprat la fel.
Atunci cnd se determin maximul i minimul pixelilor n dou
imagini, JAI execut o comparare band cu band.
Operatori logici. JAI suport operatori logici monadici, diadici i
unari. Operatorii logici monadici includ operaii pixel-cu-pixel AND, OR i
XOR ntre o imagine surs i o constant pentru a produce o imagine destinaie.
Operaiile logice diadice includ operaii pixel-cu-pixel AND, OR i XOR ntre
dou imagini surs pentru a produce o imagine destinaie. Operaia logic unar

63
este operaia NOT (complementare imagine) asupra fiecrui pixel a unei
imagini surs pe baza benzilor.
JAI suport urmtoarele operaii logice:
And preia rezultatul unei operaii pe bii AND asupra a dou
imagini surs i stocheaz rezultatul ntr-o destinaie.
AdConst preia rezultatul unei operaii pe bii AND asupra unei
imagini surs i a unei constante dintr-un set al benzilor.
Or - preia rezultatul unei operaii pe bii OR asupra a dou imagini
surs i stocheaz rezultatul ntr-o destinaie.
OrConst - preia rezultatul unei operaii pe bii OR asupra unei
imagini surs i a unei constante dintr-un set al benzilor.
Xor - preia rezultatul unei operaii pe bii XOR asupra a dou
imagini surs i stocheaz rezultatul ntr-o destinaie.
XorConst - preia rezultatul unei operaii pe bii XOR asupra unei
imagini surs i a unei constante dintr-un set al benzilor.
Not - preia rezultatul unei operaii pe bii NOT asupra fiecrui pixel
din benzi a unei imagini surs.
Asemenea operatorilor relaionali, operatorii logici necesit ca
amndou imaginile surs i imaginea destinaie s aib acelai tip de dat i
numr de benzi. Mrimea celor dou imagini (nlime i lime) poate s
difere.
Operatori aritmetici. JAI suport operatori aritmetici monadici i
diadici. Operaiile aritmetice monadice includ adunarea pe band, scderea,
divizarea i multiplicarea ntre o imagine surs i o constant pentru a produce
o imagine destinaie. Operaiile aritmetice diadice includ adunarea pe band,
scderea, divizarea i multiplicarea ntre dou imagini surs pentru a produce o
imagine destinaie.
JAI suport urmtorii operatori aritmetici:
Add adunarea a dou imagini surs i stocarea rezultatului n
imaginea destinaie
AddConst adunarea unei valori constante la pixelii dintr-o imagine
surs i stocarea rezultatelor ntr-o imagine destinaie.
AddCollection adun o colecie de imagini i stocheaz rezultatele
ntr-o imagine destinaie.
AddConstToCollection adun o arie de constante double la o
colecie de imagini Rendered.
Substract scade o imagine surs din alta i stocheaz rezultatele
ntr-o imagine destinaie.
SubstractConst scade o valoare constant din pixelii unei imagini
surs i stocheaz rezultatele ntr-o imagine destinaie.
Divide mparte o imagine surs cu alta i stocheaz rezultatele
ntr-o imagine destinaie.

64
DivideComplex mparte dou imagini surs cu date complexe i
stocheaz rezultatele ntr-o imagine destinaie.
DivideByConst mparte o imagine surs cu o valoare constant.
Multiply nmulete dou imagini surs i stocheaz rezultatele
ntr-o imagine destinaie.
MultiplyConst nmulete o imagine surs cu o valoare constant.
MultiplyComplex nmulete dou imagini reprezentnd date
complexe.
Absolute gsete valoarea absolut a pixelilor ntr-o imagine surs
i stocheaz rezultatele ntr-o imagine destinaie.
Exp preia exponentul unei imagini i stocheaz rezultatele ntr-o
imagine destinaie.
Asemenea operatorilor relaionali i logici, operatorii aritmetici
necesit ca amndou imaginile surs i destinaie s aib acelai tip de dat i
numr de benzi. Mrimea celor dou imagini (nlime i lime) poate s
difere.
Atunci cnd JAI adun dou imagini, preia valoarea de la locaia 0,0
dintr-o imagine surs, adun la valoarea de la locaia 0,0 din cea de-a doua
imagine surs i scrie suma n imaginea destinaie la locaia 0,0. Pentru toate
celelalte puncte din imagine se procedeaz la fel. Scderea, nmulirea i
mprirea sunt tratate n mod similar.
Operaiile aritmetice asupra imaginilor cu mai multe benzi se execut
pe benzile corespunztoare din imaginile surs.
Efect de vibraie (dithering). Afiarea unei imagini color de 24 bii pe
un bufer cadru de 8 bii necesit o operaie numit dithering. Aceast operaie
comprim cele trei benzi ale unei imagini RGB la o imagine byte cu o singur
band.
Operaia dithering utilizeaz un tabel de cutare prin care imaginea
surs este trecut pentru a produce imaginea destinaie. Cea mai utilizat
facilitate ale acestei operaii este conversia imaginilor true-color (byte cu trei
benzi) n imagini pseudocolor (byte cu o singur band).
Fixarea (clamping) valorilor pixelilor. Operaia clamp restricioneaz
intervalul valorilor pixelilor pentru o imagine surs prin restrngerea
intervalului pixelilor la valori low i high definite. Operaia preia o imagine
surs Rendered sau Renderable i seteaz toi pixelii a cror valoare este sub o
valoare inferioar la acea valoare inferioar i toi pixelii a cror valoare este
peste o valoare superioar la acea valoare superioar. Pixelii a cror valoare
este ntre valoarea inferioar i valoarea superioar sunt lsai nemodificai.
Copierea benzilor. Operaia BandSelect alege N benzi din o imagine
surs Rendered sau Renderable i copiaz datele pixelilor ale acestor benzi la
imaginea destinaie n ordinea specificat.

65
7.4.3.2. mbuntirea imaginilor

mbuntirea imaginilor prin operaii JAI cuprinde urmtoarele:


Adugare de borduri
Decuparea unei imagini
Rescalare de amplitudine
Egalizare de histogram
Modificare prin tabele de cutare
Filtrare prin convoluie
Filtrare median
Procesare n domeniul frecven
Procesare punctual
Binarizare (threshold)

Rescalare de amplitudine. Rescalarea de amplitudine reprezint o


transformare liniar a valorilor pixelilor de intrare la valorile pixelilor de ieire.
Aceast operaie poate fi folosit pentru mbuntirea imaginilor care au
contrast insuficient ntre valorile cele mai luminoase i cele mai ntunecoase,
cum ar fi cele cauzate prin subexpunerea sau supraexpunerea imaginii
originale.
Egalizarea de histogram. O histogram a unei imagini este un
instrument analitic utilizat pentru a msura distribuia amplitudinilor pixelilor
dintr-o imagine. Prin analizarea distribuiei amplitudinilor pixelilor, se poate
obine informaii despre apariia vizual a imaginii. O imagine cu contrast mare
conine o distribuie larg a contorizrilor pixelilor acoperind ntregul interval
de amplitudini. O imagine cu contrast mic are cele mai multe dintre
amplitudinile pixelilor adunate ntr-un spaiu relativ ngust.
Exemplul urmtor (Exemplul 7.20.) demonstreaz crearea unui obiect
histogram i o operaie de egalizare de histogram folosind acest obiect.
Operaia de egalizare de histogram se realizeaz utiliznd operatorul
MatchCDF.

Exemplul 7.20. Operaie de egalizare de histogram


PlanarImage img; // imaginea surs

// obine histograma pentru imagine.


int binCount=256;
// obine numrul de benzi
int numBands = img.getSampleModel().getNumBands();
// Aloc memorie pentru histogram
int[] numBins = new int[numBands];

66
double[] lowValue = new double[numBands];
double[] highValue = new double[numBands];
for(int i = 0; i < numBands; i++) {
numBins[i] = binCount;
lowValue[i] = 0.0;
highValue[i] = 255.0;
}
// creeaz un obiect Histogram.
Histogram hist = new Histogram(numBins, lowValue, highValue);
ROIShape roi;
if(frame.isGotSelected())// specific ROI
roi = frame.getSelection();
else
roi = new ROIShape(img.getBounds());
// creeaz o operaie histogram.
RenderedOp histImage = JAI.create("histogram", img, hist, roi,
new Integer(1), new Integer(1));
// creeaz un CDF (cumulative distribution function) pentru egalizare
float[][] CDFeq = new float[numBands][];
for(int b = 0; b < numBands; b++) {
CDFeq[b] = new float[binCount];
for(int i = 0; i < binCount; i++) {
CDFeq[b][i] = (float)(i+1)/(float)binCount;
}
}
// creeaz o imagine cu histograma egalizat
frame.setImage(JAI.create("matchcdf", histImage, CDFeq, roi));

Modificare prin tabele de cutare. Modificarea prin tabele de


cutare (lookup table) furnizeaz o transformare de amplitudine neliniar.
Transformrile de amplitudine neliniare sunt utile dac avem o diferen de
rspuns neliniar a amplitudinii dintre un senzor care captureaz datele imagine
i afiare.
Mecanismul de modificare prin tabela de cutare permite conversia
arbitrar ntre imaginea surs cu valorile pixelilor de tipul byte, short, sau
integer i una sau mai multe valori de ieire ale pixelilor. Valoarea de ieire a
pixelului imagine poate s fie byte, short, integer, float, sau double.
Valoarea de intrare a pixelului de intrare se comport ca i o adres n
intrarea n tabela de cutare (vezi Figura 7.12.). Fiecare locaie din tabela de
Tabela de
cutare stocheaz valoarea de ieire dorit
cutare pentru o adres particular.

Imagine Adres Date Imagine


Surs Ieire Destinaie

67

Figura 7.12. Principiul tabelei de cutare


Tabela de cutare este la nceput ncrcat cu datele necesare. Tabelul
7.18. definete o list parial dintr-un exemplu de tabel de cutare.
n acest exemplu, valorile de intrare variaz ntre 0 i 255. Valorile de
ieire furnizeaz o transformare ntre intrare i ieire, conform cu urmtoarea
ecuaie:
iesire 255 intrare

Intrare Ieire
0 0
1 16
2 23
3 28
... ...
253 254
254 255
255 255
Tabelul 7.18. Exemplu de tabel de cutare

Exemplul 7.21. este un fragment de cod care ilustreaz construcia i


utilizarea unei tabele de cutare.

Exemplul 7.21. Utilizarea tabelei de cutare


PlanarImage image; // imaginea surs
private byte lut[][];
private byte newlut[][];
private int brightness = 0;
...
lut = new byte[3][256];
newlut = new byte[3][256];

68
int i;
// iniializarea tabelei de cutare
for ( i = 0; i < 256; i++ ) {
lut[0][i] = (byte)i;
lut[1][i] = (byte)0;
lut[2][i] = (byte)0;
}
for ( i = 0; i < 256; i++ ) {
int red = (int)lut[0][i]&0xFF;
int green = (int)lut[1][i]&0xFF;
int blue = (int)lut[2][i]&0xFF;
newlut[0][i] = clamp(red + brightness);
newlut[1][i] = clamp(green + brightness);
newlut[2][i] = clamp(blue + brightness);
}
// creeaz tabela de cutare
LookupTableJAI lookup = new LookupTableJAI(newlut);
ParameterBlock pb = new ParameterBlock();
pb.addSource(image);
pb.add(lookup);
// aplic operaia de cutare n tabel
PlanarImage dst = JAI.create("lookup", pb, null);
}
...
final private byte clamp(int v) {
if ( v > 255 ) {
return (byte)255;
} else if ( v < 0 ) {
return (byte)0;
} else {
return (byte)v;
}
}

Filtrare prin convoluie. Filtrarea prin convoluie este utilizat pentru


a reduce efectele de zgomot din imagini ori pentru a accentua detaliile din
imagini. Aceast filtrare este o form de filtrare spaial care calculeaz fiecare
eantion de ieire prin nmulirea elementelor unui nucleu cu eantioanele
ncunjurtoare a unui eantion surs.
Operaiile de filtrare prin convoluie se realizeaz n JAI cu ajutorul
operatorului convolve.

69
Filtrarea median. Un filtru median este utilizat pentru a elimina
zgomotul de impuls din imagine i de a netezi imaginea.
Efectul de reducere a zgomotului pe care l are filtrul median asupra
imaginii depinde de extinderea spaial a vecintii (masca) i numrul de
pixeli implicai n procesare. Operaia MedianFilter suport trei forme de mti
diferite: ptrat, plus i form de X.

7.4.3.3. Manipularea geometric a imaginilor

Modificrile geometrice ale imaginii include urmtoarele:


Transformarea geometric
Transformarea de perspectiv
Transpunerea
Shear
Rsucire
Civa dintre operaiile de manipulare geometric a imaginii, cum ar fi
Affine, Rotate, Scale, Shear, Translate i Warp, utilizeaz o transformare
geometric pentru a calcula coordonatele punctului dintr-o imagine surs pentru
fiecare pixel destinaie din imagine. n cele mai multe cazuri, pixelul destinaie
nu se afl la locaia pixelului surs, dar se afl undeva printre pixelii vecini.
Valoarea estimat pentru fiecare pixel este stabilit ntr-un proces numit re-
eantionarea imaginii.
Re-eantionarea este aciunea de calculare a valorii unui pixel la o
poziie pe ct posibil ne-ntreag a imaginii. Imaginea definete valorile
pixelilor n puncte ntregi ale laticei i este la latitudinea re-eantionatorului s
produc o valoare rezonabil pentru poziii care nu cad n latice. Tehnicile
utilizate pentru aceasta sunt urmtoarele:
Cel mai apropiat vecin, care preia valoarea celui mai apropiat punct din
latice.
Bilinear, care interpoleaz linear ntre patru puncte ale laticei cele mai
apropiate.
Bicubic, care aplic o funcie polinomial pe o vecintate a punctului de
4x4.

7.4.3.4. Reprezentare de grafice

JAI furnizeaz clase care suport operaii de desenare n plus fa de


clasa Graphics2D. Sunt oferite trei tipuri de reprezentri grafice: grafic 2D
simpl, grafic de tipul Renderable i grafic de imagine segmentat.
Clasa Graphics2D extinde clasa Graphics pentru a furniza mai mult
control asupra geometriei, transformrilor de coordonate, gestiunii culorilor i
afiare de text.

70
Clasa RenderableGraphics este o implementare a Graphics2D cu
semnificaie de RenderableImage. Aceast clas permite stocarea unei secvene
de comenzi de desenare i replicarea la o rezoluie de ieire arbitrar.
Metodele clasei RenderableGraphics rescriu metodele din clasele
Graphics i Graphics2D. Acest lucru nseamn c se pot utiliza metode n
RenderableGraphics pentru a aplica culori i fonturi, pentru a crea forme
grafice i text, etc.
Clasa Graphics2D permite desenarea de linii, forme geometrice,
imagini i text. Aceste obiecte pot fi pictate deasupra unui TiledImage.

7.4.4. Procesare de imagini client-server

Procesarea client-server asigur abilitatea de calcul distribuit ntre un


set de noduri de procesare. De exemplu, este posibil s se construiasc un
server puternic care furnizeaz servicii de procesare a imaginilor ctre mai
muli clieni care nu posed putere de calcul prea mare. Cu JAI , este posibil
pentru un client s construiasc un lan de procesare a imaginilor complex,
incluznd referine la imagini surs care se afl pe alte calculatoare din reea i
s cear o reprezentare de ieire de la server.
JAI utilizeaz Java Remote Method Invocation (RMI) pentru a
implementa procesarea de imagini client-server. Pentru a comunica folosind
RMI, clientul i serverul trebuie s ruleze Java. Un obiect stub este instaniat la
client. Acest obiect transmite apelurile la metode la un obiect server
corespunztor. Argumentele apelurilor la metode i valorile returnate sunt
transmise ntre client i server prin mijloacele oferite de Java Development
Environment i anume posibilitatea de serializare a obiectelor.
Calculatorul gazd i portul depind de configurrile locale.
Calculatorul gazd trebuie s ruleze un proces RMI registry i s aib un obiect
RemoteImageServer care ascult portul dorit.
Un apel va duce la crearea pe partea de server a unui obiect de tip
RMIImageImpl i la partea de client a unui obiect stub. Obiectul client stub
serializeaz argumentele metodelor sale i le transfer la sever peste un socket,
serverul serializeaz valorile returnate i le trimite la client n acelai mod.

7.4.4.1. Cofigurarea numelui serverului i numrul portului

Constructorul clasei RemoteImage necesit un parametru serverName


care reprezint un nume de calculator gazd i un numr de port, n formatul
urmtor:
host:port
De exemplu:
hfovi.go.to:1099

71
Numrul portului este opional i trebuie s fie furnizat doar dac
numele calculatorului gazd a fost furnizat. Dac parametrul serverName este
null, n mod implicit se va cuta serviciul RMIImage de pe calculatorul local de
la portul rmiregistry (implicit 1099).

7.4.4.2. Configurarea perioadei timeout i numrul de rencercri

O eroare n reea sau o ntrziere cauzat de serverul care eueaz n a


rspunde la o cerere de imagine este tratat prin rencercri. Dac la prima
ncercare, serverul nu rspunde, programul v-a atepta un anumit timp
specificat i apoi va face o nou cerere pentru imagine. Atunci cnd limita
rencercrilor este depit, este returnat un Raster null.
Timpul de ateptare dintre rencercri este n mod implicit de 1
secund. Metoda getTimeout din RemoteImage este folosit pentru a obine
timpul dintre rencercri, n milisecunde. Metoda setTimeout este utilizat la
stabilirea timpului dintre rencercri.
Numrul de rencercri pe care programul le v-a executa n ncercarea
de a citi imaginea distant poate fi citit cu metoda getNumRetries. Metoda
setNumRetries este utilizat pentru stabilirea numrului maxim de rencercri.

7.4.4.3. Exemplu de aplicaie de procesare a imaginilor la distan

Aceast seciune conine dou programe de procesare a imaginilor la


distan.
Exemplul 7.22. ilustreaz codul complet al unui exemplu de utilizare a
clasei RemoteImage. Acest exemplu afieaz o gril 2x2 de obiecte
ScrollingImagePanel, cu fiecare fereastr afind suma a dou imagini de tip
byte care au fost rescalate n limitele [0, 127] nainte de a fi adunate. Panourile
afieaz urmtoarele rezultate:
Sus stnga: reprezentare local
Sus dreapta: rezultatul procesrii la distan a grafului
RenderedOp
Jos stnga: rezultatele ncrcrii la distan a RenderedImage
Jos dreapta: rezultatele procesrii distante a grafului
RenderableOp
Imaginea din partea de jos-dreapta este o versiune cu efect de vibraie
(dithered) a imaginii sum transmis printr-un lookup table cub de culoare i
poate s apar n mod diferit de celelalte trei imagini, care ar trebui s arate
identic.

Exemplul 7.22. Program de procesare la distan a imaginilor

72
import java.awt.*;
import java.awt.event.WindowEvent;
import java.awt.geom.*;
import java.awt.image.*;
import java.awt.image.renderable.*;
import java.util.*;
import javax.media.jai.*;
import javax.media.jai.operator.*;
import javax.media.jai.widget.*;
public class RemoteImagingTest extends WindowContainer {
/** Serverul distant implicit. */
private static final String DEFAULT_SERVER =
"utcluj.ro:1099";
/** dimensiunile segmentelor. */
private static final int TILE_WIDTH = 256;
private static final int TILE_HEIGHT = 256;
public static void main(String args[]) {
String fileName1 = null;
String fileName2 = null;
// verific argumentele
if(!(args.length >= 0 && args.length <= 3)) {
System.out.println("\nUsage: java RemoteImagingTest "+
"[[[serverName] | [fileName1 fileName2]] | "+
"[serverName fileName1 fileName2]]"+"\n");
System.exit(1);
}
// configureaz numele serverului.
String serverName = null;
if(args.length == 0 || args.length == 2) {
serverName = DEFAULT_SERVER;
System.out.println("\nUsing default server '"+
DEFAULT_SERVER+"'\n");
} else {
serverName = args[0];
}
// seteaz numele fiierelor.
if(args.length == 2) {
fileName1 = args[0];
fileName2 = args[1];
} else if(args.length == 3) {
fileName1 = args[1];
fileName2 = args[2];

73
} else {
fileName1 = "/pic1.tif";
fileName2 = "/pic2.tif";
System.out.println("\nUsing default images '"+
fileName1 + "' and '" + fileName2 + "'\n");
}
RemoteImagingTest riTest =
new RemoteImagingTest(serverName, fileName1, fileName2);
}
/**
* ruleaz un test de procesare a imaginilor distant.
*
* @param serverName numele serverului distant
* @param fileName1 prima imagine adugat.
* @param fileName2 a doua imagine adugat.
*/
RemoteImagingTest(String serverName, String fileName1, String
fileName2) {
// creeaz operaiile pentru ncrcarea imaginilor din fiiere.
RenderedOp src1 = JAI.create("fileload", fileName1);
RenderedOp src2 = JAI.create("fileload", fileName2);
// proceseaz sursele fr a nghea nodurile.
PlanarImage ren1 = src1.createInstance();
PlanarImage ren2 = src2.createInstance();
// creaz obiecte TiledImage cu fiierele imaginile ca surse
// avnd grij ca imaginile serializate sunt cu adevrat segmentate.
SampleModel sampleModel1 =
ren1.getSampleModel().createCompatibleSampleModel(
TILE_WIDTH, TILE_HEIGHT);
TiledImage ti1 = new TiledImage(ren1.getMinX(), ren1.getMinY(),
ren1.getWidth(), ren1.getHeight(), ren1.getTileGridXOffset(),
ren1.getTileGridYOffset(), sampleModel1, ren1.getColorModel());
ti1.set(src1);
SampleModel sampleModel2 =
ren2.getSampleModel().createCompatibleSampleModel(
TILE_WIDTH, TILE_HEIGHT);
TiledImage ti2 = new TiledImage(ren2.getMinX(),
ren2.getMinY(), ren2.getWidth(), ren2.getHeight(),
ren2.getTileGridXOffset(), ren2.getTileGridYOffset(),
sampleModel2, ren2.getColorModel());
ti2.set(src2);
// creaz un indiciu care specific dimansiunea segmenului.

74
ImageLayout layout = new ImageLayout();
layout.setTileWidth(TILE_WIDTH).setTileHeight(TILE_HEIGHT);
RenderingHints rh = new
RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout);
// rescaleaz imaginile n intervalul [0, 127].
ParameterBlock pb = (new ParameterBlock());
pb.addSource(ti1);
pb.add(new double[] {0.5}).add(new double[] {0.0});
RenderedOp addend1 = JAI.create("rescale", pb, rh);
pb = (new ParameterBlock());
pb.addSource(ti2);
pb.add(new double[] {0.5}).add(new double[] {0.0});
RenderedOp addend2 = JAI.create("rescale", pb, rh);
// adun imaginile rescalate.
pb = (new
ParameterBlock()).addSource(addend1).addSource(addend2);
RenderedOp sum = JAI.create("add", pb, rh);
// adaug un efect de vibraie (dither)
// sumei imaginilor rescalate.
pb = (new ParameterBlock()).addSource(sum);
pb.add(ColorCube.BYTE_496).add(KernelJAI.DITHER_MASK_443);
RenderedOp dithered = JAI.create("ordereddither", pb, rh);
// Construiete un obiect RemoteImage din lanul RenderedOp.
RemoteImage remoteImage = new RemoteImage(serverName,
sum);
// definete segmentul de afiare i modelul de fereastr.
setTitle(getClass().getName());
setLayout(new GridLayout(2, 2));
// reprezentare local
add(new ScrollingImagePanel(sum,
sum.getWidth(), sum.getHeight()));
// reprezentare distant RenderedOp.
add(new ScrollingImagePanel(remoteImage,
remoteImage.getWidth(), remoteImage.getHeight()));
// reprezentare distant RenderedImage
PlanarImage sumImage = sum.getRendering();
remoteImage = new RemoteImage(serverName, sumImage);
add(new ScrollingImagePanel(remoteImage,
remoteImage.getWidth(), remoteImage.getHeight()));
// reprezentare distant RenderableOp.
pb = new ParameterBlock();
pb.addSource(dithered);

75
RenderableOp absImage = JAI.createRenderable("absolute",pb);
pb = new ParameterBlock();
pb.addSource(absImage).add(ColorCube.BYTE_496);
RenderableOp lutImage = JAI.createRenderable("lookup", pb);
AffineTransform tf =
AffineTransform.getScaleInstance(384/dithered.getWidth(),
256/dithered.getHeight());
Rectangle aoi = new Rectangle(128, 128, 384, 256);
RenderContext rc = new RenderContext(tf, aoi, rh);
remoteImage = new RemoteImage(serverName, lutImage, rc);
add(new ScrollingImagePanel(remoteImage,
remoteImage.getWidth(), remoteImage.getHeight()));
// la sfrit afim totul
pack();
show();
}
}

Urmtorul exemplu (Exemplul 7.23.) reprezint un lan Remote-


Imaging rspndit dealungul a dou noduri distante i afieaz rezultatele local.

Exemplul 7.23. Lan de tipul RemoteImage


import java.awt.image.*;
import java.awt.image.renderable.ParameterBlock;
import javax.media.jai.*;
import javax.media.jai.widget.*;
/**
* creeaz un lan de procesare rspndit de-a lungul a
* dou noduri distante i afieaz rezultatul local.
*/
public class MultiNodeTest extends WindowContainer {
public static void main(String[] args) {
if(args.length != 3) {
throw new RuntimeException("Usage: java MultiNodeTest "+
"file node1 node2");
}
new MultiNodeTest(args[0], args[1], args[2]);
}
public MultiNodeTest(String fileName, String node1, String node2)
{
// creeaz un lan n nodul 1.

76
System.out.println("Creeaz dst1 = log(invert(fileload("+
fileName+"))) n "+node1);
RenderedOp src = JAI.create("fileload", fileName);
RenderedOp op1 = JAI.create("invert", src);
RenderedOp op2 = JAI.create("log", op1);
RemoteImage rmt1 = new RemoteImage(node1, op2);
// creeaz un lan n nodul 2.
System.out.println("Creeaz dst2 = not(exp(dst1)) n "+node2);
RenderedOp op3 = JAI.create("exp", rmt1);
RenderedOp op4 = JAI.create("not", op3);
RemoteImage rmt2 = new RemoteImage(node2, op4);
// afieaz rezultatele pentru nodul 2.
System.out.println("Afieaz rezultate");
setTitle(getClass().getName()+" "+fileName);
add(new ScrollingImagePanel(rmt2, rmt2.getWidth(),
rmt2.getHeight()));
pack();
show();
}
}

7.4.4.4. Executarea unei procesrii de imagini la distan

Pentru a executa o procesare de imagini distant utiliznd JAI, trebuie


parcurse urmtoarele etape:
1. Crearea unui fiier care specific tipul de securitate (security policy file).
2. Pornirea regitrilor RMI
3. Pornirea serverului de procesare a imaginilor distant
4. Rularea aplicaiei locale
Aceti patru pai sunt explicai n detaliu n cele ce urmeaz.

Pas 1: Crearea unui security policy file. Implementarea implicit


pentru RMI security policy este specificat n unul sau mai multe fiiere de
configurare a securitii. Aceste fiiere de configurare specific permisiunile
care sunt asociate codului din diferite surse. Exist un fiier general implicit
security policy file i un singur fiier utilizator policy file.
Fiierul policy este situat n directorul de baz unde JAI este instalat.
Dac $JAI este directorul de baz unde JAI este instalat, se poate crea (din
motive de securitate este de preferat s fie doar pentru testare) cu ajutorul unui
editor text un fiier numit $JAI/policy care conine urmtoarele:

grant {

77
// Permite orice de acum nainte.
permission java.security.AllPermission;
};

Pas 2: Pornirea regitrilor RMI. RMI registry este un server de


nume simplu care permite clienilor distani s primeasc o referin la un
obiect distant. n mod obinuit, registrul este utilizat doar pentru localizarea
primului obiect distant de care o aplicaie are nevoie pentru a conlucra. Apoi
acel obiect n schimb furnizeaz suport specific aplicaiei pentru gsirea altor
obiecte.
Pentru pornirea regitrilor pe server, trebuie nti efectuat operaia de
autentificare la sistemul distant unde serverul de procesare a imaginilor v-a rula
i executa comanda rmiregistry.
Pas 3: Pornirea serverului de procesare a imaginilor distant. Dup
efectuarea operaiei de autentificare la serverul distant, se pornete severul de
procesare a imaginilor distant. De exemplu:

$ CLASSPATH=$JAI/lib/jai.jar:\
$JAI/lib/mlibwrapper_jai.jar
$ export CLASSPATH
$ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$JAI/lib
$ export LD_LIBRARY_PATH
$ java \
-Djava.rmi.server.codebase=\
file:$JAI/lib/jai.jar \
-Djava.rmi.server.useCodebaseOnly=false \
-Djava.security.policy=file:$JAI/policy \
com.sun.media.jai.rmi.RMIImageImpl

Cnd paii de mai sus sunt executai pe o main cu adresa IP


193.226.6.174 se afieaz urmtoarele:

Server: using host 193.226.6.174 port 1099


Registering image server as
"rmi://193.226.6.174:1099/RemoteImageServer".
Server: Bound RemoteImageServer into the registry.

Pas 4: Rularea aplicaiei locale. Dup efectuarea pailor 1 la 3,


aplicaia local poate fi pornit. Atunci cnd se ruleaz aplicaia local, trebuie
ca parametrul serverName pentru orice constructor RemoteImage s corespund
mainii pe care ruleaz serverul de procesare a imaginilor distant. De exemplu,
dac avem maina cu adresa de IP 193.226.6.174, denumit myserver, atunci

78
parametrul serverName al oricrui constructor RemoteImage trebuie s fie
myserver.

7.4.4.5. Internet Imaging Protocol (IIP)

Internet Imaging Protocol (IIP) este un standard utilizat n procesrile


de imagini client/server. Exist dou operaii JAI care suport operaii IIP.
Aceste dou operaii separate furnizeaz suport pentru partea client a IIP.
Aceste operaii, IIP i IIPResolution, solicit o imagine de pe un server IIP apoi
creeaz un obiect RenderedImage sau RenderableImage.
Operaia IIP. Aceast operaie furnizeaz suport pentru partea client
a IIP n modurile Rendered i Renderable. Aceasta creeaz un obiect
RenderedImage sau RenderableImage bazndu-se pe datele recepionate de la
serverul IIP i opional aplic o secven de operaii asupra imaginii create.
Operaiile suportate sunt urmtoarele:
Filtrare (blur i sharpen)
Corecie de tonalitate i culoare (color twist)
Modificare de contrast
Selectare a unei surse de interes dreptunghiulare
Orientare spaial (transformare prin alocare independent de
reprezentare)
Selectarea unei destinaii de interes dreptunghiulare
Transformare de reprezentare (doar n mod Renderable)
Transpunere (rotire i/sau oglindire)
Dup cum se observ, transformarea de reprezentare este executat
doar n modul de procesare Renderable. Aceast transformare este derivat
dintr-un obiect AffineTransform furnizat n RenderContext atunci cnd
reprezentarea se produce. Modul de procesare Rendered creeaz un obiect
RenderedImage care este reprezentarea implicit a obiectului RenderableImage
creat n modul de procesare Renderable.
Exemplul 7.24. reprezint o operaie IIP.

Exemplul 7.24. Operaie IIP


public class IIPTest {
public static final String SERVER = "http://iipserver:8087/";
public static final String DEFAULT_IMAGE = "dog.fpx";
public static final int DEFAULT_HEIGHT = 512;

public static void main(String[] args) {


String imagePath = DEFAULT_IMAGE;
for(int i = 0; i < args.length; i++) {

79
if(args[i].equalsIgnoreCase("-image")) {
imagePath = args[++i];
if(!(imagePath.toLowerCase().endsWith(".fpx")))
imagePath += ".fpx";
}
}
String url = SERVER + "FIF=" + imagePath;
new IIPTest(url);
}

public IIPTest (String url) {


// definete blocul de parametrii.
ParameterBlock pb = (new ParameterBlock()).add(url);
// arie de sub-imagine implicit.
pb.set(-10.0F, 2); // filtru
float[] colorTwist = new float[]
{1.0F, 0.0F, 0.0F, 0.0F,
0.0F, 0.0F, 1.0F, 0.0F,
0.0F, 1.0F, 0.0F, 0.0F,
0.0F, 0.0F, 0.0F, 1.0F,};
pb.set(colorTwist, 3); //color-twist
pb.set(2.0F, 4); // contrast
pb.set(new Rectangle2D.Float(0.10F, 0.10F,
0.80F*aspectRatioSource, 0.80F), 5); // ROI surs
AffineTransform afn = AffineTransform.getShearInstance(0.2,
0.1);
pb.set(afn, 6); // transformare
Rectangle2D destBounds = null;
try {
Rectangle2D sourceRect =
new Rectangle2D.Float(0.0F, 0.0F, aspectRatioSource,
1.0F);
Shape shape =
afn.createInverse().createTransformedShape(sourceRect);
destBounds = shape.getBounds2D();
} catch(Exception e) {
}
float aspectRatio = (float)destBounds.getHeight();
pb.set(aspectRatio, 7); // raportul de aspect al destinaiei
pb.set(new Rectangle2D.Float(0.0F, 0.0F,
0.75F*aspectRatio, 0.75F), 8); // ROI destinaie
pb.set(90, 9); // unghiul de rotaie

80
pb.set("x", 10); // axa oglinzii
// rmne: profilul ICC implicit
// calitatea JPEG implicit
// tabela index JPEG implicit
int height = DEFAULT_HEIGHT;
AffineTransform at = AffineTransform.getScaleInstance(
height*aspectRatioSource, height);
RenderContext rc = new RenderContext(at);
// creeaz un obiect RenderableImage.
RenderableImage renderable =
JAI.createRenderable("iip", pb);
}
}

Operaia IIPResolution. Aceast operaie furnizeaz suport pentru


partea client a IIP n modul de procesare Rendered. Aceast operaie este cu
specific legat de rezoluie, necesitnd de la serverul IIP o imagine la un nivel de
rezoluie particular i creeaz un obiect RenderedImage bazndu-se pe datele
recepionate de la server. Odat ce este creat acest obiect RenderedImage,
nivelul de rezoluie nu poate fi schimbat.
Exemplul 7.25. prezint codul pentru o operaie IIPResolution.

Exemplul 7.25. Aplicarea operaiei IIPResolution


public class IIPResolutionTest {
public static final String SERVER = "http://iipserver:8087/";
public static final String DEFAULT_IMAGE = "dog.fpx";
public static final int DEFAULT_RESOLUTION = 3;

public static void main(String[] args) {


String imagePath = DEFAULT_IMAGE;
int resolution = DEFAULT_RESOLUTION;
for(int i = 0; i < args.length; i++) {
if(args[i].equalsIgnoreCase("-image")) {
imagePath = args[++i];
if(!(imagePath.toLowerCase().endsWith(".fpx"))) {
imagePath += ".fpx";
}
} else if(args[i].equalsIgnoreCase("-res")) {
resolution = Integer.valueOf(args[++i]).intValue();
}
}

81
String url = SERVER + "FIF=" + imagePath;
new IIPResolutionTest(url, resolution);
}

public IIPResolutionTest (String url, int resolution) {


ParameterBlock pb = new ParameterBlock();
pb.add(url).add(resolution);
PlanarImage pi = JAI.create("iipresolution", pb);
}
}

7.4.5. Codarea imaginilor

Sistemul de codoare JAI suport o mare varietate de formate de


imagine pentru scrierea imaginilor spre un fiier sau spre un obiect
OutputStream pentru urmtoarele procesri.
Pentru scrierea unei imagini ntr-un fiier specificat, n formatul i cu
parametrii de codare specificai, se folosete operaia FileStore. Formatele
suportate de operaia FileStore sunt BMP, JPEG, PNG, PNM i TIFF.
Pentru a coda o imagine spre un OutputStream n formatul specificat
utiliznd parametrii de codare furnizai de un parametru operaie
ImageEncodeParam, se folosete operaia Encode.
Exemplul 7.26. este un fragment de cod care demonstreaz utilizarea
operaiilor Encode i FileStore.

Exemplul 7.26. Scrierea unui obiect OutputStream i a unui File


// definete numele fiierelor surs i destinaie
String inputFile = /img/p1.tif
String outputFile = /img/p2.bmp
// ncarc imaginea de intrare
RenderedOp src = JAI.create("fileload", inputFile);

// codeaz fiierul ca i imagine BMP


FileOutputStream stream = new FileOutputStream(outputFile);
JAI.create("encode", src, stream, BMP, null);

// stocheaz imaginea n format BMP.


JAI.create("filestore", src, outputFile, BMP, null);

82
Pentru a coda n format BMP se poate utiliza operaia BMP mpreun
cu ali parametrii de codare (versiune BMP, modul de aezare a datelor n
fiier), ceea ce se exemplific n Exemplul 7.27.

Exemplul 7.27. Codarea i scrierea n format BMP


File f; // fiierul n care se va stoca imaginea
PlanarImage img; // imaginea surs
...
// OutputStream-ul spre care se scrie
FileOutputStream fos = new FileOutputStream(f);
// clas JAI, specific diferii parametrii de codare BMP
BMPEncodeParam param = new BMPEncodeParam();
// specific versiunea BMP
param.setVersion(BMPEncodeParam.VERSION_3);
// specific formatul de scriere a datelor de sus n jos
param.setTopDown(true);
// specific posibilitatea de compresie a datelor
param.setCompressed(false);
// creeaz un codor BMP
ImageEncoder enc = ImageCodec.createImageEncoder(
"BMP", fos,param);
// codeaz imaginea i o scrie la OutputStream
enc.encode(img);
fos.close();

La codarea n formatul JPEG se pot specifica diferii parametrii i


diferite opiuni de codare, cum ar fi posibilitatea de eliminare a header-ului
JFIF, modificarea parametrilor de codare DCT (Disrete Cosine Transform),
modificarea tabelei de cuantizare, subeantionare pe orizontal i vertical,
controlul compresiei i al calitii imaginii, etc. Fragmentul de cod urmtor
(Exemplul 7.28.) exemplific codarea unei imagini n format JPEG.

Exemplul 7.28. Codare JPEG


// tabela de cuatizare
private int[] qTable=new int[]= {
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,

83
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
};
...
File f; // fiierul n care se va stoca imaginea
PlanarImage img; // imaginea surs
...
// OutputStream-ul spre care se scrie
FileOutputStream fos = new FileOutputStream(f);
// clas JAI, specific diferii parametrii de codare JPEG
JPEGEncodeParam encodeParam = new JPEGEncodeParam();
// creeaz un nou tabel de cuantizare
encodeParam.setQTable(0, 1, qTable);
encodeParam.setQTable(1, 1, qTable);
encodeParam.setQTable(2, 1, qTable);
// tabelul de cuantizare pentru datele de luminan
encodeParam.setLumaQTable(qTable);
// tabelul de cuantizare pentru datele de crominan
encodeParam.setChromaQTable(qTable);
// creaz un nou tabel de cuantizare i l nlocuiete pe cel existent
// i configureaz nivelul de calitate a imaginii
encodeParam.setQuality(0.87F);
// subeantionare pe orizontal aplicat pentru fiecare band
encodeParam.setHorizontalSubsampling(0, 1);
encodeParam.setHorizontalSubsampling(1, 1);
encodeParam.setHorizontalSubsampling(2, 2);
// subeantionare pe vertical aplicat pentru fiecare band
encodeParam.setVerticalSubsampling(0, 1);
encodeParam.setVerticalSubsampling(1, 1);
encodeParam.setVerticalSubsampling(2, 2);
// specific intervalul de restart n Minimum Coded Units (MCU)
encodeParam.setRestartInterval(res);
// scrie doar imaginea i nu scrie tabelele (JPEG abreviat)
encodeParam.setWriteTablesOnly(false);
encodeParam.setWriteImageOnly(true);
// scrie headerul JFIF
encodeParam.setWriteJFIFHeader(true);
// creeaz un codor JPEG
ImageEncoder encoder = ImageCodec.createImageEncoder(
"JPEG", fos, encodeParam);
encoder.encode(img); // codeaz JPEG i scrie spre OutputStream
fos.close();

84
n Exemplul 7.29. se prezint codarea unei imagini n format PNG
folosind o codare pe 16 bii i ntreesere Adam7.

Exemplul 7.29. Codare PNG


File f; // fiierul n care se va stoca imaginea
PlanarImage img; // imaginea surs
...
// OutputStream-ul spre care se scrie
FileOutputStream fos = new FileOutputStream(f);
// clas JAI, specific diferii parametrii de codare PNG
PNGEncodeParam param =
PNGEncodeParam.getDefaultEncodeParam(img);
// specific numrul de bii adncime dorii
param.setBitDepth(16);
// codeaz folosind ntreesere Adam7
param.setInterlacing(true);
// creeaz un codor PNG avnd parametrii specificai
ImageEncoder enc = ImageCodec.createImageEncoder(
"PNG", fos, param);
// codare i scriere n fiier
enc.encode(img);
fos.close();

Exemplul urmtor (Exemplul 7.30.) ilustreaz modul de codare i


scriere ntr-un fiier de format PNM, folosind un format ASCII de reprezentare
a datelor.

Exemplul 7.30. Codare n format PNM


File f; // fiierul n care se va stoca imaginea
PlanarImage img; // imaginea surs
...
// OutputStream-ul spre care se scrie
FileOutputStream fos = new FileOutputStream(f);
// clas JAI, specific diferii parametrii de codare PNM
PNMEncodeParam param = new PNMEncodeParam();
// specific modul de codare ASCII
param.setRaw(true);
// creeaz codorul
ImageEncoder enc = ImageCodec.createImageEncoder(
"PNM", fos, param);

85
// codeaz imaginea apoi o scrie n fiier
enc.encode(img);
fos.close();

Exemplul 7.31. reprezint un fragment de cod care codeaz o surs


Rendered n format TIFF.

Exemplul 7.31. Codare n format TIFF


File f; // fiierul n care se va stoca imaginea
PlanarImage img; // imaginea surs
...
// OutputStream-ul spre care se scrie
FileOutputStream fos = new FileOutputStream(f);
// clas JAI, specific diferii parametrii de codare TIFF
TIFFEncodeParam param = new TIFFEncodeParam();
// scrie datele n format segmentat
param.setWriteTiled(true);
// creeaz codorul
ImageEncoder enc = ImageCodec.createImageEncoder(
"TIFF", fos, param);
// codeaz i scrie n fiier
enc.encode(img);
fos.close();

7.4.6. Extinderea JAI API

Dei nici un API de procesare a imaginilor nu sper s captureze


enorma varietate de operaii care se pot executa asupra imaginilor digitale, JAI
API suport un numr foarte mare de operaii, fiind conceput de la nceput ca s
ncurajeze programatorii s scrie extensii dect s manipuleze datele imagine n
mod direct. JAI permite n mod virtual ca orice algoritm de procesare a
imaginilor s fie adugat la API i s fie folosit ca i cum ar fi fost o parte
nativ a acestuia.
Mecanismul pentru adugarea diverselor funcionaliti la API pate fi
prezentat la mai multe nivele de ncapsulare i complexitate. Aceasta permite
programatorilor care doresc s adauge operaii simple la API s se confrunte cu
concepte simple, n timp ce extensiile mai complexe au un control total asupra
mediului lor la cel mai jos nivel de abstractizare.
JAI API suport o mare varietate de stiluri de programare, care include
modul de execuie imediat i amnat pentru tipuri diferite de aplicaii de
procesare a imaginilor.

86
Toate extensiile la JAI necesit adugarea de noi clase. Toate clasele
trebuie grupate n pachete ca mod de organizare eficient i pentru separare a
acestora de pachetele oferite de alii.

7.4.6.1. Scrierea de noi operatori

Pentru a extinde JAI API prin crearea de noi operaii, este nevoie s
scriem o nou subclas a OpImage. Aceasta se poate face prin subclasarea a
uneia sau mai multe clase utilitare pentru a automatiza unele dintre detaliile a
operatorului pe care dorim s-l implementm.
Odat creai, noii operatori pot fi fcui disponibili pentru utilizatori n
mod transparent i fr modificarea codului surs de la utilizator, folosind
mecanismul de regitrii JAI.
Pentru a crea un nou operator, trebuie create urmtoarele clase:
O clas care extinde clasa OpImage sau oricare dintre subclasele
acesteia. Aceast nou clas este cea care execut procesarea.
O clas care extinde clasa OperationDescriptor. Aceast nou
clas descrie operaia prin nume, list de parametrii, etc.
O clas care implementeaz java.awt.image.renderable.Rendered-
ImageFactory, dac operatorul va funciona doar n modul
Rendered.
Operaiile care sunt create folosind una dintre metodele JAI.create
trebuie definite n registryFile, care este inclus n arhiva jai_core.jar. Fiecare
operaie are asociat un obiect OperationDesciptor (marcat prin odesc n
registryFile), care furnizeaz o descriere textual a operaiei i specific
numrul i tipul sursei precum i parametrii. Acest descriptor specific de
asemenea dac operaia suport modul Rendered, sau Renderable, sau
amndou.
Toate numele de operaii de nivel nalt (de exemplu, Rotate, Convolve
i AddConst) sunt mapate la instane de tipul RenderedImageFactory (RIF)
i/sau ContextualRenderedImageFactory (CRIF) care sunt capabile de
instanierea de lanuri OpImage pentru execuia operaiei specificate. Obiectele
RIF sunt utilizate pentru operaii n modul Rendered, iar obiectele CRIF sunt
utilizate pentru operaii n modul Renderable sau n modurile Rendered i
Renderable.
Pentru evitarea problemelor asociate cu editarea direct a registryFile
i rempachetarea lui, se pot nregistra obiectele OperationDescriptor, RIF i
CRIF utiliznd metodele registerOperationDescription, registerRIF i
registerCRIF din clasa OperationRegistry. Singurul dezavantaj al acestei
metode de nregistrare este faptul c noul operator nu va fi n mod automat
rencrcat de fiecare dat cnd un program JAI este executat, deoarece operaia

87
nu este nregistrat n registryFile. Noua operaie va trebui nregistrat de
fiecare dat nainte de a putea fi folosit.
Pentru a nregistra temporar o nou operaie trebuie parcuri urmtorii
pai:
1. nregistrarea numelui operaiei
Numele operaiei la nivel nalt, denumit i operation descriptor
(descriptor de operaie), este nregistrat printr-un apel la metoda
registerOperationByName sau la metoda registerOperationDescriptor.
Numele descriptorului de operaie trebuie s fie unic.
Odat ce un descriptor de operaie este nregistrat, acestea pot fi
obinute prin nume prin apelul metodei getOperationDescriptor.

2. nregistrarea setului de obiecte RIF


Obiectele RIF sunt nregistrate folosind metoda registerRIF. Fiecare
RIF este nregistrat cu un nume de operaie specific. Exist de
asemenea metode similare pentru nregistrarea obiectelor CRIF.

Exemplul 7.32. prezint cteva fragmente dintr-un program n


care se nregistreaz temporar o nou operaie. Dup nregistrarea operaiei
MyThreshold se aplic aceast operaie asupra unei imagini Rendered. n
exemplu se prezint i codul surs al claselor care descriu operaia.

Exemplul 7.32. nregistrarea i utilizarea unei noi operaii JAI


//nregistreaz un nou OperationDescriptor
MyThresholdDescriptor thDescriptor = new MyThresholdDescriptor();
OperationDescriptor odesc = thDescriptor;
RenderedImageFactory rif = thDescriptor;
String operationName = "MyThreshold";
String productName = "medimaging";
OperationRegistry or =
JAI.getDefaultInstance().getOperationRegistry();
or.registerOperationDescriptor(odesc,operationName);
or.registerRIF(operationName,productName,rif);
...
PlanarImage image; // sursa
// utilizarea operatorului care tocmai a fost nregistrat
// construirea blocului de parametrii
ParameterBlock pb = new ParameterBlock();
pb.addSource(image);
pb.add(55);
pb.add(174);
// aplicarea operatorului

88
PlanarImage img = JAI.create("MyThreshold", pb, renderHints);
...
/**
* O clas de tipul OperationDescriptor i RenderedImageFactory
* i o clas de tipul OpImage pentru crearea unei
* operaieii threshold modificat.
*/
public class MyThresholdDescriptor extends OperationDescriptorImpl
implements RenderedImageFactory {
/**
* stringuri resurs care furnizeaz informaii
* generale despre operaie
*/
private static final String[][] resources = {
{"GlobalName", "MyThreshold"},
{"LocalName", "MyThreshold"},
{"Vendor", "to.go.hfovi"},
{"Description", "A operation that thresholds source pixels"},
{"DocURL", "http://www.geocities.com/hfovi/projects/jai.html"},
{"Version", "1.0"},
{"arg0Desc", "param1"},
{"arg1Desc", "param2"}
};
/**
* Numele parametrilor pentru operaia MyThreshold.
*/
private static final String[] paramNames = {
"param1", "param2"
};
/**
* Tipurile de clase pentru parametrii.
*/
private static final Class[] paramClasses = {
java.lang.Integer.class, java.lang.Integer.class
};
/**
* Parametrii implicii
*/
private static final Object[] paramDefaults = {
new Integer(0), new Integer(255)
};
/** Constructorul. */

89
public MyThresholdDescriptor() {
super(resources, 1, paramClasses, paramNames, paramDefaults);
}
/**
* creeaz un MyThresholdOpImage cu ParameterBlock dat dac
* MyThresholdOpImage accept acest ParameterBlock.
*/
public RenderedImage create(ParameterBlock paramBlock,
RenderingHints renderHints) {
if (!validateParameters(paramBlock)) {
return null;
}
return new MyThresholdOpImage(paramBlock.getRenderedSource(0),
new ImageLayout(),
(Integer)paramBlock.getObjectParameter(0),
(Integer)paramBlock.getObjectParameter(1));
}
/**
* verific dac toi parametrii din ParameterBlock au
* tipul corect nainte de construirea MyThresholdOpImage
*/
public boolean validateParameters(ParameterBlock paramBlock) {
for (int i = 0; i < this.getNumParameters(); i++) {
Object arg = paramBlock.getObjectParameter(i);
if (arg == null) {
return false;
}
if (!(arg instanceof Integer)) {
return false;
}
}
return true;
}
}
/**
* MyThresholdOpImage este o extensie a PointOpImage care preia
* doi parametri ntregi i o surs i execut threshold asupra sursei
*/
class MyThresholdOpImage extends PointOpImage {
private int param1;
private int param2;
/**

90
* Construiete un MyThresholdOpImage.
*/
public MyThresholdOpImage(RenderedImage source,
ImageLayout layout, Integer param1,
Integer param2) {
super(source, null, layout, true);
this.param1 = param1.intValue();
this.param2 = param2.intValue();
}
/**
* Execut o operaie threshold modificat asupra pixelilor n
* suprafaa dreptunghiular dat. Valorile eantioanelor sub o
* limit inferioar sunt limitate la 0, n timp ce acele peste o limit
* superioar sunt limitate la 255. Rezultatele sunt returnate n
* WritableRaster ca destinaie.
*/
protected void computeRect(Raster[] sources,
WritableRaster dest,
Rectangle destRect) {
Raster source = sources[0];
Rectangle srcRect = mapDestRect(destRect, 0);
// RasterAccessor este un mod convenabil pentru reprezentarea
// oricrui Raster ntr-un format utilizabil. Acesta cere foarte puine
// resurse dac substratul Raster este ntr-un format obinuit.
RasterFormatTag[] formatTags = getFormatTags();
RasterAccessor srcAccessor =
new RasterAccessor(sources[0], srcRect, formatTags[0],
getSource(0).getColorModel());
RasterAccessor dstAccessor =
new RasterAccessor(dest, destRect, formatTags[1],
getColorModel());
switch (dstAccessor.getDataType()) {
case DataBuffer.TYPE_BYTE:
byteLoop(srcAccessor,dstAccessor);
break;
case DataBuffer.TYPE_INT:
intLoop(srcAccessor,dstAccessor);
break;
default:
String className = this.getClass().getName();
throw new RuntimeException(className +
" nu implementeaz computeRect" +

91
" pentru date short/float/double");
}
if (dstAccessor.isDataCopy()) {
dstAccessor.clampDataArrays();
dstAccessor.copyDataToRaster();
}
}
/**
* Calculeaz o arie dintr-un Raster tip byte folosind o surs
* RasterAccessor i o destinaie RasterAccesor.
*/
private void byteLoop(RasterAccessor src, RasterAccessor dst) {
int dwidth = dst.getWidth();
int dheight = dst.getHeight();
int dnumBands = dst.getNumBands();
byte dstDataArrays[][] = dst.getByteDataArrays();
int dstBandOffsets[] = dst.getBandOffsets();
int dstPixelStride = dst.getPixelStride();
int dstScanlineStride = dst.getScanlineStride();
byte srcDataArrays[][] = src.getByteDataArrays();
int srcBandOffsets[] = src.getBandOffsets();
int srcPixelStride = src.getPixelStride();
int srcScanlineStride = src.getScanlineStride();
byte bp1 = (byte)(param1 & 0xff);
byte bp2 = (byte)(param2 & 0xff);
for (int k = 0; k < dnumBands; k++) {
byte dstData[] = dstDataArrays[k];
byte srcData[] = srcDataArrays[k];
int srcScanlineOffset = srcBandOffsets[k];
int dstScanlineOffset = dstBandOffsets[k];
for (int j = 0; j < dheight; j++) {
int srcPixelOffset = srcScanlineOffset;
int dstPixelOffset = dstScanlineOffset;
for (int i = 0; i < dwidth; i++) {
int pixel = srcData[srcPixelOffset] & 0xff;
if (pixel < param1) {
dstData[dstPixelOffset] = 0;
} else if (pixel > param2) {
dstData[dstPixelOffset] = (byte)255;
} else {
dstData[dstPixelOffset] = srcData[srcPixelOffset];
}

92
srcPixelOffset += srcPixelStride;
dstPixelOffset += dstPixelStride;
}
srcScanlineOffset += srcScanlineStride;
dstScanlineOffset += dstScanlineStride;
}
}
}
/**
* Calculeaz o arie dintr-un Raster de tip int folosind o surs
* RasterAccessor i o destinaie RasterAccesor.
*/
private void intLoop(RasterAccessor src, RasterAccessor dst) {
int dwidth = dst.getWidth();
int dheight = dst.getHeight();
int dnumBands = dst.getNumBands();
int dstDataArrays[][] = dst.getIntDataArrays();
int dstBandOffsets[] = dst.getBandOffsets();
int dstPixelStride = dst.getPixelStride();
int dstScanlineStride = dst.getScanlineStride();
int srcDataArrays[][] = src.getIntDataArrays();
int srcBandOffsets[] = src.getBandOffsets();
int srcPixelStride = src.getPixelStride();
int srcScanlineStride = src.getScanlineStride();
for (int k = 0; k < dnumBands; k++) {
int dstData[] = dstDataArrays[k];
int srcData[] = srcDataArrays[k];
int srcScanlineOffset = srcBandOffsets[k];
int dstScanlineOffset = dstBandOffsets[k];
for (int j = 0; j < dheight; j++) {
int srcPixelOffset = srcScanlineOffset;
int dstPixelOffset = dstScanlineOffset;
for (int i = 0; i < dwidth; i++) {
int pixel = srcData[srcPixelOffset];
if (pixel < param1) {
dstData[dstPixelOffset] = 0;
} else if (pixel > param2) {
dstData[dstPixelOffset] = 255;
} else {
dstData[dstPixelOffset] = srcData[srcPixelOffset];
}
srcPixelOffset += srcPixelStride;

93
dstPixelOffset += dstPixelStride;
}
srcScanlineOffset += srcScanlineStride;
dstScanlineOffset += dstScanlineStride;
}
}
}
}

7.4.6.2. Scrierea de noi decodoare i codoare de imagini

Pentru a crea un decodor i un codor pentru un anumit format specific


este nevoie de crearea a trei clase:
O clas de tipul ImageCodec pentru controlul fiierelor imagine n
formatul pentru care se dorete codorul.
O clas de tipul ImageDecoder necesar pentru citirea fiierelor
imagine n formatul pentru care se dorete decodorul
O clas de tipul ImageEncoder necesar pentru scrierea fiierelor
imagine n formatul pentru care se dorete codorul.
Clasele de codoare care acompaniaz pachetele JAI API sunt furnizate
programatorului doar ca suport convenabil pentru lucrul cu fiiere imagine.
Aceste clase nu fac parte n mod oficial din JAI API, funcionalitile oferite de
aceste clase sunt implementate n Java Image I/O API, care este disponibil n
J2SE ncepnd cu versiunea 1.4. Cu toate acestea, clasele pentru lucrul cu
fiiere imagine din JAI sunt nc disponibile n continuare, dar este posibil ca
ele s fie eliminate n urmtoarele ediii JAI. Aplicaiile care utilizeaz operaii
I/O cu imagini este de preferat s lucreze cu Java Image I/O API.
Clasa ImageCodec permite crearea de codoare i decodoare de
imagini. Instanele clasei ImageCodec pot fi nregistrate prin nume. Metoda
registerCodec asociaz un obiect ImageCodec cu un nume dat. Orice codor
care a fost nainte asociat cu acel nume este eliminat. Odat ce un codor este
nregistrat, numele asociat cu acesta poate fi folosit ca parametru name n
metodele createImageEncoder i createImageDecoder.
Clasa ImageCodec menine un registru cu obiecte FormatRecognizer
care examineaz un InputStream i determin dac acesta ader la un format
controlat de un ImageCodec particular. Un FormatRecognizer este adugat la
regitrii cu metoda registerFormatRecognizer.
Metoda getCodec returneaz obiectul ImageCodec asociat cu un nume
dat. Dac nu este nregistrat nici un codor cu acel nume, se returneaz null.

94
7.5. Bibliografie

1. Programming in Java Advanced Imaging, Sun Microsystems,


http://java.sun.com/products/java-media/jai, November 1999
2. The JAI Tutorial, Sun Microsystems,
http://java.sun.com/products-/java-media/jai, 1999
3. Programmers Guide to the Java 2D API, Sun Microsystems,
http://java.sun.com, 1999
4. The Java Tutorial, Sun Microsystems, http://java.sun.com, 2001
5. JAI Documentation, v1.1, Sun Microsystems, http://java.sun.com/-
products/java-media/jai, 2001
6. Java 2 SDK, Standard Edition Documentation, v1.4.0, Sun
Microsystems, http://java.sun.com, 2001

95

S-ar putea să vă placă și