/*****************************************************************************\ 3D Spatial Evidence Accumulation For Robot Sensor Interpretation Hans Moravec 1992 \*****************************************************************************/ #include #include #include #include #define is_volsense /* switch for volsense.h */ #include "volsense.h" MainInt LfP(MainFloat p) /*** 3D *** Convert real probability to scaled integer log odds */ {MainInt n, ip; p = LOG(fabs(p/(1.0-p)))*5.770780164; /* log base 2^(1/4) */ n = 0; if (p<0) {p = -p; n = 1;} ip = p + 0.5; if (ip>127) ip = 127; return(n?-ip:ip); } MainInt ILOG2(MainInt i) /*** 3D *** Floor[Log2[i]] */ { MainInt t, j; if ((j = i & ~BMx)) {t = 16; i=j;} else t = 0; if ((j = i & ~BM8)) {t += 8; i=j;}; if ((j = i & ~BM4)) {t += 4; i=j;}; if ((j = i & ~BM2)) {t += 2; i=j;}; return ((i & ~BM1)?++t:t); } MainInt ILOG2C(MainInt i) /*** 3D *** Ceil[Log2[i]] */ { MainInt j; j = ILOG2(i); return (((1< Floor[Log2[i]+.5] -> Floor[Log2[i*Sqrt[2]]] */ { return ILOG2(i + (i>>2) + (i>>3) + (i>>5) + (i>>7)); } MainInt MakeMap3D(MainInt msize[3], MainFloat lov[3], MainFloat hiv[3], Map3D *map) /*** 3D ***************************************************************\ * MakeMap3D(msize, lov, hiv, map) * Creates a new map "isize" wide by "jsize" deep by * "ksize" high with co-ordinates * {lov:hiv [0:2], in meters} * Each cell has dimensions "(hiv-lov)/msize" \**********************************************************************/ { MainInt i, js; js = 0; for (i=0; i<3; i++) { (*map).msize[i] = msize[i]; js += ILOG2C(msize[i]); (*map).lomv[i] = lov[i]; (*map).himv[i] = hiv[i]; }; (*map).mapm = (Int16 *) calloc( 1<>1]).rangem < range) nm=nmt+1; else nmh=nmt-1; rangefactor = range/smodels.models[nm].rangem; /* nudge array to exact range */ slor = rangefactor*smodels.models[nm].lorv; /* should be zero */ shir = rangefactor*smodels.models[nm].hirv; tslod = slod = rangefactor*smodels.models[nm].lodv; shid = rangefactor*smodels.models[nm].hidv; srsize = smodels.models[nm].rsize; sdsize = smodels.models[nm].dsize; srlog = ILOG2C(srsize); srdsize = sdsize<= |dx| >= |dy|. Maximum |dz| is essential; minimum |dy| is slight efficiency. */ tx = ABS(Dir[0]); ty = ABS(Dir[1]); tz = ABS(Dir[2]); if (tz>((lz=(ty>tx)?1:0)?ty:tx)) lz = 2; if (ABS(Dir[lx=(lz+1)%3])1e-7) /* clip by x limits */ { zlo = (mlox+(t=mxscale*1e-4)-px)/dx; zhi = (mhix-t-px)/dx; if (zlo>zhi) SWAPf(zlo,zhi); if (zlo>tslod) tslod=zlo; if (zhishid) return; } else if (pxmhix) return; if (ABS(dy)>1e-7) /* clip by y limits */ { zlo = (mloy+(t=myscale*1e-4)-py)/dy; zhi = (mhiy-t-py)/dy; if (zlo>zhi) SWAPf(zlo,zhi); if (zlo>tslod) tslod=zlo; if (zhishid) return; } else if (pymhiy) return; zlo = pz+tslod*dz; zhi = pz+shid*dz; /* clip by z limits */ if (zlo>zhi) SWAPf(zlo,zhi); izlo=(zlo-mloz)/mzscale+0.5; izhi=(zhi-mloz)/mzscale+0.5; if (izlo<0) izlo=0; if (izhi>=mzsize) izhi=mzsize-1; /* clip */ if (izlo>=izhi) return; d = ((izlo+0.5)*mzscale+mloz-pz)/dz; td = mzscale/dz; idd = FXP((d-slod)/sdscale); itdd = FXP(td/sdscale); epx = FXP((px+d*dx-mlox)/mxscale); itx = FXP(td*dx/mxscale); epy = FXP((py+d*dy-mloy)/myscale); ity = FXP(td*dy/myscale); tmzpos = 1<>16)+((epy>>16)<>16]; else if (mindy==0) for(iz=izlo;iz>16)<>16)+iz] += smodelm[idd>>16]; else for(iz=izlo;iz>16)<>16)<>16]; else if(mindx==0) for(iz=izlo;iz>16)+((epy>>16)<>16)<>16)<>16)+iz] += smodelm[(idd>>16)<>16)<>16)<>16)<1e-7) /* clip by x limits */ { zlo = (mlox-elldx-px)/dx; zhi = (mhix+elldx-px)/dx; if (zlo>zhi) SWAPf(zlo,zhi); if (zlo>tslod) tslod=zlo; if (zhishid) return; } else if (pxmhix+elldx) return; if (ABS(dy)>1e-7) /* clip by y limits */ { zlo = (mloy-elldy-py)/dy; zhi = (mhiy+elldy-py)/dy; if (zlo>zhi) SWAPf(zlo,zhi); if (zlo>tslod) tslod=zlo; if (zhishid) return; } else if (pymhiy+elldy) return; elldz = SQRT(1.0-dzdz); d1 = sdscale*adz; tyf = srscale*elldz; dv = shir*elldz/d1; dv += 2; rv = (Int16 *) calloc((1+dv+dv),sizeof(Int16)); ir = slor/srscale+2; j = (i = dv)*srsize; while ((rv[dv-i] = rv[dv+i] = j/dv-ir)>0) {i--; j -= srsize;} rv[dv-i] = rv[dv+i] = 0; ip = dv dl) dl=i; if ((i = sprofile[sdsize-1-id]-j) > dh) dh=i; } zlo = pz+tslod*dz; zhi = pz+shid*dz; if (zlo>zhi) {SWAPf(zlo,zhi); SWAPi(dl,dh);} zlo -= dl*tyf; zhi += dh*tyf; izlo=(zlo-mloz)/mzscale+0.5; izhi=(zhi-mloz)/mzscale+0.5; if (izlo<0) izlo=0; if (izhi>=mzsize) izhi=mzsize-1; /* clip */ if (izlo>=izhi) return; /* Create pointers for ellipse, bucket sorted by radius. Bucket for each radius has enough room for the number of cells that might be occupied in raster by circle of that radius, plus four cells, to avoid collisions between adjacent buckets. */ iz = ellxsz*MAX(srsize,ellysz); ellxytab = (Int32 *)malloc(i=(ellpmax=iz+(srsize<<2))*sizeof(Int32)); ellrdtab = (Int32 *) malloc(i); ellpinit = (Int32 *) malloc(i=(srsize+1)*sizeof(Int32)); ellp = (Int32 *) malloc(i); t = srsize; t = iz/(t*(t+1.0)); for (i=0; i<=srsize; i++) ellpinit[i] = ellp[i] = (t*i)*(i+1)+(i<<2); /* set up constants for ellipse (x,y) -> sensor model (r,d) map */ x = -ellxhd*(tx=mxscale/srscale); y = -ellyhd*(ty=myscale/srscale); td = srscale/sdscale; d = d1 = dy*y + dx*x; dx1 = dx*tx; dy1 = dy*ty; yf = surf = (surc = 1.0/(dydy+dzdz))/tx; t = shir/mxscale; surc *= t*t; surf *= dzdz*surf; tyf = (yf *= dx*dy)*ty; did = ((ellysz-1)<tslors) { ir = (ttslors) { ir = (t>16)-ellxhd)<>16)-ellyhd)<>16))<=0&&dh=sdsize) dh=sdsize-1; for (id = dh; id >= dl; id--) if ((j=sprofile[id])>ir && j>=rv[id-i]) ir=j; ipf = ellpinit[ir]; for (ip = 0; ip < ipf; ip++) if( ((id = ellrdtab[ip]+idinc)&srdmask)==0 && (i = smodelm[id]) != 0 && ((mxpos = ellxytab[ip]+mypos)&mxyzmask)==0 ) mmapm[mxpos] += i; } else /* slightly hairier bounds test on d */ for (iz=izlo; iz>16)-ellxhd)<>16)-ellyhd)<>16))<=0&&dh=sdsize) dh=sdsize-1; for (id = dh; id >= dl; id--) if ((j=sprofile[id])>ir && j>=rv[id-i]) ir=j; ipf = ellpinit[ir]; for (ip = 0; ip < ipf; ip++) if( ((((id = ellrdtab[ip]+idinc)+srdoff)|id)&srdmask)==0 && (i = smodelm[id]) != 0 && ((mxpos = ellxytab[ip]+mypos)&mxyzmask)==0 ) mmapm[mxpos] += i; }; free(ellpinit); free(ellrdtab); free(ellxytab); free(rv); } } void ReadCylModel(char *sfilename, CylSensorModelArray *smodels) /*** 3D ***************************************************************\ * ReadCylModel(smodelfile,&smodels) * creates a set of sensor models in "smodels" from "file" \**********************************************************************/ {MainInt i, rs, ds, ri, di, log2rs, it, n; FILE *sfile; sfile=fopen(sfilename,"r"); fscanf(sfile,"%d\n",&(*smodels).nmodels); (*smodels).models = (CylSensorModel *) calloc((*smodels).nmodels,sizeof(CylSensorModel)); for (i=0; i<(*smodels).nmodels; i++) {fscanf(sfile,"%f%d%d%f%f%f%f\n", &((*smodels).models[i].rangem), &((*smodels).models[i].rsize), &((*smodels).models[i].dsize), &((*smodels).models[i].lorv), &((*smodels).models[i].lodv), &((*smodels).models[i].hirv), &((*smodels).models[i].hidv)); rs = (*smodels).models[i].rsize; ds = (*smodels).models[i].dsize; log2rs = ILOG2C(rs); /* pad r direction to power of 2 */ (*smodels).models[i].modelm = (Int8 *) calloc((1<0?(t>35?'#':'+'):' ', " 123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[(t<0?-t:t)%36]); } fprintf(sfile,"\n"); } } fclose(sfile); } void ClearMap3D(Map3D map) /*** 3D ***************************************************************\ * ClearMap3D(map) - erase map array \**********************************************************************/ { MainInt k, km; km = 1<<(ILOG2C(map.msize[0])+ILOG2C(map.msize[1])+ILOG2C(map.msize[2])); for (k=0; k=0) dbulge = anratio-3.0-SQRT(dbulge); if (dbulge>=0) dbulge = SQRT(dbulge*0.5)/P[ans]; if (rngl<=0.0) rngl=rngh*0.02; if (nmods<=1) nmods=2; (*smodels).nmodels = nmods; (*smodels).models = (CylSensorModel *) calloc(nmods,sizeof(CylSensorModel)); rratio = EXP(LOG(fabs(rngh/rngl))/((MainFloat) (nmods-1))); for (k=0; k0.0) hd += ru*SQRT(t); t = hd*P[ans]; hr = hd*(P[anI]+Dan/(t*t + 1.0)); hr *= hd/HYPOT(hd,hr); /* cut corner */ if (dbulge>=0.0 && dbulge<=hd) { t = dbulge*P[ans]; t = dbulge*(P[anI]+Dan/(t*t + 1.0)); if (t>hr) hr=t; } dsz = (hd-ld)/cellsize+0.5; if (dsz>dszmax) dsz=dszmax; rsz = (hr-lr)/cellsize; rsz++; if (rsz>rszmax) rsz=rszmax; lrsz = ILOG2C(rsz); /* for r, lr is center, not edge, of row 0 */ (*smodels).models[k].rangem = rngl; (*smodels).models[k].rsize = rsz; (*smodels).models[k].dsize = dsz; (*smodels).models[k].lorv = lr; (*smodels).models[k].lodv = ld; (*smodels).models[k].hirv = hr; (*smodels).models[k].hidv = hd; (*smodels).models[k].modelm = grid = (Int8 *) calloc(dsz<rr?0.5:P[emI] + Dem/(d*P[ems]+1.0); p = po>pe?po:pe; if (p==0.5) {grid[id]=0; continue;} if (p<0.0001) {grid[id] = -54; continue;}; if (p>0.9999) {grid[id] = 54; continue;}; p = LOG(p/(1.0-p))*5.770780164; /* log base 2^(1/4) */ if ((grid[id] = ROUND(p))) prof[id]=1; /* if nonzero! */ d += dd; } else /* fat ray: more work */ for (id=0; idrb) {grid[gi]=0; continue;} h = r==0.0?d:HYPOT(r,d); rd = (rr-h)/ru; rd = rd*rd+1.0; po = oc/rd; pe = h>rr?0.5:P[emI] + Dem/(h*P[ems]+1.0); pc = po>pe?po:pe; t = r/rb; p = 1.0-pc+(2.0*pc-1.0)/(t*t+1.0) ; if (p==0.5) {grid[gi]=0; continue;} if (p<0.0001) {grid[gi] = -54; continue;}; if (p>0.9999) {grid[gi] = 54; continue;}; p = LOG(p/(1.0-p))*5.770780164; /* log base 2^(1/4) */ if ((grid[gi] = ROUND(p))) prof[id]=ir+1; /* if nonzero! */ } d += dd; } rngl *= rratio;} } void MakeCylModelStereo(MainInt PicWidth, MainFloat FocalLength, MainFloat CamSeparation, MainFloat Cellsize, MainFloat MaxRange, MainInt EvLo, MainInt EvHi, CylSensorModelArray *smodels) /*** 3D ***************************************************************\ * MakeCylModelStereo(PicWidth, FocalLength, * CamSeparation, GridResolution,ProbLo, ProbHi) * sensor model for stereoscopic ranging * PicWidth image width, in pixels FocalLength in pixels * CamSeparation stereo pair camera separation, in meters * Cellsize cell to cell grid spacing, in meters * MaxRange is the length of the longest ray to paint * EvLo lowest "empty" evidence (log odds) to use * EvHi highest "occupied" evidence to use * smodels holds the resulting model \**********************************************************************/ { BestFloat lr, ld, hr, hd, r, d, dd, r0, rng, rngmax, rngmin, dr, t; BestFloat rb; MainInt rsz, dsz, ir, id, k, gi, lrsz, nmods, displacement, EvHid; Int8 *grid; Int16 *prof; #define broad 4.0 /* beam broadening fudge factor (4 = wide as feature windows) */ nmods=PicWidth/2; (*smodels).nmodels = nmods; (*smodels).models = (CylSensorModel *) calloc(nmods,sizeof(CylSensorModel)); for (k=0; k127) EvHid = 127; if (EvHid<-127) EvHid = -127; if (EvLo>127) EvLo = 127; if (EvLo<-127) EvLo = -127; (*smodels).models[k].rangem = rng; (*smodels).models[k].rsize = rsz; (*smodels).models[k].dsize = dsz; (*smodels).models[k].lorv = lr; (*smodels).models[k].lodv = ld; (*smodels).models[k].hirv = hr; (*smodels).models[k].hidv = hd; (*smodels).models[k].modelm = grid = (Int8 *) calloc(dsz<rb) grid[gi]=0; else grid[gi] = drh) rh=r; if (ddh) dh=d;} if (rl>rh || dl>dh) {rl=rh; dl=dh;}; /* if sensor model empty */ if (rl>0) {printf("TrimSensor rl=%d dl=%d (rh=%d dh=%d)\n",rl,dl,rh,dh); rl=0;} rsn = rh-rl+1; rsnx = 1<tt) {it = perm[ii]; perm[ii] = perm[i]; perm[i] = it; tt=t;}; } i = perm[ii]; if ((t=a[i+ii]) == 0.0) {free(perm); return(0);}; /* singular */ if (t != 1.0) { t = 1.0/t; /* eliminate variable ii */ for (k=ii+1; k<=n; k++) a[i+k] *= t; } for (jj=ii+1; jj0; ii--) /* backsolve */ { i = perm[ii]; if ((t=a[i+n]) != 0.0) for (jj=0; jj