Commit 4f517c76b909f099e3f4a31b4256b3a782b4d9e6

Authored by David Mayerich
1 parent bbb519e6

added color-mapped networks, parallel viewing of two networks

Showing 1 changed file with 171 additions and 119 deletions   Show diff stats
main.cpp
... ... @@ -8,7 +8,7 @@
8 8  
9 9 //STIM includes
10 10 #include <stim/visualization/gl_network.h>
11   -#include <stim/visualization/gl_aabb.h>
  11 +#include <stim/visualization/gl_aaboundingbox.h>
12 12 #include <stim/parser/arguments.h>
13 13 #include <stim/visualization/camera.h>
14 14  
... ... @@ -18,62 +18,117 @@
18 18 //BOOST includes
19 19 #include <boost/tuple/tuple.hpp>
20 20  
21   -stim::gl_aabb<float> bb;
22   -stim::camera cam;
  21 +//visualization objects
  22 +stim::gl_aaboundingbox<float> bb; //axis-aligned bounding box object
  23 +stim::camera cam; //camera object
23 24  
24   -stim::gl_network<float> GT;
25   -stim::gl_network<float> T;
  25 +unsigned num_nets = 0;
  26 +stim::gl_network<float> GT; //ground truth network
  27 +stim::gl_network<float> T; //test network
26 28  
27 29 //hard-coded parameters
28   -float resample_rate = 0.5;
  30 +float resample_rate = 0.5; //sample rate for the network (fraction of sigma used as the maximum sample rate)
  31 +float camera_factor = 1.2; //start point of the camera as a function of X and Y size
  32 +float orbit_factor = 0.01; //degrees per pixel used to orbit the camera
29 33  
30 34 //mouse position tracking
31 35 int mouse_x;
32 36 int mouse_y;
33 37  
  38 +//OpenGL objects
  39 +GLuint cmap_tex = 0; //texture name for the color map
  40 +
  41 +//sets an OpenGL viewport taking up the entire window
  42 +void glut_render_single_projection(){
  43 +
  44 + glMatrixMode(GL_PROJECTION); //load the projection matrix for editing
  45 + glLoadIdentity(); //start with the identity matrix
  46 + int X = glutGet(GLUT_WINDOW_WIDTH); //use the whole screen for rendering
  47 + int Y = glutGet(GLUT_WINDOW_HEIGHT);
  48 + glViewport(0, 0, X, Y); //specify a viewport for the entire window
  49 + float aspect = (float)X / (float)Y; //calculate the aspect ratio
  50 + gluPerspective(60, aspect, 0.1, 1000000); //set up a perspective projection
  51 +}
  52 +
  53 +//sets an OpenGL viewport taking up the left half of the window
  54 +void glut_render_left_projection(){
  55 +
  56 + glMatrixMode(GL_PROJECTION); //load the projection matrix for editing
  57 + glLoadIdentity(); //start with the identity matrix
  58 + int X = glutGet(GLUT_WINDOW_WIDTH) / 2; //only use half of the screen for the viewport
  59 + int Y = glutGet(GLUT_WINDOW_HEIGHT);
  60 + glViewport(0, 0, X, Y); //specify the viewport on the left
  61 + float aspect = (float)X / (float)Y; //calculate the aspect ratio
  62 + gluPerspective(60, aspect, 0.1, 1000000); //set up a perspective projection
  63 +}
  64 +
  65 +//sets an OpenGL viewport taking up the right half of the window
  66 +void glut_render_right_projection(){
  67 +
  68 + glMatrixMode(GL_PROJECTION); //load the projection matrix for editing
  69 + glLoadIdentity(); //start with the identity matrix
  70 + int X = glutGet(GLUT_WINDOW_WIDTH) / 2; //only use half of the screen for the viewport
  71 + int Y = glutGet(GLUT_WINDOW_HEIGHT);
  72 + glViewport(X, 0, X, Y); //specify the viewport on the right
  73 + float aspect = (float)X / (float)Y; //calculate the aspect ratio
  74 + gluPerspective(60, aspect, 0.1, 1000000); //set up a perspective projection
  75 +}
  76 +
  77 +void glut_render_modelview(){
  78 +
  79 + glMatrixMode(GL_MODELVIEW); //load the modelview matrix for editing
  80 + glLoadIdentity(); //start with the identity matrix
  81 + stim::vec<float> eye = cam.getPosition(); //get the camera position (eye point)
  82 + stim::vec<float> focus = cam.getLookAt(); //get the camera focal point
  83 + stim::vec<float> up = cam.getUp(); //get the camera "up" orientation
  84 +
  85 + gluLookAt(eye[0], eye[1], eye[2], focus[0], focus[1], focus[2], up[0], up[1], up[2]); //set up the OpenGL camera
  86 +}
  87 +
  88 +//draws the network(s)
