Buscar

09. Sistemas Eletrônicos Inteligentes - Reamostragem e interpolação

Prévia do material em texto

Reamostragem 
 
A reamostragem de imagens é amplamente utilizada em processamento de imagens e vídeos. 
Ela é utilizada para ampliar, reduzir, e rotacionar imagens. Também é utilizada para criar efei-
tos como “morphing/warping”, para corrigir distorção da lente, para fazer interpolação de co-
res nos dispositivos para aquisição de imagens (câmeras, scanners,etc), para registrar imagens 
(criar uma única imagem “grudando” duas ou mais imagens), gerar imagens em coordenadas 
especiais como log-polar, estabilizar tremor da câmera de vídeo, para corrigir a movimenta-
ção do paciente em imagens médicas, para normalizar imagens médicas que envolvem vários 
sujeitos, etc. 
 
Os métodos populares para reamostragem de imagens incluem: 
• Vizinho mais próximo 
• Bilinear 
• Bicúbico 
• Spline 
• Reamostragem Lanczos 
 
Os programas abaixo fazem ampliação/redução de imagens usando interpolação vizinho mais 
próximo: 
 
// vizinho.cpp pos-2016 
#include <cekeikon.h> 
int main(int argc, char** argv) 
{ if (argc!=4) { 
 printf("vizinho ent.pgm sai.pgm fator\n"); 
 erro("Erro: Numero de argumentos invalido"); 
 } 
 Mat_<GRY> a; le(a,argv[1]); 
 double fator; sscanf(argv[3],"%lf",&fator); 
 int nl=int(a.rows*fator); 
 int nc=int(a.cols*fator); 
 Mat_<GRY> b(nl,nc); 
 for (int l=0; l<b.rows; l++) 
 for (int c=0; c<b.cols; c++) 
 b(l,c) = a(cvRound(l/fator),cvRound(c/fator)); 
 imp(b,argv[2]); 
} 
 
//vizinho.cpp - pos-2012 
#include <cekeikon.h> 
int main() 
{ Mat_<GRY> ent; 
 le(ent,"lennag.tga"); 
 Mat_<GRY> sai(600,600); 
 // cria sai 
 for (int l=0; l<sai.rows; l++) 
 for (int c=0; c<sai.cols; c++) { 
 int le = round(l * ((ent.rows-1.0)/(sai.rows-1.0))); 
 int ce = round(c * ((ent.cols-1.0)/(sai.cols-1.0))); 
 sai(l,c) = ent(le, ce); 
 } 
 imp(sai,"vizinho.tga"); 
} 
 
// camzoom.cpp grad-2014 modificado 
// Muda fator de zoom ao longo do tempo. 
#include <cekeikon.h> 
 
Mat_<GRY> amplia(Mat_<GRY> b, double fator) 
{ Mat_<GRY> d(round(b.rows*fator),round(b.cols*fator)); 
 for (int l=0; l<d.rows; l++) 
 for (int c=0; c<d.cols; c++) 
 d(l,c) = b( round(l/fator), round(c/fator) ); 
 return d; 
} 
 
int main() 
{ VideoCapture vi(0); 
 vi.set(CV_CAP_PROP_FRAME_WIDTH,640); 
 vi.set(CV_CAP_PROP_FRAME_HEIGHT,480); 
 if (!vi.isOpened()) erro("Erro abertura webcam"); 
 Mat_<COR> a; 
 Mat_<GRY> b; 
 int ch; 
 namedWindow("janela"); 
 double dt=M_PI/90; 
 double t=0; 
 do { 
 vi >> a; 
 flip(a,a,1); 
 converte(a,b); 
 
 b=amplia(b, 1+0.5*sin(t)); 
 t+=dt; 
 
 imshow("janela",b); 
 ch=waitKey(1); 
 } while (ch!=27); 
} 
 
 
// cvvizinho.cpp pos2012 - usa funcao resize do OpenCV 
//vizinho.cpp 
#include <cekeikon.h> 
int main() 
{ Mat_<GRY> ent; 
 le(ent,"lennag.tga"); 
 Mat_<GRY> sai; 
 resize(ent, sai, Size(600,600), 0, 0, INTER_NEAREST); 
 imp(sai,"cvvizinho.tga"); 
} 
 
