Commit 627eed8df6c5094b4678fc129722edd37c0999b5
1 parent
18fad6bc
added a GUI for displaying networks
Showing
3 changed files
with
387 additions
and
28 deletions
Show diff stats
CMakeLists.txt
@@ -21,6 +21,10 @@ endif(NOT STIM_INCLUDE_DIRS) | @@ -21,6 +21,10 @@ endif(NOT STIM_INCLUDE_DIRS) | ||
21 | #find BOOST | 21 | #find BOOST |
22 | find_package(Boost REQUIRED) | 22 | find_package(Boost REQUIRED) |
23 | 23 | ||
24 | +#find the GLUT library for visualization | ||
25 | +find_package(OpenGL REQUIRED) | ||
26 | +find_package(GLUT REQUIRED) | ||
27 | + | ||
24 | #find the pthreads package | 28 | #find the pthreads package |
25 | find_package(Threads) | 29 | find_package(Threads) |
26 | 30 | ||
@@ -37,8 +41,10 @@ if ( MSVC ) | @@ -37,8 +41,10 @@ if ( MSVC ) | ||
37 | endif ( MSVC ) | 41 | endif ( MSVC ) |
38 | 42 | ||
39 | include_directories( | 43 | include_directories( |
44 | + ${OpenGL_INCLUDE_DIRS} | ||
45 | + ${GLUT_INCLUDE_DIR} | ||
40 | ${STIM_INCLUDE_DIRS} | 46 | ${STIM_INCLUDE_DIRS} |
41 | - ${ANN_INCLUDE_DIR} | 47 | + ${ANN_INCLUDE_DIR} |
42 | ${Boost_INCLUDE_DIR} | 48 | ${Boost_INCLUDE_DIR} |
43 | ) | 49 | ) |
44 | 50 | ||
@@ -54,8 +60,10 @@ add_executable(netmets | @@ -54,8 +60,10 @@ add_executable(netmets | ||
54 | 60 | ||
55 | #set the link libraries | 61 | #set the link libraries |
56 | target_link_libraries(netmets | 62 | target_link_libraries(netmets |
63 | + ${OpenGL_LIBRARIES} | ||
64 | + ${GLUT_LIBRARIES} | ||
57 | ${CMAKE_THREAD_LIBS_INIT} | 65 | ${CMAKE_THREAD_LIBS_INIT} |
58 | - ${ANN_LIBRARY} | 66 | + ${ANN_LIBRARY} |
59 | ${X11_LIBRARIES} | 67 | ${X11_LIBRARIES} |
60 | ) | 68 | ) |
61 | 69 |
1 | +#.rst: | ||
2 | +# FindGLUT | ||
3 | +# -------- | ||
4 | +# | ||
5 | +# try to find glut library and include files. | ||
6 | +# | ||
7 | +# IMPORTED Targets | ||
8 | +# ^^^^^^^^^^^^^^^^ | ||
9 | +# | ||
10 | +# This module defines the :prop_tgt:`IMPORTED` targets: | ||
11 | +# | ||
12 | +# ``GLUT::GLUT`` | ||
13 | +# Defined if the system has GLUT. | ||
14 | +# | ||
15 | +# Result Variables | ||
16 | +# ^^^^^^^^^^^^^^^^ | ||
17 | +# | ||
18 | +# This module sets the following variables: | ||
19 | +# | ||
20 | +# :: | ||
21 | +# | ||
22 | +# GLUT_INCLUDE_DIR, where to find GL/glut.h, etc. | ||
23 | +# GLUT_LIBRARIES, the libraries to link against | ||
24 | +# GLUT_FOUND, If false, do not try to use GLUT. | ||
25 | +# | ||
26 | +# Also defined, but not for general use are: | ||
27 | +# | ||
28 | +# :: | ||
29 | +# | ||
30 | +# GLUT_glut_LIBRARY = the full path to the glut library. | ||
31 | +# GLUT_Xmu_LIBRARY = the full path to the Xmu library. | ||
32 | +# GLUT_Xi_LIBRARY = the full path to the Xi Library. | ||
33 | + | ||
34 | +#============================================================================= | ||
35 | +# Copyright 2001-2009 Kitware, Inc. | ||
36 | +# | ||
37 | +# Distributed under the OSI-approved BSD License (the "License"); | ||
38 | +# see accompanying file Copyright.txt for details. | ||
39 | +# | ||
40 | +# This software is distributed WITHOUT ANY WARRANTY; without even the | ||
41 | +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
42 | +# See the License for more information. | ||
43 | +#============================================================================= | ||
44 | +# (To distribute this file outside of CMake, substitute the full | ||
45 | +# License text for the above reference.) | ||
46 | + | ||
47 | +if (WIN32) | ||
48 | + find_path( GLUT_INCLUDE_DIR NAMES GL/glut.h | ||
49 | + PATHS $ENV{GLUT_ROOT_PATH}/include ) | ||
50 | + find_library( GLUT_glut_LIBRARY NAMES glut glut32 freeglut | ||
51 | + PATHS | ||
52 | + ${OPENGL_LIBRARY_DIR} | ||
53 | + $ENV{GLUT_ROOT_PATH}/lib | ||
54 | + ) | ||
55 | +else () | ||
56 | + | ||
57 | + if (APPLE) | ||
58 | + find_path(GLUT_INCLUDE_DIR glut.h ${OPENGL_LIBRARY_DIR}) | ||
59 | + find_library(GLUT_glut_LIBRARY GLUT DOC "GLUT library for OSX") | ||
60 | + find_library(GLUT_cocoa_LIBRARY Cocoa DOC "Cocoa framework for OSX") | ||
61 | + | ||
62 | + if(GLUT_cocoa_LIBRARY AND NOT TARGET GLUT::Cocoa) | ||
63 | + add_library(GLUT::Cocoa UNKNOWN IMPORTED) | ||
64 | + # Cocoa should always be a Framework, but we check to make sure. | ||
65 | + if(GLUT_cocoa_LIBRARY MATCHES "/([^/]+)\\.framework$") | ||
66 | + set_target_properties(GLUT::Cocoa PROPERTIES | ||
67 | + IMPORTED_LOCATION "${GLUT_cocoa_LIBRARY}/${CMAKE_MATCH_1}") | ||
68 | + else() | ||
69 | + set_target_properties(GLUT::Cocoa PROPERTIES | ||
70 | + IMPORTED_LOCATION "${GLUT_cocoa_LIBRARY}") | ||
71 | + endif() | ||
72 | + endif() | ||
73 | + else () | ||
74 | + | ||
75 | + if (BEOS) | ||
76 | + | ||
77 | + set(_GLUT_INC_DIR /boot/develop/headers/os/opengl) | ||
78 | + set(_GLUT_glut_LIB_DIR /boot/develop/lib/x86) | ||
79 | + | ||
80 | + else() | ||
81 | + | ||
82 | + find_library( GLUT_Xi_LIBRARY Xi | ||
83 | + /usr/openwin/lib | ||
84 | + ) | ||
85 | + | ||
86 | + find_library( GLUT_Xmu_LIBRARY Xmu | ||
87 | + /usr/openwin/lib | ||
88 | + ) | ||
89 | + | ||
90 | + if(GLUT_Xi_LIBRARY AND NOT TARGET GLUT::Xi) | ||
91 | + add_library(GLUT::Xi UNKNOWN IMPORTED) | ||
92 | + set_target_properties(GLUT::Xi PROPERTIES | ||
93 | + IMPORTED_LOCATION "${GLUT_Xi_LIBRARY}") | ||
94 | + endif() | ||
95 | + | ||
96 | + if(GLUT_Xmu_LIBRARY AND NOT TARGET GLUT::Xmu) | ||
97 | + add_library(GLUT::Xmu UNKNOWN IMPORTED) | ||
98 | + set_target_properties(GLUT::Xmu PROPERTIES | ||
99 | + IMPORTED_LOCATION "${GLUT_Xmu_LIBRARY}") | ||
100 | + endif() | ||
101 | + | ||
102 | + endif () | ||
103 | + | ||
104 | + find_path( GLUT_INCLUDE_DIR GL/glut.h | ||
105 | + /usr/include/GL | ||
106 | + /usr/openwin/share/include | ||
107 | + /usr/openwin/include | ||
108 | + /opt/graphics/OpenGL/include | ||
109 | + /opt/graphics/OpenGL/contrib/libglut | ||
110 | + ${_GLUT_INC_DIR} | ||
111 | + ) | ||
112 | + | ||
113 | + find_library( GLUT_glut_LIBRARY glut | ||
114 | + /usr/openwin/lib | ||
115 | + ${_GLUT_glut_LIB_DIR} | ||
116 | + ) | ||
117 | + | ||
118 | + unset(_GLUT_INC_DIR) | ||
119 | + unset(_GLUT_glut_LIB_DIR) | ||
120 | + | ||
121 | + endif () | ||
122 | + | ||
123 | +endif () | ||
124 | + | ||
125 | +FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLUT REQUIRED_VARS GLUT_glut_LIBRARY GLUT_INCLUDE_DIR) | ||
126 | + | ||
127 | +if (GLUT_FOUND) | ||
128 | + # Is -lXi and -lXmu required on all platforms that have it? | ||
129 | + # If not, we need some way to figure out what platform we are on. | ||
130 | + set( GLUT_LIBRARIES | ||
131 | + ${GLUT_glut_LIBRARY} | ||
132 | + ${GLUT_Xmu_LIBRARY} | ||
133 | + ${GLUT_Xi_LIBRARY} | ||
134 | + ${GLUT_cocoa_LIBRARY} | ||
135 | + ) | ||
136 | + | ||
137 | + if(NOT TARGET GLUT::GLUT) | ||
138 | + add_library(GLUT::GLUT UNKNOWN IMPORTED) | ||
139 | + set_target_properties(GLUT::GLUT PROPERTIES | ||
140 | + INTERFACE_INCLUDE_DIRECTORIES "${GLUT_INCLUDE_DIR}") | ||
141 | + if(GLUT_glut_LIBRARY MATCHES "/([^/]+)\\.framework$") | ||
142 | + set_target_properties(GLUT::GLUT PROPERTIES | ||
143 | + IMPORTED_LOCATION "${GLUT_glut_LIBRARY}/${CMAKE_MATCH_1}") | ||
144 | + else() | ||
145 | + set_target_properties(GLUT::GLUT PROPERTIES | ||
146 | + IMPORTED_LOCATION "${GLUT_glut_LIBRARY}") | ||
147 | + endif() | ||
148 | + | ||
149 | + if(TARGET GLUT::Xmu) | ||
150 | + set_property(TARGET GLUT::GLUT APPEND | ||
151 | + PROPERTY INTERFACE_LINK_LIBRARIES GLUT::Xmu) | ||
152 | + endif() | ||
153 | + | ||
154 | + if(TARGET GLUT::Xi) | ||
155 | + set_property(TARGET GLUT::GLUT APPEND | ||
156 | + PROPERTY INTERFACE_LINK_LIBRARIES GLUT::Xi) | ||
157 | + endif() | ||
158 | + | ||
159 | + if(TARGET GLUT::Cocoa) | ||
160 | + set_property(TARGET GLUT::GLUT APPEND | ||
161 | + PROPERTY INTERFACE_LINK_LIBRARIES GLUT::Cocoa) | ||
162 | + endif() | ||
163 | + endif() | ||
164 | + | ||
165 | + #The following deprecated settings are for backwards compatibility with CMake1.4 | ||
166 | + set (GLUT_LIBRARY ${GLUT_LIBRARIES}) | ||
167 | + set (GLUT_INCLUDE_PATH ${GLUT_INCLUDE_DIR}) | ||
168 | +endif() | ||
169 | + | ||
170 | +mark_as_advanced( | ||
171 | + GLUT_INCLUDE_DIR | ||
172 | + GLUT_glut_LIBRARY | ||
173 | + GLUT_Xmu_LIBRARY | ||
174 | + GLUT_Xi_LIBRARY | ||
175 | + ) |
main.cpp
@@ -2,44 +2,220 @@ | @@ -2,44 +2,220 @@ | ||
2 | #include <string> | 2 | #include <string> |
3 | #include <fstream> | 3 | #include <fstream> |
4 | #include <algorithm> | 4 | #include <algorithm> |
5 | -#include <stim/biomodels/network.h> | ||
6 | 5 | ||
6 | +//OpenGL includes | ||
7 | +#include <GL/glut.h> | ||
8 | + | ||
9 | +//STIM includes | ||
10 | +#include <stim/visualization/gl_network.h> | ||
11 | +#include <stim/visualization/gl_aabb.h> | ||
12 | +#include <stim/parser/arguments.h> | ||
13 | +#include <stim/visualization/camera.h> | ||
14 | + | ||
15 | +//ANN includes | ||
7 | #include <ANN/ANN.h> | 16 | #include <ANN/ANN.h> |
17 | + | ||
18 | +//BOOST includes | ||
8 | #include <boost/tuple/tuple.hpp> | 19 | #include <boost/tuple/tuple.hpp> |
9 | -using namespace stim; | ||
10 | -//template <typename T> | ||
11 | -network<float>* network1; | ||
12 | 20 | ||
21 | +stim::gl_aabb<float> bb; | ||
22 | +stim::camera cam; | ||
23 | + | ||
24 | +stim::gl_network<float> GT; | ||
25 | +stim::gl_network<float> T; | ||
26 | + | ||
27 | +//hard-coded parameters | ||
28 | +float resample_rate = 0.5; | ||
29 | + | ||
30 | +//mouse position tracking | ||
31 | +int mouse_x; | ||
32 | +int mouse_y; | ||
33 | + | ||
34 | +void glut_render(void) { | ||
35 | + | ||
36 | + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||
37 | + | ||
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(); | ||
43 | + | ||
44 | + gluLookAt(eye[0], eye[1], eye[2], focus[0], focus[1], focus[2], up[0], up[1], up[2]); | ||
45 | + | ||
46 | + | ||
47 | + | ||
48 | + // render the bounding box | ||
49 | + glColor3f(0.0, 0.0, 1.0); | ||
50 | + glBegin(GL_LINE_LOOP); | ||
51 | + bb.glPointsCW(); | ||
52 | + glEnd(); | ||
53 | + | ||
54 | + //render the GT network (red) | ||
55 | + glColor3f(1.0, 0.0, 0.0); | ||
56 | + GT.glCenterline(); | ||
57 | + | ||
58 | + //render the T network (green) | ||
59 | + glColor3f(0.0, 1.0, 0.0); | ||
60 | + T.glCenterline(); | ||
61 | + | ||
62 | + glutSwapBuffers(); | ||
63 | +} | ||
64 | + | ||
65 | +// defines camera motion based on mouse dragging | ||
66 | +void glut_motion(int x, int y){ | ||
67 | + float factor = 0.01; | ||
68 | + | ||
69 | + float theta = factor * (mouse_x - x); | ||
70 | + float phi = factor * (y - mouse_y); | ||
71 | + | ||
72 | + cam.OrbitFocus(theta, phi); | ||
73 | + | ||
74 | + mouse_x = x; | ||
75 | + mouse_y = y; | ||
76 | + | ||
77 | + glutPostRedisplay(); | ||
78 | +} | ||
79 | + | ||
80 | +// sets the mouse position when clicked | ||
81 | +void glut_mouse(int button, int state, int x, int y){ | ||
82 | + mouse_x = x; | ||
83 | + mouse_y = y; | ||
84 | +} | ||
85 | + | ||
86 | +// re-calculates the projection matrix if the window is reshaped | ||
87 | +void glut_reshape(int x, int y){ | ||
88 | + | ||
89 | + glMatrixMode(GL_PROJECTION); | ||
90 | + glLoadIdentity(); | ||
91 | + glViewport(0, 0, x, y); | ||
92 | + float aspect = (float)x / (float)y; | ||
93 | + gluPerspective(60, aspect, 0.1, 1000000); | ||
94 | + | ||
95 | +} | ||
96 | + | ||
97 | +void advertise(){ | ||
98 | + //output advertisement | ||
99 | + std::cout<<std::endl<<std::endl; | ||
100 | + std::cout<<"========================================================================="<<std::endl; | ||
101 | + std::cout<<"Thank you for using the NetMets network comparison tool!"<<std::endl; | ||
102 | + std::cout<<"Scalable Tissue Imaging and Modeling (STIM) Lab, University of Houston"<<std::endl; | ||
103 | + std::cout<<"Developers: Pranathi Vemuri, David Mayerich"<<std::endl; | ||
104 | + std::cout<<"Source: https://git.stim.ee.uh.edu/segmentation/netmets"<<std::endl; | ||
105 | + std::cout<<"========================================================================="<<std::endl<<std::endl; | ||
106 | + | ||
107 | + std::cout<<"usage: netmets file1 file2 --sigma 10"<<std::endl; | ||
108 | + std::cout<<" compare two files with a tolerance of 10 (units defined by the network)"<<std::endl; | ||
109 | + std::cout<<" netmets file1 --gui"<<std::endl<<std::endl; | ||
110 | + std::cout<<" load a file and display it using OpenGL"<<std::endl; | ||
111 | + | ||
112 | +} | ||
113 | + | ||
114 | +void compare(float sigma){ | ||
115 | + | ||
116 | + // compare ground truth with truth and viceversa | ||
117 | + stim::network<float> cGT = GT.compare(T, sigma); | ||
118 | + stim::network<float> cT = T.compare(GT, sigma); | ||
119 | + | ||
120 | + //calculate the metrics | ||
121 | + float FPR = cGT.average(1); | ||
122 | + float FNR = cT.average(1); | ||
123 | + // print false alarms and misses | ||
124 | + std::cout << "FNR: " << FPR << std::endl; | ||
125 | + std::cout << "FPR: " << FNR << std::endl; | ||
126 | +} | ||
127 | + | ||
128 | +void glut_initialize(){ | ||
129 | + float factor = 1.2; | ||
130 | + | ||
131 | + // init GLUT and create Window | ||
132 | + int myargc = 1; | ||
133 | + char* myargv[1]; | ||
134 | + myargv [0]=strdup ("netmets"); | ||
135 | + | ||
136 | + glutInit(&myargc, myargv); | ||
137 | + glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); | ||
138 | + glutInitWindowPosition(100,100); | ||
139 | + glutInitWindowSize(320,320); | ||
140 | + glutCreateWindow("Lighthouse3D- GLUT Tutorial"); | ||
141 | + | ||
142 | + | ||
143 | + // register callbacks | ||
144 | + glutDisplayFunc(glut_render); | ||
145 | + glutMouseFunc(glut_mouse); | ||
146 | + glutMotionFunc(glut_motion); | ||
147 | + glutReshapeFunc(glut_reshape); | ||
148 | + | ||
149 | + //set up the camera | ||
150 | + stim::vec<float> c = bb.center(); | ||
151 | + //place the camera along the z-axis at a distance determined by the network size along x and y | ||
152 | + cam.setPosition(c + stim::vec<float>(0, 0, factor * std::max(bb.size()[0], bb.size()[1]))); | ||
153 | + cam.LookAt(c[0], c[1], c[2]); //look at the center | ||
154 | + | ||
155 | +} | ||
156 | + | ||
157 | +void display(){ | ||
158 | + | ||
159 | + | ||
160 | + //generate a bounding volume | ||
161 | + bb = GT.boundingbox(); | ||
162 | + | ||
163 | + std::cout<<bb.str()<<std::endl; | ||
164 | + | ||
165 | + std::cout<<"center: "<<bb.center().str()<<std::endl; | ||
166 | + std::cout<<"size: "<<bb.size().str()<<std::endl; | ||
167 | + | ||
168 | + //create the GLUT window and set callback functions | ||
169 | + glut_initialize(); | ||
170 | + | ||
171 | + glut_reshape(glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT)); | ||
172 | + | ||
173 | + std::cout<<cam.str()<<std::endl; | ||
174 | + | ||
175 | + // enter GLUT event processing cycle | ||
176 | + glutMainLoop(); | ||
177 | +} | ||
13 | 178 | ||
14 | int main(int argc, char* argv[]) | 179 | int main(int argc, char* argv[]) |
15 | { | 180 | { |
16 | - if(argc < 4){ | ||
17 | - std::cout<<"Please specify a ground truth and test case"<<std::endl; | 181 | + //create an instance of arglist |
182 | + stim::arglist args; | ||
183 | + | ||
184 | + //add arguments | ||
185 | + args.add("help", "prints this help"); | ||
186 | + args.add("sigma", "force a sigma value to specify the tolerance of the network comparison", "10"); | ||
187 | + args.add("gui", "display the network or network comparison using OpenGL"); | ||
188 | + | ||
189 | + //parse the user arguments | ||
190 | + args.parse(argc, argv); | ||
191 | + | ||
192 | + //test for help | ||
193 | + if(args["help"].is_set() || args.nargs() == 0){ | ||
194 | + advertise(); | ||
195 | + std::cout<<args.str(); | ||
18 | exit(1); | 196 | exit(1); |
19 | } | 197 | } |
20 | 198 | ||
21 | - float resample_rate = 0.1; | 199 | + //if one file is specified, load it as the ground truth |
200 | + if(args.nargs() >= 1){ | ||
201 | + GT.load_obj(args.arg(0)); | ||
202 | + } | ||
22 | 203 | ||
23 | - float sigma = atof(argv[3]); | ||
24 | - stim::network<float> GT;stim::network<float> T; | ||
25 | - // load obj files to 3D network class | ||
26 | - | ||
27 | - //load the ground truth and test case networks | ||
28 | - GT.load_obj(argv[1]); | ||
29 | - T.load_obj(argv[2]); | 204 | + //if two files are provided, compare them |
205 | + if(args.nargs() == 2){ | ||
206 | + float sigma = args["sigma"].as_float(); //get the sigma value from the user | ||
207 | + T.load_obj(args.arg(1)); //load the second (test) network | ||
30 | 208 | ||
31 | - // resample the loaded networks | ||
32 | - stim::network<float> resampled_GT; | ||
33 | - stim::network<float> resampled_T; | 209 | + GT = GT.resample(resample_rate * sigma); //resample both networks based on the sigma value |
210 | + T = T.resample(resample_rate * sigma); | ||
34 | 211 | ||
35 | - resampled_GT = GT.resample(sigma * resample_rate); | ||
36 | - resampled_T = T.resample(sigma * resample_rate); | 212 | + compare(sigma); //run the comparison algorithm |
213 | + } | ||
37 | 214 | ||
38 | - // compare ground truth with truth and viceversa | ||
39 | - float gFPR, gFNR; | ||
40 | - gFPR = resampled_GT.compare(resampled_T, sigma); | ||
41 | - gFNR = resampled_T.compare(resampled_GT, sigma); | ||
42 | - // print false alarms and misses | ||
43 | - std::cout << "False postive rate is " << gFPR << std::endl; | ||
44 | - std::cout << "False negative rate is " << gFNR << std::endl; | 215 | + //if a GUI is requested, display the network using OpenGL |
216 | + if(args["gui"].is_set()) | ||
217 | + display(); | ||
218 | + | ||
219 | + | ||
220 | + | ||
45 | } | 221 | } |
46 | \ No newline at end of file | 222 | \ No newline at end of file |