Sunteți pe pagina 1din 12

Dithering pentru imagini color

Cuantizare este o tehnic utilizat n grafica pe calculator pentru a crea iluzia mai
multor culori la afiarea unei imagini care are un nivel sczut de adancimea de
culoare. ntr-o imagine cuantizat, culorile lips sunt reproduse prin dispunerea
pixelilor n culorile disponibile. Ochiul uman percepe aceasta ca un amestec de
culori individuale.
In domeniul graficii pe calculator, dithering este o tehnica folosita pentru a crea
iluzia unei culori ce nu exista in domeniu limitat.Astfel o culoare ce nu exista in
domeniu este aproximata printr-o difuzie de pixeli din domeniul de culoare.
Ochiul uman va percepe aceasta colectie de pixeli ca o culoare inexistenta in
paleta de culori disponibila.Metodata este similara cu adaugarea unui zgomot
slab pentru a imbunatatii calitatea.
Dithering-ul reduce efectul cuantizarii imaginii . Printr-o paleta redusa de culori se
pot reprezenta pentru ochiul uma culori inexistente in acea paleta.
Imagine originala:

Dithering cu 256 culori:

Exista mai multe tipuri de dithering:


1. Thresholging = fiecare pixel este comparat cu un prag. Este cea mai simpla
si cea mai slaba metoda.
2. Dithering aleator = pixelii sunt comparati cu praguri alese aleator
3. Folosind un tipar= pentru fiecare pixe pragul este reprezentata de valoarea
tiparului in acel punct. Exemple pentru astfel de dithering sunt: Halftone,
Ordered.
4. Error-diffusion= eroarea acumulata prin adaugarea zgomotului este
transmisa la pixelii invecinati. Exemplu: Floyd-Steinberg

Haltfone
Acest tip de dithering simuleaza culorile folosind puncte de dimensiune diferite si
aflate la distante diferite. Privite de la departare aceste colectii de puncte vor
resulta pentru ochiul uman intr-o culoare ce nu poate fi reprezentata cu o
anumita paleta.

Asftel daca dimeniunea si resolutia imaginii sunt destul de mari pixelii vor fi atat
de mici incat cor crea efectul unei noi culori.
Tehnic folosit de imprimante pentru a crea pe hrtie un mare numr de
culori, utiliznd aranjamente de puncte formate cu cele cteva culori din
paleta proprie.
Imprimantele color obinuite au n paleta lor 4 culori: cian, magenta, galben i
negru. Imprimantele foto au un numr mai mare (dar oricum limitat) de culori
de baz.
Imprimarea imaginilor digitale, care pot codifica milioane de culori
perceptibile, prin reprezentarea direct a unei culori din imagine printr-o
culoare din paleta imprimantei ar da un rezultat nesatisfctor.
Aici intra in rol halftoningul. Imaginea original e citit ca o secven de mici
arii ptrate de la stnga la dreapta i de sus n jos; pentru fiecare arie,
algoritmul de halftoning evalueaz nivelul mediu de gri i selecteaz, dintr-un
set predefinit, o celul ptrat (numit celul de halftoning,) care conine un
aranjament de puncte albe i negre corespunztor acestui nivel. Imaginea
raster, care va fi efectiv transpus pe hrtie, e alctuit din mulimea tuturor
celulelor de halftoning selectate i asamblate.
Datorit dimensiunilor mici ale celulelor, ochiul nu discerne n pagina
imprimat punctele albe sau negre din interiorul lor, ci doar combinaia de
culori -- adic un ton de gri.
Pentru imprimarea imaginilor color, halftoningul se aplic pe rnd
componentelor cian, magenta, galben i neagr ale imaginii, iar rezultatele se
suprapun pe hrtie dup aplicarea unor corecii.
In imagininile de mai jos este prezentat un model de reprezentare a nunatelor de
gri prin puncte albe pe fundal negru sau puncte negre pe fundal alb. Se observa si
cum dimensiunea punctelor variaza:

Sabloane de reprezentare a intensitatilor

Error Diffusion Dither (algoritm halftoning)


Difuzarea erorilor de cuantizare catre pixelii vecini Dispersia erorilor catre
pixelii de jos si din dreapta

Cea mai cunoscuta metoda de difuzie a erorilor este Floyd-Steinberg .


Floyd-Steinberg
Un algoritm folosit des in conversie, mai ales in trecerea de la un format ce
permite folosirea mai multor culori la unul mai restrains este Floyd-Steinberg .
Algoritmul trasmis de zgomotul acumulat ( eroarea0 de la un pixel la pixelii
invecinati folosind distributia:

Cod Java:
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];
} 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.
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);
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();
}
}

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