Transformações geométricas em coordenadas homogêneas 2-D Coordenadas homogêneas (ou coordenadas projetivas, abreviado CHs) são um sistema de coordenadas usada na geometria projetiva. Um ponto em R 2 (x,y) é representado em CHs utilizando 3 números (x,y,w). O ponto em CHs (x,y,w) representa o ponto (x/w, y/w) em R 2. Por exemplo, (4,6,2) em CHs representa o ponto (2,3) de R 2. Se w=1, dizemos que a representação está normalizada. Exemplo da representação em CHs normalizada: (2,3,1). Figura retirada de Wikipedia.
Matriz 2x2 (transformação linear): Representando os pontos por vetores 2x1, a transformação entre pontos é representada por uma matriz 2x2. Matriz 2x2 consegue representar rotação (em torno do centro do sistema de coordenadas), shearing, reflexão e mudança de escala. Exemplos: Rotação: [ x n Shearing: [ x n s y n] = [ c c][ s x v y v] y n] = [ 1 k 0 1][ x v y v] Reflexão em torno do eixo X: [ x n y n] = [ 1 0 0 1][ x v y v] Mudança de escala: [ x n y n] [ = e x 0 0 e y][ x v y v], c=cos( ) e s=sin( ) y x Uma composição de transformações pode ser obtida multiplicando as matrizes de transformação. A transformação inversa é calculada pela inversa da matriz.
Matriz 2x3 (transformação afim): Se utilizar matrizes de transformação 2x3, consegue representar transformações afins. Elas incluem (além das transformações 2x2) a translação. Consegue mapear retângulo em paralelograma (mantém o paralelismo das retas). Translação por (t x, t y ): [ x n y n] [ = 1 0 t x y][ x v ] y 0 1 t v 1 A função getaffinetransform consegue determinar a matriz de transformação 2x3 a partir de 3 pares de pontos correspondentes. O problema de transformação 2x3 é que não dá para multiplicar duas matrizes 2x3, assim como não existe matriz inversa de uma matriz 2x3. Exemplo: //shear.cpp pos2016 #include <cekeikon.h> int main() { Mat_<FLT> src = (Mat_<FLT>(3,2) << 0,0, 0,511, 511,511); cout << src << endl; Mat_<FLT> dst = (Mat_<FLT>(3,2) << 200,100, 100,400, 400,400); cout << dst << endl; Mat_<FLT> m=getaffinetransform(src,dst); cout << m << endl; Mat_<GRY> a; le(a,"lenna.jpg"); Mat_<GRY> b; warpaffine(a,b,m,a.size(),inter_linear,border_wrap); imp(b,"afim.png"); [0.58708417, -0.19569471, 200; 0, 0.58708417, 100]
O seguinte programa faz rotação em torno de um ponto arbitrário: #include <cekeikon.h> int main() { Mat_<GRY> ent; le(ent,"lenna.jpg"); 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); Saída: [0.8660254037844387, 0.4999999999999999, -93.70250336881629; -0.4999999999999999, 0.8660254037844387, 162.2974966311837]
Como construir a matriz m manualmente, sem usar a função getrotationmatrix2d? Utilizando matrizes 3x3. dx=256; dy=256; (T(dx,dy) * R(30) * T(-dx,-dy)) * (xv, yv, 1) t //manual.cpp #include <cekeikon.h> Mat_<double> translacao(double tx, double ty) { Mat_<double> m(3,3, 0.0); m(0,0)=1; m(1,1)=1; m(2,2)=1; m(0,2)=tx; m(1,2)=ty; return m; Mat_<double> rotacao(double graus) { double radianos=deg2rad(graus); double co=cos(radianos); double se=sin(radianos); Mat_<double> m(3,3, 0.0); m(0,0)=co; m(0,1)=se; m(1,0)=-se; m(1,1)=co; m(2,2)=1; return m; int main() { Mat_<double> m=translacao(256,256)*rotacao(30)*translacao(-256,-256); cout << m << endl; Saída: [0.8660254037844387, 0.4999999999999999, -93.70250336881628; -0.4999999999999999, 0.8660254037844387, 162.2974966311837; 0, 0, 1] Despreza-se a última linha.
Matriz 3x3 (transformação perspectiva): Usando sistema de coordenadas homogêneas (matriz 3x3) permitem efetuar rotação, translação, reflexão, mudança de escala, transformação afim e transformação em perspectiva. A composição das transformações é calculada pela multiplicação matricial. A transformação inversa é dada pela inversa da matriz. Rotação em coordenadas homogêneas: [ x n ]=[ c s 0 ] y n s c 0 y v R A, onde c=cos(a) e s=sin(a) 1 1 0 0 1][ xv Translação em coordenadas homogêneas: [ x ]=[1 0 t n x ] y n 0 1 t y y v T t, onde t = (t x, t y ). 1 1 0 0 1][ xv Mudança de escala em coordenadas homogêneas: [ x ]=[ex 0 0 n ] y n 0 e y 0 y v E e, onde e = (e x, e y ). 1 1 0 0 1][ xv As matrizes podem ser multiplicadas para obter transformação composta. Por exemplo, rotação de A graus em torno de centro c = (c x, c y ): T -c R A T c.
O seguinte programa corrige o efeito em perspectiva (usando rotinas de OpenCV): pv warppers quadrado1.bmp quadrado1b.pgm 55 156 585 156 0 324 639 324 10 156 630 156 10 324 630 324 pv warppers quadrado2.bmp quadrado2b.pgm 237 156 639 205 0 260 451 324 10 10 630 10 10 470 630 470 pv warppers ka0.jpg ka1.jpg 73 0 533 0-22 479 626 479 10 10 630 10 10 470 630 470 quadrado1.bmp quadrado1b.pgm quadrado2.bmp quadrado2b.pgm ka0.jpg ka1.jpg
//pers.cpp grad-2017 #include <cekeikon.h> int main() { Mat_<FLT> src = (Mat_<FLT>(4,2) << 70,0, 533,0, -22,479, 626,479); Mat_<FLT> dst = (Mat_<FLT>(4,2) << 10,0, 630,0, 10,479, 630,479); Mat_<FLT> m=getperspectivetransform(src,dst); cout << m << endl; Mat_<FLT> v=(mat_<flt>(3,1) << 70,0,1); Mat_<FLT> w=m*v; cout << w << endl; Mat_<COR> a; le(a,"ka0.jpg"); Mat_<COR> b; warpperspective(a,b,m,a.size()); imp(b,"ka1.jpg"); C:\haepi\algpi\transgeom\grad2017>persp [1.3390929, 0.26553699, -83.736504; 1.373901e-015, 1.3995681, -5.6843419e-013; 6.3154777e-018, 0.00083417125, 1] [9.9999924; -4.7226112e-013; 1] É possível usar mais de 4 pontos para achar a transformação em perspectiva. Fica mais robusto. Mat findhomography(inputarray srcpoints, InputArray dstpoints, int method=0, double ransacreprojthreshold=3, OutputArray mask=noarray() ) method Method used to computed a homography matrix. The following methods are possible: 0 - a regular method using all the points CV_RANSAC - RANSAC-based robust method CV_LMEDS - Least-Median robust method Veja o manual do OpenCV.
Escrever sobre calibração de câmera. Escrever sobre correção de defeito da lente.