34 89 void glut_render(void) {
35 90  
36   - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  91 + if(num_nets == 1){ //if a single network is loaded
  92 + glut_render_single_projection(); //fill the entire viewport
  93 + glut_render_modelview(); //set up the modelview matrix with camera details
  94 + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear the screen
  95 + GT.glCenterline(GT.nmags() - 1); //render the GT network (the only one loaded)
  96 + }
37 97  
38   - glMatrixMode(GL_MODELVIEW);
39   - glLoadIdentity();
40   - stim::vec<float> eye = cam.getPosition();
41   - stim::vec<float> focus = cam.getLookAt();
42   - stim::vec<float> up = cam.getUp();
  98 + if(num_nets == 2){ //if two networks are loaded
43 99  
44   - gluLookAt(eye[0], eye[1], eye[2], focus[0], focus[1], focus[2], up[0], up[1], up[2]);
  100 + glut_render_left_projection(); //set up a projection for the left half of the window
  101 + glut_render_modelview(); //set up the modelview matrix using camera details
  102 + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear the screen
45 103  
46   -
  104 + glEnable(GL_TEXTURE_1D); //enable texture mapping
  105 + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //texture map will be used as the network color
  106 + glBindTexture(GL_TEXTURE_1D, cmap_tex); //bind the Brewer texture map
47 107  
48   - // render the bounding box
49   - glColor3f(0.0, 0.0, 1.0);
50   - bb.glWire();
51   -
  108 + GT.glCenterline(GT.nmags() - 1); //render the GT network
52 109  
53   - //render the GT network (red)
54   - glColor3f(1.0, 0.0, 0.0);
55   - GT.glCenterline();
  110 + glut_render_right_projection(); //set up a projection for the right half of the window
  111 + glut_render_modelview(); //set up the modelview matrix using camera details
  112 + T.glCenterline(T.nmags() - 1); //render the T network
56 113  
57   - //render the T network (green)
58   - glColor3f(0.0, 1.0, 0.0);
59   - T.glCenterline();
  114 + }
60 115  
61 116 glutSwapBuffers();
62 117 }
63 118  
64 119 // defines camera motion based on mouse dragging
65 120 void glut_motion(int x, int y){
66   - float factor = 0.01;
  121 +
67 122  
68   - float theta = factor * (mouse_x - x);
69   - float phi = factor * (y - mouse_y);
  123 + float theta = orbit_factor * (mouse_x - x); //determine the number of degrees along the x-axis to rotate
  124 + float phi = orbit_factor * (y - mouse_y); //number of degrees along the y-axis to rotate
70 125  
71   - cam.OrbitFocus(theta, phi);
  126 + cam.OrbitFocus(theta, phi); //rotate the camera around the focal point
72 127  
73   - mouse_x = x;
  128 + mouse_x = x; //update the mouse position
74 129 mouse_y = y;
75   -
76   - glutPostRedisplay();
  130 +
  131 + glutPostRedisplay(); //re-draw the visualization
77 132 }
78 133  
79 134 // sets the mouse position when clicked
... ... @@ -82,19 +137,78 @@ void glut_mouse(int button, int state, int x, int y){
82 137 mouse_y = y;
83 138 }
84 139  
85   -// re-calculates the projection matrix if the window is reshaped
86   -void glut_reshape(int x, int y){
  140 +#define BREWER_CTRL_PTS 11 //number of control points in the Brewer map
  141 +void texture_initialize(){
  142 +
  143 + //define the colormap
  144 + static float brewer_map[BREWER_CTRL_PTS][3] = { //generate a Brewer color map (blue to red)
  145 + {0.192157f, 0.211765f, 0.584314f},
  146 + {0.270588f, 0.458824f, 0.705882f},
  147 + {0.454902f, 0.678431f, 0.819608f},
  148 + {0.670588f, 0.85098f, 0.913725f},
  149 + {0.878431f, 0.952941f, 0.972549f},
  150 + {1.0f, 1.0f, 0.74902f},
  151 + {0.996078f, 0.878431f, 0.564706f},
  152 + {0.992157f, 0.682353f, 0.380392f},
  153 + {0.956863f, 0.427451f, 0.262745f},
  154 + {0.843137f, 0.188235f, 0.152941f},
  155 + {0.647059f, 0.0f, 0.14902f}
  156 + };
  157 +
  158 + glGenTextures(1, &cmap_tex); //generate a texture map name
  159 + glBindTexture(GL_TEXTURE_1D, cmap_tex); //bind the texture map
  160 +
  161 + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //enable linear interpolation
  162 + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  163 + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP); //clamp the values at the minimum and maximum
  164 + glTexImage1D(GL_TEXTURE_1D, 0, 3, BREWER_CTRL_PTS, 0, GL_RGB, GL_FLOAT, //upload the texture map to the GPU
  165 + brewer_map);
  166 +}
  167 +
  168 +//Initialize the OpenGL (GLUT) window, including starting resolution, callbacks, texture maps, and camera
  169 +void glut_initialize(){
  170 +
  171 + int myargc = 1; //GLUT requires arguments, so create some bogus ones
  172 + char* myargv[1];
  173 + myargv [0]=strdup ("netmets");
  174 +
  175 + glutInit(&myargc, myargv); //pass bogus arguments to glutInit()
  176 + glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); //generate a color buffer, depth buffer, and enable double buffering
  177 + glutInitWindowPosition(100,100); //set the initial window position
  178 + glutInitWindowSize(320,320); //set the initial window size
  179 + glutCreateWindow("NetMets - STIM Lab, UH"); //set the dialog box title
