1
PSI-2651 2005/2006
Hae Yong Kim hae@lps.usp.br
http://www.lps.usp.br/~hae
Tópicos a serem abordados:
1. Dispositivos e formatos para imagens; 2. Halftoning;
2.1. Difusão de erro; 2.2. Ordered dithering;
2
1. Dispositivos e formatos para imagens
Em níveis de cinza ou colorido.
Número de bits por pixel (Ex: 1, 4, 8, 16, 24, 32). Com ou sem palette.
Número de colunas e número de linhas. Resolução (pixels/polegada).
Modelo de cor aditivo ou subtrativo.
Exemplos:
Monitor de computador CRT: Colorido.
4, 8, 16 ou 24 bits por pixel.
Com palette: 4 bits (16 cores) e 8 bits (256 cores).
Sem palette: 16 bits (5 bits ou 32 níveis por cor) e 24 bits (8 bits ou 256 níveis por cor).
640×480, 800×600, 1024×764 ou 1280×1024 pixels. Modelo de cor aditivo.
Monitor de notebook (cristal líquido): Colorido.
16 ou 32 bits por pixel. Sem palette.
1024×764 pixels (800×600 por interpolação). Modelo de cor aditivo.
Impressora laser: Preto e branco. 1 bit por pixel.
Impressora jato de tinta: Colorido.
1 bit por pixel.
Modelo de cor subtrativo. Imagem BMP, TIF e TGA:
Colorido ou cinza.
Não compactado ou compactado sem perdas. Vários escolhas de bits por pixel.
Com ou sem palette. Imagem GIF:
Colorido.
8 bits por pixel com palette. Compactado sem perdas.
5 Imagem PNG:
Colorido.
Várias escolhas de bits/pixel. Compactado sem perdas.
Imagem JPG ou JPEG (antigo e 2000): Colorido.
Compactado com perdas. Imagem JBIG1/JBIG2:
Binário.
Compactado com ou sem perdas.
6 Escolha de palette e difusão de erro:
original (24 bits/pixel)
palette uniforme (4 bits/pixel)
palette uniforme com difusão de erro
median cut (4 bits/pixel)
median cut com difusão de erro
1. Como é possível mostrar fotografia em níveis de cinzas numa impressora laser?
2. Como é possível mostrar fotografia colorida numa impressora jato de tinta?
3. Como escolher o melhor palette para imagem GIF?
9
//Thresh.cpp #include <imgall>
int main(int argc, char** argv)
{ if (argc!=3) erro(“Thresh ent.tga sai.bmp”); IMGGRY ent; IMGBIN sai;
le(ent,argv[1]); sai=ent; imp(sai,argv[2]); } 10
2. Halftoning
Dada uma imagem em níveis de cinza G com valores reais entre 0 e 1, construir uma imagem binária B com valores 0 ou 1 tal que
) , ( ) , (l c G l c B ≈
onde B( cl, ) é a média dos valores de B em torno do pixel (l,c).
Thresholding Ruído branco ±0,5
//NoiseB.cpp #include <imgall>
int main(int argc, char** argv)
{ if (argc!=3) erro("NoiseB ent.tga sai.bmp"); IMGGRY ent; le(ent,argv[1]);
IMGBIN sai(ent.nl(),ent.nc()); mysrand(7);
for (int l=0; l<ent.nl(); l++) for (int c=0; c<ent.nc(); c++)
if (ent(l,c)+myrand()%128-64>=128) sai(l,c)=branco;
else sai(l,c)=preto; imp(sai,argv[2]);
13 Ruído branco ±0,5 Ordered dithering dispersed dots
14 Ordered dithering clustered dots
(meu programa)
Ordered dithering clustered dots (alchemy)
//Ordered dithering pontos dispersos //DispersB.cpp - versao mudanca de limiar #include <imgall>
int main(int argc, char** argv) { if (argc!=3)
erro(“DispersB ent.tga sai.bmp”); MATRIZ<int> D(8,8, 0, 32, 8, 40, 2, 34, 10, 42, 48, 16, 56, 24, 50, 18, 58, 26, 12, 44, 4, 36, 14, 46, 6, 38, 60, 28, 52, 20, 62, 30, 54, 22, 3, 35, 11, 43, 1, 33, 9, 41, 51, 19, 59, 27, 49, 17, 57, 25, 15, 47, 7, 39, 13, 45, 5, 37, 63, 31, 55, 23, 61, 29, 53, 21); IMGGRY ent; le(ent,argv[1]); IMGBIN sai(ent.nl(),ent.nc()); for (int l=0; l<ent.nl(); l++) for (int c=0; c<ent.nc(); c++) { int l2=l%8; int c2=c%8; if (ent(l,c)<4*D(l2,c2)+2) sai(l,c)=false; else sai(l,c)=true; } imp(sai,argv[2]); }
17
//Ordered dithering - pontos dispersos //Versao acrescimo de ruido
#include <imgall>
int main(int argc, char** argv) { if (argc!=3)
erro("DispersB ent.tga sai.bmp"); MATRIZ<int> D(8,8, 0, 32, 8, 40, 2, 34, 10, 42, 48, 16, 56, 24, 50, 18, 58, 26, 12, 44, 4, 36, 14, 46, 6, 38, 60, 28, 52, 20, 62, 30, 54, 22, 3, 35, 11, 43, 1, 33, 9, 41, 51, 19, 59, 27, 49, 17, 57, 25, 15, 47, 7, 39, 13, 45, 5, 37, 63, 31, 55, 23, 61, 29, 53, 21); IMGGRY ent; le(ent,argv[1]); 18 IMGBIN sai(ent.nl(),ent.nc()); for (int l=0; l<ent.nl(); l++) for (int c=0; c<ent.nc(); c++) { int l2=l%8; int c2=c%8; if (ent(l,c)+(4*D(l2,c2)+2-128)<128) sai(l,c)=preto; else sai(l,c)=branco; } imp(sai,argv[2]); } //Clustered dots MATRIZ<int> D(8, 8, 1, 9, 23, 27, 31, 20, 6, 2, 8, 15, 38, 47, 38, 39, 14, 7, 22, 37, 52, 53, 54, 49, 40, 21, 30, 46, 60, 61, 62, 55, 41, 28, 26, 45, 59, 64, 63, 56, 42, 32, 17, 36, 51, 58, 57, 50, 33, 18, 11, 16, 35, 44, 43, 34, 13, 12, 3, 10, 24, 29, 25, 19, 5, 4);
Nota: Tem que subtrair 1 para ir de 0 a 63.
Difusão de erro (Floyd and Steinberg)
Difusão de erro (Rogers)
21 Difusão de erro
(Jarvis, Judice and Ninke)
Difusão de erro (Stucki) 22
2.2 Difusão de erro
//RogersB.cpp #include <imgall>int main(int argc, char** argv)
{ if (argc!=3) erro("RogersB ent.tga sai.bmp"); IMGFLT ent; IMGBIN sai;
le(ent,argv[1]); ent.backg()=0.0; sai.resize(ent.nl(),ent.nc()); double error;
for (int l=0; l<ent.nl(); l++) for (int c=0; c<ent.nc(); c++) { if (ent(l,c)<0.5)
{ sai(l,c)=preto; error=ent(l,c); } else
{ sai(l,c)=branco; error=ent(l,c)-1.0; } ent(l,c+1) = ent(l,c+1) + 3.0/8.0*error; ent(l+1,c) = ent(l+1,c) + 3.0/8.0*error; ent(l+1,c+1) = ent(l+1,c+1) + 2.0/8.0*error; }
imp(sai,argv[2]); }
Nota: Não precisa fazer tratamento de borda.
⎥ ⎦ ⎤ ⎢ ⎣ ⎡• × ⎥⎦ ⎤ ⎢⎣ ⎡ 2 3 3 8 1 Rogers ⎥ ⎦ ⎤ ⎢ ⎣ ⎡ • × ⎥⎦ ⎤ ⎢⎣ ⎡ 1 5 3 7 16 1
Floyd and Steinberg
⎥ ⎥ ⎥ ⎦ ⎤ ⎢ ⎢ ⎢ ⎣ ⎡ • × ⎥⎦ ⎤ ⎢⎣ ⎡ 1 3 5 3 1 3 5 7 5 3 5 7 48 1
Jarvis, Judice and Ninke
⎥ ⎥ ⎥ ⎦ ⎤ ⎢ ⎢ ⎢ ⎣ ⎡ • × ⎥⎦ ⎤ ⎢⎣ ⎡ 1 2 4 2 1 2 4 8 4 2 4 8 42 1
25
Halftoning inverso
(1a) Input sample Ax (1b) Output sample Ay
(1c) To-be-processed Qx (1d) Ideal output Qy
26 (1e) Gaussian 2.8 PSNR 30.23dB (1f) 10-ID3 PSNR 34.75dB
(2a) Dispersed-dot OD (2b) PSNR 33.69 dB
Exercício:
Reduzir true color (24 bits/pixel) para 6 bits/pixel usando ordered dithering e difusão de erro.
Dada uma imagem halftone, como descobrir qual foi o método de halftoning usado?