/* ** This code fragment converts the data in an Odetics range image into 3D ** cartesian coordinate data. The range image is 8-bit, and comes ** already separated from the intensity image. ** (needs stdio.h and math.h) */ void ConvertRangeToCartesian(unsigned char *RangeImage, double **P) { int r,c; double cp[8]; double bvav; double xangle,yangle,dist; double ScanDirectionFlag,SlantCorrection; ScanDirectionFlag=-1; /******* BVAV => Beam Vertical Angular Velocity *******/ cp[0]=1220.7; /* horizontal mirror angular velocity in rpm */ cp[1]=32.0; /* scan time per single pixel in microseconds */ cp[2]=63.5; /* middle value of columns */ cp[3]=1220.7/192.0; /* vertical mirror angular velocity in rpm */ cp[4]=6.14; /* scan time (with retrace) per line in milliseconds */ cp[5]=63.5; /* middle value of rows */ cp[0]=cp[0]*3.1415927/30.0; /* convert rpm to rad/sec */ cp[3]=cp[3]*3.1415927/30.0; /* convert rpm to rad/sec */ cp[0]=2.0*cp[0]; /* beam ang. vel. is twice mirror ang. vel. */ cp[3]=2.0*cp[3]; /* beam ang. vel. is twice mirror ang. vel. */ cp[1]/=1000000.0; /* units are microseconds : 10^-6 */ cp[4]/=1000.0; /* units are milliseconds : 10^-3 */ /* start with semi-spherical coordinates from laser-range-finder: */ /* (r,c,RangeImage[r*128+c]) */ /* convert those to axis-independant spherical coordinates: */ /* (xangle,yangle,dist) */ /* then convert the spherical coordinates to cartesian: */ /* (P => X[] Y[] Z[]) */ bvav=cp[3]; for (r=0; r<128; r++) { for (c=0; c<128; c++) { SlantCorrection=cp[1]*((double)c-cp[2]); xangle=cp[0]*cp[1]*((double)c-cp[2]); yangle=(bvav*cp[4]*(cp[5]-(double)r))+ /* Standard Transform Part */ SlantCorrection*ScanDirectionFlag; /* + slant correction */ dist=(double)RangeImage[r*128+c]; P[2][r*128+c]=sqrt((dist*dist)/(1.0+(tan(xangle)*tan(xangle)) +(tan(yangle)*tan(yangle)))) + 10.0; P[0][r*128+c]=tan(xangle)*P[2][r*128+c]; P[1][r*128+c]=tan(yangle)*P[2][r*128+c]; } } } /* This function computes the unit normal vector at each point in the image and marks particular pixels with a gray level to indicate that it is a part of a surface */ unsigned char * ComputeUnitNormals(double **P) { double vector1[3], vector2[3], cross[3]; int x, y, i, max; double magnitude; int alpha, beta; int accumulator[72][36] = {0}; int normal[128*128][2]; unsigned char *image; /* Allocate memory for the image */ image = (unsigned char *)malloc(128*128); /* Compute the cross product and unit normals and increment the accumulator based alpha and beta */ for (x=20; x<100; x++) { for (y=20; y<100; y++) { /* Get two vectors */ vector1[0] = (P[0][(x-1)*128+y] - P[0][x*128+y]); vector1[1] = (P[1][(x-1)*128+y] - P[1][x*128+y]); vector1[2] = (P[2][(x-1)*128+y] - P[2][x*128+y]); vector2[0] = (P[0][x*128+y+1] - P[0][x*128+y]); vector2[1] = (P[1][x*128+y+1] - P[1][x*128+y]); vector2[2] = (P[2][x*128+y+1] - P[2][x*128+y]); /* The cross product */ cross[0] = vector1[1]*vector2[2] - vector2[1]*vector1[2]; cross[1] = vector1[2]*vector2[0] - vector2[2]*vector1[0]; cross[2] = vector1[0]*vector2[1] - vector2[0]*vector1[1]; /* Magnitude of the normal vector */ magnitude = sqrt(cross[0]*cross[0] + cross[1]*cross[1] + cross[2]*cross[2]); /*The alpha and beta */ alpha = (int)(57.2958 * acos(cross[2]/magnitude)); beta = (int)(57.2958 * atan(cross[1]/cross[0])); // if (alpha > 90) alpha -= 90; if (beta < 0 ) beta += 360; // Make sure angle betwwen 0 - 360 alpha = alpha/5; beta = beta/5; ++accumulator[beta][alpha]; normal[(x-1)*128 + y][0] = alpha; normal[(x-1)*128 + y][1] = beta; } } /* Find the 7th highest accumulator value because 1 - 6 highest values are from the floor and walls */ for (i = 0; i < 7; i++) { max = 0; for (x=0; x<72; x++) for (y=0; y<36; y++) if (accumulator[x][y] > max) { max = accumulator[x][y]; alpha = y ; beta = x ; } accumulator[beta][alpha] = 0; } /* Mark pixels as surface pixels if alpha and beta within tolerance */ for (i = 0; i < 128*128; i++) { if (((normal[i][0] == alpha) || (normal[i][0] == alpha-1) || (normal[i][0] == alpha+1)) && ((normal[i][1] == beta) || (normal[i][1] == beta-1) || (normal[i][1] == beta+1))) image[i] = 255; else image[i] = 0; } /* Find the next highest accumulator array value */ max = 0; for (x=0; x<72; x++) for (y=0; y<36; y++) if (accumulator[x][y] > max) { max = accumulator[x][y]; alpha = y ; beta = x ; } accumulator[beta][alpha] = 0; /* Mark surface pixels */ for (i = 0; i < 128*128; i++) { if (((normal[i][0] == alpha) || (normal[i][0] == alpha-1) || (normal[i][0] == alpha+1)) && ((normal[i][1] == beta) || (normal[i][1] == beta-1) || (normal[i][1] == beta+1))) image[i] = 170; } /* Find the next highest accumulator value */ max = 0; for (x=0; x<72; x++) for (y=0; y<36; y++) if (accumulator[x][y] > max) { max = accumulator[x][y]; alpha = y ; beta = x ; } accumulator[beta][alpha] = 0; /* Mark surface pixels */ for (i = 0; i < 128*128; i++) { if (((normal[i][0] == alpha) || (normal[i][0] == alpha-1) || (normal[i][0] == alpha+1)) && ((normal[i][1] == beta) || (normal[i][1] == beta-1) || (normal[i][1] == beta+1))) image[i] = 100; } return image; }