87 180  
88   - glMatrixMode(GL_PROJECTION);
89   - glLoadIdentity();
90   - glViewport(0, 0, x, y);
91   - float aspect = (float)x / (float)y;
92   - gluPerspective(60, aspect, 0.1, 1000000);
  181 +
  182 + // register callback functions
  183 + glutDisplayFunc(glut_render); //function executed for rendering - renders networks
  184 + glutMouseFunc(glut_mouse); //executed on a mouse click - sets starting mouse positions for rotations
  185 + glutMotionFunc(glut_motion); //executed when the mouse is moved while a button is pressed
  186 +
  187 + texture_initialize(); //set up texture mapping (create texture maps, enable features)
  188 +
  189 + stim::vec<float> c = bb.center(); //get the center of the network bounding box
93 190  
  191 + //place the camera along the z-axis at a distance determined by the network size along x and y
  192 + cam.setPosition(c + stim::vec<float>(0, 0, camera_factor * std::max(bb.size()[0], bb.size()[1])));
  193 + cam.LookAt(c[0], c[1], c[2]); //look at the center of the network
94 194 }
95 195  
  196 +//compare both networks and fill the networks with error information
  197 +void compare(float sigma){
  198 +
  199 + GT = GT.compare(T, sigma); //compare the ground truth to the test case - store errors in GT
  200 + T = T.compare(GT, sigma); //compare the test case to the ground truth - store errors in T
  201 +
  202 + //calculate the metrics
  203 + float FPR = GT.average(1); //calculate the metrics
  204 + float FNR = T.average(1);
  205 +
  206 + std::cout << "FNR: " << FPR << std::endl; //print false alarms and misses
  207 + std::cout << "FPR: " << FNR << std::endl;
  208 +}
  209 +
  210 +// Output an advertisement for the lab, authors, and usage information