//INTER_NEAREST nearest-neighbor interpolation 
//INTER_LINEAR bilinear interpolation (used by default) 
//INTER_AREA resampling using pixel area relation. It may be the preferred 
// method for image decimation, as it gives moire-free results. 
// But when the image is zoomed, it is similar to 
// the INTER_NEAREST method 
//INTER_CUBIC bicubic interpolation over 4x4 pixel neighborhood 
//INTER_LANCZOS4 Lanczos interpolation over 8x8 pixel neighborhood 
Os programas abaixo fazem ampliação de imagens usando interpolação bilinear: 
 
//linear.cpp pos2016 
#include <cekeikon.h> 
int main() 
{ Mat_<GRY> a; 
 le(a,"lenna.jpg"); 
 Mat_<GRY> b(600,600); 
 // cria b 
 for (int l=0; l<b.rows; l++) 
 for (int c=0; c<b.cols; c++) { 
 double ald = l * ((a.rows-1.0)/(b.rows-1.0)); 
 double acd = c * ((a.cols-1.0)/(b.cols-1.0)); 
 
 int fal=int(ald); int fac=int(acd); 
 double dl=ald-fal; double dc=acd-fac; 
 
 double p1=(1-dl)*(1-dc); 
 double p2=(1-dl)*dc; 
 double p3=dl*(1-dc); 
 double p4=dl*dc; 
 
 b(l,c) = round( 
 p1*a(fal,fac) + p2*a(fal,fac+1) + 
 p3*a(fal+1,fac) + p4*a(fal+1,fac+1) 
 ); 
 } 
 imp(b,"linear.pgm"); 
} 
 
 
 
//cvlinear.cpp pos2012 interpolacao linear usando resize 
// do OpenCV 
#include <cekeikon.h> 
int main() 
{ Mat_<GRY> ent; 
 le(ent,"lennag.tga"); 
 Mat_<GRY> sai; 
 resize(ent, sai, Size(600,600), 0, 0, INTER_LINEAR); 
 imp(sai,"cvlinear.tga"); 
} 
Abaixo, a imagem lennag.tga com 512×512 pixels foi reamostrada para 600×700 pixels usan-
do interpolações vizinho mais próximo e bilinear: 
 
 
vizinho mais próximo 
 
 
bilinear 
Abaixo, a imagem lennag.tga com 512×512 pixels foi aumentada 320% usando as interpola-
ções do programa Jasc Paint Shop Pro e Alchemy: 
 vizinho mais próximo 
 bilinear 
 bicúbico 
 lanczos3 (sinc)
Existem situações em que é preferível acessar uma imagem fornecendo coordenadas (x, y), em 
vez de coordenadas (l, c). Efetuar uma rotação de uma imagem é uma destas situações. Seria 
muito conveniente se pudesse definir o pixel central da imagem, e se pudesse acessar os pi-
xels da imagem fornecendo coordenadas (x, y). 
 
A biblioteca Cekeikon permite este tipo de acesso, através do modo atC (centralizado com 
background), atX (estendido) e atR (replicado). Veja o programa abaixo: 
 
//coordxy.cpp 
#include <cekeikon.h> 
 
int main() { 
 
// Mat_<GRY> t=(Mat_<GRY>(3,3) << 1,2,3, 
// 4,5,6, 
// 7,8,9); 
// ImgXyb<GRY> a=t; 
 
 ImgXyb<GRY> a=(ImgXyb<GRY>)(Mat_<GRY>(3,3) << 1,2,3, 
 4,5,6, 
 7,8,9); 
 a.centro(1,1); a.backg=255; 
 printf("a(-1,-1)=%d\n",a(-1,-1)); 
 printf("a(-1,+1)=%d\n",a(-1,+1)); 
 printf("minx=%d maxx=%d miny=%d maxy=%d\n", 
 a.minx, a.maxx, a.miny, a.maxy); 
 printf("a(-2,-1)=%d\n",a(-2,-1)); 
} 
 
Saída: 
a(-1,-1)=7 
a(-1,+1)=1 
minx=-1 maxx=1 miny=-1 maxy=1 
a(-2,-1)=255 
 
Neste programa, foi criada uma imagem 3×3, e o pixel central foi definido como o centro da 
imagem através do comando a.centro(1,1); 
 
Daí em diante, a(-1,-1) irá acessar o pixel a(x,y)=a(-1,-1). 
 
A variável a.minx devolve o menor valor da coordenada x do domínio da imagem, isto é, 
-1. As funções a.maxx,a.miny,a.maxy são análogos. 
 
