Scanner.cpp

Go to the documentation of this file.
00001 
00011 #include "../common/standard.h"
00012 #include <windows.h>
00013 #include <GL/glu.h>
00014 
00015 #include "GLutils.h"
00016 #include "Scanner.h"
00017 #include "GLBitmapBuffer.h"
00018 #include "XmlNode.h"
00019 
00020 
00021 
00027 void Scanner::getVoxelParamsFromScnFile(const char *filename, Vertex &center, int &voxelsPerSide, double &voxelCubeSize)
00028 {
00029     XmlNode d;
00030     d.loadFile(filename);
00031 
00032     d.getAttrib (center[0],     "scanner/voxel_parameters/voxelcube_center/@x");
00033     d.getAttrib (center[1],     "scanner/voxel_parameters/voxelcube_center/@y");
00034     d.getAttrib (center[2],     "scanner/voxel_parameters/voxelcube_center/@z");
00035 
00036     d.getAttrib (voxelsPerSide, "scanner/voxel_parameters/voxels_per_side/@value");
00037     d.getAttrib (voxelCubeSize,     "scanner/voxel_parameters/voxelcube_size/@value");
00038 }
00039 
00040 
00041 
00049 void Scanner::drawItemBufferForImage (Viewpoint &image)
00050 {
00051         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00052 
00053     assert(image.getWidth() && image.getHeight());
00054     image.imageBuffer.resize (image.getWidth() * image.getHeight());
00055 
00056     voxelCube.fillItemBufferArray(image);
00057 }
00058 
00059 
00060 
00069 bool Scanner::getColorsForVoxel (SurfaceVoxelList::iterator &svl_iter,  std::vector< RgbByte > &colorsToAgreeOn, std::vector< int > &numPixelsFound, bool bUseSilhouettes) const
00070 {
00071     VoxelPos pos = *svl_iter;
00072 
00073     unsigned int x,y,z;
00074     x = pos[0];
00075     y = pos[1];
00076     z = pos[2];
00077 
00078     std::vector< Vertex > vertices = voxelCube.calculateVoxelCorners(x,y,z);
00079     assert (vertices.size() == 8);
00080 
00081 /*
00082  * For each image...
00083  */
00084 
00085     ViewpointList::const_iterator view_iter;
00086     for (view_iter = images.begin(); view_iter != images.end(); view_iter++)
00087     {
00088         bool bSeen = false;
00089         const Viewpoint &view = *view_iter;
00090         std::vector< RgbByte > colorsToAverage;
00091     
00092         GLint viewport[4];
00093         viewport[0] = 0; viewport[1] = 0;
00094         viewport[2] = view.getWidth(); viewport[3] = view.getHeight();
00095 
00096         Rect< double > bounds = voxelCube.getBoundingRect(vertices, view.getModelviewMatrix(), view.getProjectionMatrix(), viewport);
00097     
00098         // if the voxel projects completely off the image, the area of the
00099         // bounding rectangle may be negative
00100         if (!bounds.hasPositiveArea())
00101             continue; // go to next image
00102     
00103      /*
00104       * Okay, we have a bounding rectangle defined by (xmin->xmax, ymin->ymax).
00105       * Let's see which pixels are visible in the item buffer
00106       */
00107         int nMatchesWeShouldFind = 0;
00108         int nMatchesFound = 0;
00109     
00110         unsigned int curVoxelID = voxelCube.PosToIdentifier (x,y,z);
00111     
00112         int nPixelsChecked = 0;
00113         int nPixelsTransparentSilhouette = 0;
00114         for (int u = bounds.left; u <= bounds.right; u++)
00115         {
00116             for (int v = bounds.bottom; v <= bounds.top; v++)
00117             {
00118                 nPixelsChecked++;
00119                 unsigned int ibuf_color = view.imageBuffer[v * view.getWidth() + u];
00120             
00121                 RGBQUAD *ic = (RGBQUAD*)&ibuf_color;
00122                 ic->rgbReserved = 0;
00123             
00124                 if (ibuf_color == curVoxelID)
00125                 {
00126                     if (bUseSilhouettes && view.pixelIsTransparent(u,v))
00127                         nPixelsTransparentSilhouette++;
00128 
00129                     bSeen = true;
00130                     nMatchesWeShouldFind++;
00131                     RgbByte &img_color = view.colorAt(u,v);
00132             
00133                     nMatchesFound++;
00134                     colorsToAverage.push_back (img_color);
00135                 }
00136             }
00137         }
00138 
00139         double pctTransparentViaSilhouette = (double)nPixelsTransparentSilhouette / nMatchesWeShouldFind;
00140         if (pctTransparentViaSilhouette > .5)
00141             return false;
00142 
00143 
00144         if (bSeen)
00145         {
00146             RgbDouble avg = averageColor (colorsToAverage);
00147             colorsToAgreeOn.push_back (RgbByte (avg[0], avg[1], avg[2]));
00148             numPixelsFound.push_back (nMatchesWeShouldFind);
00149         }
00150     }
00151     return true;
00152 
00153 }
00154 
00155 
00164 void Scanner::drawFromImagePerspective (bool bSmooth, int imgIndex)
00165 {
00166     if (imgIndex > images.size())
00167         throw LogicError("Scanner::drawFromImagePerspective(): no such image index");
00168 
00169     Viewpoint &image = images[imgIndex];
00170     
00171     glMatrixMode (GL_PROJECTION);
00172     glLoadMatrixd(image.getProjectionMatrix());
00173     glMatrixMode (GL_MODELVIEW);
00174     glLoadMatrixd (image.getModelviewMatrix());
00175 
00176     drawModel (bSmooth, false /* no wire frame */);
00177 }
00178 
00179 
00180 
00193 void Scanner::drawModel(bool bSmooth, bool bDrawWireFrame)
00194 {
00195     glMatrixMode (GL_MODELVIEW);
00196     if (bSmooth)
00197     {
00198         Vertex center = voxelCube.getCenter();
00199         double halfVoxelSize = voxelCube.getVoxelSize() / 2.;
00200         double halfCubeSize = voxelCube.getVoxelsPerSide() * halfVoxelSize;
00201 
00202         // translate to center
00203         glTranslated(center[0], center[1], center[2]);
00204 
00205         glPushMatrix();
00206             glTranslated(-halfCubeSize, -halfCubeSize, -halfCubeSize);
00207             glTranslated(halfVoxelSize, halfVoxelSize, halfVoxelSize);
00208 
00209             mesh.draw();
00210         glPopMatrix();
00211 
00212         if (bDrawWireFrame) 
00213         {
00214             glColor3f(1,1,1);
00215             drawCube(voxelCube.getVoxelSize()*voxelCube.getVoxelsPerSide(), GL_LINE_LOOP);
00216         }
00217     }
00218     else
00219     {
00220         voxelCube.draw (true /*bTranslateToCenter*/);
00221         if (bDrawWireFrame) 
00222         {
00223             glPushMatrix();
00224             
00225                 // translate to center
00226                 Vertex center = voxelCube.getCenter();
00227                 glTranslated(center[0], center[1], center[2]);
00228             
00229                 // draw the cube
00230                 glColor3f(1,1,1);
00231                 drawCube(voxelCube.getVoxelSize()*voxelCube.getVoxelsPerSide(), GL_LINE_LOOP);
00232 
00233             glPopMatrix();
00234         }
00235     }
00236 }
00237 
00238 
00239 
00251 void Scanner::drawWithAngle(bool bSmooth, double latitude, double longitude)
00252 {
00253     Viewpoint &image = images[0];
00254 
00255     Vertex cop = image.getCenterOfProjection();
00256     ColVector3 up = image.getUpVector();
00257     Vertex center = voxelCube.getCenter();
00258 
00259     ModelviewMatrix m;
00260     m.setToIdentity();
00261     m.lookAtWithOffset (cop, center, up, latitude, longitude);
00262 
00263     glMatrixMode (GL_MODELVIEW);
00264     glLoadMatrixd (&m[0]);
00265 
00266     drawModel(bSmooth, true /* draw wire frame */);    
00267 }
00268 
00269 
00270 
00281 bool Scanner::isConsistent (SurfaceVoxelList::iterator &svl_iter, bool bUseSilhouettes) const
00282 {
00283     std::vector< RgbByte > colorsToAgreeOn;
00284 
00285     std::vector< int > numPixelsSeen;
00286 
00287     // if this returns false, then the silhouette has told us to carve the voxel
00288     if (!getColorsForVoxel (svl_iter, colorsToAgreeOn, numPixelsSeen, bUseSilhouettes))
00289         return false;
00290 
00291     int numImagesThatCanSeeIt = colorsToAgreeOn.size();
00292     
00293     if (numImagesThatCanSeeIt < 2)
00294         return true;
00295 
00296     // if no images can theoretically "see" the voxel, then 
00297     // we would leave this voxel uncarved.
00298     if (colorsToAgreeOn.size() == 0)
00299         return true;
00300 
00301     if (!colorsAgree (colorsToAgreeOn, numPixelsSeen))
00302         return false;
00303 
00304     return true;
00305 }
00306 
00307 
00308 
00321 void Scanner::carveVoxels (double threshold, bool bUseSilhouettes)
00322 {
00323     thresholdSquared = threshold*threshold;
00324     if (images.empty())
00325         throw LogicError ("Scanner::carveVoxels(): Please load some images before you construct a voxel list.");
00326     
00327     int nVoxelsRemoved;
00328     mesh.clear();
00329 
00330     // the voxel cube has a surface voxel list, which is a list of opaque
00331     // voxels that are not completely surrounded by other opaque voxels
00332     SurfaceVoxelList &svl = voxelCube.svl;
00333 
00334     int nVoxelsPerSide = voxelCube.getVoxelsPerSide();
00335     int nTotalNumVoxels = pow(nVoxelsPerSide, 3);
00336     int nTotalNumVoxelsRemoved = 0;
00337 
00338     do // ...while (nVoxelsRemoved > 0)
00339     {
00340         nVoxelsRemoved = 0;
00341         
00342         // For each input image, calculate per-pixel voxel visibility.
00343         // This is done by making an item buffer.
00344         ViewpointList::iterator view_iter;
00345 
00346 
00347         int curImg = 0;
00348         for (view_iter = images.begin(); view_iter != images.end(); view_iter++)
00349         {
00350             Viewpoint &image = *view_iter;
00351 
00352             drawItemBufferForImage(image);
00353 
00354             if (0 == curImg % 8)
00355             {
00356                 doProgressUpdate(
00357                     false, 
00358                     (float)nTotalNumVoxelsRemoved/nTotalNumVoxels,
00359                     "Drawing item buffers");
00360             }
00361             curImg++;
00362         }      
00363 
00364 
00365         SurfaceVoxelList::iterator svl_iter = svl.begin();
00366     
00367         int startingNumberOfVoxels = svl.size();
00368 
00369         //  For each voxel in the surface voxel list...
00370         while (svl_iter != svl.end())
00371         {                
00372             // if the voxel isn't consistent between images...
00373             VoxelPos &p = *svl_iter;
00374             if (!isConsistent (svl_iter, bUseSilhouettes))
00375             {
00376                 // ...expose surrounding voxels, and remove this voxel
00377                 voxelCube.exposeSurroundingVoxels (svl_iter);
00378 
00379                 assert (!voxelCube.isTransparent (p[0],p[1],p[2]));
00380                 voxelCube.setTransparent (svl_iter);
00381                 svl_iter = svl.erase(svl_iter); // go to next voxel
00382 
00383                 nVoxelsRemoved++;
00384                 nTotalNumVoxelsRemoved++;
00385             }
00386             else
00387             {
00388                 svl_iter++; // go to next voxel
00389             }
00390 
00391             doProgressUpdate (false,  (float)nTotalNumVoxelsRemoved/nTotalNumVoxels, "Carving voxels");
00392             
00393         } // looping through voxels
00394 
00395         MTRACE ("%d voxels removed this time around\n", nVoxelsRemoved);
00396         
00397     } while (nVoxelsRemoved);
00398 
00399     for (SurfaceVoxelList::iterator svl_iter = svl.begin(); svl_iter != svl.end(); svl_iter++)
00400     {
00401         std::vector< RgbByte > colors;
00402 
00403         std::vector< int > numPixelsSeen;
00404         getColorsForVoxel (svl_iter, colors, numPixelsSeen, bUseSilhouettes);
00405         RgbDouble avgFloat = weightedAverageColor (colors, numPixelsSeen);
00406         RgbByte avg;
00407         avg.r() = avgFloat.r();
00408         avg.b() = avgFloat.b();
00409         avg.g() = avgFloat.g();
00410         
00411         voxelCube.setFinalColor (svl_iter, avg);
00412     }
00413 
00414     voxelCube.makeMesh(.5, this->mesh);
00415 
00416     doProgressUpdate (true,  1., "");
00417 
00418 
00419 //    mesh.recalculateCosts();
00420 //    mesh.doCollapse(mesh.getNumFacesTotal() / 2);
00421 }
00422 
00423 
00424 
00425 void Scanner::doProgressUpdate(bool bForce, float pctDone, const char *format, ...)
00426 {
00427     if (!progressReportCB) return;
00428 
00429 
00430     if (bForce || (time(NULL) - lastTime) > updateInterval)
00431     {
00432             va_list args; 
00433             char    buffer[512];
00434             va_start(args,format);
00435             _vsnprintf(buffer,sizeof(buffer)-1,format,args);
00436         va_end(args);
00437 
00438         progressReportCB(buffer, pctDone, progressUpdateData);
00439         lastTime = time(NULL);
00440     }
00441 }
00442 
00443 
00444 RgbDouble Scanner::averageColor (std::vector< RgbByte > &colors) const
00445 {
00446     RgbDouble avgColorPrecise;
00447     avgColorPrecise.setToZero();
00448 
00449     for (int i = 0; i < colors.size(); i++)
00450     {
00451         avgColorPrecise.r() += (float)colors[i].r();
00452         avgColorPrecise.g() += (float)colors[i].g();
00453         avgColorPrecise.b() += (float)colors[i].b();
00454     }
00455 
00456     avgColorPrecise.r() /= colors.size();
00457     avgColorPrecise.g() /= colors.size();
00458     avgColorPrecise.b() /= colors.size();
00459     return avgColorPrecise;
00460 }
00461 
00462 
00463 
00474 void Scanner::setProgressCallback (void (*updateCB)(char *str, float pctDone, void *data), int intervalInSeconds, void *data)
00475 {
00476     progressReportCB = updateCB;
00477     updateInterval = intervalInSeconds;
00478     progressUpdateData = data;
00479 }
00480 
00481 
00482 
00483 
00484 RgbDouble Scanner::weightedAverageColor (std::vector< RgbByte > &colors, std::vector< int > &numPixelsSeen) const
00485 {
00486     assert (colors.size() == numPixelsSeen.size());
00487 
00488     int totalPixelsSeen = std::accumulate (numPixelsSeen.begin(), numPixelsSeen.end(), 0);
00489 
00490     RgbColor< double > avgColor;
00491     avgColor.setToZero();
00492 
00493     for (int i = 0; i < colors.size(); i++)
00494     {
00495         double ratio = (double)numPixelsSeen[i] / totalPixelsSeen;
00496         avgColor.r() += colors[i].r() * ratio;
00497         avgColor.g() += colors[i].g() * ratio;
00498         avgColor.b() += colors[i].b() * ratio;
00499     }
00500 
00501     return avgColor;
00502 }
00503 
00504 
00505 
00506 bool Scanner::colorsAgree (std::vector< RgbByte > &colors, std::vector< int > numPixelsSeen) const
00507 {
00508     RgbDouble avgColor = weightedAverageColor (colors, numPixelsSeen);
00509 
00510     int totalPixelsSeen = std::accumulate (numPixelsSeen.begin(),numPixelsSeen.end(),0);
00511 
00512     double dist = 0.;
00513     for (int i = 0; i < colors.size(); i++)
00514     {
00515         RgbDouble color;
00516         color.r() = colors[i].r();
00517         color.g() = colors[i].g();
00518         color.b() = colors[i].b();
00519 
00520         RgbDouble diff =  avgColor - color;
00521         double difflength = diff.getLengthSquared();
00522 
00523         double ratio = (double)numPixelsSeen[i] / totalPixelsSeen;
00524         dist += ratio * difflength;
00525     }
00526 
00527     return (dist < thresholdSquared);
00528 }
00529 
00530 
00531 
00536 void Scanner::takeSnapshots(const char *directoryName) 
00537 {
00538     int curImage = 0;
00539     for (ViewpointList::iterator i = images.begin(); i != images.end(); i++)
00540     {
00541         Viewpoint &img = *i;
00542         int width = img.getWidth()/2;
00543         int height = img.getHeight()/2;
00544 
00545         // create our bitmap buffer
00546         GLBitmapBuffer bitbuff;
00547         bitbuff.create(width*3,height);
00548         bitbuff.select();
00549 
00550             glEnable (GL_DEPTH_TEST);
00551             glClear (GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
00552 
00553         /*
00554          * Draw original image
00555          */
00556             glViewport (0,0,width,height);
00557             glPixelZoom(.5,.5);
00558             glDrawPixels(img.getWidth(), img.getHeight(), GL_RGB, GL_UNSIGNED_BYTE, &img.photo[0][0]);
00559             printBitmapString("Original Image", bitbuff.getHDC());
00560             glPixelZoom(2,2);
00561 
00562         /*
00563          * Draw voxel-cube version
00564          */
00565             glViewport (width,0,width,height);
00566             drawFromImagePerspective(false, curImage);
00567             printBitmapString("Voxel-cubes", bitbuff.getHDC());
00568 
00569         /*
00570          * Draw smooth version
00571          */
00572             glViewport (width*2,0,width,height);
00573             drawFromImagePerspective(true, curImage);
00574             printBitmapString("Polygonized with Marching Cubes", bitbuff.getHDC());
00575 
00576             glFinish();
00577             bitbuff.saveAs (fmtString("%s\\snapshot%.4d.ppm", directoryName, curImage));
00578 
00579         bitbuff.unselect();
00580         curImage++;
00581     }
00582 }
00583 
00585 Vertex Scanner::guessVoxelcubeCenter ()
00586 {
00587     Vertex center(0,0,0);
00588     ViewpointList::iterator view_iter;
00589     for (view_iter = images.begin(); view_iter != images.end(); view_iter++)
00590     {
00591         Viewpoint &view = *view_iter;
00592         center = center + view.getLookatPoint();
00593     }
00594 
00595     return center / (double)images.size();
00596 }
00597 
00607 void Scanner::loadImages (const char *filename, int defaultVoxelsPerSide, float defaultVoxelCubeSize)
00608 {
00609     doProgressUpdate(true, 0., "Loading files");
00610     images.loadFromFile (filename);
00611     mesh.clear();
00612 }
00613 
00614 
00616 bool Scanner::hasSilhouettes() const
00617 {     
00618     ViewpointList::const_iterator view_iter;
00619     for (view_iter = images.begin(); view_iter != images.end(); view_iter++)
00620     {
00621         const Viewpoint &view = *view_iter;
00622         if (view.hasSilhouette())
00623             return true;
00624     }
00625 
00626     return false;
00627 }

Generated on Tue May 21 03:34:51 2002 for Archimedes by doxygen1.2.15