96 211 void advertise(){
97   - //output advertisement
98 212 std::cout<<std::endl<<std::endl;
99 213 std::cout<<"========================================================================="<<std::endl;
100 214 std::cout<<"Thank you for using the NetMets network comparison tool!"<<std::endl;
... ... @@ -107,94 +221,32 @@ void advertise(){
107 221 std::cout<<" compare two files with a tolerance of 10 (units defined by the network)"<<std::endl;
108 222 std::cout<<" netmets file1 --gui"<<std::endl<<std::endl;
109 223 std::cout<<" load a file and display it using OpenGL"<<std::endl;
110   -
111   -}
112   -
113   -void compare(float sigma){
114   -
115   - // compare ground truth with truth and viceversa
116   - stim::network<float> cGT = GT.compare(T, sigma);
117   - stim::network<float> cT = T.compare(GT, sigma);
118   -
119   - //calculate the metrics
120   - float FPR = cGT.average(1);
121   - float FNR = cT.average(1);
122   - // print false alarms and misses
123   - std::cout << "FNR: " << FPR << std::endl;
124   - std::cout << "FPR: " << FNR << std::endl;
125   -}
126   -
127   -void glut_initialize(){
128   - float factor = 1.2;
129   -
130   - // init GLUT and create Window
131   - int myargc = 1;
132   - char* myargv[1];
133   - myargv [0]=strdup ("netmets");
134   -
135   - glutInit(&myargc, myargv);
136   - glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
137   - glutInitWindowPosition(100,100);
138   - glutInitWindowSize(320,320);
139   - glutCreateWindow("Lighthouse3D- GLUT Tutorial");
140   -
141   -
142   - // register callbacks
143   - glutDisplayFunc(glut_render);
144   - glutMouseFunc(glut_mouse);
145   - glutMotionFunc(glut_motion);
146   - glutReshapeFunc(glut_reshape);
147   -
148   - //set up the camera
149   - stim::vec<float> c = bb.center();
150   - //place the camera along the z-axis at a distance determined by the network size along x and y
151   - cam.setPosition(c + stim::vec<float>(0, 0, factor * std::max(bb.size()[0], bb.size()[1])));
152   - cam.LookAt(c[0], c[1], c[2]); //look at the center
153   -
154   -}
155   -
156   -void display(){
157   -
158   -
159   - //generate a bounding volume
160   - bb = GT.boundingbox();
161   -
162   - //create the GLUT window and set callback functions
163   - glut_initialize();
164   -
165   - glut_reshape(glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT));
166   -
167   - // enter GLUT event processing cycle
168   - glutMainLoop();
169 224 }
170 225  
171 226 int main(int argc, char* argv[])
172 227 {
173   - //create an instance of arglist
174   - stim::arglist args;
  228 + stim::arglist args; //create an instance of arglist
175 229  
176 230 //add arguments
177 231 args.add("help", "prints this help");
178 232 args.add("sigma", "force a sigma value to specify the tolerance of the network comparison", "10");
179 233 args.add("gui", "display the network or network comparison using OpenGL");
180 234  
181   - //parse the user arguments
182   - args.parse(argc, argv);
  235 + args.parse(argc, argv); //parse the user arguments
183 236  
184   - //test for help
185   - if(args["help"].is_set() || args.nargs() == 0){
186   - advertise();
187   - std::cout<<args.str();
188   - exit(1);
  237 + if(args["help"].is_set() || args.nargs() == 0){ //test for help
  238 + advertise(); //output the advertisement
  239 + std::cout<<args.str(); //output arguments
  240 + exit(1); //exit
189 241 }
190   -
191   - //if one file is specified, load it as the ground truth
192   - if(args.nargs() >= 1){
193   - GT.load_obj(args.arg(0));
  242 +
  243 + if(args.nargs() >= 1){ //if at least one network file is specified
  244 + num_nets = 1; //set the number of networks to one
  245 + GT.load_obj(args.arg(0)); //load the specified file as the ground truth
194 246 }
195   -
196   - //if two files are provided, compare them
197   - if(args.nargs() == 2){
  247 +
  248 + if(args.nargs() == 2){ //if two files are specified, they will be displayed in neighboring viewports and compared
  249 + num_nets = 2; //set the number of networks to two
198 250 float sigma = args["sigma"].as_float(); //get the sigma value from the user
199 251 T.load_obj(args.arg(1)); //load the second (test) network
200 252  
... ... @@ -205,9 +257,9 @@ int main(int argc, char* argv[])
205 257 }
206 258  
207 259 //if a GUI is requested, display the network using OpenGL
208   - if(args["gui"].is_set())
209   - display();
210   -
211   -
212   -
  260 + if(args["gui"].is_set()){
  261 + bb = GT.boundingbox(); //generate a bounding volume
  262 + glut_initialize(); //create the GLUT window and set callback functions
  263 + glutMainLoop(); // enter GLUT event processing cycle
  264 + }
213 265 }
214 266 \ No newline at end of file
... ...