Text archives Help
- From: abhinav@sci.utah.edu
- To: manta@sci.utah.edu
- Subject: [MANTA] r457 - in trunk: Engine Engine/Control Engine/Display Engine/ImageTraversers Engine/ImageTraversers/AFR Image Interface Model/Cameras
- Date: Fri, 29 Jul 2005 13:16:41 -0600 (MDT)
Author: abhinav
Date: Fri Jul 29 13:16:36 2005
New Revision: 457
Added:
trunk/Engine/ImageTraversers/AFImageTraverser.cc
trunk/Engine/ImageTraversers/AFImageTraverser.h
trunk/Engine/ImageTraversers/AFR/
trunk/Engine/ImageTraversers/AFR/CQ.h
trunk/Engine/ImageTraversers/AFR/evil.h
trunk/Engine/ImageTraversers/AFR/kdtree.cc
trunk/Engine/ImageTraversers/AFR/kdtree.h
trunk/Engine/ImageTraversers/AFR/sample.h
trunk/Engine/ImageTraversers/AFR/stats.cc
trunk/Engine/ImageTraversers/AFR/stats.h
trunk/Engine/ImageTraversers/AFR/tiles.cc
trunk/Engine/ImageTraversers/AFR/tiles.h
Modified:
trunk/Engine/CMakeLists.txt
trunk/Engine/Control/RTRT.cc
trunk/Engine/Control/RTRT_register.cc
trunk/Engine/Display/OpenGLDisplay.cc
trunk/Engine/Display/OpenGLDisplay.h
trunk/Engine/ImageTraversers/CMakeLists.txt
trunk/Engine/ImageTraversers/DissolveImageTraverser.h
trunk/Engine/ImageTraversers/FramelessImageTraverser.cc
trunk/Engine/ImageTraversers/FramelessImageTraverser.h
trunk/Engine/ImageTraversers/NullImageTraverser.cc
trunk/Engine/ImageTraversers/NullImageTraverser.h
trunk/Engine/ImageTraversers/TiledImageTraverser.cc
trunk/Engine/ImageTraversers/TiledImageTraverser.h
trunk/Image/SimpleImage.h
trunk/Interface/Camera.h
trunk/Interface/Context.h
trunk/Interface/Fragment.h
trunk/Interface/ImageTraverser.h
trunk/Model/Cameras/EnvironmentCamera.cc
trunk/Model/Cameras/EnvironmentCamera.h
trunk/Model/Cameras/FisheyeCamera.cc
trunk/Model/Cameras/FisheyeCamera.h
trunk/Model/Cameras/OrthogonalCamera.cc
trunk/Model/Cameras/OrthogonalCamera.h
trunk/Model/Cameras/PinholeCamera.cc
trunk/Model/Cameras/PinholeCamera.h
Log:
SimpleImage.h: added bounds checking while inserting a sample in image
Fragment.h: Added some functions to add items coinveniently and set size/flags
Context.h: Added variable to have multipleGLwindows in display context and
setupContext
Camera (all camera related files): corrected reprojection in
PinHoleCamrea.cc, rest just specified the const specifier for project function
RTRT.cc: swapped order of calling of setup context for display and
imagetraverser so that multipleGLWindows can be set properly
no changes in any imagetraversers, might have just touched these files again
Added Adaptive Frameless ImageTraverser
in the additional window, press m to switch display modes and b/l to
brighten/lighten the display
Sampling rate is hard coded to 400k samples/sec but it will be modified later.
OpenGLDisplay; added support for conditional calls to glxMakeCurrent
- Abhinav
Modified: trunk/Engine/CMakeLists.txt
==============================================================================
--- trunk/Engine/CMakeLists.txt (original)
+++ trunk/Engine/CMakeLists.txt Fri Jul 29 13:16:36 2005
@@ -27,5 +27,5 @@
Manta_Core
SCIRun_Core)
-TARGET_LINK_LIBRARIES(Manta_Engine ${OPENGL_LIBRARIES}
+TARGET_LINK_LIBRARIES(Manta_Engine ${OPENGL_LIBRARIES}
${X11_LIBRARIES})
Modified: trunk/Engine/Control/RTRT.cc
==============================================================================
--- trunk/Engine/Control/RTRT.cc (original)
+++ trunk/Engine/Control/RTRT.cc Fri Jul 29 13:16:36 2005
@@ -622,8 +622,8 @@
for(vector<SetupCallback*>::iterator iter = setupCallbacks.begin();
iter != setupCallbacks.end(); iter++)
(*iter)->setupDisplayChannel(context);
- channel->display->setupDisplayChannel(context);
currentImageTraverser->setupDisplayChannel(context);
+ channel->display->setupDisplayChannel(context);
} while(context.isChanged() && --iteration > 0);
if(!iteration)
throw InternalError("Pipeline/resolution negotiation failed",
Modified: trunk/Engine/Control/RTRT_register.cc
==============================================================================
--- trunk/Engine/Control/RTRT_register.cc (original)
+++ trunk/Engine/Control/RTRT_register.cc Fri Jul 29 13:16:36 2005
@@ -6,6 +6,7 @@
#include <Engine/ImageTraversers/NullImageTraverser.h>
#include <Engine/ImageTraversers/TiledImageTraverser.h>
#include <Engine/ImageTraversers/FramelessImageTraverser.h>
+#include <Engine/ImageTraversers/AFImageTraverser.h>
#include <Engine/LoadBalancers/CyclicLoadBalancer.h>
#include <Engine/LoadBalancers/SimpleLoadBalancer.h>
#include <Engine/LoadBalancers/WQLoadBalancer.h>
@@ -50,6 +51,7 @@
rtrt->registerComponent("null", &NullImageTraverser::create);
rtrt->registerComponent("tiled", &TiledImageTraverser::create);
rtrt->registerComponent("frameless", &FramelessImageTraverser::create);
+ rtrt->registerComponent("afr", &AFImageTraverser::create);
// Register image types
rtrt->registerComponent("null", &NullImage::create);
Modified: trunk/Engine/Display/OpenGLDisplay.cc
==============================================================================
--- trunk/Engine/Display/OpenGLDisplay.cc (original)
+++ trunk/Engine/Display/OpenGLDisplay.cc Fri Jul 29 13:16:36 2005
@@ -61,6 +61,7 @@
win = 0;
// If this is zero then the value hasn't been used yet.
last_frame_time = 0;
+ alwaysMakeContextCurrent = false;
}
OpenGLDisplay::~OpenGLDisplay()
@@ -85,6 +86,10 @@
old_xres = xres;
old_yres = yres;
}
+ if(context.getMultipleGLWindows())
+ {
+ alwaysMakeContextCurrent = true;
+ }
}
void OpenGLDisplay::createWindow(int xres, int yres, XWindow* masterWindow)
@@ -211,7 +216,7 @@
// Compute the framerate
double currentTime = SCIRun::Time::currentSeconds();
- if(!madeCurrent){
+ if(!madeCurrent || alwaysMakeContextCurrent){
if(!glXMakeCurrent(dpy, win, cx))
throw InternalError("glXMakeCurrent failed!\n", __FILE__, __LINE__);
madeCurrent=true;
@@ -226,7 +231,6 @@
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.375, 0.375, 0.0);
-
if(typeid(*image) == typeid(SimpleImage<RGBA8Pixel>)){
const SimpleImage<RGBA8Pixel>* si = dynamic_cast<const
SimpleImage<RGBA8Pixel>*>(image);
if(stereo){
Modified: trunk/Engine/Display/OpenGLDisplay.h
==============================================================================
--- trunk/Engine/Display/OpenGLDisplay.h (original)
+++ trunk/Engine/Display/OpenGLDisplay.h Fri Jul 29 13:16:36 2005
@@ -45,6 +45,7 @@
// Used to display the frame rate on the screen
void display_frame_rate(double framerate);
+ bool alwaysMakeContextCurrent;
};
}
Added: trunk/Engine/ImageTraversers/AFImageTraverser.cc
==============================================================================
--- (empty file)
+++ trunk/Engine/ImageTraversers/AFImageTraverser.cc Fri Jul 29 13:16:36
2005
@@ -0,0 +1,756 @@
+
+#include <Engine/ImageTraversers/AFImageTraverser.h>
+#include <Interface/RayPacket.h>
+#include <Interface/Renderer.h>
+#include <Core/Exceptions/IllegalArgument.h>
+#include <Core/Exceptions/InternalError.h>
+#include <Core/Util/Args.h>
+#include <Interface/Context.h>
+#include <Interface/Fragment.h>
+#include <Interface/Camera.h>
+#include <Interface/Image.h>
+#include <Interface/LoadBalancer.h>
+#include <Interface/PixelSampler.h>
+#include <Core/Thread/Mutex.h>
+#include <Core/Util/NotFinished.h>
+#include <GL/glut.h>
+#include <SCIRun/Core/Thread/Time.h>
+#include <Engine/Display/XHelper.h>
+#include <Core/Exceptions/IllegalValue.h>
+#include <Core/Exceptions/InternalError.h>
+
+#define MAX_MIN_RATIO 0.5
+#define MAX_MERGE_SPLIT_LIMIT 50
+
+using namespace Manta;
+using namespace std;
+using SCIRun::IllegalValue;
+using SCIRun::InternalError;
+// args are the command line options, if the user wants to pas to th
+// eimage traverser look in TiledimageTraverser.cc for usage
+ImageTraverser* AFImageTraverser::create(const vector<string>& args)
+{
+ return new AFImageTraverser(args);
+}
+
+AFImageTraverser::AFImageTraverser(const vector<string>& args)
+{
+ myRandomNumber = NULL;
+ // below we can easily pass command line arguments like
+ // storing stream to some file
+ // sampling rate etc.
+ // This we will do later
+ // following code is commented for demo purposes
+ /*
+ int argc = static_cast<int>(args.size());
+ for(int i = 0; i<argc;i++) {
+ string arg = args[i];
+ if(arg == "-tilesize") {
+ if(!getResolutionArg(i, args, xtilesize, ytilesize))
+ throw IllegalArgument("AFImageTraverser -tilesize", i, args);
+ } else {
+ throw IllegalArgument("AFImageTraverser", i, args);
+ }
+ }*/
+}
+
+AFImageTraverser::~AFImageTraverser()
+{
+ if(myRandomNumber!=NULL) delete [] myRandomNumber;
+ // free the kdtree and queues. I suppose this will be done automatically
+ // confirm!
+}
+
+void AFImageTraverser::createStatsWin()
+{
+ // Open the display and make sure it has opengl
+ dpy = XOpenDisplay(NULL);
+ if(!dpy)
+ throw InternalError("Error opening display", __FILE__, __LINE__);
+ int error, event;
+ if ( !glXQueryExtension( dpy, &error, &event) ) {
+ XCloseDisplay(dpy);
+ dpy=0;
+ throw InternalError("GL extension NOT available!\n", __FILE__, __LINE__);
+ }
+
+ int screen=DefaultScreen(dpy);
+
+ // Form the criteria for the
+ vector<int> attribList;
+ attribList.push_back(GLX_RGBA);
+ attribList.push_back(GLX_RED_SIZE); attribList.push_back(1);
+ attribList.push_back(GLX_GREEN_SIZE); attribList.push_back(1);
+ attribList.push_back(GLX_BLUE_SIZE); attribList.push_back(1);
+ attribList.push_back(GLX_ALPHA_SIZE); attribList.push_back(0);
+ attribList.push_back(GLX_DEPTH_SIZE); attribList.push_back(0);
+ attribList.push_back(GLX_DOUBLEBUFFER); // This must be the last one
+ attribList.push_back(None);
+
+ XVisualInfo* vi = glXChooseVisual(dpy, screen, &attribList[0]);
+ if(!vi){
+ // We failed to choose a visual. Try again without the double-buffer
flag
+ attribList.pop_back();
+ attribList.pop_back();
+ attribList.push_back(None);
+ vi = glXChooseVisual(dpy, screen, &attribList[0]);
+ }
+
+ Colormap cmap = XCreateColormap(dpy, RootWindow(dpy, screen),
+ vi->visual, AllocNone);
+
+ XSetWindowAttributes atts;
+ int flags=CWColormap|CWEventMask|CWBackPixmap|CWBorderPixel;
+ atts.background_pixmap = None;
+ atts.border_pixmap = None;
+ atts.border_pixel = 0;
+ atts.colormap=cmap;
+
atts.event_mask=StructureNotifyMask|ExposureMask|KeyPressMask|KeyReleaseMask;
+ Window parent = RootWindow(dpy, screen);
+ statsWindow.window=XCreateWindow(dpy, parent, 600, 0, DISPLAY_WIDTH,
DISPLAY_HEIGHT, 0, vi->depth,
+ InputOutput, vi->visual, flags, &atts);
+
+ XTextProperty tp;
+ char* name = "AFR Debug";
+ XStringListToTextProperty(&name, 1, &tp);
+ XSizeHints sh;
+ sh.flags = USPosition|USSize;
+
+ XSetWMProperties(dpy, statsWindow.window, &tp, &tp, 0, 0, &sh, 0, 0);
+ XMapWindow(dpy, statsWindow.window);
+
+ // Wait for the window to appear before proceeding
+ for(;;){
+ XEvent e;
+ XNextEvent(dpy, &e);
+ if(e.type == MapNotify)
+ break;
+ }
+
+ windowOpen = true;
+
+ cx = glXCreateContext(dpy, vi, NULL, True);
+ XFree(vi);
+
+ glXMakeCurrent(dpy, statsWindow.window, cx);
+
+ glViewport(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ gluOrtho2D(0, DISPLAY_WIDTH, 0, DISPLAY_HEIGHT);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ glClearColor(.05, .1, .2, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glXSwapBuffers(dpy, statsWindow.window);
+ glFinish();
+
+ // Get the fonts. You need to call this with a current GL context.
+ fontInfo = XHelper::getX11Font(dpy);
+ fontbase = XHelper::getGLFont(fontInfo);
+ glXMakeCurrent(dpy, None, NULL);
+}
+
+void AFImageTraverser::display_stats() {
+ static int fcount = 0;
+ if(samples_done/1000 > fcount)
+ {
+ // Display textual information on the screen:
+ char text[200];
+
+ switch(tmode)
+ {
+ case SOLID: sprintf(text, "Random Color Tiles; scale: %d",
(int)visScale); break;
+ case BOUNDARY: sprintf(text, "Tiles colored by size; scale: %d",
(int)visScale); break;
+ case DERIVATIVE: sprintf(text, "Derivative; scale: %d",
(int)visScale); break;
+ case OCCLUSION: sprintf(text, "Occlusion; scale: %d", (int)visScale);
break;
+ case ABSOLUTE_GRADIENT: sprintf(text, "ABS Gradients; scale: %d",
(int)visScale); break;
+ case RELATIVE_GRADIENT: sprintf(text, "REL Gradients; scale: %d",
(int)visScale); break;
+ case SAMPLING_DENSITY: sprintf(text, "Sample density; scale: %d",
(int)visScale); break;
+ case UNDERSAMPLING: sprintf(text, "Undersampling; scale: %d",
(int)visScale); break;
+ case AVERAGE_AGE: sprintf(text, "Average Age; scale: %d",
(int)visScale); break;
+ case JITTERING: sprintf(text, "Jittering; scale: %d", (int)visScale);
break;
+ default: sprintf(text, "Random Color Tiles; scale: %d",
(int)visScale); break;
+ };
+
+ glXMakeCurrent(dpy, statsWindow.window, cx);
+ glClearColor(.05, .1, .2, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ kdtree.displayTiles(tmode, samplingrate, chunkTimeStamp, visScale);
+ // Figure out how wide the string is
+ int width = XHelper::calc_width(fontInfo, text);
+ // Now we want to draw a gray box beneth the font using blending. :)
+ glEnable(GL_BLEND);
+ glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+ glColor4f(0.5,0.5,0.5,0.5);
+ glRecti(8,3-fontInfo->descent-2,25+width,fontInfo->ascent+3);
+ glDisable(GL_BLEND);
+ XHelper::printString(fontbase, 10, 3, text, RGBColor(1,1,1));
+ glXSwapBuffers(dpy, statsWindow.window);
+ glFinish();
+ // Suck up X events to keep opengl happy
+ while (XPending(dpy)) {
+ XEvent e;
+ XNextEvent(dpy, &e);
+ switch (e.type) {
+ case KeyPress:
+ {
+ char buf[100];
+ int rv;
+ KeySym ks;
+
+ rv = XLookupString(&e.xkey, buf, sizeof(buf), &ks, 0);
+ switch (ks) {
+ case XK_m:
+ case XK_M:
+ toggleTileDisplayMode();
+ break;
+ case XK_b:
+ case XK_B:
+ visScale++;
+ break;
+ case XK_l:
+ case XK_L:
+ if (visScale>0) visScale--;
+ break;
+ }
+ }
+ };
+ fcount++;
+ }
+ }
+
+}
+
+void AFImageTraverser::setupBegin(SetupContext& context,
+ int numChannels)
+{
+ context.loadBalancer->setupBegin(context, numChannels);
+ context.setMultipleGLWindows();
+ statsWindow.xres = DISPLAY_WIDTH; statsWindow.yres = DISPLAY_HEIGHT;
+ createStatsWin();
+}
+
+void AFImageTraverser::setupDisplayChannel(SetupContext& context)
+{
+ // char **argv;
+ // argv = (char**)malloc(sizeof(char*));
+ // argv[0] = (char*)malloc(12*sizeof(char));
+ // sprintf(argv[0],"tile_display");
+ // my_main(1, argv);
+ context.setMultipleGLWindows();
+ context.constrainPipelineDepth(1,1); // single buffer mode is set here
+ bool stereo; // get whether it is stereo, (shoot two rays for left
+ // and right eye)
+ int i;
+ int xres,yres;
+ samplingrate = 400000; // let us for now assume something realistic
+ samples_done = 0;
+ initpass = false;
+ // this will change when we can actually simulate
+ context.getResolution(stereo, xres, yres);
+ //---------------------------------------------------------
+ // initialize random number generators for each thread.
+ //---------------------------------------------------------
+ myRandomNumber = new MT_RNG[context.numProcs];
+ for(i=0; i<context.numProcs; i++)
+ {
+ myRandomNumber[i].seed_rng(1234*(i+1)); // just to begin give a simple
seed
+ }
+ //---------------------------------------------------------
+ // make our kdtree, given the resolution of image/channel
+ //---------------------------------------------------------
+ kdtree.setAB(xres, yres, samplingrate);
+ int numlevels = kdtree.init(xres, yres, samplingrate); // initialize
the tree
+ kdtree.setTileCut(numlevels/2, 0, samplingrate);
+ // set a mean number of tiles, i.e. cut at middle of tree
+ kdtree.resetPseudoRandomSeed();
+
+ //--------------------------------------------------------------------
+ // allocate the queues, based on samplinrate and number of processors.
+ //--------------------------------------------------------------------
+ if(context.numProcs<2)
+ {
+ throw IllegalValue<int>("numProcs must be > 1 for AFR, use -np 2 or
more", context.numProcs);
+ }
+ num_clients = context.numProcs-1;
+ // note that max fragment size is hard coded to 32 in fragment.h
+ // so not to exceed that limit.
+ fragment_size = 16; // ****** HARD CODED *******
+ chunk_size = num_clients*256; // this is done so that
+ // program scales well when #processors increase
+ int qSize = (int)(samplingrate*0.1);
+ frametype = new FrameType[num_clients+1];
+ numFragments = chunk_size/(num_clients*fragment_size);
+ temporalQ = new CQ<Sample>[num_clients];
+ sampleQ[EVEN_FRAME] = new Sample[chunk_size];
+ sampleQ[ODD_FRAME] = new Sample[chunk_size];
+ samplesetQ[EVEN_FRAME] = new CQ<SampleSet>[num_clients];
+ samplesetQ[ODD_FRAME] = new CQ<SampleSet>[num_clients];
+ for(i = 0; i<num_clients; i++)
+ {
+ temporalQ[i].init(qSize+1);
+ samplesetQ[EVEN_FRAME][i].init(chunk_size);
+ samplesetQ[ODD_FRAME][i].init(chunk_size);
+ frametype[i] = EVEN_FRAME;
+ }
+ frametype[num_clients] = EVEN_FRAME;
+
+ //--------------------------------------------------------------------
+ // tell load balancer to balance num_clients # of assignments
+ // we intend to have one assignment per client. Unless some client
+ // takes longer.
+ //--------------------------------------------------------------------
+ cout << "numFragments = " << numFragments << endl;
+ context.loadBalancer->setupDisplayChannel(context, numFragments);
+ tmode = SOLID;
+ visScale = 1.0;
+ // make fist set of fragments from uniform tiling
+ allocateFragments(EVEN_FRAME);
+}
+
+void AFImageTraverser::setupFrame(const RenderContext& context)
+{
+ if(context.proc==0) // master gthread
+ {
+ // get the current time
+ //using namespace SCIRun;
+ //cout << "setting up frame in master " << endl;
+ chunkTimeStamp =
(float)samples_done/(float)samplingrate;//Time::currentSeconds();
+ }
+ //else
+ //{
+ //cout << "setting up frame in client" << endl;
+ // get the assignment from the load balancer.
+ context.loadBalancer->setupFrame(context);
+ //}
+ //cout << "done setup frame" << endl;
+}
+
+
+void AFImageTraverser::allocateFragments(const FrameType f)
+{
+ int i, j;
+ int x, y;
+ Sample s;
+ for(j=0; j<chunk_size; j++)
+ {
+ kdtree.getRandomSample(x, y, myRandomNumber[0]);
+ // jitter if we need to here
+ sampleQ[f][j].reset();
+ sampleQ[f][j].init(x, y, chunkTimeStamp);
+ //cout << "allocated sample: " << x << ", " << y << endl;
+ }
+}
+
+void AFImageTraverser::renderCrossHair(const RenderContext& context, int
myID,
+ Image *image, int xres, int yres,
Sample *s)
+{
+ float xfrac, yfrac, sx, sy;
+ int size = 5;
+ int flags = RayPacket::HaveImageCoordinates | RayPacket::ConstantEye;
+ sx = s->viewCoord[0];
+ sy = s->viewCoord[1];
+ //cout << "now rendering xhair" << endl;
+ int depth = 0;
+ Point *p;
+ RayPacketData raydata;
+ RayPacket rays(raydata, size, depth, flags);
+ double cx, cy;
+ Fragment f; // for output to image
+ f.setSize(size);
+ f.setFlags(Fragment::ConstantEye);
+ int isx, isy;
+ isx = (int)sx;
+ isy = (int)sy;
+ SampleSet ss;
+ ss.set(TEMPORAL_SAMPLE, sx, sy, s->t,
+ s->worldCoord[0], s->worldCoord[1], s->worldCoord[2],
+ s->c[0], s->c[1], s->c[2]);
+
+ float t = (float)chunkTimeStamp;
+
+ for(int i=0;i<size;i++) {
+ // normalized
+ Fragment::Element& fe = f.get(i);
+ fe.which_eye = 0;
+ double px, py;
+ switch(i)
+ {
+ case 0: cx = sx; cy = sy; fe.x = isx; fe.y = isy;
+ break; // center
+ case 1: cx = sx-1; cy = sy; fe.x = isx-1; fe.y = isy;
+ break; // left
+ case 2: cx = sx+1; cy = sy; fe.x = isx+1; fe.y = isy;
+ break; // right
+ case 3: cx = sx; cy = sy-1; fe.x = isx; fe.y = isy-1;
+ break; // bottom
+ case 4: cx = sx; cy = sy+1; fe.x = isx; fe.y = isy+1;
+ break; // top
+ };
+ //cout << "raytracing: " << cx << ", " << cy << endl;
+ // we will jitter later, now just add 0.5 <TODO>
+ if(xres>yres) // let the smaller dimension be mapped to [-1,1]
+ {
+ px = (double)(-1.0 + 2.0*cx/(double)yres);
+ py = (double)(-1.0 + 2.0*cy/(double)yres);
+ }
+ else
+ {
+ px = (double)(-1.0 + 2.0*cx/(double)xres);
+ py = (double)(-1.0 + 2.0*cy/(double)xres);
+ }
+ //printf("%f, %f\n", (float)px, (float)py);
+ rays.setPixel(i, 0, px, py, &fe.color);
+ }
+ // Trace the rays. The results will automatically go into the fragment
+ context.renderer->traceEyeRays(context, rays);
+ rays.computeHitPositions();
+ // okay now copy from fragment to temporalQ
+ for(int i=0;i<size;i++) {
+ RayPacket::Element& re = rays.get(i);
+ Fragment::Element& fe = f.get(i);
+ RGBColor tempcol = fe.color.convertRGB();
+ Point p = re.hitPosition;
+ switch(i)
+ {
+ case 0:
+ ss.set(CENTER_SAMPLE, sx, sy, t, p.x(), p.y(), p.z(),
+ tempcol.r(), tempcol.g(), tempcol.b());
+ break;
+ case 1:
+ ss.set(LEFT_SAMPLE, sx-1, sy, t, p.x(), p.y(), p.z(),
+ tempcol.r(), tempcol.g(), tempcol.b());
+ break;
+ case 2:
+ ss.set(RIGHT_SAMPLE, sx+1, sy, t, p.x(), p.y(), p.z(),
+ tempcol.r(), tempcol.g(), tempcol.b());
+ break;
+ case 3:
+ ss.set(BOTTOM_SAMPLE, sx, sy-1, t, p.x(), p.y(), p.z(),
+ tempcol.r(), tempcol.g(), tempcol.b());
+ break;
+ case 4:
+ ss.set(TOP_SAMPLE, sx, sy+1, t, p.x(), p.y(), p.z(),
+ tempcol.r(), tempcol.g(), tempcol.b());
+ break;
+ };
+ }
+ //cout << "computing gradients" << endl;
+ ss.computeGradients(t);
+ //cout << "inserting in Q, commented" << endl;
+ samplesetQ[frametype[myID]][myID-1].qInsert(&ss);
+ //cout << "setting image for the xhair fragment" << endl;
+ image->set(f);
+ //cout << "DONE" << endl;
+}
+
+void AFImageTraverser::renderFragment(const RenderContext& context,
+ int assignment, Image* image,
+ int xres, int yres)
+{
+ //cout << "inside renderFragment " << endl;
+ // renders the fragment by jittering it and stores result in temporalQ
+ int flags = RayPacket::HaveImageCoordinates | RayPacket::ConstantEye;
+ Fragment fragment;
+ int fsize = (fragment_size<(chunk_size-assignment*fragment_size))?
+ fragment_size : (chunk_size-assignment*fragment_size);
+ fragment.setSize(fsize);
+ fragment.setFlags(Fragment::ConstantEye);
+ int myID = context.proc;
+ for(int f=0;f<fsize;f+=RayPacket::MaxSize) {
+ int size = RayPacket::MaxSize;
+ if(size<fragment_size) size = fsize;
+ if(size >= fsize-f)
+ size = fsize-f;
+ // Create a ray packet
+ int depth = 0;
+ RayPacketData raydata;
+ RayPacket rays(raydata, size, depth, flags);
+
+ for(int i=0;i<size;i++) {
+ Fragment::Element& fe = fragment.get(f+i);
+ float cx, cy;
+ int sind = fragment_size*assignment + f+i;
+ cx = sampleQ[frametype[myID]][sind].viewCoord[0];
+ cy = sampleQ[frametype[myID]][sind].viewCoord[1];
+
+ fe.x = (int)cx;
+ fe.y = (int)cy;
+ fe.which_eye = 0;
+ // normalized
+ double px, py;
+ //cout << "raytracing: " << fe.x << ", " << fe.y << endl;
+ // we will jitter later, now just add 0.5 <TODO>
+ if(xres>yres) // let the smaller dimension be mapped to [-1,1]
+ {
+ px = (double)(-1.0 + 2.0*(double)(cx)/(double)yres);
+ py = (double)(-1.0 + 2.0*(double)(cy)/(double)yres);
+ }
+ else
+ {
+ px = (double)(-1.0 + 2.0*(double)(cx)/(double)xres);
+ py = (double)(-1.0 + 2.0*(double)(cy)/(double)xres);
+ }
+ //printf("%f, %f\n", (float)px, (float)py);
+ rays.setPixel(i, 0, px, py, &fe.color);
+ }
+
+ // Trace the rays. The results will automatically go into the fragment
+ context.renderer->traceEyeRays(context, rays);
+ rays.computeHitPositions();
+ // okay now copy from fragment to temporalQ
+ for(int i=0;i<size;i++) {
+ int sind = fragment_size*assignment + f+i;
+ Fragment::Element& fe = fragment.get(f+i);
+
+ RayPacket::Element& re = rays.get(i);
+ RGBColor tempcol = fe.color.convertRGB();
+ sampleQ[frametype[myID]][sind].c[0] = tempcol.r();
+ sampleQ[frametype[myID]][sind].c[1] = tempcol.g();
+ sampleQ[frametype[myID]][sind].c[2] = tempcol.b();
+ sampleQ[frametype[myID]][sind].worldCoord[0] = re.hitPosition.x();
+ sampleQ[frametype[myID]][sind].worldCoord[1] = re.hitPosition.y();
+ sampleQ[frametype[myID]][sind].worldCoord[2] = re.hitPosition.z();
+ }
+ }
+ //cout << "setting image" << endl;
+ image->set(fragment);
+}
+
+void AFImageTraverser::renderImage(const RenderContext& context,
+ Image* image)
+{
+ /*
+ basically do the following, if it is a master thread call master
function, else
+ call the client function
+ */
+ if(context.proc == 0) // master thread
+ {
+ masterThread(context, image);
+ image->setValid(true);
+ //cout << "masterthread done" << endl;
+ }
+ else
+ {
+ //cout << "here we call client" << endl;
+ int s,e;
+ // this is what every thread does: gets the next assignment and render
it.
+ while(context.loadBalancer->getNextAssignment(context, s, e)) {
+ //cout << "loadbalancer returned " << s << ", " << e << endl;
+ for(int assignment = s; assignment < e; assignment++) {
+ clientThread(context, image, assignment);
+ }
+ }
+ // update the frame type
+ if(frametype[context.proc]==EVEN_FRAME)
+ frametype[context.proc] = ODD_FRAME;
+ else
+ frametype[context.proc] = EVEN_FRAME;
+ //cout << "clientThread done" << endl;
+ }
+}
+
+
+void AFImageTraverser::toggleTileDisplayMode()
+{
+ switch(tmode)
+ {
+ case SOLID: tmode = BOUNDARY; break;
+ case BOUNDARY: tmode = DERIVATIVE; break;
+ case DERIVATIVE: tmode = OCCLUSION; break;
+ case OCCLUSION: tmode = ABSOLUTE_GRADIENT; break;
+ case ABSOLUTE_GRADIENT: tmode=RELATIVE_GRADIENT;
break;
+ case RELATIVE_GRADIENT: tmode=SAMPLING_DENSITY; break;
+ case SAMPLING_DENSITY: tmode = AVERAGE_AGE; break;
+ case AVERAGE_AGE: tmode = UNDERSAMPLING; break;
+ case UNDERSAMPLING: tmode = JITTERING; break;
+ case JITTERING: tmode = SOLID; break;
+ default: tmode = SOLID; break;
+ };
+}
+
+void AFImageTraverser::masterThread(const RenderContext& context,
+ Image* image)
+{
+ //cout << "inside masterthread for frametype " << frametype[0] << endl;
+ // update kdtree based on previous results from the client threads
+
+ bool stereo;
+ int xres, yres;
+ image->getResolution(stereo, xres, yres);
+ // now let us do our display stuff
+ display_stats();
+
+ FrameType prevFrameType = (frametype[0]==EVEN_FRAME)? ODD_FRAME :
EVEN_FRAME;
+
+ // return during intialization here
+ if(!initpass)
+ {
+ if(samples_done >= xres*yres) initpass = true;
+ samples_done += chunk_size;
+ if(samples_done>chunk_size)
+ for(int i=0; i<chunk_size; i++)
+ {
+ kdtree.updateStatsAddSample(&sampleQ[prevFrameType][i],
(float)chunkTimeStamp, samplingrate, 0.0, false);
+ }
+ }
+ else
+ {
+ //cout << "samples_done = " << samples_done << endl;
+ //cout << "now calling adjust tiles, for now commented" << endl;
+ // adjust tiles based on current status
+ adjustTiles((float)chunkTimeStamp);
+ //cout << "now updaing kdtree" << endl;
+ SampleSet *sampleset;
+ int i, j;
+ for(i=0; i<num_clients; i++)
+ {
+ while(!samplesetQ[prevFrameType][i].isEmpty())
+ {
+ //cout << "getting sampleset from Q" << endl;
+ sampleset = samplesetQ[prevFrameType][i].seekLast();
+ samplesetQ[prevFrameType][i].qDelete();
+ kdtree.updateStatsAddSampleSet(sampleset, (float)chunkTimeStamp,
samplingrate);
+ samples_done += 6;
+ }
+
+ }
+ for(int i=0; i<chunk_size; i++)
+ {
+ kdtree.ageStats(&sampleQ[prevFrameType][i], (float)chunkTimeStamp,
samplingrate);
+ }
+ }
+ //cout << "allocating fragments for next frame" << endl;
+ // allocate samples for next chunk for all clients
+ if(frametype[0]==EVEN_FRAME)
+ {
+ allocateFragments(ODD_FRAME);
+ frametype[0] = ODD_FRAME;
+ }
+ else
+ {
+ allocateFragments(EVEN_FRAME);
+ frametype[0] = EVEN_FRAME;
+ }
+ //cout << "allocation done, now incrementing sample count" << endl;
+ //cout << "masterThread done" << endl;
+}
+
+void AFImageTraverser::clientThread(const RenderContext& context,
+ Image* image, int assignment)
+{
+ //cout << "inside clientThread for frametype " << frametype[context.proc]
<< endl;
+ bool stereo;
+ int xres, yres;
+ image->getResolution(stereo, xres, yres);
+ int myID = context.proc;
+ Sample s;
+ //cout << "calling renderFragment for allotted fragment, myID = " << myID
<< endl;
+ renderFragment(context, assignment, image, xres, yres);
+ //cout << "done RenderFragment" << endl;
+
+ // let us not write temporal samples to image
+
+ float t = (float)chunkTimeStamp;
+ //cout << "now placing fragment in temporalQ" << endl;
+ for(int i=0; i<fragment_size; i++)
+ {
+ //cout << "placing id: " << frametype[myID] << ", " <<
fragment_size*assignment+i << endl;
+
temporalQ[myID-1].qInsert(&sampleQ[frametype[myID]][fragment_size*assignment+i]);
+ }
+ //cout << "placement in temporalQ done" << endl;
+ /* place the fragment in the temporalQ, take fragment_size number of
+ * items from the temporalQ one by one, reproject them and complete
+ * a crosshair, placing it in samplesetQ.
+ */
+ if(initpass)
+ {
+ int i;
+ Sample *sp;
+ //cout << "now making xhairs" << endl;
+ for(i=0; i<fragment_size; i++)
+ {
+ sp = temporalQ[myID-1].seekLast();
+ if(sp!=NULL)
+ {
+ temporalQ[myID-1].qDelete();
+ Manta::Real px, py, pz;
+ px = sp->worldCoord[0];
+ py = sp->worldCoord[1];
+ pz = sp->worldCoord[2];
+ /*
+ * if the point is INF, no need to reproject as it will remain the
same
+ *
+ */
+ //printf("projecting %f,%f,%f from %f,%f to .. ", px, py, pz,
+ // sp->viewCoord[0], sp->viewCoord[1]);
+ if(!isinf(px) && !isinf(py) && !isinf(pz))
+ {
+ const Point p(px, py, pz);
+ Point rp;
+ //Camera* camera =
context.rtrt_int->getCamera(context.channelIndex);
+ rp = context.camera->project(p);
+ //rp = camera->project(p);
+ sp->viewCoord[0] = rp.x()*xres;
+ sp->viewCoord[1] = rp.y()*yres;
+ sp->viewCoord[2] = rp.z();
+ //printf(".. %f,%f (%f,%f, %f)\n",
+ // sp->viewCoord[0], sp->viewCoord[1], rp.x(), rp.y(),
rp.z());
+ }
+ if(sp->viewCoord[0]<xres && sp->viewCoord[0]>=0
+ && sp->viewCoord[1]<yres && sp->viewCoord[1]>=0
+ && sp->viewCoord[2]<=1.0)
+ renderCrossHair(context, myID, image, xres, yres, sp);
+ //cout << "returned from renderCrossHair" << endl;
+ }
+ }
+ }
+ //cout << "making xhairs done" << endl;
+}
+
+void AFImageTraverser::adjustTiles(Timestamp currenttime)
+{
+ float minError, maxError;
+ int count;
+ int required_tiles = 2048;
+ if(kdtree.number_of_tiles()!=required_tiles)
+ {
+ do
+ {
+ while(kdtree.number_of_tiles()>required_tiles)
+ {
+ kdtree.merge(kdtree.getminErrorParentTile(), currenttime,
samplingrate);
+ }
+ while(kdtree.number_of_tiles()<required_tiles)
+ {
+ kdtree.split(kdtree.getmaxErrorTile(), currenttime, samplingrate);
+ }
+ }
+ while(kdtree.number_of_tiles()!=required_tiles);
+ }
+
+ minError = kdtree.getminError();
+ maxError = kdtree.getmaxError();
+ //cout << "minError = " << minError << ", maxError = " << maxError <<
endl;
+ if(minError/maxError<MAX_MIN_RATIO)
+ {
+ int num_tiles_merged, i;
+ count = 0;
+ do
+ {
+ count++;
+ num_tiles_merged = kdtree.merge(kdtree.getminErrorParentTile(),
currenttime, samplingrate);
+ for(i=0; i<num_tiles_merged && count<MAX_MERGE_SPLIT_LIMIT; i++)
+ {
+ count++;
+ kdtree.split(kdtree.getmaxErrorTile(), currenttime, samplingrate);
+ }
+ minError = kdtree.getminError();
+ maxError = kdtree.getmaxError();
+ }
+ while(minError/maxError<MAX_MIN_RATIO && count<MAX_MERGE_SPLIT_LIMIT);
+ }
+}
Added: trunk/Engine/ImageTraversers/AFImageTraverser.h
==============================================================================
--- (empty file)
+++ trunk/Engine/ImageTraversers/AFImageTraverser.h Fri Jul 29 13:16:36
2005
@@ -0,0 +1,73 @@
+
+#ifndef Manta_Engine_AFImageTraverser_h
+#define Manta_Engine_AFImageTraverser_h
+
+#include <Interface/ImageTraverser.h>
+#include <Interface/Fragment.h>
+#include <sgi_stl_warnings_off.h>
+#include <string>
+#include <vector>
+#include <sgi_stl_warnings_on.h>
+#include <Engine/ImageTraversers/AFR/kdtree.h>
+#include <Engine/ImageTraversers/AFR/CQ.h>
+#include <Engine/ImageTraversers/AFR/sample.h>
+#include <Interface/XWindow.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#include <GL/glx.h>
+
+namespace Manta {
+ using namespace std;
+ enum FrameType { EVEN_FRAME, ODD_FRAME };
+ class AFImageTraverser : public ImageTraverser {
+ public:
+ AFImageTraverser(const vector<string>& args);
+ virtual ~AFImageTraverser();
+ virtual void setupBegin(SetupContext&, int numChannels);
+ virtual void setupDisplayChannel(SetupContext&);
+ virtual void setupFrame(const RenderContext& context);
+ virtual void renderImage(const RenderContext& context, Image* image);
+ void allocateFragments(const FrameType f);
+ void AFImageTraverser::renderFragment(const RenderContext& context,
+ int assignment, Image* image,
+ int xres, int yres);
+ void AFImageTraverser::renderCrossHair(const RenderContext& context, int
myID,
+ Image *image, int xres, int yres,
Sample *s);
+ void masterThread(const RenderContext& context, Image* image);
+ void clientThread(const RenderContext& context, Image* image, int
assignment);
+ void adjustTiles(Timestamp currenttime);
+ void createStatsWin();
+ void display_stats();
+ void toggleTileDisplayMode();
+ static ImageTraverser* create(const vector<string>& args);
+ private:
+ AFImageTraverser(const AFImageTraverser&);
+ AFImageTraverser& operator=(const AFImageTraverser&);
+ KDTree kdtree;
+ int numFragments;
+ CQ<Sample> *temporalQ;
+ Sample *sampleQ[2];
+ CQ<SampleSet> *samplesetQ[2];
+ MT_RNG *myRandomNumber;
+ int num_clients;
+ int chunk_size, fragment_size;
+ int samplingrate;
+ unsigned int samples_done;
+ int *client_done_counter;
+ FrameType *frametype;
+ double chunkTimeStamp;
+ bool initpass;
+ XWindow statsWindow;
+ Display* dpy;
+ GLXContext cx;
+ // These contain stuff for font stuff.
+ XFontStruct* fontInfo;
+ GLuint fontbase;
+ bool windowOpen;
+ bool madeCurrent;
+ TileDisplayMode tmode;
+ float visScale;
+ };
+}
+
+#endif
Added: trunk/Engine/ImageTraversers/AFR/CQ.h
==============================================================================
--- (empty file)
+++ trunk/Engine/ImageTraversers/AFR/CQ.h Fri Jul 29 13:16:36 2005
@@ -0,0 +1,140 @@
+/***************************************************************************
+ * dqueue.h
+ *
+ * Thu Jan 13 11:13:45 2005
+ * Copyright 2005 Abhinav Dayal
+ * abhinav@cs.northwestern.edu
+
****************************************************************************/
+#ifndef _CQ_H
+#define _CQ_H
+
+#include <Core/Thread/Mutex.h>
+
+template<class T>
+class CQ
+{
+ private:
+ T *item;
+ SCIRun::Mutex qlock;
+ int start, end, max_n;
+
+ int getN_help()
+ {
+ return (max_n+start-end)%max_n;
+ }
+
+ public:
+
+ CQ() : qlock( "qlock" )
+ {
+ max_n = 0;
+ start = end = 0;
+ item = NULL;
+ }
+
+ void init(int size)
+ {
+ max_n = size+1;
+ item = new T[max_n];
+ start = end = 0;
+ T sample_item;
+ sample_item.reset();
+ qInsert(&sample_item);
+ }
+
+ bool isEmpty()
+ {
+ bool ret = true;
+
+ qlock.lock( );
+ ret = (getN_help()==1);
+ qlock.unlock( );
+ return( ret );
+ }
+
+ bool isFull()
+ {
+ bool ret = true;
+
+ qlock.lock( );
+ ret = (getN_help()==(max_n-1));
+ qlock.unlock( );
+ return( ret );
+ }
+
+ T* seekLast()
+ {
+ T *ret = NULL;
+
+ qlock.lock( );
+ if(start==end) {
+ qlock.unlock( );
+ return NULL;
+ }
+ ret = &item[end];
+ qlock.unlock( );
+ return( ret );
+ }
+
+ void qInsert(T *newItem)
+ {
+ qlock.lock( );
+ item[start] = *newItem;
+ start = (start+1)%max_n;
+ if(start==end)
+ end = (end+1)%max_n;
+ qlock.unlock( );
+ }
+
+ void qDelete()
+ {
+ qlock.lock( );
+ if(start==end) {
+ qlock.unlock( );
+ return;
+ }
+ end = (end+1)%max_n;
+ qlock.unlock( );
+ }
+
+ T* getKthItem(int k)
+ {
+ T *ret = NULL;
+
+ qlock.lock( );
+ if(k>getN_help()) {
+ qlock.unlock( );
+ return NULL;
+ }
+ ret = &item[(max_n+start-k)%max_n];
+ qlock.unlock( );
+ return( ret );
+ }
+
+ void print()
+ {
+ qlock.lock( );
+ if(getN_help()>0)
item[(max_n+start-1)%max_n].print();
+ qlock.unlock( );
+ }
+
+ int getN()
+ {
+ int ret = 0;
+
+ qlock.lock( );
+ ret = getN_help( );
+ qlock.unlock( );
+ return( ret );
+ }
+
+ ~CQ()
+ {
+ delete[] item;
+ }
+
+};
+
+
+
+#endif
Added: trunk/Engine/ImageTraversers/AFR/evil.h
==============================================================================
--- (empty file)
+++ trunk/Engine/ImageTraversers/AFR/evil.h Fri Jul 29 13:16:36 2005
@@ -0,0 +1,365 @@
+
+/**
+ * @defgroup EVIL Evil implementations of various functions
+ * @{
+ */
+
+/**
+ * @file evil.h
+ *
+ * It's Doctor Evil, actually. I didn't spend four years at Evil
+ * Medical School to be called Mister Evil, thank you very much.
+ */
+
+#ifndef EVIL_H
+#define EVIL_H
+
+/**
+ * meta evil: evil documentation.
+ *
+ * pick one of these as your EVIL_LEVEL.
+ *
+ * in reality, of course, EVIL_NOT_AT_ALL, EVIL_QUASI_EVIL,
+ * EVIL_EVIL, and EVIL_FAST_AND_WRONG_BUT_WHO_CARES are all
+ * that matter. but this *IS* evil.h, so we have to have a
+ * lot of evilness.
+ *
+ * @{
+ */
+#define EVIL_WHY_ARE_YOU_EVEN_BOTHERING_WITH_THIS (-1)
+#define EVIL_NOT_AT_ALL 0
+#define EVIL_DEAD 1
+#define EVIL_DEAD_PART_II 2
+#define EVIL_DEAD_ARMY_OF_DARKNESS 3
+#define EVIL_THE_DIET_COKE_OF_EVIL 5
+#define EVIL_KNIEVEL 6
+#define EVIL_MCBRIDE 7
+#define EVIL_QUASI_EVIL 10
+#define EVIL_PSEUDO_EVIL 20
+#define EVIL_SNIFFLES 50
+#define EVIL_PAPER_CUT 75
+#define EVIL_UNUSED_EVIL_LEVEL_TO_TAKE_UP_SPACE 99
+#define EVIL_SNOWBOARDING 100
+#define EVIL_EVIL 250
+#define EVIL_HOMER 350
+#define EVIL_AND_WE_MEAN_EVIL 500
+#define EVIL_FRUITS_OF_SATAN 666
+#define EVIL_YOUR_WORST_NIGHTMARE 999
+#define EVIL_THE_SICKNESS 1000
+#define EVIL_STENCIL_BUFFER 1024
+#define EVIL_CTHULHU 4096
+#define EVIL_UNSPEAKABLE_HORROR 8192
+#define EVIL_BROGANIZATION 65536
+#define EVIL_FAST_AND_WRONG_BUT_WHO_CARES 314150
+/** @} */
+
+/* if you're not going to define it yourself you deserve what you get. */
+#ifndef EVIL_LEVEL
+#define EVIL_LEVEL EVIL_EVIL
+#endif
+
+#if EVIL_LEVEL < EVIL_NOT_AT_ALL
+#error "You're not evil enough to use this header."
+#endif
+
+#include <math.h>
+
+#ifdef __cplusplus
+# ifdef WIN32
+# define INLINE __forceinline
+# else
+# define INLINE inline
+# endif
+#else
+# define INLINE
+#endif
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef MAX
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* most evil tricks involve bitwise manipulation of IEEE floats */
+typedef union INTORFLOAT
+{
+ int i;
+ float f;
+} INTORFLOAT;
+
+/**********************************************************************/
+/**
+ * @defgroup INVERSE_EXPONENTIAL Evil Inverse Exponential
+ * @{
+ */
+#define NUMBUCKETS 100001
+#define MAXBUCKETVAL 100.0f
+static float gInvexpLookup[NUMBUCKETS];
+static const float gInvexpIncrement = MAXBUCKETVAL/(NUMBUCKETS - 1);
+
+/* populate the table */
+static void invexpInit(void)
+{
+ int i;
+ for (i=0; i<NUMBUCKETS; i++) {
+ gInvexpLookup[i] = exp(-i*gInvexpIncrement);
+ }
+}
+
+/**
+ * Inverse Exponential
+ *
+ * X-Evil-Rating: Quasi-evil
+ *
+ * This function approximates the inverse exponential by way of
+ * a lookup table for exponents in the range 0..10. (Exponents
+ * higher than 10 very close to zero).
+ *
+ * Exponents outside the range 0..10 are clamped to that range
+ * before lookup.
+ *
+ * @param exponent The exponent
+ * @return An approximation of e^(-exponent)
+ */
+#if EVIL_LEVEL > EVIL_NOT_AT_ALL
+static INLINE float invexp(const float exponent)
+{
+ INTORFLOAT bias;
+ INTORFLOAT n;
+
+ /* hash for our table lookup */
+ n.f = exponent/gInvexpIncrement;
+
+ /*
+ * evil float->int cast.
+ *
+ * this is evil.
+ * hence i like it.
+ *
+ * basically what we do is assume the number is less than 1<<23,
+ * which it had better be for our lookup table anyway, and then
+ * we force the float representation down into the mantissa by
+ * adding the bias, which causes the exponent to be a known value
+ * that we can then subtract away. this allows a float->int cast
+ * to be done in only a few instructions rather than 25 or 30.
+ *
+ * this is equivalent to:
+ * int i = (int)(exponent/gInvexpIncrement+0.5f);
+ *
+ * from game programming gems ii, pp.169-171
+ */
+ bias.i = (23 + 127) << 23;
+ n.f += bias.f;
+ n.i -= bias.i;
+
+ /* clamp to the bounds of our table */
+ n.i = MIN(MAX(n.i,0),(NUMBUCKETS-1));
+
+ /* finally, lookup the answer */
+ return gInvexpLookup[n.i];
+}
+#else
+static float invexp(const float exponent)
+{
+ return exp(-exponent);
+}
+#endif
+/** @} */
+
+/**********************************************************************/
+/**
+ * @defgroup POWER_OF_TWO Evil Powers-of-two
+ * @{
+ */
+/**
+ * Is Power Of Two
+ *
+ * X-Evil-Rating: Not very evil
+ *
+ * @param in Any integer
+ * @return true if in is a power of two, false otherwise.
+ */
+static INLINE int ispoweroftwo(int in)
+{
+ return (in&(in-1)) == 0;
+}
+
+/**
+ * Next Power Of Two
+ *
+ * X-Evil-Rating: Cliff Evil
+ *
+ * @param in Any integer
+ * @return The next highest power of two integer >= in
+ */
+#if EVIL_LEVEL > EVIL_NOT_AT_ALL
+static INLINE int nextpoweroftwo(int orig)
+{
+ INTORFLOAT floatrep;
+ int exponent;
+
+ floatrep.f = (float)orig;
+
+ exponent = ((floatrep.i & 0x7f800000) >> 23) - 127; /* decode exponent */
+
+ if (floatrep.i & 0x007fffff) { /* if non-zero fractional part */
+ exponent++;
+ }
+
+ return 1<<exponent;
+}
+#else
+static int nextpoweroftwo(int orig)
+{
+ orig--;
+ orig |= orig >> 1;
+ orig |= orig >> 2;
+ orig |= orig >> 4;
+ orig |= orig >> 8;
+ orig |= orig >> 16;
+ return orig+1;
+}
+#endif
+
+/**
+ * Log base 2
+ *
+ * X-Evil-Rating: Inline Assembly Evil
+ *
+ * @param n Any integer
+ * @return The base-2 logarithm of n
+ */
+#if EVIL_LEVEL >= EVIL_EVIL
+static INLINE int evil_log2(int n)
+{
+ int eax;
+# ifdef WIN32
+ __asm bsr eax, n
+# else
+ asm("bsr %1,%0;" : "=a" (eax) : "m" (n));
+# endif
+ return eax;
+}
+#else
+static int evil_log2(int n)
+{
+ int i = 0;
+
+ if (n == 0 || !ispoweroftwo(n)) {
+ return -1; /* um, can't do that? */
+ }
+ while (!(n&0x1)) {
+ n >>= 1;
+ i++;
+ }
+ return i;
+}
+#endif
+/** @} */
+
+/**********************************************************************/
+/**
+ * @defgroup FLOAT Evil analysis of float numbers
+ * @{
+ */
+/**
+ * Get sign of a float number
+ *
+ * X-Evil-Rating: Yannick Evil
+ *
+ * @param f A floating point number
+ * @return -1 if the number is negative, 1 if the number is positive
+ */
+#if EVIL_LEVEL >= EVIL_EVIL
+static INLINE int getsign(const float f)
+{
+ /*
+ * The following nasty assembly is equivalent to:
+ *
+ * return ((*((int*)&f)>>31)<<1)+1;
+ *
+ * So why did we go inline asm? To change an shl/inc
+ * or add/inc pair generated by the compiler into a
+ * single lea instruction, for a savings of about 10%
+ *
+ */
+#ifdef WIN32
+ __asm {
+ mov eax, f
+ sar eax, 0x1f
+ lea eax, [eax+eax+1]
+ }
+#else
+ int i;
+ asm ("movl %1,%0;" /* copy f into i */
+ "sarl $0x1f,%0;" /* extract sign: neg = -1, pos = 0 */
+ "lea 0x1(%0,%0,1),%0" /* 1+(x+x*1): neg = -1, pos = 1 */
+ : "=a" (i) /* output: register int i is in %eax */
+ : "m" (f)); /* input: memory f */
+ return i;
+#endif
+}
+#else
+static INLINE int getsign(const float f)
+{
+ return (f>=0.0)?1:-1;
+}
+#endif
+/** @} */
+
+
+/**********************************************************************/
+/**
+ * @defgroup RSQRT Evil Reciprocal Square Root
+ * @{
+ */
+/**
+ * Reciprocal Square Root
+ *
+ * X-Evil-Rating: Carmack Evil
+ *
+ * This function is so evil that it took somebody 14 pages of research
+ * paper to explain how it works.
+ *
+ *
http://www.math.purdue.edu/~clomont/Math/Papers/2003/InvSqrt.pdf
+ *
+ * @param in Any integer
+ * @return The next highest power of two integer >= in
+ */
+#if EVIL_LEVEL > EVIL_NOT_AT_ALL
+static INLINE float rsqrt(float x)
+{
+ float xhalf = 0.5f*x;
+ int i = *(int*)&x; /* get bits for floating value */
+ i = 0x5f375a86 - (i>>1); /* what the fuck? */
+ x = *(float*)&i; /* convert bits back to float */
+# if EVIL_LEVEL < EVIL_FAST_AND_WRONG_BUT_WHO_CARES
+ x = x*(1.5f-xhalf*x*x); /* Newton step, repeating increases accuracy */
+# endif
+# if EVIL_LEVEL < EVIL_EVIL
+ x = x*(1.5f-xhalf*x*x); /* accurate within 0.0001% now */
+# endif
+ return x;
+}
+#else
+static float rsqrt(float x)
+{
+ return 1.0f/sqrtf(x);
+}
+#endif
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#undef INLINE
+
+#endif
+
+/** @} */
Added: trunk/Engine/ImageTraversers/AFR/kdtree.cc
==============================================================================
--- (empty file)
+++ trunk/Engine/ImageTraversers/AFR/kdtree.cc Fri Jul 29 13:16:36 2005
@@ -0,0 +1,611 @@
+/***************************************************************************
+ * kdtree.cpp
+ *
+ * Sat Oct 30 14:37:54 2004
+ * Copyright 2004 Abhinav Dayal
+ * abhinav@cs.northwestern.edu
+
****************************************************************************/
+
+#include <Engine/ImageTraversers/AFR/kdtree.h>
+#include <assert.h>
+
+KDTree::KDTree()
+{
+ totalNodes = numLevels = numTiles = pseudostart = 0;
+ tile = NULL;
+}
+
+// initialize a kdtree with width x height leaf nodes
+void KDTree::setAB(int width, int height, int samplingrate)
+{
+ A = 1.0;
+ // B is calculated such that the oldest sample after 2/3rd sec
weight >=0.1
+ //B = -1.0*log(0.1)/(2.0/3.0);
+ B = -1.0*log(0.01)/(2.0/3.0);
+
+ //cout << "in kdtree init: sampling rate = " << samplingrate << endl;
+ //cout << "A = " << A << ", B = " << B << endl;
+ //getchar();
+}
+
+int KDTree::init(int width, int height, int samplingrate)
+{
+ myRandomNumber.seed_rng(1234); // just to begin give a simple seed
+ numLevels = 0;
+ rootwidth = width;
+ rootheight = height;
+ int tsize = width*height;
+ invexp_init();
+ while(tsize!=1)
+ {
+ numLevels++;
+ tsize/=2;
+ }
+ numLevels -= 2;
+ cout << "numLevels = " << numLevels << endl;
+ int i, j, k;
+ totalNodes = (int)(pow(2.0, numLevels+1));
+ cout << "totalNodes = " << totalNodes << endl;
+ tile = new Tile[totalNodes]; // allocate memory to our array based
tree
+ // now we will assign the indices
+
+ Tile::leafMapping = (int**)malloc((width/2)*sizeof(int*));
+ cout << "leafmapping ranges until: " << (width/2) << ", " << (height/2) <<
endl;
+ for(i=0; i<width/2; i++)
+ {
+ Tile::leafMapping[i] = (int*)malloc((height/2)*sizeof(int));
+ }
+ buildtree(0, 1, 0, 0, width, height, samplingrate);
+ for(i=width*height/4; i<width*height/2; i++)
+ {
+ //printf("mapping: %d,%d = %d\n",tile[i].getLeft()/2,
tile[i].getBottom()/2, i);
+ Tile::leafMapping[tile[i].getLeft()/2][tile[i].getBottom()/2]
= i;
+ }
+ //exit(1);
+ Tile::meanLevel = (numLevels/2)+1;
+ //cout << "meanLevel = " << Tile::meanLevel << endl;
+ return numLevels;
+}
+
+void KDTree::buildtree(int level, int index, int left, int bottom, int
right, int top,
+ int samplingrate)
+{
+ tile[index].initialize(left, bottom, right, top, level, index,
rootwidth, rootheight, samplingrate, A, B);
+ if(level==numLevels) return;
+ if(level%2==0) // even levels, split along x axis
+ {
+ buildtree(level+1, index*2, left, bottom, left +
(right-left)/2, top, samplingrate); // build left subtree
+ buildtree(level+1, index*2+1, left + (right-left)/2, bottom,
right, top, samplingrate); // build right subtree
+ }
+ else // odd levels, split along y axis
+ {
+ buildtree(level+1, index*2, left, bottom, right, bottom +
(top-bottom)/2, samplingrate); // build left subtree
+ buildtree(level+1, index*2+1, left, bottom + (top-bottom)/2,
right, top, samplingrate); // build right subtree
+ }
+}
+
+// split all tiles at the cut i.e. take the cut a level down
+bool KDTree::splitCut(Timestamp currenttime, int sampling_rate)
+{
+ int index = tile[0].getNextTile();
+ int temp;
+ // traverse the cut
+ while(index!=0)
+ {
+ temp = tile[index].getNextTile();
+ split(index, currenttime, sampling_rate); //split
+ index = temp;
+ }
+ return true;
+}
+
+// merge all tiles at the cut i.e. take the cut a level up
+bool KDTree::mergeCut(Timestamp currenttime, int sampling_rate)
+{
+ int index = tile[0].getNextTile();
+ int temp;
+ // traverse the cut
+ while(index!=0)
+ {
+ if (merge(index, currenttime, sampling_rate)) // merge
+ index = tile[index/2].getNextTile(); // get the next
tile on updated cut
+ else
+ index = tile[index].getNextTile();
+ }
+ return true;
+}
+// set a level of tree as a set of valid tiles
+// this is useful for initializing with a set of
+// uniform tiles
+bool KDTree::setTileCut(int level, Timestamp currenttime, int sampling_rate)
+{
+
+ // no need to recurse
+ // for level n, 2^n to 2^(n+1)-1 are the tiles
+
+ int i;
+ if(level>numLevels)
+ {
+ //cout << "max levels = " << numLevels << "; request
rejected" << endl;
+ return false;
+ }
+ if(tile[0].getNextRandomTile()!=0)
+ {
+ // refresh the tree structure
+ int ctile;
+ ctile = tile[0].getNextTile();
+ while(ctile!=0)
+ {
+ tile[ctile].unsetValidTile();
+ ctile = tile[ctile].getNextTile();
+ }
+ }
+ tile[1].setValidTile();
+ tile[1].setPrevTile(0);
+ tile[0].setNextTile(1);
+ tile[1].setNextTile(0);
+ tile[0].setPrevTile(1);
+ tile[1].setPrevRandomTile(0);
+ tile[0].setNextRandomTile(1);
+ tile[1].setNextRandomTile(0);
+ tile[0].setPrevRandomTile(1);
+ numTiles = 1;
+ pseudostart = 1;
+ for(i=0; i<level; i++)
+ splitCut(currenttime, sampling_rate);
+
+ return true;
+}
+
+bool KDTree::isLeftChild(int index)
+{
+ if (index%2 == 0)
+ return true;
+ else
+ return false;
+}
+
+bool KDTree::isRightChild(int index)
+{
+ if(index%2 == 1)
+ return true;
+ else
+ return false;
+}
+
+// split a tile in O(log n)
+bool KDTree::split(int index, Timestamp currenttime, int sampling_rate)
+{
+ //cout << "inside split" << endl;
+ assert(index<totalNodes);
+ if(tile[index].getLevel()==numLevels && index>0)
+ {
+ //cout << "cannot split, already at leaf level" << endl;
+ return false;
+ }
+ if(!tile[index].isValid())
+ {
+ //cout << "This is not a valid tile, Cant split" << endl;
+ return false;
+ }
+ // insert left child in the random list; we do it first because we do
not want it to be valid yet
+ insertRandom(index*2); // O(log n)
+ // set the left child as valid tile
+ tile[index*2].setValidTile();
+ tile[index*2].setTimeLastDerivativeSet(currenttime);
+ tile[index*2].updateCommon(currenttime, tile, numTiles,
sampling_rate);
+ // insert right child in the random list; we do it first because we
do not want it to be valid yet
+ insertRandom(index*2+1);
+ // set the right child as valid tile
+ tile[index*2+1].setValidTile();
+ tile[index*2+1].setTimeLastDerivativeSet(currenttime);
+ tile[index*2+1].updateCommon(currenttime, tile, numTiles,
sampling_rate);
+ numTiles+=2; // update valid tile counter
+
+ // connect the two children
+ tile[index*2].setNextTile(index*2+1);
+ tile[index*2+1].setPrevTile(index*2);
+
+ // connect the left child with the previos tile
+ tile[index*2].setPrevTile(tile[index].getPrevTile());
+ tile[tile[index].getPrevTile()].setNextTile(index*2);
+
+ // connect the right child to the next tile
+ tile[index*2+1].setNextTile(tile[index].getNextTile());
+ tile[tile[index].getNextTile()].setPrevTile(index*2+1);
+
+ // set this tile as invalid
+ tile[index].unsetValidTile();
+ numTiles--; // update valid tile counter
+ if(pseudostart==index) pseudostart = index*2;
+ // update the random queue
+
+ // delete this tile from random list
+ deleteRandom(index);
+
+ // update changes up the tree
+ updateMinMax(index*2);
+ //cout << "done split" << endl;
+ return true;
+}
+
+// merge a tile, what this does is that
+// it sets the parent of the tile to be merged as a valid tile
+// dissolving the entire subtree of the parent
+int KDTree::merge(int index, Timestamp currenttime, int sampling_rate)
+{
+ //<TODO> adding updating to tile stats and min/max variances
+ // this may not be necessary for merges, if we maintain an updated
thing
+ // we can also maintain total grad, error at each node
+ // this way at root we have stats for entire image
+ //cout << "inside merge" << endl;
+ assert(index<totalNodes && index>0);
+ if(tile[index].getLevel()==0)
+ {
+ //cout << "cannot merge, already at root level" << endl;
+ return 0;
+ }
+ if(!(tile[index*2].isValid() || tile[index*2+1].isValid()))
+ {
+ //cout << "This is not a valid tile, Cant merge" << endl;
+ return 0;
+ }
+
+ int count = numTiles;
+ // insert parent in random list
+ insertRandom(index);
+ // set parent as a valid tile
+ tile[index].setValidTile();
+ tile[index].setTimeLastDerivativeSet(currenttime);
+ //tile[index].updateCommon(currenttime, tile[1], numTiles,
sampling_rate);
+ // increment valid tile counter
+ numTiles++;
+
+ // if this is the left child
+ if(tile[index*2].isValid())
+ {
+ // make left child tile invalid
+ tile[index*2].unsetValidTile();
+ // delete left child tile from the random list
+ deleteRandom(index*2);
+ if(pseudostart==index*2) pseudostart = index;
+ // decrement valid tile counter
+ numTiles--;
+ // connect previous tile to parent
+ tile[tile[index*2].getPrevTile()].setNextTile(index);
+ tile[index].setPrevTile(tile[index*2].getPrevTile());
+
+ // traverse the right half of the subtree under index
+ // until we leave the subtree, set all tiles on the path to
invalid
+ int rindex = tile[index*2].getNextTile();
+ while(rindex!=0 && tile[rindex].isSibling(tile[index]))
+ {
+ tile[rindex].unsetValidTile(); // set the tile
invalid
+
+ if(pseudostart==rindex) pseudostart = index;
+ numTiles--; //decrement the valid tile counter
+ deleteRandom(rindex); // delete if from random list
+ rindex = tile[rindex].getNextTile(); // move on to
the next tile
+ }
+
+ // connect parent to rindex
+ tile[index].setNextTile(rindex);
+ tile[rindex].setPrevTile(index);
+ }
+ // if the right child is valid tile
+ else
+ {
+ // make right child tile invalid
+ tile[index*2+1].unsetValidTile();
+ if(pseudostart==index*2+1) pseudostart = index;
+ // delete right child tile from the random list
+ deleteRandom(index*2+1);
+ // decrement valid tile counter
+ numTiles--;
+ // connect next tile to parent
+ tile[tile[index*2+1].getNextTile()].setPrevTile(index);
+ tile[index].setNextTile(tile[index*2+1].getNextTile());
+
+ // traverse the left half of the subtree under index
+ // until we leave the subtree, set all tiles on the path to
invalid
+ int lindex = tile[index*2+1].getPrevTile();
+ while(lindex!=0 && tile[lindex].isSibling(tile[index]))
+ {
+ tile[lindex].unsetValidTile(); // set the tile invalid
+ if(pseudostart==lindex) pseudostart = index;
+
+ numTiles--; //decrement the valid tile counter
+ deleteRandom(lindex); // delete if from random list
+ lindex = tile[lindex].getPrevTile(); // move on to
the next tile
+ }
+
+ // connect parent to rindex
+ tile[index].setPrevTile(lindex);
+ tile[lindex].setNextTile(index);
+ }
+
+ tile[index].setMinMax();
+
+ // update the min/max now
+ // first update the immediate parent of newly merged tile
+ // now traverse up the tree from the parent
+ updateMinMax(index);
+ //done
+ //cout << "done merge " << endl;
+ count -= numTiles;
+ return count;
+}
+
+// return a random tile
+// this returna a random valid tile in O(log n). we traverse from the root
+// randomly picking up left or right until we reach the cut
+int KDTree::getRandomTile()
+{
+ int j;
+ int count;
+
+
+ if(numTiles==0) return 0;
+ int retval = pseudostart; //tile[0].getNextTile();;
+
+ j = (int)(myRandomNumber.genfrand()*numTiles/5);
+ for(count=0; count<j; count++)
+ retval = tile[retval].getNextRandomTile();
+ if(retval==0)
+ retval = tile[retval].getNextRandomTile();
+ return retval;
+}
+
+int KDTree::getNextTile(int index)
+{
+ int retval = tile[index].getNextTile();
+ if(retval!=0)
+ return retval;
+ else
+ return tile[retval].getNextTile();
+}
+
+// get a random sample in x and y and return the tile too
+int KDTree::getRandomSample(int &x, int &y, MT_RNG &rnogen)
+{
+ // fetch a pseudo random tile in O(1)
+ int randomtile = getPseudoRandomTile();
+
+ // get a pseudo random sample from the random tile in O(1)
+ getRandomSamplefromTile(randomtile, x, y, rnogen);
+
+ return randomtile;
+}
+
+void KDTree::getRandomSamplefromTile(int index, int &x, int &y, MT_RNG
&rnogen)
+{
+ // get a pseudo random sample from the random tile in O(1)
+ tile[index].getNextSample(x,y, rnogen);
+}
+
+// insert a tile in the random list
+void KDTree::insertRandom(int index)
+{
+ resetPseudoRandomSeed();
+ // get a pseudo random tile O(1)
+ int loc = getPseudoRandomTile();
+ //cout << "in insertRandom, inserting after " << loc << endl;
+ // insert it in the random list next to this tile
+ tile[index].setNextRandomTile(tile[loc].getNextRandomTile());
+ tile[index].setPrevRandomTile(loc);
+
+ tile[tile[loc].getNextRandomTile()].setPrevRandomTile(index);
+ tile[loc].setNextRandomTile(index);
+ //printRandomList();
+ //done
+ return;
+}
+
+// delete a tile from th erandom list
+void KDTree::deleteRandom(int index)
+{
+ //cout << "in deleteRandom" << endl;
+ // simple reassignmnet of indices for next and previous tiles on the
random list
+
tile[tile[index].getNextRandomTile()].setPrevRandomTile(tile[index].getPrevRandomTile());
+
tile[tile[index].getPrevRandomTile()].setNextRandomTile(tile[index].getNextRandomTile());
+ tile[index].setNextRandomTile(0);
+ tile[index].setPrevRandomTile(0);
+ //printRandomList();
+}
+
+// get the maximum variance tile in O(log n)
+// we follow the max_at_left pointer from root to reach the cut
+int KDTree::getmaxErrorTile()
+{
+ return tile[1].getMaxIndex();
+
+}
+
+// get the minimum variance tile in O(log n)
+// we follow the min_at_left pointer from root to reach the parent of the cut
+// this is a bit tricky
+int KDTree::getminErrorParentTile()
+{
+ return tile[1].getMinIndex();
+
+}
+
+// update min/max up the tree in O(log n)
+void KDTree::updateMinMax(int index)
+{
+ while(index>1)
+ {
+ index = index/2; // get the parent
+ tile[index].updateMinMax(tile);
+ }
+}
+
+// return a pseudo random tile by traversing the random list in O(1)
+int KDTree::getPseudoRandomTile()
+{
+ int retval = pseudostart;
+ pseudostart = tile[pseudostart].getNextRandomTile();
+ if(pseudostart==0)
+ pseudostart = tile[pseudostart].getNextRandomTile();
+ return retval;
+}
+
+void KDTree::updateStatsAddSampleSet(SampleSet *newsampleset, Timestamp
currenttime, int sampling_rate)
+{
+ /*
+ do the following:
+ check the queue in deepbuffer, if full delete the last element and
delete its contribution from tile
+ add the new element
+ */
+ int x, y;
+
+ x = (int)newsampleset->viewX;
+ y = (int)newsampleset->viewY;
+ int index = Tile::leafMapping[x/2][y/2];
+ tile[index].checkBounds(x,y);
+ int vtileindex;
+ while(index>0)
+ {
+ tile[index].updateStatsAddSampleSet(newsampleset,
currenttime, A, B, tile, sampling_rate, numTiles);
+ if(tile[index].isValid()) vtileindex = index;
+ index/=2;
+ }
+ updateMinMax(vtileindex);
+}
+
+void KDTree::ageStats(Sample *newsample, Timestamp currenttime, int
sampling_rate)
+
+{
+ int x, y;
+
+ x = (int)newsample->viewCoord[0];
+ y = (int)newsample->viewCoord[1];
+ int index = Tile::leafMapping[x/2][y/2];
+ tile[index].checkBounds(x,y);
+ int vtileindex;
+ while(index>0)
+ {
+ tile[index].ageStats(currenttime, A, B, tile, sampling_rate,
numTiles);
+ if(tile[index].isValid()) vtileindex = index;
+ index/=2;
+ }
+ updateMinMax(vtileindex);
+}
+
+void KDTree::updateStatsAddSample(Sample *newsample, Timestamp currenttime,
int sampling_rate,
+ float tgrad, bool occ)
+{
+ int x, y;
+
+ x = (int)newsample->viewCoord[0];
+ y = (int)newsample->viewCoord[1];
+ int index = Tile::leafMapping[x/2][y/2];
+ tile[index].checkBounds(x,y);
+ int vtileindex;
+ while(index>0)
+ {
+ tile[index].updateStatsAddSample(newsample, currenttime, A,
B, tile, sampling_rate,
+ numTiles, tgrad, occ);
+ if(tile[index].isValid()) vtileindex = index;
+ index/=2;
+ }
+ updateMinMax(vtileindex);
+}
+
+int KDTree::printTiles_to_file(FILE *fp, Timestamp currenttime, float
samplingrate)
+{
+ int tile_to_print;
+ int count = 0;
+ tile_to_print = tile[0].getNextTile();
+ while(tile_to_print!=0)
+ {
+ count++;
+
+ tile[tile_to_print].print_to_file(fp, tile, numTiles,
currenttime, samplingrate);
+ tile_to_print = tile[tile_to_print].getNextTile();
+ }
+ return count;
+}
+
+void KDTree::bruteforceMinMax(int &min, int &max, float &min_error, float
&max_error, Timestamp currenttime, int samplingrate)
+{
+ int currenttile;
+ currenttile = tile[0].getNextTile();
+ min = currenttile/2;
+ max = currenttile;
+ max_error = -9999.0;
+ min_error = 9999.0;
+ while(currenttile!=0)
+ {
+ if(tile[currenttile].getLevel()>Tile::meanLevel && min_error
>
tile[currenttile/2].getTotalError())
+ {
+ tile[currenttile/2].setTotalError(tile, currenttime,
numTiles, samplingrate);
+ min_error = tile[currenttile/2].getTotalError();
+ min = currenttile/2;
+ }
+ if(tile[currenttile].getLevel()<numLevels-1 && max_error <
tile[currenttile].getTotalError())
+ {
+ tile[currenttile].setTotalError(tile, currenttime,
numTiles, samplingrate);
+ max_error = tile[currenttile].getTotalError();
+ max = currenttile;
+ }
+ currenttile = tile[currenttile].getNextTile();
+ }
+}
+
+int KDTree::getTileforXY(float x, float y)
+{
+ int index = 1;
+ while(!tile[index].isValid())
+ {
+ if(tile[index*2].isInside(x,y))
+ index = index*2;
+ else
+ index = index*2+1;
+ }
+
+ return index;
+}
+
+float KDTree::tGrad()
+{
+ return tile[1].tGrad();
+}
+
+float KDTree::getUndersampling(float x, float y, Timestamp currenttime)
+{
+ int index = getTileforXY(x,y);
+ return tile[index].getAverageAgeMeasure(tile[1], currenttime, 0.33);
+}
+
+int KDTree::isUsampledOrOccluded(float x, float y, Timestamp currenttime)
+{
+ int index = getTileforXY(x,y);
+ int retval = 0;
+ if((tile[index].getAverageAgeMeasure(tile[1], currenttime, 0.33)>0))
retval=1;
+ if(tile[index].getOcclusionMeasure(tile, numTiles)>0) retval = 2;
+ return retval;
+}
+
+
+void KDTree::displayTiles(TileDisplayMode displaymode, int sampling_rate,
Timestamp currenttime, float visScale)
+{
+ if(displaymode==INDIVIDUAL_SAMPLES) return;
+ int tile_to_display, start;
+ int i;
+
+ int count = 0;
+ tile_to_display = start = pseudostart;
+ do
+ {
+ if(tile_to_display!=0)
+ {
+ count++;
+ tile[tile_to_display].display(displaymode, numTiles,
tile, sampling_rate, currenttime, A, B, visScale);
+ }
+ tile_to_display = tile[tile_to_display].getNextRandomTile();
+ }
+ while(tile_to_display!=start);
+ //cout << "count = " << count << ", numTiles = " << numTiles << endl;
+ //assert(count==numTiles);
+}
Added: trunk/Engine/ImageTraversers/AFR/kdtree.h
==============================================================================
--- (empty file)
+++ trunk/Engine/ImageTraversers/AFR/kdtree.h Fri Jul 29 13:16:36 2005
@@ -0,0 +1,109 @@
+/***************************************************************************
+ * kdtree.h
+ *
+ * Sat Oct 30 14:38:52 2004
+ * Copyright 2004 Abhinav Dayal
+ * abhinav@cs.northwestern.edu
+
****************************************************************************/
+
+#ifndef _KDTREE_H
+#define _KDTREE_H
+#include <Engine/ImageTraversers/AFR/tiles.h>
+
+//namespace Manta {
+// using namespace std;
+
+
+ /*
+ * KD tree structure is as follows
+
+ _x_ <----- NULL node (0 index), this is the root of
root and the start and end of tile list
+ / | \
+ / x \ <----- Index (1), root of tree
+ / / \ \
+ / / \ \
+ / / \ \
+ / x x \ <----- Index 2,3 from left to right
+ / / \ / \ \
+ ( / \ / \ )
+ \x-----x-x-----x/ <---------- Index 4,5,6,7 from left to
right. These are also valid tiles
+ / /| |\ \
+ x x x x x x <---- and so on
+ :
+ :
+ */
+ class KDTree
+ {
+ private:
+ int totalNodes, numLevels, numTiles, pseudostart;
+ int rootwidth, rootheight;
+ int **samples, **reprojSamples;
+ Tile *tile;
+ float A, B; // constants for A*exp(-Bt)
+ MT_RNG myRandomNumber;
+
+ public:
+ KDTree();
+ void setAB(int width, int height, int samplingrate);
+ int init(int width, int height, int samplingrate); // initialize
the tree for max width x height tiles
+ void buildtree(int level, int index, int left, int bottom, int right,
int top,
+ int samplingrate); // recusive routine to build tree
+ bool setTileCut(int level, Timestamp currenttime,
+ int sampling_rate); // set a particular level as
cut in the tree
+ bool isLeftChild(int index); // is the tile labeled index left
child of its parent
+ bool isRightChild(int index); // is the tile labeled index right
child of its parent
+ bool split(int index, Timestamp currenttime, int sampling_rate); //
split the tile labeled index to its children
+ int merge(int index, Timestamp currenttime, int sampling_rate); //
merge the tile labeled index and all its siblings to the parent tile
+ bool splitCut(Timestamp currenttime, int sampling_rate); // split all
tiles; move the cut a level down
+ bool mergeCut(Timestamp currenttime, int sampling_rate); // merge all
tiles; move the cut a level up
+ int getmaxErrorTile(); // get the max var tile
+ void bruteforceMinMax(int &min, int &max, float &min_error, float
&max_error, Timestamp currenttime, int samplingrate); // seach for min/max by
brute force linear search; included for debugging
+ int getminErrorParentTile(); // get the min var tile
+ inline double getmaxError() { return tile[1].maxError(); } //
get the maximum variance value
+ inline double getminError() { return tile[1].minError(); } // get the
minimum variance value
+ int getRandomTile(); // get a random tile
+ int getRandomSample(int &x, int &y, MT_RNG &rnogen); // get a random
sample in x,y and returns the tile index too
+ void getRandomSamplefromTile(int index, int &x, int &y, MT_RNG
&rnogen);
+ inline Tile* getTile(int index) { return &(tile[index]); } // return
the tile with the index value
+ int getNextTile(int index);
+ inline int getTileSize(int index) { return tile[index].getTileSize(); }
+ inline float getNumSamples(int index) { return
tile[index].getNumSamples(); }
+ void insertRandom(int index); // insert tile in the random list
+ void deleteRandom(int index); // delete tile from the random list
+ void updateMinMax(int index); // update the min/max when some tile
changes
+ void ageStats(Sample *newsample, Timestamp currenttime, int
sampling_rate);
+ int getPseudoRandomTile(); // get a pseudo random tile
+ void resetPseudoRandomSeed() { pseudostart = getRandomTile(); } //
update seed for pseudo random tile
+ inline float xGrad() { return tile[1].xGrad(); }
+ inline float yGrad() { return tile[1].yGrad(); }
+ float tGrad();
+ inline float getAvgTileGrad(int index)
+ {
+ return tile[index].tGrad();
+ }
+ inline int number_of_tiles() { return numTiles; }
+ inline bool isValidTile(int index) { return tile[index].isValid(); }
+ int getTileforXY(float x, float y);
+ inline double getTotalError(int index) { return
tile[index].getTotalError(); }
+ int printTiles_to_file(FILE *fp, Timestamp currenttime, float
samplingrate);
+ inline bool isInside(int index, float x, float y)
+ {
+ return tile[index].isInside(x,y);
+ }
+ inline int getNumLevels()
+ {
+ return numLevels;
+ }
+ inline float getB() { return B; };
+ float getUndersampling(float x, float y, Timestamp currenttime);
+ inline float getOcclusionMeasure(int index)
+ {
+ return tile[index].getOcclusionMeasure(tile, numTiles);
+ }
+ int isUsampledOrOccluded(float x, float y, Timestamp currenttime);
+ void updateStatsAddSampleSet(SampleSet *newsampleset, Timestamp
currenttime, int sampling_rate);
+ void updateStatsAddSample(Sample *newsample, Timestamp
currenttime, int sampling_rate, float tgrad, bool occ);
+ void displayTiles(TileDisplayMode displaymode, int
sampling_rate, Timestamp currenttime, float visScale);
+ };
+//}
+#endif /* _KDTREE_H */
Added: trunk/Engine/ImageTraversers/AFR/sample.h
==============================================================================
--- (empty file)
+++ trunk/Engine/ImageTraversers/AFR/sample.h Fri Jul 29 13:16:36 2005
@@ -0,0 +1,331 @@
+
+/** @ingroup Recon */
+/** @{ */
+
+#ifndef SAMPLE_H
+#define SAMPLE_H
+
+#include <Interface/RayPacket.h>
+#include <Interface/Renderer.h>
+#include <Interface/Context.h>
+#include <iostream>
+using namespace std;
+
+#define NTSC_WT_R 0.299f
+#define NTSC_WT_G 0.587f
+#define NTSC_WT_B 0.114f
+#define REPROJECT_STATIC_POINTS
+/**
+ * @class Sample
+ * @brief A single rendering result.
+ *
+ * This is the data type returned to us by the sampler
+ * from which we will reconstruct our image.
+ */
+//namespace Manta {
+// using namespace std;
+ typedef float Timestamp;
+ typedef float FloatColor[3];
+ const FloatColor UNDEFINED_SAMPLE_COLOR = {0.0,0.0,0.0};
+ const Timestamp UNDEFINED_SAMPLE_TIMESTAMP = 0.0f;
+ struct SamplePrintFormat
+ {
+ float worldCoord[3], vel[3];
+ unsigned char rgb[3];
+ float timestamp;
+ };
+
+ class Sample
+ {
+ public:
+ /** color of the sample */
+ FloatColor c;
+ float viewCoord[3]; // floating point 2D coordinate of the sample on
camera viewport
+ /** time at which the sample was generated (in milliseconds) */
+ float worldCoord[3]; // the 3d location of the sample
+ Timestamp t; // timestamp of the sample.
+ /**
+ * @name Constructors
+ * @{
+ */
+ Sample()
+ {
+ reset();
+ }
+
+ void reset()
+ {
+ c[0]= UNDEFINED_SAMPLE_COLOR[0];
+ c[1]= UNDEFINED_SAMPLE_COLOR[1];
+ c[2]= UNDEFINED_SAMPLE_COLOR[2];
+ t = UNDEFINED_SAMPLE_TIMESTAMP;
+ }
+
+ void init(const float x, const float y, const Timestamp tstamp)
+ {
+ t = tstamp;
+ viewCoord[0] = x;
+ viewCoord[1] = y;
+ // <TODO> find viewCoord[2] by eucledian dist from
+ // eye and hit point
+ }
+
+ void set(const float x, const float y, const Timestamp tstamp,
+ const float wx, const float wy, const float wz,
+ const float r, const float g, const float b )
+ {
+ c[0]= UNDEFINED_SAMPLE_COLOR[0];
+ c[1]= UNDEFINED_SAMPLE_COLOR[1];
+ c[2]= UNDEFINED_SAMPLE_COLOR[2];
+ t = tstamp;
+ viewCoord[0] = x;
+ viewCoord[1] = y;
+ viewCoord[2] = 1.0;
+ c[0] = r;
+ c[1] = g;
+ c[2] = b;
+ worldCoord[0] = wx;
+ worldCoord[1] = wy;
+ worldCoord[2] = wz;
+ }
+
+ void operator=(const Sample &value)
+ {
+ int i;
+ for(i=0; i<3; i++)
+ {
+ c[i] = value.c[i];
+ viewCoord[i] = value.viewCoord[i];
+ worldCoord[i] = value.worldCoord[i];
+ }
+ t = value.t;
+ }
+
+ void print_to_file(FILE *fp)
+ {
+ SamplePrintFormat spf;
+ spf.worldCoord[0] = worldCoord[0];
+ spf.worldCoord[1] = worldCoord[1];
+ spf.worldCoord[2] = worldCoord[2];
+ spf.vel[0] = 0;
+ spf.vel[1] = 0;
+ spf.vel[2] = 0;
+ spf.timestamp = t;
+ spf.rgb[0] = (unsigned char)(c[0]*255);
+ spf.rgb[1] = (unsigned char)(c[1]*255);
+ spf.rgb[2] = (unsigned char)(c[2]*255);
+ fwrite(&spf, sizeof(spf), 1, fp);
+ }
+
+ void print()
+ {
+ /* cout << "worldCoord = " << worldCoord[0] << ", " << worldCoord[1] <<
", " << worldCoord[2]
+ << "; viewCoord = " << viewCoord[0] << ", " << viewCoord[1] << endl
+ << "timestamp = " << t << endl
+ << "; color = " << c[0] << ", " << c[1] << ", " << c[2] << endl
+ << endl;*/
+ }
+
+ inline float getRGBDistance(FloatColor &fc)
+ {
+ return sqrt((c[0]-fc[0])*(c[0]-fc[0])
+ + (c[1]-fc[1])*(c[1]-fc[1])
+ + (c[2]-fc[2])*(c[2]-fc[2]));
+ }
+ inline float getRGBMeasure()
+ {
+ return sqrt((c[0]-0.5)*(c[0]-0.5)
+ + (c[1]-0.5)*(c[1]-0.5)
+ + (c[2]-0.5)*(c[2]-0.5));
+ }
+ // Indicates whether the sample has been set to a valid value
+ inline int isUndefined()
+ {
+ return (t == UNDEFINED_SAMPLE_TIMESTAMP);
+ };
+
+ // Returns the standard NTSC intensity (normalized) of the sample
+ inline float intensity()
+ {
+ return NTSC_WT_R*c[0] + NTSC_WT_G*c[1] + NTSC_WT_B*c[2];
+ };
+ };
+
+ enum CrosshairSampleLoc { CENTER_SAMPLE, LEFT_SAMPLE, RIGHT_SAMPLE,
+ TOP_SAMPLE, BOTTOM_SAMPLE, TEMPORAL_SAMPLE};
+ class SampleSet
+ {
+ public:
+ Sample left, right, bottom, top, center, temporal;
+ float tgrad, xgrad, ygrad;
+ Timestamp timestamp;
+ float viewX, viewY, viewZ;
+
+ SampleSet()
+ {
+ reset();
+ }
+
+ void reset()
+ {
+ xgrad = ygrad = tgrad = 0.0;
+ viewX = viewY = viewZ = 0;
+ timestamp = 0.0;
+ left.reset();
+ right.reset();
+ top.reset();
+ bottom.reset();
+ center.reset();
+ temporal.reset();
+ }
+
+ void set(CrosshairSampleLoc sloc, const float x, const float y, const
Timestamp tstamp,
+ const float wx, const float wy, const float wz,
+ const float r, const float g, const float b)
+ {
+ switch(sloc)
+ {
+ case CENTER_SAMPLE: center.set(x,y,tstamp,wx,wy,wz,r,g,b);
+ break;
+ case LEFT_SAMPLE: left.set(x,y,tstamp,wx,wy,wz,r,g,b);;
+ break;
+ case RIGHT_SAMPLE: right.set(x,y,tstamp,wx,wy,wz,r,g,b);;
+ break;
+ case BOTTOM_SAMPLE: bottom.set(x,y,tstamp,wx,wy,wz,r,g,b);;
+ break;
+ case TOP_SAMPLE: top.set(x,y,tstamp,wx,wy,wz,r,g,b);;
+ break;
+ case TEMPORAL_SAMPLE: temporal.set(x,y,tstamp,wx,wy,wz,r,g,b);;
+ break;
+ default: return;
+ };
+ timestamp = tstamp;
+ }
+
+ void computeGradients(Timestamp currenttime)
+ {
+ float li, ri, bi, ti, ci, tmpi;
+
+ viewX = center.viewCoord[0];
+ viewY = center.viewCoord[1];
+ viewZ = center.viewCoord[2];
+ timestamp = currenttime;
+ li = left.intensity();
+ ri = right.intensity();
+ ti = top.intensity();
+ bi = bottom.intensity();
+ ci = center.intensity();
+ tmpi = temporal.intensity();
+
+ if(fabsf(center.viewCoord[0]-left.viewCoord[0])>0.001
+ && fabsf(center.viewCoord[0]-right.viewCoord[0])>0.001 )
+ {
+ //xgrad =
fabsf(ci-li)/fabsf(center.viewCoord[0]-left.viewCoord[0])
+ // + fabsf(ci-ri)/fabsf(center.viewCoord[0]-right.viewCoord[0]);
+ xgrad =
center.getRGBDistance(left.c)/fabsf(center.viewCoord[0]-left.viewCoord[0])
+ +
center.getRGBDistance(right.c)/fabsf(center.viewCoord[0]-right.viewCoord[0]);
+ }
+ else
+ {
+ //xgrad = (fabsf(ci-li) + fabsf(ci-ri))/2.0;
+ xgrad = (center.getRGBDistance(left.c) +
center.getRGBDistance(right.c))/2.0;
+ }
+
+ if(fabsf(center.viewCoord[0]-top.viewCoord[1])>0.001
+ && fabsf(center.viewCoord[0]-bottom.viewCoord[1])>0.001 )
+ {
+ //ygrad = fabsf(ci-bi)/fabsf(center.viewCoord[1]-top.viewCoord[1])
+ // +
fabsf(ci-ti)/fabsf(center.viewCoord[1]-bottom.viewCoord[1]);
+ ygrad =
center.getRGBDistance(bottom.c)/fabsf(center.viewCoord[1]-top.viewCoord[1])
+ +
center.getRGBDistance(top.c)/fabsf(center.viewCoord[1]-bottom.viewCoord[1]);
+ }
+ else
+ {
+ //ygrad = (fabsf(ci-bi) + fabsf(ci-ti))/2.0;
+ ygrad = (center.getRGBDistance(bottom.c) +
center.getRGBDistance(top.c))/2.0;
+ }
+
+ if(fabsf(center.t-temporal.t)>0.001)
+ {
+ //tgrad = fabsf(ci-tmpi)/(center.t - temporal.t);
+ tgrad = center.getRGBDistance(temporal.c)/(center.t - temporal.t);
+ }
+ else
+ {
+ //tgrad = fabsf(ci-tmpi);
+ tgrad = center.getRGBDistance(bottom.c);
+ }
+
+ //<TODO> set occlusion status here
+ }
+
+ void print_to_file(FILE *fp)
+ {
+ left.print_to_file(fp);
+ right.print_to_file(fp);
+ top.print_to_file(fp);
+ bottom.print_to_file(fp);
+ center.print_to_file(fp);
+ }
+
+ void print()
+ {
+ /* cout << "sample set ---------------->" << endl;
+ cout << "center: "; center.print();
+ cout << "left: "; left.print();
+ cout << "right: "; right.print();
+ cout << "top: "; top.print();
+ cout << "bottom: "; bottom.print();
+ cout << "temporal: "; temporal.print();
+ cout << "<---------------------------" << endl << endl;*/
+ }
+
+ float getIntensity(CrosshairSampleLoc sloc)
+ {
+ switch(sloc)
+ {
+ case CENTER_SAMPLE: return center.intensity();
+ break;
+ case LEFT_SAMPLE: return left.intensity();
+ break;
+ case RIGHT_SAMPLE: return right.intensity();
+ break;
+ case BOTTOM_SAMPLE: return bottom.intensity();
+ break;
+ case TOP_SAMPLE: return top.intensity();
+ break;
+ case TEMPORAL_SAMPLE: return temporal.intensity();
+ break;
+ default: return 0.0;
+ };
+ }
+
+ Timestamp getSampleTimeStamp(CrosshairSampleLoc sloc)
+ {
+ switch(sloc)
+ {
+ case CENTER_SAMPLE: return center.t;
+ break;
+ case LEFT_SAMPLE: return left.t;
+ break;
+ case RIGHT_SAMPLE: return right.t;
+ break;
+ case BOTTOM_SAMPLE: return bottom.t;
+ break;
+ case TOP_SAMPLE: return top.t;
+ break;
+ case TEMPORAL_SAMPLE: return temporal.t;
+ break;
+ default: return 0.0;
+ };
+ }
+
+ bool isOccluded()
+ {
+ return false; //<TODO>
+ }
+ };
+//}
+#endif
+
+/** @} */
Added: trunk/Engine/ImageTraversers/AFR/stats.cc
==============================================================================
--- (empty file)
+++ trunk/Engine/ImageTraversers/AFR/stats.cc Fri Jul 29 13:16:36 2005
@@ -0,0 +1,136 @@
+#include <Engine/ImageTraversers/AFR/stats.h>
+//#define DERIVED_METHOD
+#define EPSILON 0.00001;
+#include <assert.h>
+
+Stats::Stats()
+{
+ reset();
+}
+
+void Stats::reset()
+{
+ n = 0;
+ sigma_wi = sigma_xi_wi = sigma_xi_wi_sqr = 0.0;
+}
+
+void Stats::addElement(float xi, float wi, float uniform_decrease)
+{
+ n++;
+ //assert(xi>=0);
+ assert(wi>0);
+ assert(uniform_decrease>0);
+ sigma_wi *= uniform_decrease;
+ sigma_xi_wi *= uniform_decrease;
+
+ sigma_xi_wi_sqr *= uniform_decrease;
+ sigma_wi += wi;
+ sigma_xi_wi += wi*xi;
+ sigma_xi_wi_sqr += wi*xi*xi;
+
+}
+
+void Stats::deleteElement(float xi, float wi, float uniform_decrease)
+{
+ assert(n>0);
+ //if(!(xi>=0)) xi = 0;
+ //assert(xi>=0);if(!(wi>0)) cout << "wi = " << wi << endl;
+ assert(wi>0);
+ assert(uniform_decrease>0);
+ n--;
+ sigma_wi *= uniform_decrease;
+ sigma_xi_wi *= uniform_decrease;
+
+ sigma_xi_wi_sqr *= uniform_decrease;
+ sigma_wi -= wi;
+ sigma_xi_wi -= wi*xi;
+ sigma_xi_wi_sqr -= wi*xi*xi;
+
+ //if(sigma_xi_wi<0) sigma_xi_wi = 0.0;
+ //if(sigma_xi_wi_sqr<0) sigma_xi_wi_sqr = 0.0;
+ //if(sigma_wi<0) sigma_wi = 0.0;
+ if(n==0)
+ reset();
+}
+
+void Stats::uniformDecrease(float ratio)
+{
+ sigma_wi *= ratio;
+ sigma_xi_wi *= ratio;
+ sigma_xi_wi_sqr *= ratio;
+}
+
+float Stats::getVariance()
+{
+ float variance, mean;
+ if(n<=0) //if(fabsf(sigma_wi)<EPSILON)
+ {
+ reset();
+ return 0.0;
+ }
+ mean = getMean();
+ if(sigma_wi>0.00001)
+ {
+ variance = sigma_xi_wi_sqr/sigma_wi -mean*mean;
+ }
+ else variance = 0.0;
+
+ if(variance<0) variance = 0.0;
+ return variance;
+}
+
+float Stats::getMean()
+{
+ if(n<=0) //if(fabsf(sigma_wi)<EPSILON)
+ {
+ reset();
+ return 0.0;
+ }
+ return (sigma_wi>0.0001)?(sigma_xi_wi/sigma_wi):0.0;
+}
+
+void Stats::sum(Stats &a, Stats &b, float adec, float bdec)
+{
+ n = a.n + b.n;
+ sigma_wi = a.sigma_wi*adec + b.sigma_wi*bdec;
+ sigma_xi_wi = a.sigma_xi_wi*adec + b.sigma_xi_wi*bdec;
+ sigma_xi_wi_sqr = a.sigma_xi_wi_sqr*adec + b.sigma_xi_wi_sqr*bdec;
+}
+
+
+Stats Stats::operator+(Stats &a)
+{
+ Stats s;
+ s.n = n + a.n;
+ s.sigma_wi = sigma_wi + a.sigma_wi;
+ s.sigma_xi_wi = sigma_xi_wi + a.sigma_xi_wi;
+ s.sigma_xi_wi_sqr = sigma_xi_wi_sqr + a.sigma_xi_wi_sqr;
+ return s;
+}
+
+Stats Stats::operator-(Stats &a)
+{
+ Stats s;
+ s.n = n - a.n;
+ s.sigma_wi = sigma_wi - a.sigma_wi;
+ s.sigma_xi_wi = sigma_xi_wi - a.sigma_xi_wi;
+ s.sigma_xi_wi_sqr = sigma_xi_wi_sqr - a.sigma_xi_wi_sqr;
+ return s;
+}
+
+Stats Stats::operator/(float denom)
+{
+ Stats s;
+ assert(denom>0);
+ s.n = n/denom;
+ s.sigma_wi = sigma_wi/denom;
+ s.sigma_xi_wi = sigma_xi_wi/denom;
+ s.sigma_xi_wi_sqr = sigma_xi_wi_sqr/denom;
+
+ return s;
+}
+
+void Stats::print()
+{
+ //cout << n << ", " << sigma_wi << ", " << sigma_xi_wi << ", " <<
sigma_xi_wi_sqr << endl;
+}
Added: trunk/Engine/ImageTraversers/AFR/stats.h
==============================================================================
--- (empty file)
+++ trunk/Engine/ImageTraversers/AFR/stats.h Fri Jul 29 13:16:36 2005
@@ -0,0 +1,32 @@
+#ifndef _STATS_H
+#define _STATS_H
+
+//namespace Manta {
+// using namespace std;
+ class Stats
+ {
+ private:
+ Stats(const Stats&);
+ Stats& operator=(const Stats&);
+ int n;
+ float sigma_wi, sigma_xi_wi, sigma_xi_wi_sqr;
+ public:
+ Stats();
+ void reset();
+ void uniformDecrease(float ratio);
+ void sum(Stats &a, Stats &b, float adec, float bdec);
+ void addElement(float xi, float wi=1.0, float uniform_decrease=1.0);
+ void deleteElement(float xi, float wi=1.0, float uniform_decrease=1.0);
+ float getVariance();
+ inline float getWeightedSum() { return sigma_xi_wi; };
+ inline int getN() { return n; };
+ inline float getSumWeights() { return sigma_wi; };
+ float getMean();
+ Stats operator+(Stats &a);
+ Stats operator-(Stats &a);
+ Stats operator/(float denom);
+ void print();
+ };
+//}
+
+#endif
Added: trunk/Engine/ImageTraversers/AFR/tiles.cc
==============================================================================
--- (empty file)
+++ trunk/Engine/ImageTraversers/AFR/tiles.cc Fri Jul 29 13:16:36 2005
@@ -0,0 +1,548 @@
+/***************************************************************************
+ * tiles.cpp
+ *
+ * Sat Oct 30 14:40:20 2004
+ * Copyright 2004 Abhinav Dayal
+ * abhinav@cs.northwestern.edu
+
****************************************************************************/
+
+#include <Engine/ImageTraversers/AFR/tiles.h>
+#include <Engine/ImageTraversers/AFR/evil.h>
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <assert.h>
+#include <math.h>
+#define PARENT_LEVEL 2
+#define GRAND_PARENT_LEVEL 4
+#define GREAT_GRAND_PARENT_LEVEL 8
+#define TG_FILTER_WIDTH GRAND_PARENT_LEVEL
+#define DERIVATIVE_GAP 10
+#define KOEFF 0.2
+
+#define AMBIENT_ERROR 0.01
+
+int** Tile::leafMapping;
+int Tile::meanLevel=8;
+int Tile::max_tile_area = 256;
+
+Tile::Tile()
+{
+ error =AMBIENT_ERROR;
+ previous_error = total_error = 0.0;
+ time_last_derivative_set = time_last_updated =
UNDEFINED_SAMPLE_TIMESTAMP;
+ derivative_gap_count = 0;
+ derivative = 0.0;
+ num_pixels = left = right = top = bottom = level = 0;
+ max_index = min_index = 0; //<TODO> use these rather than log n
traversal
+ isValidTile = false;
+ next = prev = 0;
+ max_error=min_error=0;
+ nextrandom=prevrandom=0;
+}
+
+void Tile::initialize(int l, int b, int r, int t,
+ int currlevel, int address,
+ int width, int height,
+ int samplingrate, float A, float B)
+{
+ int i, j, k;
+ left = l;
+ right = r;
+ bottom = b;
+ top = t;
+ num_pixels = (r-l)*(t-b);
+ //if(num_pixels==0) exit(1);
+ if(num_pixels<=MIN_VALID_TILE_AREA) min_size_violation = true;
+ else min_size_violation = false;
+ level = currlevel;
+ index = address;
+ max_index = index;
+ min_index = index;
+ intensity.reset();
+ xGradient.reset();
+ yGradient.reset();
+ tGradient.reset();
+ occlusion.reset();
+ error = AMBIENT_ERROR;
+ sum_tstamps.reset();
+ color[0] = drand48();
+ color[1] = drand48();
+ color[2] = drand48();
+}
+
+
+float Tile::getAverageAgeMeasure(Tile &roottile, Timestamp currenttime,
float gvisScale)
+{
+ float retval=0.0;
+ float mean_age = fabsf(currenttime - sum_tstamps.getMean());
+ float mean_age_overall = 0.1651225;//fabsf(currenttime -
roottile.sum_tstamps.getMean());
+ retval = gvisScale*mean_age/mean_age_overall;
+ retval -= 1.0;
+ if(retval<0.0) retval = 0.0;
+ return retval;
+}
+
+// returns the next pseudo random sample.
+void Tile::getNextSample(int &x, int &y, MT_RNG &myRandomNumber)
+{
+ //float r1 = myRandomNumber.genfrand();
+ //printf("%.f ",r1);
+ x = (int)(left + myRandomNumber.genfrand()*(right-left));
+ y = (int)(bottom + myRandomNumber.genfrand()*(top-bottom));
+
+ //x = (int)(left + drand48()*(right-left));
+ //y = (int)(bottom + drand48()*(top-bottom));
+}
+
+bool Tile::isSibling(Tile &t)
+{
+ if (left>=t.left && bottom>=t.bottom && right<=t.right && top<=t.top)
+ return true;
+ else
+ return false;
+}
+
+void Tile::setDerivative(Timestamp currenttime)
+{
+ if(currenttime>time_last_updated && currenttime >
time_last_derivative_set)
+ derivative_gap_count++;
+ if(derivative_gap_count>=DERIVATIVE_GAP)
+ {
+ derivative_gap_count = 0;
+ float denom;
+ denom = (currenttime - time_last_derivative_set);
+ if(denom>0)
+ derivative = fabsf(error - previous_error)/denom;
+ else
+ derivative = 0.0;
+ previous_error = error;
+ time_last_derivative_set = currenttime;
+ }
+}
+
+void Tile::setError(Tile *tree, int nTiles, int sampling_rate, Timestamp
currenttime)
+{
+ // now we add some monitoring factor so that variance 0 does not mean
a single tile
+
+ float verror = intensity.getVariance()+AMBIENT_ERROR;
+ float uerror = (currenttime - sum_tstamps.getMean())*0.33/0.1651225 -
1.0;
+ if(uerror>1.0) uerror = 1.0;
+ if(uerror<0.0) uerror = 0.0;
+ float oerror = getOcclusionMeasure(tree, nTiles);
+ if(oerror>1.0) oerror = 1.0;
+ error = (0.25*(uerror) + 2.0*(verror) +0.25*(oerror))*num_pixels ;
+}
+
+void Tile::setTotalError(Tile *tree, Timestamp currenttime, int nTiles, int
sampling_rate)
+{
+ // update the mean & variance
+ setError(tree, nTiles, sampling_rate, currenttime);
+ // well what about the derivative
+ setDerivative(currenttime);
+ total_error = KOEFF*(error) + (1.0-KOEFF)*derivative;
+ time_last_updated = currenttime;
+}
+
+void Tile::updateCommon(Timestamp currenttime, Tile *tree, int nTiles, int
sampling_rate)
+{
+ // set the total error
+ setTotalError(tree, currenttime, nTiles, sampling_rate);
+ if(num_pixels<=MIN_VALID_TILE_AREA) min_size_violation = true;
+ else min_size_violation = false;
+ max_error = min_error = total_error; // check if we need variance here
+ max_index = min_index = index;
+ if(min_size_violation) max_error = 0;
+}
+
+void Tile::setStatsFromChildren(Timestamp currenttime, float A, float B,
+ Tile *tree, int sampling_rate, int nTiles, bool
validreached)
+{
+ Tile *leftChild, *rightChild;
+ leftChild = &tree[index*2];
+ rightChild = &tree[index*2+1];
+ float ratioL = getWeight(A, B, (currenttime -
leftChild->time_last_updated));
+ float ratioR = getWeight(A, B, (currenttime -
rightChild->time_last_updated));
+
+ intensity.sum(leftChild->intensity, rightChild->intensity, ratioL,
ratioR);
+ xGradient.sum(leftChild->xGradient, rightChild->xGradient, ratioL,
ratioR);
+ yGradient.sum(leftChild->yGradient, rightChild->yGradient, ratioL,
ratioR);
+ tGradient.sum(leftChild->tGradient, rightChild->tGradient, ratioL,
ratioR);
+ sum_tstamps.sum(leftChild->sum_tstamps, rightChild->sum_tstamps,
ratioL, ratioR);
+ occlusion.sum(leftChild->occlusion, rightChild->occlusion, ratioL,
ratioR);
+ if(isValid()) updateCommon(currenttime, tree, nTiles, sampling_rate);
+ else setTotalError(tree, currenttime, nTiles, sampling_rate);
+
+ if(validreached) updateMinMax(tree);
+}
+
+
+
+void Tile::updateStatsAddSampleSet(SampleSet *newsampleset, Timestamp
currenttime, float A, float B,
+ Tile *tree, int sampling_rate, int nTiles)
+{
+ int i, j;
+ float wt_new = 1.0;
+ float ratio = getWeight(A, B, (currenttime - time_last_updated));
+ float temptime = newsampleset->getSampleTimeStamp(TEMPORAL_SAMPLE);
+ float stime = newsampleset->timestamp;
+ intensity.addElement(newsampleset->getIntensity(CENTER_SAMPLE),
wt_new, ratio);
+ intensity.addElement(newsampleset->getIntensity(TOP_SAMPLE), wt_new,
1.0);
+ intensity.addElement(newsampleset->getIntensity(BOTTOM_SAMPLE),
wt_new, 1.0);
+ intensity.addElement(newsampleset->getIntensity(LEFT_SAMPLE), wt_new,
1.0);
+ intensity.addElement(newsampleset->getIntensity(RIGHT_SAMPLE),
wt_new, 1.0);
+ intensity.addElement(newsampleset->getIntensity(TEMPORAL_SAMPLE),
+ getWeight(A, B, (currenttime
- temptime)),
+ 1.0);
+
+ xGradient.addElement(newsampleset->xgrad, wt_new, ratio);
+ yGradient.addElement(newsampleset->ygrad, wt_new, ratio);
+
+ sum_tstamps.addElement(stime, wt_new, ratio);
+ sum_tstamps.addElement(stime, wt_new, 1.0);
+ sum_tstamps.addElement(stime, wt_new, 1.0);
+ sum_tstamps.addElement(stime, wt_new, 1.0);
+ sum_tstamps.addElement(stime, wt_new, 1.0);
+ sum_tstamps.addElement(temptime, wt_new, 1.0);
+
+ float occ = (newsampleset->isOccluded())? 1.0 : 0.0;
+ //occlusion.addElement(occ, wt_new, getWeight(A, 4.0*B, (currenttime
- time_last_updated)));
+ float denom = 1.0 - occlusion.getMean();
+ if(denom<0.1) denom = 0.1;
+
+ float tgradRatio = ratio;//getWeight(A, B/denom, (currenttime -
time_last_updated));
+ tGradient.addElement(newsampleset->tgrad, wt_new, tgradRatio);
+ occlusion.addElement(occ, wt_new, tgradRatio);
+ updateCommon(currenttime, tree, nTiles, sampling_rate);
+}
+
+void Tile::ageStats(Timestamp currenttime, float A, float B,
+ Tile *tree, int sampling_rate, int nTiles)
+{
+ int i, j;
+ float ratio = getWeight(A, B, (currenttime - time_last_updated));
+ intensity.uniformDecrease(ratio);
+ sum_tstamps.uniformDecrease(ratio);
+ xGradient.uniformDecrease(ratio);
+ yGradient.uniformDecrease(ratio);
+ //occlusion.uniformDecrease(getWeight(A, 4.0*B, (currenttime -
time_last_updated)));
+ float denom = 1.0 - occlusion.getMean();
+ if(denom<0.1) denom = 0.1;
+ float tgradRatio = getWeight(A, B/denom, (currenttime -
time_last_updated));
+ tGradient.uniformDecrease(tgradRatio);
+ occlusion.uniformDecrease(tgradRatio);
+ updateCommon(currenttime, tree, nTiles, sampling_rate);
+}
+
+void Tile::updateStatsAddSample(Sample *newsample, Timestamp currenttime,
float A, float B,
+ Tile *tree, int sampling_rate, int nTiles, float
tgrad, bool occ)
+{
+ int i, j;
+ float wt_new = 1.0;
+ float ratio = getWeight(A, B, (currenttime - time_last_updated));
+ //intensity.uniformDecrease(ratio);
+ intensity.addElement(newsample->intensity(), wt_new, ratio);
+ sum_tstamps.uniformDecrease(ratio);
+ xGradient.uniformDecrease(ratio);
+ yGradient.uniformDecrease(ratio);
+ //occlusion.addElement(1.0, wt_new, getWeight(A, 4.0*B, (currenttime
- time_last_updated)));
+ float denom = 1.0 - occlusion.getMean();
+ if(denom<0.1) denom = 0.1;
+ float tgradRatio = ratio;//getWeight(A, B/denom, (currenttime -
time_last_updated));
+ tGradient.addElement(tgrad, wt_new, tgradRatio);
+ if(occ)
+ occlusion.addElement(1.0, wt_new, tgradRatio);
+ else
+ occlusion.addElement(0.0, wt_new, tgradRatio);
+ updateCommon(currenttime, tree, nTiles, sampling_rate);
+}
+
+void Tile::updateMinMax(Tile *tree)
+{
+ Tile *leftChild, *rightChild;
+
+ leftChild = &tree[index*2];
+ rightChild = &tree[index*2+1];
+
+ // set the max pointer
+ if(leftChild->min_size_violation && rightChild->min_size_violation)
+ {
+ min_size_violation = true;
+ max_error = 0;
+ }
+ else if(leftChild->min_size_violation &&
!rightChild->min_size_violation)
+ {
+ min_size_violation = false;
+ max_error = rightChild->max_error;
+ max_index = rightChild->max_index;
+ }
+ else if(rightChild->min_size_violation &&
!leftChild->min_size_violation)
+ {
+ min_size_violation = false;
+ max_error = leftChild->max_error;
+ max_index = leftChild->max_index;
+ }
+ else
+ {
+ if(leftChild->max_error > rightChild->max_error)
+ {
+ min_size_violation = false;
+ max_error = leftChild->max_error;
+ max_index = leftChild->max_index;
+ }
+ else
+ {
+ min_size_violation = false;
+ max_error = rightChild->max_error;
+ max_index = rightChild->max_index;
+ }
+ }
+
+ // set the min pointer; well we are looking for min of parent
+ // so it is little bit tricky here
+ if(leftChild->isValid() && rightChild->isValid())
+ {
+ min_error = total_error;
+ min_index = index;
+ }
+ else if(leftChild->isValid() && !rightChild->isValid())
+ {
+ if(num_pixels<=max_tile_area &&
total_error<rightChild->min_error)
+ //if(total_error<rightChild->min_error)
+ {
+ min_error = total_error;
+ min_index = index;
+ }
+ else
+ {
+ min_error = rightChild->min_error;
+ min_index = rightChild->min_index;
+ }
+ }
+ else if(!leftChild->isValid() && rightChild->isValid())
+ {
+ if(num_pixels<=max_tile_area &&
total_error<leftChild->min_error)
+ //if(total_error<leftChild->min_error)
+ {
+ min_error = total_error;
+ min_index = index;
+ }
+ else
+ {
+ min_error = leftChild->min_error;
+ min_index = leftChild->min_index;
+ }
+ }
+ else
+ {
+ if(tree[leftChild->min_index].num_pixels<=max_tile_area &&
tree[rightChild->min_index].num_pixels<=max_tile_area)
+ {
+ if(leftChild->min_error < rightChild->min_error)
+ {
+ min_error = leftChild->min_error;
+ min_index = leftChild->min_index;
+ }
+ else
+ {
+ min_error = rightChild->min_error;
+ min_index = rightChild->min_index;
+ }
+ }
+ else
+ {
+
if(tree[leftChild->min_index].num_pixels<=max_tile_area)
+ {
+ min_error = leftChild->min_error;
+ min_index = leftChild->min_index;
+ }
+ else
+ {
+ min_error = rightChild->min_error;
+ min_index = rightChild->min_index;
+ }
+ }
+ }
+}
+
+void Tile::print_to_file(FILE *fp, Tile *tree, int nTiles, Timestamp
currenttime, float samplingrate)
+{
+ // we have to output in binart, so make a struct and use fwrite
+ TilePrintFormat tpf;
+
+ tpf.index = index;
+ float r,g,b,tgrads;
+ r = xGradient.getMean();
+ g = yGradient.getMean();
+ /*if(getOcclusionMeasure(tree, nTiles)>0.05)
+ {
+ int p = index/TG_FILTER_WIDTH;
+ while(tree[p].level<meanLevel) p *= 2;
+ b = tree[p].tGradient.getMean();
+ float sumspat = r+g;
+ if(sumspat>b) b = sumspat;
+ }
+ else
+ {
+ b = tGradient.getMean();
+ }
+ */
+ int p = index/TG_FILTER_WIDTH;
+ while(tree[p].level<meanLevel) p *= 2;
+ b = tree[p].tGradient.getMean();
+ int cl = level;
+ while(r<0.001 && g<0.001 && b<0.001 && cl>1)
+ {
+ cl = cl/2;
+ r = tree[cl].xGradient.getMean();
+ g = tree[cl].yGradient.getMean();
+ b = tree[cl].tGradient.getMean();
+ }
+ tpf.xGrad = r;
+ tpf.yGrad = g;
+ tpf.tGrad = b;
+
+ tpf.oldest_sample_timestamp = currenttime -
getNumSamples()*((float)nTiles/(float)samplingrate);
+ fwrite(&tpf, sizeof(tpf), 1, fp);
+}
+
+float Tile::getOcclusionMeasure(Tile *tree, int nTiles)
+{
+ int p = index/TG_FILTER_WIDTH; if(p<1) p = 1;
+ while(tree[p].level < meanLevel)
+ {
+ p*=2;
+ }
+ float retval = tree[p].occlusion.getMean();
+ return retval;
+}
+
+void invexp_init()
+{
+ invexpInit();
+}
+
+float getWeight(float A, float B, float age)
+{
+ return (A*invexp(B*age));
+ //return (A*expf(-B*age));
+}
+
+void Tile::checkBounds(int x, int y)
+{
+ assert(left<=x && x<right && bottom<=y && y<top);
+}
+
+
+void Tile::display(TileDisplayMode displaymode, int nTiles, Tile *tree,
+ int sampling_rate, Timestamp currenttime,
float A, float B, float visScale)
+{
+ float gvisScale;
+ gvisScale = 0.33;
+ switch(displaymode)
+ {
+ case SOLID:
+ {
+ //color[0] = drand48();
+ //color[1] = drand48();
+ //color[2] = drand48();
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glColor3fv(color);
+ }
+ break;
+ case BOUNDARY:
+ {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ glColor3f(1.0, 1.0, 0.0);
+ }
+ break;
+ case UNDERSAMPLING:
+ {
+ float dcol=0.0;
+ glColor3f(dcol*0.5, dcol*0.8, dcol*0.4);
+ }
+ break;
+ case DERIVATIVE:
+ {
+ float dcol=0.0;
+ dcol = visScale*derivative/10.0;
+ glColor3f(dcol*0.8, dcol*0.8, dcol*0.4);
+ }
+ break;
+ case AVERAGE_AGE:
+ {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ float dcol=1.0;// = (currenttime -
sum_tstamps.getMean())*0.33/0.1651225 - 1.0;
+ //if(dcol<0.0) dcol = 0.0;
+ dcol *=
visScale*getAverageAgeMeasure(tree[1], currenttime, gvisScale);
+ glColor3f(0.6*dcol, 0.3*dcol, 0.9*dcol);
+ }
+ break;
+ case OCCLUSION:
+ {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ float dcol;
+ dcol = getOcclusionMeasure(tree, nTiles);
+ dcol *= visScale;
+ glColor3f(dcol, dcol, 0);
+ }
+ break;
+ case ABSOLUTE_GRADIENT:
+ {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ float r,g,b,tgrads;
+ int p = index/TG_FILTER_WIDTH;
+ while(tree[p].level<meanLevel) p *= 2;
+ b = tree[p].tGradient.getMean();
+ r = visScale*xGradient.getMean();
+ g = visScale*yGradient.getMean();
+ int cl = level;
+ while(r<0.001 && g<0.001 && b<0.001 && cl>1)
+ {
+ cl = cl/2;
+ r = tree[cl].xGradient.getMean();
+ g = tree[cl].yGradient.getMean();
+ b = tree[cl].tGradient.getMean();
+ }
+ //b =
visScale*getMaxSiblingTgrad(TG_FILTER_WIDTH, tree);
+ glColor3f(r,g,b);
+ }
+ break;
+ case RELATIVE_GRADIENT:
+ {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ float r,g,b,tgrads;
+ int p = index/TG_FILTER_WIDTH;
+ while(tree[p].level<meanLevel) p *= 2;
+ b = tree[p].tGradient.getMean();
+ //b = getMaxSiblingTgrad(TG_FILTER_WIDTH,
tree);
+ tgrads = xGradient.getWeightedSum() +
yGradient.getWeightedSum() + b;//tGradient.getWeightedSum();
+ b =
visScale*b/tgrads;//visScale*tGradient.getWeightedSum()/tgrads;
+ r =
visScale*xGradient.getWeightedSum()/tgrads;
+ g =
visScale*yGradient.getWeightedSum()/tgrads;
+
+ glColor3f(r,g,b);
+ }
+ break;
+ case JITTERING:
+ {
+ float dcol;
+ // compare tgrads and set values
+ dcol = (tGrad() < 0.05)?visScale:0.0;
+ glColor3f(0.5*dcol, 0.8*dcol, 0.4*dcol);
+ }
+ break;
+ case SAMPLING_DENSITY:
+ {
+ float dcol =
visScale*getNumSamples()/(float)num_pixels;
+ glColor3f(0.3*dcol, 0.6*dcol, 0.8*dcol);
+ }
+ break;
+ };
+ int xfac = (tree[1].right-tree[1].left)/DISPLAY_WIDTH;
+ int yfac = (tree[1].top-tree[1].bottom)/DISPLAY_HEIGHT;
+ glBegin(GL_QUADS);
+ glVertex2d(left/xfac,bottom/yfac);
+ glVertex2d(right/xfac,bottom/yfac);
+ glVertex2d(right/xfac,top/yfac);
+ glVertex2d(left/xfac,top/yfac);
+ glEnd();
+}
Added: trunk/Engine/ImageTraversers/AFR/tiles.h
==============================================================================
--- (empty file)
+++ trunk/Engine/ImageTraversers/AFR/tiles.h Fri Jul 29 13:16:36 2005
@@ -0,0 +1,193 @@
+/***************************************************************************
+ * tiles.h
+ *
+ * Sat Oct 30 14:40:28 2004
+ * Copyright 2004 Abhinav Dayal
+ * abhinav@cs.northwestern.edu
+
****************************************************************************/
+
+#ifndef _TILES_H
+#define _TILES_H
+
+#include <Engine/ImageTraversers/AFR/sample.h>
+#include <Engine/ImageTraversers/AFR/stats.h>
+#include <Core/Math/MT_RNG.h>
+#define JITTER_THRESHOLD 0.005
+#define MIN_GRAD 0.01
+#define MIN_VALID_TILE_AREA 4
+#define DISPLAY_WIDTH 512
+#define DISPLAY_HEIGHT 512
+
+//namespace Manta {
+// using namespace std;
+
+using namespace Manta;
+using namespace std;
+// returns a random integer in [0,myMax)
+// use extern to define it elsewhere and use it
+
+enum TileDisplayMode {SOLID, BOUNDARY, INDIVIDUAL_SAMPLES, DERIVATIVE,
+ ABSOLUTE_GRADIENT, RELATIVE_GRADIENT,
SAMPLING_DENSITY, OCCLUSION,
+ UNDERSAMPLING, JITTERING, AVERAGE_AGE};
+
+
+struct TilePrintFormat
+{
+ int index;
+ float xGrad, yGrad, tGrad;
+ float oldest_sample_timestamp;
+};
+
+class Tile
+{
+ private:
+ /*
+ * variance = the variance of luminosities of samples within
a node
+ * mean = the mean of luminosities of samples within a node
+ * sum = the weighted sum of luminosities of samples within a
node
+ * sum_of_sqrs = the weighted sum of squares of luminosities
of samples within a node
+ * sum_wt = sum of the weights of each sample
+ * previous_variance = the previous variance, i.e. the
variance when the node was last updated
+ * total_error = the total error = K*variance +
(1-k)*derivative ;
+ * more to be added (gradient dependency) <TODO>
+ * time_derivative_set = time when the derivative was last set
+ * x,y,tGradsum = the total x, y and t gradient in the node
+ * num_pixels = number of samples in the node
+ * left,right,top,bottom = screenspace extents of the node
(in pixels)
+ * level = the depth of the node in the tree
+ * isValidTile = true if the node is part of current tiling
else it is false
+ * next, prev = next and previous valid tile indices
+ * color = color for displaying the tile
+ * lastSampleIndex = index of the last sample that was
samples from this tile
+ */
+
+ Stats xGradient, yGradient, tGradient,
+ intensity, sum_tstamps, occlusion;
+ float error, previous_error, total_error;
+ Timestamp time_last_derivative_set, time_last_updated;
+ int derivative_gap_count;
+ float derivative;
+ int num_pixels, left, right, top, bottom, level;
+ bool isValidTile;
+ int lastSampleIndex;
+ int next, prev;
+ bool min_size_violation;
+ float max_error, min_error;
+ int max_index, min_index;
+ int nextrandom, prevrandom;
+ int index;
+ float color[3];
+ public:
+ static int **leafMapping, meanLevel, max_tile_area;
+ Tile();
+ void print( int nTiles, Tile *tree, int sampling_rate,
Timestamp currenttime);
+ void initialize(int l, int b, int r, int t,
+ int currlevel, int address,
+ int width, int height,
+ int samplingrate, float A,
float B);
+ inline void setNextTile(int index) { next = index; }
+ inline void setPrevTile(int index) { prev = index; }
+ inline void setNextRandomTile(int index) { nextrandom =
index; }
+ inline void setPrevRandomTile(int index) { prevrandom =
index; }
+ inline void setValidTile()
+ {
+ isValidTile = true;
+ max_index = min_index = index;
+ max_error = min_error = total_error;
+ if(num_pixels <= MIN_VALID_TILE_AREA)
+ min_size_violation = true;
+ else
+ min_size_violation = false;
+ }
+ inline int getTileSize() { return num_pixels; }
+ inline int getLeft() { return left; };
+ inline int getBottom() { return bottom; };
+ inline void unsetValidTile()
+ {
+ isValidTile = false;
+ }
+ inline bool isValid() { return isValidTile; }
+ inline int getNextTile() { return next; }
+ inline int getPrevTile() { return prev; }
+ inline int getNextRandomTile() { return nextrandom; }
+ inline int getPrevRandomTile() { return prevrandom; }
+ inline float getNumSamples() { return
xGradient.getSumWeights(); }
+ int getLevel() { return level; }
+ inline double maxError() { return max_error; }
+ inline double minError() { return min_error; }
+ void getNextSample(int &x, int &y, MT_RNG &myRandomNumber);
+ inline void setmaxError(double value) { max_error = value; }
+ inline void setminError(double value) { min_error = value; }
+ bool isSibling(Tile &t);
+ inline bool isInside(float x, float y)
+ {
+ if(left<=x && x<right && bottom<=y && y<top)
+ return true;
+ return false;
+ }
+ void setStatsFromChildren(Timestamp currenttime, float A,
float B,
+ Tile *tree, int sampling_rate, int nTiles, bool
validreached);
+ void updateCommon(Timestamp currenttime, Tile *tree, int
nTiles, int sampling_rate);
+ void ageStats(Timestamp currenttime, float A, float B,
+ Tile *tree, int sampling_rate, int
nTiles);
+ void updateStatsAddSampleSet(SampleSet *newsampleset,
Timestamp currenttime, float A, float B,
+ Tile *tree, int sampling_rate, int
nTiles);
+ void updateStatsAddSample(Sample *newsample, Timestamp
currenttime, float A, float B,
+ Tile *tree, int sampling_rate, int nTiles, float
tgrad, bool occ);
+ void updateMinMax(Tile *tree);
+ inline float xGrad() { return xGradient.getMean(); }
+ inline float yGrad() { return yGradient.getMean(); }
+ inline float tGrad() { return tGradient.getMean(); }
+ inline float getTotalError() { return total_error; }
+ inline float getError() { return error; }
+ inline int getMinIndex() { return min_index; }
+ inline int getMaxIndex()
+ {
+ //if (min_size_violation)
+ // cout << "min_size_violation for index " <<
index << ", has max_index " << max_index << endl;
+ return max_index; }
+ inline void setMinMax()
+ {
+ min_error = max_error = total_error;
+ min_index = max_index = index;
+ }
+ inline void getCenter(float &x, float &y)
+ {
+ x = ((float)left+(float)right)/2.0;
+ y = ((float)bottom+(float)top)/2.0;
+ }
+ void setDerivative(Timestamp currenttime);
+ void setError(Tile *tree, int nTiles, int sampling_rate,
Timestamp currenttime);
+ void setTotalError(Tile *tree, Timestamp currenttime, int
nTiles, int sampling_rate);
+ inline void setTimeLastDerivativeSet(Timestamp currenttime)
+ {
+ time_last_derivative_set = currenttime;
+ derivative_gap_count = 0;
+ }
+ inline void setTimeLastUpdated(Timestamp currenttime)
+ {
+ time_last_updated = currenttime;
+ }
+ inline bool isLeaf()
+ {
+ return (num_pixels==1);
+ }
+ void print_to_file(FILE *fp, Tile *tree, int nTiles,
Timestamp currenttime, float samplingrate);
+ inline bool isZeroGrad()
+ {
+ return (xGradient.getMean()<MIN_GRAD &&
yGradient.getMean()<MIN_GRAD && tGradient.getMean()<MIN_GRAD);
+ }
+ float getAverageAgeMeasure(Tile &roottile, Timestamp
currenttime, float gvisScale);
+ float getOcclusionMeasure(Tile *tree, int nTiles);
+ void checkBounds(int x, int y);
+ void display(TileDisplayMode displaymode, int nTiles, Tile *tree,
+ int sampling_rate, Timestamp currenttime,
float A, float B, float visScale);
+
+};
+
+void shuffleOrder(int *buf, int size); // shuffle elements of the buffer of
size w*h
+float getWeight(float A, float B, float age);
+void invexp_init();
+
+//}
+#endif /* _TILES_H */
Modified: trunk/Engine/ImageTraversers/CMakeLists.txt
==============================================================================
--- trunk/Engine/ImageTraversers/CMakeLists.txt (original)
+++ trunk/Engine/ImageTraversers/CMakeLists.txt Fri Jul 29 13:16:36 2005
@@ -3,4 +3,8 @@
ImageTraversers/NullImageTraverser.cc
ImageTraversers/TiledImageTraverser.cc
ImageTraversers/FramelessImageTraverser.cc
+ ImageTraversers/AFImageTraverser.cc
+ ImageTraversers/AFR/stats.cc
+ ImageTraversers/AFR/tiles.cc
+ ImageTraversers/AFR/kdtree.cc
)
Modified: trunk/Engine/ImageTraversers/DissolveImageTraverser.h
==============================================================================
--- trunk/Engine/ImageTraversers/DissolveImageTraverser.h (original)
+++ trunk/Engine/ImageTraversers/DissolveImageTraverser.h Fri Jul 29
13:16:36 2005
@@ -14,7 +14,7 @@
public:
DissolveImageTraverser(const vector<string>& args);
virtual ~DissolveImageTraverser();
- virtual void setupBegin(const SetupContext&, int numChannels);
+ virtual void setupBegin(SetupContext&, int numChannels);
virtual void setupDisplayChannel(SetupContext&);
virtual void setupFrame(const RenderContext& context);
virtual void renderImage(const RenderContext& context, Image* image);
Modified: trunk/Engine/ImageTraversers/FramelessImageTraverser.cc
==============================================================================
--- trunk/Engine/ImageTraversers/FramelessImageTraverser.cc (original)
+++ trunk/Engine/ImageTraversers/FramelessImageTraverser.cc Fri Jul 29
13:16:36 2005
@@ -43,7 +43,7 @@
if(shuffledTiles!=NULL) delete [] shuffledTiles;
}
-void FramelessImageTraverser::setupBegin(const SetupContext& context,
+void FramelessImageTraverser::setupBegin(SetupContext& context,
int numChannels)
{
context.loadBalancer->setupBegin(context, numChannels);
@@ -99,7 +99,8 @@
}
nx/=2;
ny/=2;
-
+ nx--;
+ ny--;
xtilesize = 1;
for(i=0; i<nx; i++) xtilesize *= 2;
@@ -151,6 +152,8 @@
shuffleMyTiles(); // shuffle them up
int numAssignments = xtiles * ytiles; // these will be the number of
assignments to make to threads
+ cout << "numAssignments = " << numAssignments << endl;
+ cout << "xtiles = " << xtiles << ", ytiles = " << ytiles << endl;
context.loadBalancer->setupDisplayChannel(context, numAssignments);
//context.pixelSampler->setupDisplayChannel(context);
}
Modified: trunk/Engine/ImageTraversers/FramelessImageTraverser.h
==============================================================================
--- trunk/Engine/ImageTraversers/FramelessImageTraverser.h (original)
+++ trunk/Engine/ImageTraversers/FramelessImageTraverser.h Fri Jul 29
13:16:36 2005
@@ -19,7 +19,7 @@
public:
FramelessImageTraverser(const vector<string>& args);
virtual ~FramelessImageTraverser();
- virtual void setupBegin(const SetupContext&, int numChannels);
+ virtual void setupBegin(SetupContext&, int numChannels);
virtual void setupDisplayChannel(SetupContext&);
virtual void setupFrame(const RenderContext& context);
virtual void renderImage(const RenderContext& context, Image* image);
Modified: trunk/Engine/ImageTraversers/NullImageTraverser.cc
==============================================================================
--- trunk/Engine/ImageTraversers/NullImageTraverser.cc (original)
+++ trunk/Engine/ImageTraversers/NullImageTraverser.cc Fri Jul 29 13:16:36
2005
@@ -19,7 +19,7 @@
{
}
-void NullImageTraverser::setupBegin(const SetupContext&, int)
+void NullImageTraverser::setupBegin(SetupContext&, int)
{
}
Modified: trunk/Engine/ImageTraversers/NullImageTraverser.h
==============================================================================
--- trunk/Engine/ImageTraversers/NullImageTraverser.h (original)
+++ trunk/Engine/ImageTraversers/NullImageTraverser.h Fri Jul 29 13:16:36
2005
@@ -14,7 +14,7 @@
public:
NullImageTraverser(const vector<string>& args);
virtual ~NullImageTraverser();
- virtual void setupBegin(const SetupContext&, int numChannels);
+ virtual void setupBegin(SetupContext&, int numChannels);
virtual void setupDisplayChannel(SetupContext&);
virtual void setupFrame(const RenderContext& context);
virtual void renderImage(const RenderContext& context, Image* image);
Modified: trunk/Engine/ImageTraversers/TiledImageTraverser.cc
==============================================================================
--- trunk/Engine/ImageTraversers/TiledImageTraverser.cc (original)
+++ trunk/Engine/ImageTraversers/TiledImageTraverser.cc Fri Jul 29 13:16:36
2005
@@ -37,7 +37,7 @@
{
}
-void TiledImageTraverser::setupBegin(const SetupContext& context, int
numChannels)
+void TiledImageTraverser::setupBegin(SetupContext& context, int numChannels)
{
context.loadBalancer->setupBegin(context, numChannels);
context.pixelSampler->setupBegin(context, numChannels);
Modified: trunk/Engine/ImageTraversers/TiledImageTraverser.h
==============================================================================
--- trunk/Engine/ImageTraversers/TiledImageTraverser.h (original)
+++ trunk/Engine/ImageTraversers/TiledImageTraverser.h Fri Jul 29 13:16:36
2005
@@ -14,7 +14,7 @@
public:
TiledImageTraverser(const vector<string>& args);
virtual ~TiledImageTraverser();
- virtual void setupBegin(const SetupContext&, int numChannels);
+ virtual void setupBegin(SetupContext&, int numChannels);
virtual void setupDisplayChannel(SetupContext&);
virtual void setupFrame(const RenderContext& context);
virtual void renderImage(const RenderContext& context, Image* image);
Modified: trunk/Image/SimpleImage.h
==============================================================================
--- trunk/Image/SimpleImage.h (original)
+++ trunk/Image/SimpleImage.h Fri Jul 29 13:16:36 2005
@@ -104,6 +104,7 @@
template<class Pixel>
void SimpleImage<Pixel>::set(const Fragment& fragment)
{
+ //cout << "inside set image" << endl;
if(fragment.getFlags() & (Fragment::ConsecutiveX|Fragment::ConstantEye)
== (Fragment::ConsecutiveX|Fragment::ConstantEye)){
int nf = fragment.getSize();
@@ -113,6 +114,8 @@
} else {
for(int i=0;i<fragment.getSize();i++){
const Fragment::Element& f = fragment.get(i);
+ //cout << "setting " << f.x << ", " << f.y << endl;
+ if(f.x<xres && f.x>=0 && f.y<yres && f.y>=0)
convertToPixel(eyeStart[f.which_eye][f.y][f.x], f.color.convertRGB());
}
}
Modified: trunk/Interface/Camera.h
==============================================================================
--- trunk/Interface/Camera.h (original)
+++ trunk/Interface/Camera.h Fri Jul 29 13:16:36 2005
@@ -17,7 +17,7 @@
virtual void scaleFOV(double) = 0;
virtual void translate(Vector v) = 0;
virtual void dolly(double) = 0;
- virtual Point project(const Point &point) = 0; // project the 3D
point on to the camera image plane
+ virtual Point project(const Point &point) const = 0; // project the 3D
point on to the camera image plane
enum TransformCenter {
LookAt,
Eye,
Modified: trunk/Interface/Context.h
==============================================================================
--- trunk/Interface/Context.h (original)
+++ trunk/Interface/Context.h Fri Jul 29 13:16:36 2005
@@ -60,6 +60,7 @@
minPipelineDepth =1;
maxPipelineDepth = 1000;
masterWindow = 0;
+ multipleGLWindows = false;
}
RTRTInterface* rtrt_int;
int channelIndex;
@@ -108,12 +109,21 @@
void clearMasterWindow() {
masterWindow = 0;
}
-
+ void setMultipleGLWindows() {
+ multipleGLWindows = true;
+ }
+ void unsetMultipleGLWindows() {
+ multipleGLWindows = false;
+ }
+ bool getMultipleGLWindows() {
+ return multipleGLWindows;
+ }
private:
SetupContext(const SetupContext&);
SetupContext& operator=(const SetupContext&);
bool stereo;
+ bool multipleGLWindows;
int xres, yres;
int minPipelineDepth, maxPipelineDepth;
bool changed;
Modified: trunk/Interface/Fragment.h
==============================================================================
--- trunk/Interface/Fragment.h (original)
+++ trunk/Interface/Fragment.h Fri Jul 29 13:16:36 2005
@@ -41,9 +41,9 @@
ASSERTRANGE(xend-xstart, 0, MaxFragmentSize+1);
int nx = xend-xstart;
for(int i=0; i< nx;i++){
- data[i].x = i+xstart;
- data[i].y = y;
- data[i].which_eye = which_eye;
+ data[i].x = i+xstart;
+ data[i].y = y;
+ data[i].which_eye = which_eye;
}
flags = ConsecutiveX|ConstantEye;
size = nx;
@@ -51,25 +51,44 @@
~Fragment() {
}
-
- void createRandom(int numElements, int xstart, int ystart, int xend, int
yend, int which_eye, MT_RNG &myRandomNumber)
- {
- size = numElements;
- flags = ConstantEye;
- for(int i=0;i<size;i++)
- {
- data[i].x =
(int)(xstart+myRandomNumber.genfrand()*(xend - xstart));
- data[i].y =
(int)(ystart+myRandomNumber.genfrand()*(yend - ystart));
- data[i].which_eye = which_eye;
- }
- }
-
+
+ // input: a rectangular tile and number of sample locations to generate
+ // output: creates randomly oriented sample locations in given range
+ void createRandom(const int numElements, const int xstart, const int
ystart,
+ const int xend, const int yend, const int which_eye,
+ MT_RNG &myRandomNumber)
+ {
+ size = numElements;
+ flags = ConstantEye;
+ for(int i=0;i<size;i++)
+ {
+ data[i].x = (int)(xstart+myRandomNumber.genfrand()*(xend - xstart));
+ data[i].y = (int)(ystart+myRandomNumber.genfrand()*(yend - ystart));
+ data[i].which_eye = which_eye;
+ }
+ }
+
+ // add a sample location to the fragment and return if fragment has more
space
+ // left or not
+ bool addItem(const int x, const int y, const int which_eye, int index) {
+ data[index].x = x;
+ data[index].y = y;
+ data[index].which_eye = which_eye;
+ if(index+1>=size) return false; else return true;
+ }
+
int getFlags() const {
return flags;
}
+ int setFlags(const int newflags) {
+ flags = newflags;
+ }
int getSize() const {
return size;
}
+ void setSize(const int newSize) {
+ size = newSize;
+ }
void setColor(int which, const Color& color) {
data[which].color = color;
}
@@ -80,8 +99,8 @@
// Represents a Pixel
struct Element {
- // Pixel position in image space
- int x, y;
+ // Pixel position in image space
+ int x, y;
int which_eye; // monocular: always 0, stereo: 0=left, 1=right
Color color; // Final result
};
Modified: trunk/Interface/ImageTraverser.h
==============================================================================
--- trunk/Interface/ImageTraverser.h (original)
+++ trunk/Interface/ImageTraverser.h Fri Jul 29 13:16:36 2005
@@ -9,7 +9,7 @@
class ImageTraverser {
public:
virtual ~ImageTraverser();
- virtual void setupBegin(const SetupContext&, int numChannels) = 0;
+ virtual void setupBegin(SetupContext&, int numChannels) = 0;
virtual void setupDisplayChannel(SetupContext&) = 0;
virtual void setupFrame(const RenderContext& context) = 0;
virtual void renderImage(const RenderContext& context, Image* image) = 0;
Modified: trunk/Model/Cameras/EnvironmentCamera.cc
==============================================================================
--- trunk/Model/Cameras/EnvironmentCamera.cc (original)
+++ trunk/Model/Cameras/EnvironmentCamera.cc Fri Jul 29 13:16:36 2005
@@ -165,7 +165,7 @@
// This functionality doesn't make much sense with the environment camera
}
-Point EnvironmentCamera::project(const Point &point)
+Point EnvironmentCamera::project(const Point &point) const
{
// NOT FINISHED
return Point(0., 0., 0.);
Modified: trunk/Model/Cameras/EnvironmentCamera.h
==============================================================================
--- trunk/Model/Cameras/EnvironmentCamera.h (original)
+++ trunk/Model/Cameras/EnvironmentCamera.h Fri Jul 29 13:16:36 2005
@@ -24,7 +24,7 @@
virtual void dolly(double);
virtual void transform(AffineTransform t, TransformCenter);
virtual void autoview(double fov);
- virtual Point project(const Point &point); // project a 3D point to the
camera image plane
+ virtual Point project(const Point &point) const; // project a 3D point
to the camera image plane
static Camera* create(const vector<string>& args);
private:
void setup();
Modified: trunk/Model/Cameras/FisheyeCamera.cc
==============================================================================
--- trunk/Model/Cameras/FisheyeCamera.cc (original)
+++ trunk/Model/Cameras/FisheyeCamera.cc Fri Jul 29 13:16:36 2005
@@ -180,7 +180,7 @@
setup();
}
-Point FisheyeCamera::project(const Point &point)
+Point FisheyeCamera::project(const Point &point) const
{
// NOT FINISHED
return Point(0,0,0); // just a placeholder
Modified: trunk/Model/Cameras/FisheyeCamera.h
==============================================================================
--- trunk/Model/Cameras/FisheyeCamera.h (original)
+++ trunk/Model/Cameras/FisheyeCamera.h Fri Jul 29 13:16:36 2005
@@ -24,7 +24,7 @@
virtual void dolly(double);
virtual void transform(AffineTransform t, TransformCenter);
virtual void autoview(double fov);
- virtual Point project(const Point &point); // project a 3D point
to the camera image plane
+ virtual Point project(const Point &point) const; // project a 3D point
to the camera image plane
static Camera* create(const vector<string>& args);
private:
void setup();
Modified: trunk/Model/Cameras/OrthogonalCamera.cc
==============================================================================
--- trunk/Model/Cameras/OrthogonalCamera.cc (original)
+++ trunk/Model/Cameras/OrthogonalCamera.cc Fri Jul 29 13:16:36 2005
@@ -158,7 +158,7 @@
setup();
}
-Point OrthogonalCamera::project(const Point &point)
+Point OrthogonalCamera::project(const Point &point) const
{
// NOT FINISHED
return Point(0,0,0); // just a placeholder
Modified: trunk/Model/Cameras/OrthogonalCamera.h
==============================================================================
--- trunk/Model/Cameras/OrthogonalCamera.h (original)
+++ trunk/Model/Cameras/OrthogonalCamera.h Fri Jul 29 13:16:36 2005
@@ -23,7 +23,7 @@
virtual void dolly(double);
virtual void transform(AffineTransform t, TransformCenter);
virtual void autoview(double fov);
- virtual Point project(const Point &point);
+ virtual Point project(const Point &point) const;
static Camera* create(const vector<string>& args);
private:
void setup();
Modified: trunk/Model/Cameras/PinholeCamera.cc
==============================================================================
--- trunk/Model/Cameras/PinholeCamera.cc (original)
+++ trunk/Model/Cameras/PinholeCamera.cc Fri Jul 29 13:16:36 2005
@@ -63,36 +63,65 @@
void PinholeCamera::setup()
{
- int i;
- vfov = hfov;
- direction=lookat-eye;
- nearZ=direction.length();
+ int i, j, k;
+ vfov = hfov; // set field of view
+ direction=lookat-eye; // the normal vector
+ nearZ=direction.length(); // lenghth to near plane
Vector n = direction;
n.normalize();
-
- for(i=0; i<3; i++)
- uvn[2][i] = n[i];
-
+
+ up.normalize();
v=Cross(direction, up);
if(v.length2() == 0.0){
std::cerr << __FILE__ << " line: " << __LINE__ << " Ambiguous up
direciton...\n";
}
v.normalize();
- for(i=0; i<3; i++)
- uvn[1][i] = v[i];
-
u=Cross(v, direction);
u.normalize();
- for(i=0; i<3; i++)
- uvn[0][i] = u[i];
+ for(i=0; i<4; i++)
+ for(j=0; j<4; j++)
+ proj[i][j] = mv[i][j] = 0.0;
+
+ // form modelview matrix
+ mv[0][0] = v.x(); mv[0][1] = v.y(); mv[0][2] = v.z();
+ mv[0][3] = (-eye.x()*v.x()) + (-eye.y()*v.y()) + (-eye.z()*v.z());
+ mv[1][0] = u.x(); mv[1][1] = u.y(); mv[1][2] = u.z();
+ mv[1][3] = (-eye.x()*u.x()) + (-eye.y()*u.y()) + (-eye.z()*u.z());
+ mv[2][0] = -1.0*n.x(); mv[2][1] = -1.0*n.y(); mv[2][2] = -1.0*n.z();
+ mv[2][3] = (eye.x()*n.x()) + (eye.y()*n.y()) + (eye.z()*n.z());
+ mv[3][3]= 1.0;
height=nearZ*tan(vfov*0.5*M_PI/180.0);
u*=height;
width=nearZ*tan(hfov*0.5*M_PI/180.0);
- v*=width;
+ v*=width;
+ // form projection matrix
+ double f = 1.0/tan((vfov*M_PI/180.0)/2.0);
+ double aspect = width/height;
+ double farZ = nearZ*1000.0;
+
+
+ proj[0][0] = f/aspect;
+ proj[1][1] = f;
+ proj[2][2] = (farZ+nearZ)/(nearZ-farZ);
+ proj[2][3] = (2.0*farZ*nearZ)/(nearZ-farZ);
+ proj[3][2] = -1.0;
+
+ // product of two
+ for(i=0; i<4; i++)
+ {
+ for(j=0; j<4; j++)
+ {
+ prodMat[i][j] = 0.0;
+ for(k=0; k<4; k++)
+ {
+ prodMat[i][j] += proj[i][k]*mv[k][j];
+ }
+ }
+ }
}
void PinholeCamera::makeRays(RayPacket& rays) const
@@ -191,27 +220,14 @@
setup();
}
-Point PinholeCamera::project(const Point &point)
+Point PinholeCamera::project(const Point &point) const
{
- // translate camera center to origin
- Vector trans(-eye.x(), -eye.y(), -eye.z());
- Point p1 = point + trans;
-
- // rotate to align with camera axis
- Point p2((uvn[0][0]*p1.x() + uvn[0][1]*p1.y() + uvn[0][2]*p1.z()),
- (uvn[1][0]*p1.x() + uvn[1][1]*p1.y() + uvn[1][2]*p1.z()),
- (uvn[2][0]*p1.x() + uvn[2][1]*p1.y() + uvn[2][2]*p1.z()));
-
- // project the point to the image plane using simlar triangles
- // the viewZ is just a ratio to tell whether point is valid or not
- // if returned viewZ>1, it means that the point lied beyong the image plane
- // and is visible to camera, else it is not
- // It is not a sufficient condition though, the x and y coordinates should
lie within the
- // width and height of the image, so returned coordinates are in the
normalized space [-1,1]
- if(fabs(p2.z())<0.0001) // check for inconsistencies
- return Point(0,0,0);
- else
- return Point((p2.x()*nearZ/p2.z())/(width/2.0),
- (p2.y()*nearZ/p2.z())/(height/2.0),
- p2.z()/nearZ);
+ Point p2(prodMat[0][0]*point.x() + prodMat[0][1]*point.y() +
prodMat[0][2]*point.z() + prodMat[0][3],
+ prodMat[1][0]*point.x() + prodMat[1][1]*point.y() +
prodMat[1][2]*point.z() + prodMat[1][3],
+ prodMat[2][0]*point.x() + prodMat[2][1]*point.y() +
prodMat[2][2]*point.z() + prodMat[2][3]);
+ double zval = prodMat[3][0]*point.x() + prodMat[3][1]*point.y() +
prodMat[3][2]*point.z() + prodMat[3][3];
+
+ return Point(((p2.x()/zval)+1.0)/2.0,
+ ((p2.y()/zval)+1.0)/2.0,
+ ((p2.z()/zval)+1.0)/2.0);
}
Modified: trunk/Model/Cameras/PinholeCamera.h
==============================================================================
--- trunk/Model/Cameras/PinholeCamera.h (original)
+++ trunk/Model/Cameras/PinholeCamera.h Fri Jul 29 13:16:36 2005
@@ -24,7 +24,7 @@
virtual void dolly(double);
virtual void transform(AffineTransform t, TransformCenter);
virtual void autoview(double fov);
- virtual Point project(const Point &point); // project a 3D point
to the camera image plane
+ virtual Point project(const Point &point) const; // project a 3D
point to the camera image plane
static Camera* create(const vector<string>& args);
private:
void setup();
@@ -38,9 +38,7 @@
Vector direction;
Vector u,v;
-
- // for projection we maintain a uvn rotation matrix
- double uvn[3][3];
+ double proj[4][4], mv[4][4], prodMat[4][4];
};
}
- [MANTA] r457 - in trunk: Engine Engine/Control Engine/Display Engine/ImageTraversers Engine/ImageTraversers/AFR Image Interface Model/Cameras, abhinav, 07/29/2005
Archive powered by MHonArc 2.6.16.