1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
/*
L'algorithme vient de:
Projective Mappings for Image Warping (1989)
by Paul Heckbert
in Fundamentals of Texture Mapping and Image Warping (Paul Heckbert,
Master’s Thesis), U.C.Berkeley
http://www.cs.utah.edu/classes/cs6964-whitaker/heckbert_projective.pdf
Le cas des parallèlogrames n'est pas pris en compte dans cette implémentation.
Merci à pseudocode pour le débroussaillage :)
*/
double *getPerspectiveTransform(CvPoint2D32f *P) {
double *H=calloc(18,sizeof(double));
double *adj=H+9;
double sx = (P[0].x-P[1].x)+(P[2].x-P[3].x);
double sy = (P[0].y-P[1].y)+(P[2].y-P[3].y);
double dx1 = P[1].x-P[2].x;
double dx2 = P[3].x-P[2].x;
double dy1 = P[1].y-P[2].y;
double dy2 = P[3].y-P[2].y;
double z = (dx1*dy2)-(dy1*dx2);
double g = ((sx*dy2)-(sy*dx2))/z;
double h = ((sy*dx1)-(sx*dy1))/z;
// matrice de transformation
double a=H[0]=P[1].x-P[0].x+g*P[1].x;
double b=H[1]=P[3].x-P[0].x+h*P[3].x;
double c=H[2]=P[0].x;
double d=H[3]=P[1].y-P[0].y+g*P[1].y;
double e=H[4]=P[3].y-P[0].y+h*P[3].y;
double f=H[5]=P[0].y;
H[6]=g;
H[7]=h;
H[8]=1;
// matrice de transformation inverse (matrice adjointe)
adj[0]=e-f*h;
adj[1]=c*h-b;
adj[2]=b*f-c*e;
adj[3]=f*g-d;
adj[4]=a-c*g;
adj[5]=c*d-a*f;
adj[6]=d*h-e*g;
adj[7]=b*g-a*h;
adj[8]=a*e-b*d;
return H;
}
void projective_mapping(double *u, double *v, double *H) {
double x = (H[0]*u[0]+H[1]*v[0]+H[2])/(H[6]*u[0]+H[7]*v[0]+1);
double y = (H[3]*u[0]+H[4]*v[0]+H[5])/(H[6]*u[0]+H[7]*v[0]+1);
u[0]=x;
v[0]=y;
}
void inverse_projective_mapping(double *u, double *v, double *H) {
double x = (H[0]*u[0]+H[1]*v[0]+H[2])/(H[6]*u[0]+H[7]*v[0]+1);
double y = (H[3]*u[0]+H[4]*v[0]+H[5])/(H[6]*u[0]+H[7]*v[0]+1);
double z = (H[6]*u[0]+H[7]*v[0]+H[8])/(H[6]*u[0]+H[7]*v[0]+1);
u[0]=x/z;
v[0]=y/z;
}
void perspectiveTransform(IplImage *img,CvPoint *I, double *H) {
// conversion dans le repère orthonormé (u,v) [0,1]x[0,1]
double u = (double)I->x/(double)img->width;
double v = (double)I->y/(double)img->height;
// passage dans le repère perspective
projective_mapping(&u, &v, H);
// pixel correspondant dans le quadrilatère
I->x=(int)round(u);
I->y=(int)round(v);
}
void inversePerspectiveTransform(IplImage *img,CvPoint *I, double *H) {
double u=I->x;
double v=I->y;
// passage dans le repère orthonormé
inverse_projective_mapping(&u, &v, H+9);
// pixel correspondant dans le carré
I->x=(int)round(u*(double)img->width);
I->y=(int)round(v*(double)img->height);
}
/*
L'image source est transformée pour tenir dans dst.
Quand map n'est pas nul c'est un pointeur sur un tableau de
dimension sizeof(CvPoint)*dst->width*dst->height
qui contiendra les coordonées d'origine des pixels.
*/
void perspectiveTransformImage(IplImage *src,CvPoint2D32f *P,IplImage *dst,CvPoint *map,double *H) {
double x;
double y;
double width=dst->width;
double height=dst->height;
// pour chaque pixel de l'image cible
for(y=0;y<height;y++) {
for(x=0;x<width;x++) {
// conversion dans le repère orthonormé (u,v) [0,1]x[0,1]
double u = x/width;
double v = y/height;
// passage dans le repère perspective
projective_mapping(&u, &v, H);
// pixel correspondant de l'image source
int sx=(int)round(u);
int sy=(int)round(v);
// pixel source
CvScalar rgb=cvGet2D(src,sy,sx);
// pixel destination
int dx=x;
int dy=y;
cvSet2D(dst,dy,dx,rgb);
// conserver position pixel source
if (map) {
size_t index=dy*dst->width+dx;
map[index].x=sx;
map[index].y=sy;
}
}
}
} |
Partager