Se acessar um pixel fora do domínio da imagem, acessa-se o pixel a.backg. 
A fórmula da rotação é: 
)cos(θ=c )sen(θ=s 






−
=
cs
sc
yxyx vvnn ],[],[ 





 −
=
cs
sc
yxyx nnvv ],[],[ 
onde θ é o ângulo da rotação, [xv, yv] são as coordenadas de um pixel antes da rotação e [xv, 
yv] são as suas coordenadas após a rotação. 
 
Usando coordenadas [l,c], a fórmula não muda: 






−
=
cs
sc
clcl vvnn ],[],[ 
 
 
 
 
 
 
Também pode-se escrever o mesmo como (notação usada no OpenCV): 












−
=





v
v
n
n
y
x
cs
sc
y
x
 











 −
=





n
n
v
v
y
x
cs
sc
y
x
 
 
x 
y 
l 
c 
x 
y 
Os seguintes programas efetuam uma rotação na imagem, usando interpolação vizinho mais 
próximo. 
 
//rotacao.cpp pos2016 
#include <cekeikon.h> 
int main(int argc, char** argv) 
{ if (argc!=4) { 
 printf("rotacao ent.pgm sai.pgm graus\n"); 
 erro("Erro: Numero de argumentos invalido"); 
 } 
 
 double graus; sscanf(argv[3],"%lf",&graus);double radianos=deg2rad(graus); 
 double co=cos(radianos); 
 double se=sin(radianos); 
 
 ImgXyb<GRY> a; le(a,argv[1]); 
 //a.centro(a.rows/2,a.cols/2); a.backg=255; 
 a.centro(); a.backg=255; 
 
 ImgXyb<GRY> b(a.rows,a.cols); 
 b.centro(); b.backg=255; 
 
 for (int xn=b.minx; xn<=b.maxx; xn++) 
 for (int yn=b.miny; yn<=b.maxy; yn++) { 
 int xv=round(xn*co+yn*se); 
 int yv=round(-xn*se+yn*co); 
 b(xn,yn)=a(xv,yv); 
 } 
 imp(b,argv[2]); 
} 
 
 
 
 
// rotacao_cv.cpp pos2016 
#include <cekeikon.h> 
int main() 
{ Mat_<GRY> ent; le(ent,"lenna.jpg"); //mostra(ent); 
 Mat_<GRY> sai; 
 Mat_<double> m=getRotationMatrix2D(Point2f(ent.cols/2,ent.rows/2), 30, 1); 
 cout << m << endl; 
 warpAffine(ent, sai, m, ent.size(), INTER_LINEAR, BORDER_CONSTANT, Scalar(255)); 
 mostra(sai); 
} 
 
[0.8660254037844387, 0.4999999999999999, -93.70250336881629; 
 -0.4999999999999999, 0.8660254037844387, 162.2974966311837] 
 
 
//camrot.cpp grad-2014 modificado 
#include <cekeikon.h> 
 
Mat_<GRY> rotacao(Mat_<GRY> ap, double angrad) 
{ Mat_<GRY> bp(ap.rows,ap.cols); 
 IMG_<GRY> a(ap); a.backg=255; 
 IMG_<GRY> b(bp); 
 double c=cos(angrad); 
 double s=sin(angrad); 
 for (int x=b.minx; x<=b.maxx; x++) 
 for (int y=b.miny; y<b.maxy; y++) { 
 double xv=x*c+y*s; 
 double yv=-x*s+y*c; 
 b.atC(x,y) = a.atR(round(xv),round(yv)); 
 } 
 return bp; 
} 
 
int main() 
{ VideoCapture vi(0); 
 vi.set(CV_CAP_PROP_FRAME_WIDTH,640); 
 vi.set(CV_CAP_PROP_FRAME_HEIGHT,480); 
 if (!vi.isOpened()) erro("Erro abertura webcam"); 
 Mat_<COR> a; 
 Mat_<GRY> b; 
 int ch; 
 namedWindow("janela"); 
 double t=0; 
 do { 
 vi >> a; 
 flip(a,a,1); 
 converte(a,b); 
 
 b=rotacao(b,deg2rad(t)); 
 t=t+1; 
 
 imshow("janela",b); 
 ch=waitKey(1); 
 } while (ch!=27); 
} 
Referências: 
[1] William K. Pratt, “Digital Image Processing,” 2nd ed., John Wiley & Sons, 1991. 
 
Escrever programa que faz warping 
Explicar direito interpolação sinc (mudar amostragem 40 kHz para 44 kHz). 
Explicar interpolação bicúbica 
 
Nota: Suponha um senoide de 450 Hz amostrado a 1000 amostras/segundo. Não parece se-
nóide. Teoricamente, é possível reconstruir. Como fazer? 
 
 
 
imagem original 
 
imagem log-polar

Continue navegando