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 ¢er, 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
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
00099
00100 if (!bounds.hasPositiveArea())
00101 continue;
00102
00103
00104
00105
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 );
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
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 );
00221 if (bDrawWireFrame)
00222 {
00223 glPushMatrix();
00224
00225
00226 Vertex center = voxelCube.getCenter();
00227 glTranslated(center[0], center[1], center[2]);
00228
00229
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 );
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
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
00297
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
00331
00332 SurfaceVoxelList &svl = voxelCube.svl;
00333
00334 int nVoxelsPerSide = voxelCube.getVoxelsPerSide();
00335 int nTotalNumVoxels = pow(nVoxelsPerSide, 3);
00336 int nTotalNumVoxelsRemoved = 0;
00337
00338 do
00339 {
00340 nVoxelsRemoved = 0;
00341
00342
00343
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
00370 while (svl_iter != svl.end())
00371 {
00372
00373 VoxelPos &p = *svl_iter;
00374 if (!isConsistent (svl_iter, bUseSilhouettes))
00375 {
00376
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);
00382
00383 nVoxelsRemoved++;
00384 nTotalNumVoxelsRemoved++;
00385 }
00386 else
00387 {
00388 svl_iter++;
00389 }
00390
00391 doProgressUpdate (false, (float)nTotalNumVoxelsRemoved/nTotalNumVoxels, "Carving voxels");
00392
00393 }
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
00420
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
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
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
00564
00565 glViewport (width,0,width,height);
00566 drawFromImagePerspective(false, curImage);
00567 printBitmapString("Voxel-cubes", bitbuff.getHDC());
00568
00569
00570
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 }