#include #include #include #include #include #include #include #include #include #include /* define only one of the options below */ /* CAUTION: the FULL_POINTERS option targets only a single array, set by getfish */ /* #define FULL_POINTERS*/ /* full is 25% faster, but twice as big (about 2MB) */ #define OFFSET_POINTERS /* offset is slower, but only about 1MB of storage */ /* Fast (= paced for robot runtime) fisheye image rectifier, applying calibration parameters from the "flatfish" wide angle image calibration program. Fast interest operator, samples left member of stereo image pair, classifying regions suitable for stereo ranging. Fast correlator, for finding regions in right image corresponding to selected feastures in left image. Created 4/96 Hans Moravec Carnegie Mellon University Pittsburgh, PA 15213 working at Daimler Benz research, Berlin */ /************************************************************************\ Camera Rectification Routines \***********************************************************************/ int FishHead(char *CalFile, Calib *Cal) /* FishHead reads in flatfish calibration file named "CalFile", into a calibration structure Cal. It does not expand the parameters into a pointer table in Cal (done by FishBody) */ { FILE *fp; float t; int i; /* Read in calibration parameters from .calib file */ fp = fopen(CalFile,"r"); if (!fp) return(0); /* read in the calibration setup, Ph, Pw, Xaim, Yaim, Distance, FOV, The polynomial degree+1, the distortion center i and j pixel coordinates, the aspect ratio, the distortion center i and j spot coordinates, the image rotation angle, the Spot->Pixel polynomial coefficients, the Pixel->Spot polynomial coefficients */ fscanf(fp,"%d%d%g%g%g%g\n", &(*Cal).Ph, &(*Cal).Pw, &(*Cal).Yaim, &(*Cal).Xaim, &(*Cal).Distance, &(*Cal).FOV); fscanf(fp,"%d%g%g%g%g%g%g\n", &(*Cal).PN,&(*Cal).Pi,&(*Cal).Pj,&(*Cal).AS,&(*Cal).Si,&(*Cal).Sj,&(*Cal).AN); (*Cal).P = (Float32 *) malloc((*Cal).PN*sizeof(Float32)); (*Cal).S = (Float32 *) malloc((*Cal).PN*sizeof(Float32)); for (i=0; i<(*Cal).PN; i++) { fscanf(fp,"%g",&t); (*Cal).P[i] = t;}; fscanf(fp,"\n"); for (i=0; i<(*Cal).PN; i++) { fscanf(fp,"%g",&t); (*Cal).S[i] = t;}; fscanf(fp,"\n"); fclose(fp); return(1); }; int FishBody(Calib *Cal, gray **picin) { /* FishBody calculates the per pixel rectification, and store in either the offset or the direct pointer tables, depending on compile switches */ double Xaim, Yaim, AN; int i, j, k, l, ii, jj, Ph, Pw, PN; float isc, jsc; /* Image axis center */ double rp, is, js, rs, ang, sang, cang; double ipc, jpc, aspect, rootaspect; double SpotSpacing; #ifdef OFFSET_POINTERS int di, dj; #endif #ifdef FULL_POINTERS gray **trect; /* full pointers */ #endif #ifdef OFFSET_POINTERS (*Cal).di = (signed char *) malloc((*Cal).Ph*(*Cal).Pw); /* precalculated rectification */ (*Cal).dj = (signed char *) malloc((*Cal).Ph*(*Cal).Pw); /* storage arrays */ if (!(*Cal).dj || !(*Cal).di) return(0); #endif #ifdef FULL_POINTERS trect = (*Cal).pij = (gray **) malloc((*Cal).Pw*(*Cal).Ph*sizeof(gray *)); if (!trect) return(0); #endif Ph = (*Cal).Ph; Pw = (*Cal).Pw; PN = (*Cal).PN; Xaim = (*Cal).Xaim; Yaim = (*Cal).Yaim; AN = (*Cal).AN; ipc = (*Cal).Pi; jpc = (*Cal).Pj; aspect = (*Cal).AS; isc = (*Cal).Si; jsc = (*Cal).Sj; rootaspect = sqrt(aspect); /* Desired spot spacing calculated from user FOV request and Distance */ SpotSpacing = Pw/((*Cal).Distance*2.0*tan((*Cal).FOV*PI/360.0)); l=0; /* calculate the rectification */ for (i=0; i=0; k--) rp = rp*rs+(*Cal).P[k]; /* project pixel radius back onto to spot radius direction, rotated by grid angle from horizontal, and recenter */ ang = atan2(is,js); sang = sin(ang-AN); cang = cos(ang-AN); ii = rp*sang/rootaspect + ipc; jj = rp*cang*rootaspect + jpc; /* make sure neither picture nor offset bounds are exceeded */ if (ii<0) ii=0; else if (ii>Ph-1) ii=Ph-1; if (jj<0) jj=0; else if (jj>Pw-1) jj=Pw-1; #ifdef FULL_POINTERS *(trect++) = &(picin[ii][jj]); #endif #ifdef OFFSET_POINTERS di = ii-i; dj = jj-j; if (di>127) di=127; else if (di<-127) di=-127; if (dj>127) dj=127; else if (dj<-127) dj=-127; (*Cal).di[l] = di; (*Cal).dj[l] = dj; l++; #endif }; return(1); }; int GoFish(char *CalFile, Calib *Cal, gray **picin) /* GoFish reads in flatfish calibration file named "CalFile", expands the parameters into a pointer table into pgm picture "picin", whose parameters must match those given in CalFile, and stores the result in structure "Cal" */ { return (FishHead(CalFile, Cal)? FishBody(Cal,picin):0); }; void FishTail(gray **picin, Calib *Cal, gray **picout) /* FishTail applies the transformation stored in "Cal" to the pgm picture "picin" to produce the rectified image "picout" */ { int Ph, Pw, i, j; gray *tout; /* outgoing pixel pointer */ #ifdef OFFSET_POINTERS signed char *tdi, *tdj; /* the offsets */ #endif #ifdef FULL_POINTERS gray **trect; /* the full pixel addresses */ #endif Ph = (*Cal).Ph; Pw = (*Cal).Pw; #ifdef OFFSET_POINTERS tdi = (*Cal).di; tdj = (*Cal).dj; for (i=0; i>3)*(Pw>>3)] */ { int i, j, k, l, rz; int top, ring; int temp[(Ph>>3)*(Pw>>3)]; /* Macros for in-line coding entire 8x8 interest window calculation */ #define A1 sumv+=ISQ[(ti=*(pptr+Pw))-(t=*pptr)]; sumh+=ISQ[(tj=*(++pptr))-t]; #define A2 sumhv+=ISQ[*(pptr+Pw)-t]; sumvh+=ISQ[tj-ti]; #define A3 sumv+=ISQ[(ti=*(pptr+Pw))-tj]; sumh+=ISQ[(t=*(++pptr))-tj]; #define A4 sumhv+=ISQ[*(pptr+Pw)-tj]; sumvh+=ISQ[t-ti]; #define A5 sumv+=ISQ[(ti=*(pptr+Pw))-t]; sumh+=ISQ[(tj=*(++pptr))-t]; #define A6 A2 #define LL A1 A2 A3 A4 A5 A6 A3 A4 A5 A6 A3 A4 A5 A6 #define LN LL pptr += Pw-7; k = 0; /* Compute raw interest operator: among horizontal, vertical, right and left diagonal directions, return minimum sum of squares of differences of adjacent pixels, computed over non-overlapping 8x8 windows */ for (i = 0; i < Ph-7; i += 8) for (j = 0; j < Pw-7; j += 8) { register gray *pptr; register int t, ti, tj, sumh, sumv, sumhv, sumvh; sumh = sumv = sumhv = sumvh = 0; pptr = &(picin[i][j]); LN LN LN LN LN LN LL if (sumv>3; top = 0; k = 0; for (i = 0; i < (Ph>>3); i++) for (j=0; j>3)-1 || j==0 || j==rz-1) out[k++]=0; else { ring = temp[k-1] + temp[k+1] + temp[k-rz] + temp[k+rz] +temp[k-rz-1]+temp[k-rz+1]+temp[k+rz-1]+temp[k+rz+1]; out[k] = l = (temp[k]<<3) - ring; k++; if (l>top) top = l; }; return(top); }; int HInterest(gray **picin, int Ph, int Pw, int *out) /* Horizontal Interest Operator, computes interest function on 8 x 8 windows. Image regions scored high by the interest operator contain enough brightness variations in horizontal directions to be good candidates for finding by correlator in other views of the same scene */ /* picin is picin[Ph][Pw], out must be out[(Ph>>3)*(Pw>>3)] */ { int i, j, k, l, rz; int top, ring; int temp[(Ph>>3)*(Pw>>3)]; /* Macros for in-line coding entire 8x8 interest window calculation */ #define A1 sumv+=ISQ[(ti=*(pptr+Pw))-(t=*pptr)]; sumh+=ISQ[(tj=*(++pptr))-t]; #define A2 sumhv+=ISQ[*(pptr+Pw)-t]; sumvh+=ISQ[tj-ti]; #define A3 sumv+=ISQ[(ti=*(pptr+Pw))-tj]; sumh+=ISQ[(t=*(++pptr))-tj]; #define A4 sumhv+=ISQ[*(pptr+Pw)-tj]; sumvh+=ISQ[t-ti]; #define A5 sumv+=ISQ[(ti=*(pptr+Pw))-t]; sumh+=ISQ[(tj=*(++pptr))-t]; #define A6 A2 #define LL A1 A2 A3 A4 A5 A6 A3 A4 A5 A6 A3 A4 A5 A6 #define LN LL pptr += Pw-7; k = 0; /* Compute raw interest operator: among horizontal, vertical, right and left diagonal directions, return minimum sum of squares of differences of adjacent pixels, computed over non-overlapping 8x8 windows */ for (i = 0; i < Ph-7; i += 8) for (j = 0; j < Pw-7; j += 8) { register gray *pptr; register int t, ti, tj, sumh, sumv, sumhv, sumvh; sumh = sumv = sumhv = sumvh = 0; pptr = &(picin[i][j]); LN LN LN LN LN LN LL /*printf("temp[%d] = %d\n", k, sumh);*/ temp[k++] = sumh; }; #undef A1 #undef A2 #undef A3 #undef A4 #undef A5 #undef A6 #undef LL #undef LN /* for (i=0; i<20; ++i) printf("temp[%d] = %d ", i, temp[i]);*/ /*printf("\n");*/ /* high-pass filter the raw operator */ rz = Pw>>3; top = 0; k = 0; for (i = 0; i < (Ph>>3); i++) for (j=0; j>3)-1 || j==0 || j==rz-1) out[k++]=0; else { ring = temp[k-1] + temp[k+1] + temp[k-rz] + temp[k+rz] +temp[k-rz-1]+temp[k-rz+1]+temp[k+rz-1]+temp[k+rz+1]; /*printf("out[%d] = %d", k, (temp[k] << 3) - ring);*/ out[k] = l = (temp[k]<<3) - ring; k++; /*printf(" %d %d\n", out[k-1], l);*/ if (l>top) top = l; }; /* for (i=0; i<20; ++i) printf("out[%d] = %d ", i, out[i]);*/ /*printf("\ntop = %d\n", top);*/ /* exit(0);*/ return(top); }; int Correl8(gray **left, int ileft, int jleft, int Ph, int Pw, gray **right, int irlo, int jrlo, int irhi, int jrhi, int *correl, int *corri) /* Scan image feature in "left" image centered on [ileft,jleft] across centers in "right" image rectangle bounded by [irlo,jrlo] [irhi,jrhi] inclusive. The best correlation values for each j position, over all i positions are returned in indices jrlo to jrhi of array "correl". The array "corri" contains the i value at which the best match for each j was found. Correl8 is hard coded to use 8x8 windows around the selected locations. */ { /* Correlate across selected position */ int i, j, lasti, cptr, bestcorel, bestj; int Lsum, Rsum; gray lefts[64]; register int t, tsum, sum; register gray *lptr, *rptr; /* set up source window in left image */ Lsum = 0; lptr = lefts; for (i = -4; i<4; i++) for (j=-4; j<4; j++) Lsum += *(lptr++) = left[i+ileft][j+jleft]; /* Macros for building inline version of correlation window matching step */ #define PIXa Rsum += (t = *(rptr++)); tsum += ISQ[*(lptr++) - t]; #define PIXb Rsum += (t = *(rptr)); tsum += ISQ[*(lptr++) - t]; #define PIXc Rsum += (t = *(++rptr)); tsum += ISQ[*(lptr++) - t]; #define PIXd Rsum += (t = *(rptr += Pw-7)); tsum += ISQ[*(lptr++) - t]; #define R1c PIXa PIXa PIXa PIXa PIXa PIXa PIXa PIXb /* first window row */ #define RNc PIXd PIXc PIXc PIXc PIXc PIXc PIXc PIXc /* Other rows */ /* censor, then scan destination area in right image */ if (irlo>irhi) SWAP(irlo,irhi); if (jrlo>jrhi) SWAP(jrlo,jrhi); if (irlo<4) irlo=4; if (irhi>Ph-4) irhi=Ph-4; if (jrlo<4) jrlo=4; if (jrhi>Pw-4) jrhi=Pw-4; cptr = jrlo; bestj = bestcorel = 1e9; for (j = jrlo; j <= jrhi; j++) { lasti = sum = 1e9; for (i = irlo; i <= irhi; i++) { tsum = Rsum = 0; lptr = lefts; rptr = &(right[i-4][j-4]); /* accumulate sum of squares of differences */ R1c RNc RNc RNc RNc RNc RNc RNc tsum -= ISQ[(Lsum-Rsum)>>3]; /* subtract out means */ if (tsumirhi) SWAP(irlo,irhi); if (jrlo>jrhi) SWAP(jrlo,jrhi); if (irlo<4) irlo=3; if (irhi>Ph-4) irhi=Ph-4; if (jrlo<4) jrlo=3; if (jrhi>Pw-4) jrhi=Pw-4; cptr = jrlo; bestj = bestcorel = 1e9 + 1; for (j = jrlo; j <= jrhi; j++) { lasti = irlo; sum = 1e9; for (i = irlo; i <= irhi; i++) { tsum = Rsum = 0; lptr = lefts; rptr = &(right[i-3][j-3]); /* accumulate sum of squares of differences */ R1c RNc RNc RNc RNc RNc RNc k = Lsum-Rsum; if (k<0) k = -k; if (k < 49*20) { tsum -= ISQ[k]/49; if (tsumirhi) SWAP(irlo,irhi); if (jrlo>jrhi) SWAP(jrlo,jrhi); if (irlo<4) irlo=3; if (irhi>Ph-4) irhi=Ph-4; if (jrlo<4) jrlo=3; if (jrhi>Pw-4) jrhi=Pw-4; cptr = jrlo; bestj = bestcorel = 1e9 + 1; for (j = jrlo; j <= jrhi; j++) { lasti = irlo; sum = 1e9; for (i = irlo; i <= irhi; i++) if ((k = rightmean[i][j] - Lmn) > -25 && k < 25) { lptr = lefts; rptr = &(right[i-3][j-3]); /* accumulate sum of squares of differences */ tsum = -ISQ[k*7]; /* subtract out means */ R1c RNc RNc RNc RNc RNc RNc if (tsumjrhi) SWAP(jrlo,jrhi); if (irlo<4) irlo=3; if (irlo>Ph-4) irlo=Ph-4; if (jrlo<4) jrlo=3; if (jrhi>Pw-4) jrhi=Pw-4; #define meantol 25.75 /* 25.75 optimum for run1 data set */ bestj = bestcorel = 1e9 + 1; rmpt = &rightmean[irlo*Pw+jrlo]; for (j = jrlo; j <= jrhi; j++) { tsum = 1e9; if ((k = *(rmpt++) - Lmn) > -meantol*49 && k < meantol*49) { lptr = lefts; rptr = &(right[irlo-3][j-3]); /* accumulate sum of squares of differences */ tsum = -((ISQ[k]+25)/49); /* subtract out means */ R1c RNc RNc RNc RNc RNc RNc if (tsumirhi) SWAP(irlo,irhi); if (jrlo>jrhi) SWAP(jrlo,jrhi); if (irlo<3) irlo=3; if (irhi>Ph-3) irhi=Ph-3; if (jrlo<3) jrlo=3; if (jrhi>Pw-3) jrhi=Pw-3; cptr = jrlo; bestj = bestcorel = 1e9; for (j = jrlo; j <= jrhi; j++) { lasti = sum = 1e9; for (i = irlo; i <= irhi; i++) { tsum = Rsum = 0; lptr = lefts; rptr = &(right[i-3][j-3]); /* accumulate sum of squares of differences */ R1c RNc RNc RNc RNc RNc tsum -= ISQ[(Lsum-Rsum)/6]; /* subtract out means */ if (tsum=correl[jul-1]) jul++; jll = bestj-1; /* mark left slope */ while (jll>=sjl && correl[jll]<1e8 && correl[jll]>=correl[jll+1]) jll--; if (jllsjh) jul=sjh; for (j=jll; j<=jul; j++) correl[j]=1e9; /* remove whole hill */ }; k=0; while (ppos[k]>=0) wt[k++] /= wtsum; /* normalize probabilities */ return(nwt); };