/* * calibracao.c * * Calibracao de camera e demonstrada neste programa. * Atraves do click sobre as marcas no padrao de calibracao, * estabelece-se 10 (dez) correspondencia na janela esquerda. * A marca clicada e "highlighted" com a cor vermelha. * Com base destas 10 correspondencias e estimada a matriz * de projecao e os parametros intrisecos e extrinsecos da * camera. Para validar a matriz de projecao obtida, sao * reprojetados os vertices da cena sintetica (um cubo azul e * um cubo rosa) e as marcas na janela direita. * Atraves das teclas pode-se alterar os parametros da camera: * 'x': decrementa 5.0 o angulo de rotacao em torno de 'x' * 'X': incrementa 5.0 o angulo de rotacao em torno de 'x' * 'y': decrementa 5.0 o angulo de rotacao em torno de 'y' * 'Y': incrementa 5.0 o angulo de rotacao em torno de 'y' * 'z': decrementa 5.0 o angulo de rotacao em torno de 'z' * 'Z': incrementa 5.0 o angulo de rotacao em torno de 'z' * 'r': reseta os angulos de rotacao para (35,35,0) * 'R': reseta as marcas selecionadas manualmente * * Ting (07/11/08) */ #include #include #include #include int win; // id da janela principal int swin1, swin2; // id das subjanelas do glut int width = 300, height = 300; #define d 1. static GLfloat ndata[8][3] = { {-d, -d, -d}, {d, -d, -d}, {d,d,-d}, {-d, d, -d}, {-d, -d, d}, {d, -d, d}, {d,d,d}, {-d, d, d} }; static GLfloat mdata[18][3] = { {-d/2,-d/2,d}, {d/2,-d/2,d}, {d/2,d/2,d}, {-d/2,d/2,d}, {d/2,0,d}, {-d/2,0,d}, {0,-d/2,d}, {0,d/2,d},{0,0,d}, {-d/2, d, -d/2}, {d/2, d, -d/2},{-d/2, d, d/2}, {d/2, d, d/2}, {-d/2, d, 0}, {d/2, d, 0},{0, d, -d/2}, {0, d, d/2}, {0,d,0} }; static GLuint vindices[6][4] = { {2,3,7,6}, {4,5,6,7}, {0,3,2,1}, {0,4,7,3}, {1,2,6,5}, {0,1,5,4} }; typedef struct POINT_struct { /* pontos */ GLdouble x, y; // coordenadas em imagem GLuint label; // referencia a 3D } Point2D; int nsamples=0; Point2D samples[18]; float **A, W[13], **V; float M[3][4]; double anglex, angley, anglez; double T[3], R[3][3], F[2], aspRatio; int O[2]; /********************************************************** * SVD * * Esta rotina faz parte da coletânea dos programas * do livro Numerical Recipes: The Art of Scientific Computing * * Observe que o indice de um arranjo comeca com 1!!!! * * http://www.nr.com/ * */ #define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a)) static float maxarg1,maxarg2; #define FMAX(a,b) (maxarg1=(a),maxarg2=(b),(maxarg1) > (maxarg2) ?\ (maxarg1) : (maxarg2)) static int iminarg1,iminarg2; #define IMIN(a,b) (iminarg1=(a),iminarg2=(b),(iminarg1) < (iminarg2) ?\ (iminarg1) : (iminarg2)) static float sqrarg; #define SQR(a) ((sqrarg=(a)) == 0.0 ? 0.0 : sqrarg*sqrarg) float pythag(float a, float b) { float absa,absb; absa=fabs(a); absb=fabs(b); if (absa > absb) return absa*sqrt(1.0f+SQR(absb/absa)); else return (absb == 0.0 ? 0.0 : absb*sqrt(1.0f+SQR(absa/absb))); } void svdcmp(float **a, int m, int n, float w[], float **v) { float pythag(float a, float b); int flag,i,its,j,jj,k,l,nm; float anorm,c,f,g,h,s,scale,x,y,z,*rv1; rv1 = (float *) malloc((n+1) * sizeof(float)); g=scale=anorm=0.0; for (i=1;i<=n;i++) { l=i+1; rv1[i]=scale*g; g=s=scale=0.0; if (i <= m) { for (k=i;k<=m;k++) scale += fabs(a[k][i]); if (scale) { for (k=i;k<=m;k++) { a[k][i] /= scale; s += a[k][i]*a[k][i]; } f=a[i][i]; g = -SIGN(sqrt(s),f); h=f*g-s; a[i][i]=f-g; for (j=l;j<=n;j++) { for (s=0.0,k=i;k<=m;k++) s += a[k][i]*a[k][j]; f=s/h; for (k=i;k<=m;k++) a[k][j] += f*a[k][i]; } for (k=i;k<=m;k++) a[k][i] *= scale; } } w[i]=scale *g; g=s=scale=0.0; if (i <= m && i != n) { for (k=l;k<=n;k++) scale += fabs(a[i][k]); if (scale) { for (k=l;k<=n;k++) { a[i][k] /= scale; s += a[i][k]*a[i][k]; } f=a[i][l]; g = -SIGN(sqrt(s),f); h=f*g-s; a[i][l]=f-g; for (k=l;k<=n;k++) rv1[k]=a[i][k]/h; for (j=l;j<=m;j++) { for (s=0.0,k=l;k<=n;k++) s += a[j][k]*a[i][k]; for (k=l;k<=n;k++) a[j][k] += s*rv1[k]; } for (k=l;k<=n;k++) a[i][k] *= scale; } } anorm=FMAX(anorm,(fabs(w[i])+fabs(rv1[i]))); } for (i=n;i>=1;i--) { if (i < n) { if (g) { for (j=l;j<=n;j++) v[j][i]=(a[i][j]/a[i][l])/g; for (j=l;j<=n;j++) { for (s=0.0,k=l;k<=n;k++) s += a[i][k]*v[k][j]; for (k=l;k<=n;k++) v[k][j] += s*v[k][i]; } } for (j=l;j<=n;j++) v[i][j]=v[j][i]=0.0; } v[i][i]=1.0; g=rv1[i]; l=i; } for (i=IMIN(m,n);i>=1;i--) { l=i+1; g=w[i]; for (j=l;j<=n;j++) a[i][j]=0.0; if (g) { g=1.0/g; for (j=l;j<=n;j++) { for (s=0.0,k=l;k<=m;k++) s += a[k][i]*a[k][j]; f=(s/a[i][i])*g; for (k=i;k<=m;k++) a[k][j] += f*a[k][i]; } for (j=i;j<=m;j++) a[j][i] *= g; } else for (j=i;j<=m;j++) a[j][i]=0.0; ++a[i][i]; } for (k=n;k>=1;k--) { for (its=1;its<=30;its++) { flag=1; for (l=k;l>=1;l--) { nm=l-1; if ((float)(fabs(rv1[l])+anorm) == anorm) { flag=0; break; } if ((float)(fabs(w[nm])+anorm) == anorm) break; } if (flag) { c=0.0; s=1.0; for (i=l;i<=k;i++) { f=s*rv1[i]; rv1[i]=c*rv1[i]; if ((float)(fabs(f)+anorm) == anorm) break; g=w[i]; h=pythag(f,g); w[i]=h; h=1.0/h; c=g*h; s = -f*h; for (j=1;j<=m;j++) { y=a[j][nm]; z=a[j][i]; a[j][nm]=y*c+z*s; a[j][i]=z*c-y*s; } } } z=w[k]; if (l == k) { if (z < 0.0) { w[k] = -z; for (j=1;j<=n;j++) v[j][k] = -v[j][k]; } break; } if (its == 30) { printf("svdcmp nao convergiu em 30 iteracoes!"); exit(1); } x=w[l]; nm=k-1; y=w[nm]; g=rv1[nm]; h=rv1[k]; f=((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y); g=pythag(f,1.0); f=((x-z)*(x+z)+h*((y/(f+SIGN(g,f)))-h))/x; c=s=1.0; for (j=l;j<=nm;j++) { i=j+1; g=rv1[i]; y=w[i]; h=s*g; g=c*g; z=pythag(f,h); rv1[j]=z; c=f/z; s=h/z; f=x*c+g*s; g = g*c-x*s; h=y*s; y *= c; for (jj=1;jj<=n;jj++) { x=v[jj][j]; z=v[jj][i]; v[jj][j]=x*c+z*s; v[jj][i]=z*c-x*s; } z=pythag(f,h); w[j]=z; if (z) { z=1.0/z; c=f*z; s=h*z; } f=c*g+s*y; x=c*y-s*g; for (jj=1;jj<=m;jj++) { y=a[jj][j]; z=a[jj][i]; a[jj][j]=y*c+z*s; a[jj][i]=z*c-y*s; } } rv1[l]=0.0; rv1[k]=f; w[k]=x; } } free((char *)rv1); } void monta_2_linhas (int k) { int i,j; j = (k-1)/2; i = k; A[i][1] = mdata[samples[j].label][0]; A[i][2] = mdata[samples[j].label][1]; A[i][3] = mdata[samples[j].label][2]; A[i][4] = 1; A[i][5] = 0; A[i][6] = 0; A[i][7] = 0; A[i][8] = 0; A[i][9] = -samples[j].x*mdata[samples[j].label][0]; A[i][10] = -samples[j].x*mdata[samples[j].label][1]; A[i][11] = -samples[j].x*mdata[samples[j].label][2]; A[i][12] = -samples[j].x; A[i+1][1] = 0; A[i+1][2] = 0; A[i+1][3] = 0; A[i+1][4] = 0; A[i+1][5] = mdata[samples[j].label][0]; A[i+1][6] = mdata[samples[j].label][1]; A[i+1][7] = mdata[samples[j].label][2]; A[i+1][8] = 1; A[i+1][9] = -samples[j].y*mdata[samples[j].label][0]; A[i+1][10] = -samples[j].y*mdata[samples[j].label][1]; A[i+1][11] = -samples[j].y*mdata[samples[j].label][2]; A[i+1][12] = -samples[j].y; } /* Determinar m, tal que Am=0 * */ void proj_mat_calib(void) { int i, j; double k; //Alocacao de memoria. Uma posicao a mais é alocada porque //a base dos indices inicia com 1 em Numerical Recipes A = (float **)malloc (sizeof (float *) * (2*nsamples+1)); for (i=1; i< (2*nsamples+1); i++) A[i] = (float *)malloc (sizeof (float) * 13); V = (float **)malloc (sizeof (float *) * 13); for (i=1; i< 13; i++) V[i] = (float *)malloc (sizeof (float) * 13); // Montar matriz A for (i=1; i<(2*nsamples+1); i=i+2) { monta_2_linhas(i); } svdcmp(A,16,12,W,V); // Selcionar o menor auto-valor (que deve ser teoricamente nulo) // correspondente ao espaço nulo de A, ou seja, Am=0 for (k=1.E6,i=1; i<13; i++) { if (W[i]